cryptonite_decaf_error_t cryptonite_decaf_ed448_verify ( const uint8_t signature[CRYPTONITE_DECAF_EDDSA_448_SIGNATURE_BYTES], const uint8_t pubkey[CRYPTONITE_DECAF_EDDSA_448_PUBLIC_BYTES], const uint8_t *message, size_t message_len, uint8_t prehashed, const uint8_t *context, uint8_t context_len ) { API_NS(point_t) pk_point, r_point; cryptonite_decaf_error_t error = API_NS(point_decode_like_eddsa_and_ignore_cofactor)(pk_point,pubkey); if (CRYPTONITE_DECAF_SUCCESS != error) { return error; } error = API_NS(point_decode_like_eddsa_and_ignore_cofactor)(r_point,signature); if (CRYPTONITE_DECAF_SUCCESS != error) { return error; } API_NS(scalar_t) challenge_scalar; { /* Compute the challenge */ hash_ctx_t hash; hash_init_with_dom(hash,prehashed,0,context,context_len); hash_update(hash,signature,CRYPTONITE_DECAF_EDDSA_448_PUBLIC_BYTES); hash_update(hash,pubkey,CRYPTONITE_DECAF_EDDSA_448_PUBLIC_BYTES); hash_update(hash,message,message_len); uint8_t challenge[2*CRYPTONITE_DECAF_EDDSA_448_PRIVATE_BYTES]; hash_final(hash,challenge,sizeof(challenge)); hash_destroy(hash); API_NS(scalar_decode_long)(challenge_scalar,challenge,sizeof(challenge)); cryptonite_decaf_bzero(challenge,sizeof(challenge)); } API_NS(scalar_sub)(challenge_scalar, API_NS(scalar_zero), challenge_scalar); API_NS(scalar_t) response_scalar; API_NS(scalar_decode_long)( response_scalar, &signature[CRYPTONITE_DECAF_EDDSA_448_PUBLIC_BYTES], CRYPTONITE_DECAF_EDDSA_448_PRIVATE_BYTES ); #if EDDSA_BASE_POINT_RATIO == 2 API_NS(scalar_add)(response_scalar,response_scalar,response_scalar); #endif /* pk_point = -c(x(P)) + (cx + k)G = kG */ API_NS(base_double_scalarmul_non_secret)( pk_point, response_scalar, pk_point, challenge_scalar ); return cryptonite_decaf_succeed_if(API_NS(point_eq(pk_point,r_point))); }
c448_error_t c448_ed448_verify( const uint8_t signature[EDDSA_448_SIGNATURE_BYTES], const uint8_t pubkey[EDDSA_448_PUBLIC_BYTES], const uint8_t *message, size_t message_len, uint8_t prehashed, const uint8_t *context, uint8_t context_len) { curve448_point_t pk_point, r_point; c448_error_t error; curve448_scalar_t challenge_scalar; curve448_scalar_t response_scalar; /* Order in little endian format */ static const uint8_t order[] = { 0xF3, 0x44, 0x58, 0xAB, 0x92, 0xC2, 0x78, 0x23, 0x55, 0x8F, 0xC5, 0x8D, 0x72, 0xC2, 0x6C, 0x21, 0x90, 0x36, 0xD6, 0xAE, 0x49, 0xDB, 0x4E, 0xC4, 0xE9, 0x23, 0xCA, 0x7C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00 }; int i; /* * Check that s (second 57 bytes of the sig) is less than the order. Both * s and the order are in little-endian format. This can be done in * variable time, since if this is not the case the signature if publicly * invalid. */ for (i = EDDSA_448_PUBLIC_BYTES - 1; i >= 0; i--) { if (signature[i + EDDSA_448_PUBLIC_BYTES] > order[i]) return C448_FAILURE; if (signature[i + EDDSA_448_PUBLIC_BYTES] < order[i]) break; } if (i < 0) return C448_FAILURE; error = curve448_point_decode_like_eddsa_and_mul_by_ratio(pk_point, pubkey); if (C448_SUCCESS != error) return error; error = curve448_point_decode_like_eddsa_and_mul_by_ratio(r_point, signature); if (C448_SUCCESS != error) return error; { /* Compute the challenge */ EVP_MD_CTX *hashctx = EVP_MD_CTX_new(); uint8_t challenge[2 * EDDSA_448_PRIVATE_BYTES]; if (hashctx == NULL || !hash_init_with_dom(hashctx, prehashed, 0, context, context_len) || !EVP_DigestUpdate(hashctx, signature, EDDSA_448_PUBLIC_BYTES) || !EVP_DigestUpdate(hashctx, pubkey, EDDSA_448_PUBLIC_BYTES) || !EVP_DigestUpdate(hashctx, message, message_len) || !EVP_DigestFinalXOF(hashctx, challenge, sizeof(challenge))) { EVP_MD_CTX_free(hashctx); return C448_FAILURE; } EVP_MD_CTX_free(hashctx); curve448_scalar_decode_long(challenge_scalar, challenge, sizeof(challenge)); OPENSSL_cleanse(challenge, sizeof(challenge)); } curve448_scalar_sub(challenge_scalar, curve448_scalar_zero, challenge_scalar); curve448_scalar_decode_long(response_scalar, &signature[EDDSA_448_PUBLIC_BYTES], EDDSA_448_PRIVATE_BYTES); /* pk_point = -c(x(P)) + (cx + k)G = kG */ curve448_base_double_scalarmul_non_secret(pk_point, response_scalar, pk_point, challenge_scalar); return c448_succeed_if(curve448_point_eq(pk_point, r_point)); }
void cryptonite_decaf_ed448_sign ( uint8_t signature[CRYPTONITE_DECAF_EDDSA_448_SIGNATURE_BYTES], const uint8_t privkey[CRYPTONITE_DECAF_EDDSA_448_PRIVATE_BYTES], const uint8_t pubkey[CRYPTONITE_DECAF_EDDSA_448_PUBLIC_BYTES], const uint8_t *message, size_t message_len, uint8_t prehashed, const uint8_t *context, uint8_t context_len ) { API_NS(scalar_t) secret_scalar; hash_ctx_t hash; { /* Schedule the secret key */ struct { uint8_t secret_scalar_ser[CRYPTONITE_DECAF_EDDSA_448_PRIVATE_BYTES]; uint8_t seed[CRYPTONITE_DECAF_EDDSA_448_PRIVATE_BYTES]; } __attribute__((packed)) expanded; hash_hash( (uint8_t *)&expanded, sizeof(expanded), privkey, CRYPTONITE_DECAF_EDDSA_448_PRIVATE_BYTES ); clamp(expanded.secret_scalar_ser); API_NS(scalar_decode_long)(secret_scalar, expanded.secret_scalar_ser, sizeof(expanded.secret_scalar_ser)); /* Hash to create the nonce */ hash_init_with_dom(hash,prehashed,0,context,context_len); hash_update(hash,expanded.seed,sizeof(expanded.seed)); hash_update(hash,message,message_len); cryptonite_decaf_bzero(&expanded, sizeof(expanded)); } /* Decode the nonce */ API_NS(scalar_t) nonce_scalar; { uint8_t nonce[2*CRYPTONITE_DECAF_EDDSA_448_PRIVATE_BYTES]; hash_final(hash,nonce,sizeof(nonce)); API_NS(scalar_decode_long)(nonce_scalar, nonce, sizeof(nonce)); cryptonite_decaf_bzero(nonce, sizeof(nonce)); } uint8_t nonce_point[CRYPTONITE_DECAF_EDDSA_448_PUBLIC_BYTES] = {0}; { /* Scalarmul to create the nonce-point */ API_NS(scalar_t) nonce_scalar_2; API_NS(scalar_halve)(nonce_scalar_2,nonce_scalar); for (unsigned int c = 2*EDDSA_BASE_POINT_RATIO; c < COFACTOR; c <<= 1) { API_NS(scalar_halve)(nonce_scalar_2,nonce_scalar_2); } API_NS(point_t) p; API_NS(precomputed_scalarmul)(p,API_NS(precomputed_base),nonce_scalar_2); API_NS(point_mul_by_cofactor_and_encode_like_eddsa)(nonce_point, p); API_NS(point_destroy)(p); API_NS(scalar_destroy)(nonce_scalar_2); } API_NS(scalar_t) challenge_scalar; { /* Compute the challenge */ hash_init_with_dom(hash,prehashed,0,context,context_len); hash_update(hash,nonce_point,sizeof(nonce_point)); hash_update(hash,pubkey,CRYPTONITE_DECAF_EDDSA_448_PUBLIC_BYTES); hash_update(hash,message,message_len); uint8_t challenge[2*CRYPTONITE_DECAF_EDDSA_448_PRIVATE_BYTES]; hash_final(hash,challenge,sizeof(challenge)); hash_destroy(hash); API_NS(scalar_decode_long)(challenge_scalar,challenge,sizeof(challenge)); cryptonite_decaf_bzero(challenge,sizeof(challenge)); } API_NS(scalar_mul)(challenge_scalar,challenge_scalar,secret_scalar); API_NS(scalar_add)(challenge_scalar,challenge_scalar,nonce_scalar); cryptonite_decaf_bzero(signature,CRYPTONITE_DECAF_EDDSA_448_SIGNATURE_BYTES); memcpy(signature,nonce_point,sizeof(nonce_point)); API_NS(scalar_encode)(&signature[CRYPTONITE_DECAF_EDDSA_448_PUBLIC_BYTES],challenge_scalar); API_NS(scalar_destroy)(secret_scalar); API_NS(scalar_destroy)(nonce_scalar); API_NS(scalar_destroy)(challenge_scalar); }
c448_error_t c448_ed448_sign( uint8_t signature[EDDSA_448_SIGNATURE_BYTES], const uint8_t privkey[EDDSA_448_PRIVATE_BYTES], const uint8_t pubkey[EDDSA_448_PUBLIC_BYTES], const uint8_t *message, size_t message_len, uint8_t prehashed, const uint8_t *context, size_t context_len) { curve448_scalar_t secret_scalar; EVP_MD_CTX *hashctx = EVP_MD_CTX_new(); c448_error_t ret = C448_FAILURE; curve448_scalar_t nonce_scalar; uint8_t nonce_point[EDDSA_448_PUBLIC_BYTES] = { 0 }; unsigned int c; curve448_scalar_t challenge_scalar; if (hashctx == NULL) return C448_FAILURE; { /* * Schedule the secret key, First EDDSA_448_PRIVATE_BYTES is serialised * secret scalar,next EDDSA_448_PRIVATE_BYTES bytes is the seed. */ uint8_t expanded[EDDSA_448_PRIVATE_BYTES * 2]; if (!oneshot_hash(expanded, sizeof(expanded), privkey, EDDSA_448_PRIVATE_BYTES)) goto err; clamp(expanded); curve448_scalar_decode_long(secret_scalar, expanded, EDDSA_448_PRIVATE_BYTES); /* Hash to create the nonce */ if (!hash_init_with_dom(hashctx, prehashed, 0, context, context_len) || !EVP_DigestUpdate(hashctx, expanded + EDDSA_448_PRIVATE_BYTES, EDDSA_448_PRIVATE_BYTES) || !EVP_DigestUpdate(hashctx, message, message_len)) { OPENSSL_cleanse(expanded, sizeof(expanded)); goto err; } OPENSSL_cleanse(expanded, sizeof(expanded)); } /* Decode the nonce */ { uint8_t nonce[2 * EDDSA_448_PRIVATE_BYTES]; if (!EVP_DigestFinalXOF(hashctx, nonce, sizeof(nonce))) goto err; curve448_scalar_decode_long(nonce_scalar, nonce, sizeof(nonce)); OPENSSL_cleanse(nonce, sizeof(nonce)); } { /* Scalarmul to create the nonce-point */ curve448_scalar_t nonce_scalar_2; curve448_point_t p; curve448_scalar_halve(nonce_scalar_2, nonce_scalar); for (c = 2; c < C448_EDDSA_ENCODE_RATIO; c <<= 1) curve448_scalar_halve(nonce_scalar_2, nonce_scalar_2); curve448_precomputed_scalarmul(p, curve448_precomputed_base, nonce_scalar_2); curve448_point_mul_by_ratio_and_encode_like_eddsa(nonce_point, p); curve448_point_destroy(p); curve448_scalar_destroy(nonce_scalar_2); } { uint8_t challenge[2 * EDDSA_448_PRIVATE_BYTES]; /* Compute the challenge */ if (!hash_init_with_dom(hashctx, prehashed, 0, context, context_len) || !EVP_DigestUpdate(hashctx, nonce_point, sizeof(nonce_point)) || !EVP_DigestUpdate(hashctx, pubkey, EDDSA_448_PUBLIC_BYTES) || !EVP_DigestUpdate(hashctx, message, message_len) || !EVP_DigestFinalXOF(hashctx, challenge, sizeof(challenge))) goto err; curve448_scalar_decode_long(challenge_scalar, challenge, sizeof(challenge)); OPENSSL_cleanse(challenge, sizeof(challenge)); } curve448_scalar_mul(challenge_scalar, challenge_scalar, secret_scalar); curve448_scalar_add(challenge_scalar, challenge_scalar, nonce_scalar); OPENSSL_cleanse(signature, EDDSA_448_SIGNATURE_BYTES); memcpy(signature, nonce_point, sizeof(nonce_point)); curve448_scalar_encode(&signature[EDDSA_448_PUBLIC_BYTES], challenge_scalar); curve448_scalar_destroy(secret_scalar); curve448_scalar_destroy(nonce_scalar); curve448_scalar_destroy(challenge_scalar); ret = C448_SUCCESS; err: EVP_MD_CTX_free(hashctx); return ret; }