@@ -1040,7 +1040,7 @@ decaf_error_t API_NS(direct_scalarmul) ( | |||
return succ; | |||
} | |||
void API_NS(point_mul_by_cofactor_and_encode_like_eddsa) ( | |||
void API_NS(point_mul_by_ratio_and_encode_like_eddsa) ( | |||
uint8_t enc[DECAF_EDDSA_25519_PUBLIC_BYTES], | |||
const point_t p | |||
) { | |||
@@ -1133,7 +1133,7 @@ void API_NS(point_mul_by_cofactor_and_encode_like_eddsa) ( | |||
} | |||
decaf_error_t API_NS(point_decode_like_eddsa_and_ignore_cofactor) ( | |||
decaf_error_t API_NS(point_decode_like_eddsa_and_mul_by_ratio) ( | |||
point_t p, | |||
const uint8_t enc[DECAF_EDDSA_25519_PUBLIC_BYTES] | |||
) { | |||
@@ -1352,13 +1352,16 @@ void decaf_x25519_generate_key ( | |||
decaf_x25519_derive_public_key(out,scalar); | |||
} | |||
void API_NS(point_mul_by_cofactor_and_encode_like_x25519) ( | |||
void API_NS(point_mul_by_ratio_and_encode_like_x25519) ( | |||
uint8_t out[X_PUBLIC_BYTES], | |||
const point_t p | |||
) { | |||
point_t q; | |||
#if COFACTOR == 8 | |||
point_double_internal(q,p,1); | |||
for (unsigned i=1; i<COFACTOR/4; i<<=1) point_double_internal(q,q,1); | |||
#else | |||
API_NS(point_copy)(q,p); | |||
#endif | |||
gf_invert(q->t,q->x,0); /* 1/x */ | |||
gf_mul(q->z,q->t,q->y); /* y/x */ | |||
gf_sqr(q->y,q->z); /* (y/x)^2 */ | |||
@@ -1384,24 +1387,13 @@ void decaf_x25519_derive_public_key ( | |||
scalar_t the_scalar; | |||
API_NS(scalar_decode_long)(the_scalar,scalar2,sizeof(scalar2)); | |||
/* We're gonna isogenize by 2, so divide by 2. | |||
* | |||
* Why by 2, even though it's a 4-isogeny? | |||
* | |||
* The isogeny map looks like | |||
* Montgomery <-2-> Jacobi <-2-> Edwards | |||
* | |||
* Since the Jacobi base point is the PREimage of the iso to | |||
* the Montgomery curve, and we're going | |||
* Jacobi -> Edwards -> Jacobi -> Montgomery, | |||
* we pick up only a factor of 2 over Jacobi -> Montgomery. | |||
*/ | |||
for (unsigned i=1; i<COFACTOR; i<<=1) { | |||
/* Compensate for the encoding ratio */ | |||
for (unsigned i=1; i<DECAF_X25519_ENCODE_RATIO; i<<=1) { | |||
API_NS(scalar_halve)(the_scalar,the_scalar); | |||
} | |||
point_t p; | |||
API_NS(precomputed_scalarmul)(p,API_NS(precomputed_base),the_scalar); | |||
API_NS(point_mul_by_cofactor_and_encode_like_x25519)(out,p); | |||
API_NS(point_mul_by_ratio_and_encode_like_x25519)(out,p); | |||
API_NS(point_destroy)(p); | |||
} | |||
@@ -31,6 +31,7 @@ | |||
#define NO_CONTEXT DECAF_EDDSA_25519_SUPPORTS_CONTEXTLESS_SIGS | |||
#define EDDSA_USE_SIGMA_ISOGENY 1 | |||
#define COFACTOR 8 | |||
#define EDDSA_PREHASH_BYTES 64 | |||
#if NO_CONTEXT | |||
const uint8_t NO_CONTEXT_POINTS_HERE = 0; | |||
@@ -41,7 +42,7 @@ const uint8_t * const DECAF_ED25519_NO_CONTEXT = &NO_CONTEXT_POINTS_HERE; | |||
* Because EdDSA25519 is not on E_d but on the isogenous E_sigma_d, | |||
* its base point is twice ours. | |||
*/ | |||
#define EDDSA_BASE_POINT_RATIO (1+EDDSA_USE_SIGMA_ISOGENY) | |||
#define EDDSA_BASE_POINT_RATIO (1+EDDSA_USE_SIGMA_ISOGENY) /* TODO: remove */ | |||
static void clamp ( | |||
uint8_t secret_scalar_ser[DECAF_EDDSA_25519_PRIVATE_BYTES] | |||
@@ -128,14 +129,14 @@ void decaf_ed25519_derive_public_key ( | |||
* the decaf base point is on Etwist_d, and when converted it effectively | |||
* picks up a factor of 2 from the isogenies. So we might start at 2 instead of 1. | |||
*/ | |||
for (unsigned int c = EDDSA_BASE_POINT_RATIO; c < COFACTOR; c <<= 1) { | |||
for (unsigned int c=1; c<DECAF_255_EDDSA_ENCODE_RATIO; c <<= 1) { | |||
API_NS(scalar_halve)(secret_scalar,secret_scalar); | |||
} | |||
API_NS(point_t) p; | |||
API_NS(precomputed_scalarmul)(p,API_NS(precomputed_base),secret_scalar); | |||
API_NS(point_mul_by_cofactor_and_encode_like_eddsa)(pubkey, p); | |||
API_NS(point_mul_by_ratio_and_encode_like_eddsa)(pubkey, p); | |||
/* Cleanup */ | |||
API_NS(scalar_destroy)(secret_scalar); | |||
@@ -191,13 +192,13 @@ void decaf_ed25519_sign ( | |||
/* 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) { | |||
for (unsigned int c = 2; c < DECAF_255_EDDSA_ENCODE_RATIO; 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_mul_by_ratio_and_encode_like_eddsa)(nonce_point, p); | |||
API_NS(point_destroy)(p); | |||
API_NS(scalar_destroy)(nonce_scalar_2); | |||
} | |||
@@ -237,7 +238,7 @@ void decaf_ed25519_sign_prehash ( | |||
const uint8_t *context, | |||
uint8_t context_len | |||
) { | |||
uint8_t hash_output[64]; /* MAGIC but true for all existing schemes */ | |||
uint8_t hash_output[EDDSA_PREHASH_BYTES]; | |||
{ | |||
decaf_ed25519_prehash_ctx_t hash_too; | |||
memcpy(hash_too,hash,sizeof(hash_too)); | |||
@@ -259,10 +260,10 @@ decaf_error_t decaf_ed25519_verify ( | |||
uint8_t context_len | |||
) { | |||
API_NS(point_t) pk_point, r_point; | |||
decaf_error_t error = API_NS(point_decode_like_eddsa_and_ignore_cofactor)(pk_point,pubkey); | |||
decaf_error_t error = API_NS(point_decode_like_eddsa_and_mul_by_ratio)(pk_point,pubkey); | |||
if (DECAF_SUCCESS != error) { return error; } | |||
error = API_NS(point_decode_like_eddsa_and_ignore_cofactor)(r_point,signature); | |||
error = API_NS(point_decode_like_eddsa_and_mul_by_ratio)(r_point,signature); | |||
if (DECAF_SUCCESS != error) { return error; } | |||
API_NS(scalar_t) challenge_scalar; | |||
@@ -287,9 +288,10 @@ decaf_error_t decaf_ed25519_verify ( | |||
&signature[DECAF_EDDSA_25519_PUBLIC_BYTES], | |||
DECAF_EDDSA_25519_PRIVATE_BYTES | |||
); | |||
#if EDDSA_BASE_POINT_RATIO == 2 | |||
API_NS(scalar_add)(response_scalar,response_scalar,response_scalar); | |||
#endif | |||
for (unsigned c=1; c<DECAF_255_EDDSA_DECODE_RATIO; c<<=1) { | |||
API_NS(scalar_add)(response_scalar,response_scalar,response_scalar); | |||
} | |||
/* pk_point = -c(x(P)) + (cx + k)G = kG */ | |||
@@ -312,7 +314,7 @@ decaf_error_t decaf_ed25519_verify_prehash ( | |||
) { | |||
decaf_error_t ret; | |||
uint8_t hash_output[64]; /* MAGIC but true for all existing schemes */ | |||
uint8_t hash_output[EDDSA_PREHASH_BYTES]; | |||
{ | |||
decaf_ed25519_prehash_ctx_t hash_too; | |||
memcpy(hash_too,hash,sizeof(hash_too)); | |||
@@ -1040,7 +1040,7 @@ decaf_error_t API_NS(direct_scalarmul) ( | |||
return succ; | |||
} | |||
void API_NS(point_mul_by_cofactor_and_encode_like_eddsa) ( | |||
void API_NS(point_mul_by_ratio_and_encode_like_eddsa) ( | |||
uint8_t enc[DECAF_EDDSA_448_PUBLIC_BYTES], | |||
const point_t p | |||
) { | |||
@@ -1133,7 +1133,7 @@ void API_NS(point_mul_by_cofactor_and_encode_like_eddsa) ( | |||
} | |||
decaf_error_t API_NS(point_decode_like_eddsa_and_ignore_cofactor) ( | |||
decaf_error_t API_NS(point_decode_like_eddsa_and_mul_by_ratio) ( | |||
point_t p, | |||
const uint8_t enc[DECAF_EDDSA_448_PUBLIC_BYTES] | |||
) { | |||
@@ -1352,13 +1352,16 @@ void decaf_x448_generate_key ( | |||
decaf_x448_derive_public_key(out,scalar); | |||
} | |||
void API_NS(point_mul_by_cofactor_and_encode_like_x448) ( | |||
void API_NS(point_mul_by_ratio_and_encode_like_x448) ( | |||
uint8_t out[X_PUBLIC_BYTES], | |||
const point_t p | |||
) { | |||
point_t q; | |||
#if COFACTOR == 8 | |||
point_double_internal(q,p,1); | |||
for (unsigned i=1; i<COFACTOR/4; i<<=1) point_double_internal(q,q,1); | |||
#else | |||
API_NS(point_copy)(q,p); | |||
#endif | |||
gf_invert(q->t,q->x,0); /* 1/x */ | |||
gf_mul(q->z,q->t,q->y); /* y/x */ | |||
gf_sqr(q->y,q->z); /* (y/x)^2 */ | |||
@@ -1384,24 +1387,13 @@ void decaf_x448_derive_public_key ( | |||
scalar_t the_scalar; | |||
API_NS(scalar_decode_long)(the_scalar,scalar2,sizeof(scalar2)); | |||
/* We're gonna isogenize by 2, so divide by 2. | |||
* | |||
* Why by 2, even though it's a 4-isogeny? | |||
* | |||
* The isogeny map looks like | |||
* Montgomery <-2-> Jacobi <-2-> Edwards | |||
* | |||
* Since the Jacobi base point is the PREimage of the iso to | |||
* the Montgomery curve, and we're going | |||
* Jacobi -> Edwards -> Jacobi -> Montgomery, | |||
* we pick up only a factor of 2 over Jacobi -> Montgomery. | |||
*/ | |||
for (unsigned i=1; i<COFACTOR; i<<=1) { | |||
/* Compensate for the encoding ratio */ | |||
for (unsigned i=1; i<DECAF_X448_ENCODE_RATIO; i<<=1) { | |||
API_NS(scalar_halve)(the_scalar,the_scalar); | |||
} | |||
point_t p; | |||
API_NS(precomputed_scalarmul)(p,API_NS(precomputed_base),the_scalar); | |||
API_NS(point_mul_by_cofactor_and_encode_like_x448)(out,p); | |||
API_NS(point_mul_by_ratio_and_encode_like_x448)(out,p); | |||
API_NS(point_destroy)(p); | |||
} | |||
@@ -31,6 +31,7 @@ | |||
#define NO_CONTEXT DECAF_EDDSA_448_SUPPORTS_CONTEXTLESS_SIGS | |||
#define EDDSA_USE_SIGMA_ISOGENY 0 | |||
#define COFACTOR 4 | |||
#define EDDSA_PREHASH_BYTES 64 | |||
#if NO_CONTEXT | |||
const uint8_t NO_CONTEXT_POINTS_HERE = 0; | |||
@@ -41,7 +42,7 @@ const uint8_t * const DECAF_ED448_NO_CONTEXT = &NO_CONTEXT_POINTS_HERE; | |||
* Because EdDSA25519 is not on E_d but on the isogenous E_sigma_d, | |||
* its base point is twice ours. | |||
*/ | |||
#define EDDSA_BASE_POINT_RATIO (1+EDDSA_USE_SIGMA_ISOGENY) | |||
#define EDDSA_BASE_POINT_RATIO (1+EDDSA_USE_SIGMA_ISOGENY) /* TODO: remove */ | |||
static void clamp ( | |||
uint8_t secret_scalar_ser[DECAF_EDDSA_448_PRIVATE_BYTES] | |||
@@ -128,14 +129,14 @@ void decaf_ed448_derive_public_key ( | |||
* the decaf base point is on Etwist_d, and when converted it effectively | |||
* picks up a factor of 2 from the isogenies. So we might start at 2 instead of 1. | |||
*/ | |||
for (unsigned int c = EDDSA_BASE_POINT_RATIO; c < COFACTOR; c <<= 1) { | |||
for (unsigned int c=1; c<DECAF_448_EDDSA_ENCODE_RATIO; c <<= 1) { | |||
API_NS(scalar_halve)(secret_scalar,secret_scalar); | |||
} | |||
API_NS(point_t) p; | |||
API_NS(precomputed_scalarmul)(p,API_NS(precomputed_base),secret_scalar); | |||
API_NS(point_mul_by_cofactor_and_encode_like_eddsa)(pubkey, p); | |||
API_NS(point_mul_by_ratio_and_encode_like_eddsa)(pubkey, p); | |||
/* Cleanup */ | |||
API_NS(scalar_destroy)(secret_scalar); | |||
@@ -191,13 +192,13 @@ void decaf_ed448_sign ( | |||
/* 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) { | |||
for (unsigned int c = 2; c < DECAF_448_EDDSA_ENCODE_RATIO; 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_mul_by_ratio_and_encode_like_eddsa)(nonce_point, p); | |||
API_NS(point_destroy)(p); | |||
API_NS(scalar_destroy)(nonce_scalar_2); | |||
} | |||
@@ -237,7 +238,7 @@ void decaf_ed448_sign_prehash ( | |||
const uint8_t *context, | |||
uint8_t context_len | |||
) { | |||
uint8_t hash_output[64]; /* MAGIC but true for all existing schemes */ | |||
uint8_t hash_output[EDDSA_PREHASH_BYTES]; | |||
{ | |||
decaf_ed448_prehash_ctx_t hash_too; | |||
memcpy(hash_too,hash,sizeof(hash_too)); | |||
@@ -259,10 +260,10 @@ decaf_error_t decaf_ed448_verify ( | |||
uint8_t context_len | |||
) { | |||
API_NS(point_t) pk_point, r_point; | |||
decaf_error_t error = API_NS(point_decode_like_eddsa_and_ignore_cofactor)(pk_point,pubkey); | |||
decaf_error_t error = API_NS(point_decode_like_eddsa_and_mul_by_ratio)(pk_point,pubkey); | |||
if (DECAF_SUCCESS != error) { return error; } | |||
error = API_NS(point_decode_like_eddsa_and_ignore_cofactor)(r_point,signature); | |||
error = API_NS(point_decode_like_eddsa_and_mul_by_ratio)(r_point,signature); | |||
if (DECAF_SUCCESS != error) { return error; } | |||
API_NS(scalar_t) challenge_scalar; | |||
@@ -287,9 +288,10 @@ decaf_error_t decaf_ed448_verify ( | |||
&signature[DECAF_EDDSA_448_PUBLIC_BYTES], | |||
DECAF_EDDSA_448_PRIVATE_BYTES | |||
); | |||
#if EDDSA_BASE_POINT_RATIO == 2 | |||
API_NS(scalar_add)(response_scalar,response_scalar,response_scalar); | |||
#endif | |||
for (unsigned c=1; c<DECAF_448_EDDSA_DECODE_RATIO; c<<=1) { | |||
API_NS(scalar_add)(response_scalar,response_scalar,response_scalar); | |||
} | |||
/* pk_point = -c(x(P)) + (cx + k)G = kG */ | |||
@@ -312,7 +314,7 @@ decaf_error_t decaf_ed448_verify_prehash ( | |||
) { | |||
decaf_error_t ret; | |||
uint8_t hash_output[64]; /* MAGIC but true for all existing schemes */ | |||
uint8_t hash_output[EDDSA_PREHASH_BYTES]; | |||
{ | |||
decaf_ed448_prehash_ctx_t hash_too; | |||
memcpy(hash_too,hash,sizeof(hash_too)); | |||
@@ -42,6 +42,12 @@ extern const uint8_t * const DECAF_ED25519_NO_CONTEXT DECAF_API_VIS; | |||
#define decaf_ed25519_prehash_update decaf_sha512_update | |||
#define decaf_ed25519_prehash_destroy decaf_sha512_destroy | |||
/** EdDSA encoding ratio. */ | |||
#define DECAF_255_EDDSA_ENCODE_RATIO 4 | |||
/** EdDSA decoding ratio. */ | |||
#define DECAF_255_EDDSA_DECODE_RATIO (8 / 4) | |||
/** | |||
* @brief EdDSA key generation. This function uses a different (non-Decaf) | |||
* encoding. | |||
@@ -169,25 +175,43 @@ decaf_error_t decaf_ed25519_verify_prehash ( | |||
/** | |||
* @brief EdDSA point encoding. Used internally, exposed externally. | |||
* Multiplies the point by the current cofactor first. | |||
* Multiplies by DECAF_255_EDDSA_ENCODE_RATIO first. | |||
* | |||
* The multiplication is required because the EdDSA encoding represents | |||
* the cofactor information, but the Decaf encoding ignores it (which | |||
* is the whole point). So if you decode from EdDSA and re-encode to | |||
* EdDSA, the cofactor info must get cleared, because the intermediate | |||
* representation doesn't track it. | |||
* | |||
* The way libdecaf handles this is to multiply by | |||
* DECAF_255_EDDSA_DECODE_RATIO when decoding, and by | |||
* DECAF_255_EDDSA_ENCODE_RATIO when encoding. The product of these | |||
* ratios is always exactly the cofactor 8, so the cofactor | |||
* ends up cleared one way or another. But exactly how that shakes | |||
* out depends on the base points specified in RFC 8032. | |||
* | |||
* The upshot is that if you pass the Decaf/Ristretto base point to | |||
* this function, you will get DECAF_255_EDDSA_ENCODE_RATIO times the | |||
* EdDSA base point. | |||
* | |||
* @param [out] enc The encoded point. | |||
* @param [in] p The point. | |||
*/ | |||
void decaf_255_point_mul_by_cofactor_and_encode_like_eddsa ( | |||
void decaf_255_point_mul_by_ratio_and_encode_like_eddsa ( | |||
uint8_t enc[DECAF_EDDSA_25519_PUBLIC_BYTES], | |||
const decaf_255_point_t p | |||
) DECAF_API_VIS DECAF_NONNULL DECAF_NOINLINE; | |||
/** | |||
* @brief EdDSA point decoding. Remember that while points on the | |||
* EdDSA curves have cofactor information, Decaf ignores (quotients | |||
* out) all cofactor information. | |||
* @brief EdDSA point decoding. Multiplies by DECAF_255_EDDSA_DECODE_RATIO, | |||
* and ignores cofactor information. | |||
* | |||
* See notes on decaf_255_point_mul_by_ratio_and_encode_like_eddsa | |||
* | |||
* @param [out] enc The encoded point. | |||
* @param [in] p The point. | |||
*/ | |||
decaf_error_t decaf_255_point_decode_like_eddsa_and_ignore_cofactor ( | |||
decaf_error_t decaf_255_point_decode_like_eddsa_and_mul_by_ratio ( | |||
decaf_255_point_t p, | |||
const uint8_t enc[DECAF_EDDSA_25519_PUBLIC_BYTES] | |||
) DECAF_API_VIS DECAF_NONNULL DECAF_NOINLINE; | |||
@@ -41,6 +41,12 @@ extern "C" { | |||
#define decaf_ed448_prehash_update decaf_shake256_update | |||
#define decaf_ed448_prehash_destroy decaf_shake256_destroy | |||
/** EdDSA encoding ratio. */ | |||
#define DECAF_448_EDDSA_ENCODE_RATIO 4 | |||
/** EdDSA decoding ratio. */ | |||
#define DECAF_448_EDDSA_DECODE_RATIO (4 / 4) | |||
/** | |||
* @brief EdDSA key generation. This function uses a different (non-Decaf) | |||
* encoding. | |||
@@ -168,25 +174,43 @@ decaf_error_t decaf_ed448_verify_prehash ( | |||
/** | |||
* @brief EdDSA point encoding. Used internally, exposed externally. | |||
* Multiplies the point by the current cofactor first. | |||
* Multiplies by DECAF_448_EDDSA_ENCODE_RATIO first. | |||
* | |||
* The multiplication is required because the EdDSA encoding represents | |||
* the cofactor information, but the Decaf encoding ignores it (which | |||
* is the whole point). So if you decode from EdDSA and re-encode to | |||
* EdDSA, the cofactor info must get cleared, because the intermediate | |||
* representation doesn't track it. | |||
* | |||
* The way libdecaf handles this is to multiply by | |||
* DECAF_448_EDDSA_DECODE_RATIO when decoding, and by | |||
* DECAF_448_EDDSA_ENCODE_RATIO when encoding. The product of these | |||
* ratios is always exactly the cofactor 4, so the cofactor | |||
* ends up cleared one way or another. But exactly how that shakes | |||
* out depends on the base points specified in RFC 8032. | |||
* | |||
* The upshot is that if you pass the Decaf/Ristretto base point to | |||
* this function, you will get DECAF_448_EDDSA_ENCODE_RATIO times the | |||
* EdDSA base point. | |||
* | |||
* @param [out] enc The encoded point. | |||
* @param [in] p The point. | |||
*/ | |||
void decaf_448_point_mul_by_cofactor_and_encode_like_eddsa ( | |||
void decaf_448_point_mul_by_ratio_and_encode_like_eddsa ( | |||
uint8_t enc[DECAF_EDDSA_448_PUBLIC_BYTES], | |||
const decaf_448_point_t p | |||
) DECAF_API_VIS DECAF_NONNULL DECAF_NOINLINE; | |||
/** | |||
* @brief EdDSA point decoding. Remember that while points on the | |||
* EdDSA curves have cofactor information, Decaf ignores (quotients | |||
* out) all cofactor information. | |||
* @brief EdDSA point decoding. Multiplies by DECAF_448_EDDSA_DECODE_RATIO, | |||
* and ignores cofactor information. | |||
* | |||
* See notes on decaf_448_point_mul_by_ratio_and_encode_like_eddsa | |||
* | |||
* @param [out] enc The encoded point. | |||
* @param [in] p The point. | |||
*/ | |||
decaf_error_t decaf_448_point_decode_like_eddsa_and_ignore_cofactor ( | |||
decaf_error_t decaf_448_point_decode_like_eddsa_and_mul_by_ratio ( | |||
decaf_448_point_t p, | |||
const uint8_t enc[DECAF_EDDSA_448_PUBLIC_BYTES] | |||
) DECAF_API_VIS DECAF_NONNULL DECAF_NOINLINE; | |||
@@ -55,6 +55,9 @@ typedef struct gf_25519_s { | |||
/** The cofactor the curve would have, if we hadn't removed it */ | |||
#define DECAF_255_REMOVED_COFACTOR 8 | |||
/** X25519 encoding ratio. */ | |||
#define DECAF_X25519_ENCODE_RATIO 4 | |||
/** Number of bytes in an x25519 public key */ | |||
#define DECAF_X25519_PUBLIC_BYTES 32 | |||
@@ -401,12 +404,26 @@ decaf_error_t decaf_x25519 ( | |||
) DECAF_API_VIS DECAF_NONNULL DECAF_WARN_UNUSED DECAF_NOINLINE; | |||
/** | |||
* @brief Multiply a point by the cofactor, then encode it like RFC 7748 | |||
* @brief Multiply a point by DECAF_X25519_ENCODE_RATIO, | |||
* then encode it like RFC 7748. | |||
* | |||
* This function is mainly used internally, but is exported in case | |||
* it will be useful. | |||
* | |||
* The ratio is necessary because the internal representation doesn't | |||
* track the cofactor information, so on output we must clear the cofactor. | |||
* This would multiply by the cofactor, but in fact internally libdecaf's | |||
* points are always even, so it multiplies by half the cofactor instead. | |||
* | |||
* As it happens, this aligns with the base point definitions; that is, | |||
* if you pass the Decaf/Ristretto base point to this function, the result | |||
* will be DECAF_X25519_ENCODE_RATIO times the X25519 | |||
* base point. | |||
* | |||
* @param [out] out The scaled and encoded point. | |||
* @param [in] p The point to be scaled and encoded. | |||
*/ | |||
void decaf_255_point_mul_by_cofactor_and_encode_like_x25519 ( | |||
void decaf_255_point_mul_by_ratio_and_encode_like_x25519 ( | |||
uint8_t out[DECAF_X25519_PUBLIC_BYTES], | |||
const decaf_255_point_t p | |||
) DECAF_API_VIS DECAF_NONNULL; | |||
@@ -64,9 +64,6 @@ static inline int bits() { return 255; } | |||
/** The curve's cofactor (removed, but useful for testing) */ | |||
static const int REMOVED_COFACTOR = 8; | |||
/** The curve's cofactor (removed, but useful for testing) */ | |||
static const int EDDSA_RATIO = 4; | |||
/** Residue class of field modulus: p == this mod 2*(this-1) */ | |||
static const int FIELD_MODULUS_TYPE = 5; | |||
@@ -263,6 +260,15 @@ public: | |||
/** Bytes required for EdDSA encoding */ | |||
static const size_t LADDER_BYTES = DECAF_X25519_PUBLIC_BYTES; | |||
/** Ratio due to EdDSA encoding */ | |||
static const int EDDSA_ENCODE_RATIO = DECAF_255_EDDSA_ENCODE_RATIO; | |||
/** Ratio due to EdDSA decoding */ | |||
static const int EDDSA_DECODE_RATIO = DECAF_255_EDDSA_DECODE_RATIO; | |||
/** Ratio due to ladder decoding */ | |||
static const int LADDER_ENCODE_RATIO = DECAF_X25519_ENCODE_RATIO; | |||
/** | |||
* Size of a stegged element. | |||
@@ -348,44 +354,49 @@ public: | |||
* @return DECAF_FAILURE the string was the wrong length, or wasn't the encoding of a point. | |||
* Contents of the point are undefined. | |||
*/ | |||
inline decaf_error_t DECAF_WARN_UNUSED decode_like_eddsa_and_ignore_cofactor_noexcept ( | |||
inline decaf_error_t DECAF_WARN_UNUSED decode_like_eddsa_and_mul_by_ratio_noexcept ( | |||
const FixedBlock<DECAF_EDDSA_25519_PUBLIC_BYTES> &buffer | |||
) DECAF_NOEXCEPT { | |||
return decaf_255_point_decode_like_eddsa_and_ignore_cofactor(p,buffer.data()); | |||
return decaf_255_point_decode_like_eddsa_and_mul_by_ratio(p,buffer.data()); | |||
} | |||
inline void decode_like_eddsa_and_ignore_cofactor ( | |||
/** | |||
* Decode from EDDSA, multiply by EDDSA_DECODE_RATIO, and ignore any | |||
* remaining cofactor information. | |||
* @throw CryptoException if the input point was invalid. | |||
*/ | |||
inline void decode_like_eddsa_and_mul_by_ratio( | |||
const FixedBlock<DECAF_EDDSA_25519_PUBLIC_BYTES> &buffer | |||
) /*throw(CryptoException)*/ { | |||
if (DECAF_SUCCESS != decode_like_eddsa_and_ignore_cofactor_noexcept(buffer)) throw(CryptoException()); | |||
if (DECAF_SUCCESS != decode_like_eddsa_and_mul_by_ratio_noexcept(buffer)) throw(CryptoException()); | |||
} | |||
/** Multiply out cofactor and encode like EdDSA. */ | |||
inline SecureBuffer mul_by_cofactor_and_encode_like_eddsa() const { | |||
/** Multiply by EDDSA_ENCODE_RATIO and encode like EdDSA. */ | |||
inline SecureBuffer mul_by_ratio_and_encode_like_eddsa() const { | |||
SecureBuffer ret(DECAF_EDDSA_25519_PUBLIC_BYTES); | |||
decaf_255_point_mul_by_cofactor_and_encode_like_eddsa(ret.data(),p); | |||
decaf_255_point_mul_by_ratio_and_encode_like_eddsa(ret.data(),p); | |||
return ret; | |||
} | |||
/** Multiply out cofactor and encode like X25519/X448. */ | |||
inline SecureBuffer mul_by_cofactor_and_encode_like_ladder() const { | |||
SecureBuffer ret(LADDER_BYTES); | |||
decaf_255_point_mul_by_cofactor_and_encode_like_x25519(ret.data(),p); | |||
return ret; | |||
} | |||
/** Multiply out cofactor and encode like EdDSA. */ | |||
inline void mul_by_cofactor_and_encode_like_eddsa( | |||
/** Multiply by EDDSA_ENCODE_RATIO and encode like EdDSA. */ | |||
inline void mul_by_ratio_and_encode_like_eddsa( | |||
FixedBuffer<DECAF_EDDSA_25519_PUBLIC_BYTES> &out | |||
) const { | |||
decaf_255_point_mul_by_cofactor_and_encode_like_eddsa(out.data(),p); | |||
decaf_255_point_mul_by_ratio_and_encode_like_eddsa(out.data(),p); | |||
} | |||
/** Multiply by LADDER_ENCODE_RATIO and encode like X25519/X448. */ | |||
inline SecureBuffer mul_by_ratio_and_encode_like_ladder() const { | |||
SecureBuffer ret(LADDER_BYTES); | |||
decaf_255_point_mul_by_ratio_and_encode_like_x25519(ret.data(),p); | |||
return ret; | |||
} | |||
/** Multiply out cofactor and encode like X25519/X448. */ | |||
inline void mul_by_cofactor_and_encode_like_ladder( | |||
/** Multiply by LADDER_ENCODE_RATIO and encode like X25519/X448. */ | |||
inline void mul_by_ratio_and_encode_like_ladder( | |||
FixedBuffer<LADDER_BYTES> &out | |||
) const { | |||
decaf_255_point_mul_by_cofactor_and_encode_like_x25519(out.data(),p); | |||
decaf_255_point_mul_by_ratio_and_encode_like_x25519(out.data(),p); | |||
} | |||
/** | |||
@@ -55,6 +55,9 @@ typedef struct gf_448_s { | |||
/** The cofactor the curve would have, if we hadn't removed it */ | |||
#define DECAF_448_REMOVED_COFACTOR 4 | |||
/** X448 encoding ratio. */ | |||
#define DECAF_X448_ENCODE_RATIO 2 | |||
/** Number of bytes in an x448 public key */ | |||
#define DECAF_X448_PUBLIC_BYTES 56 | |||
@@ -401,12 +404,26 @@ decaf_error_t decaf_x448 ( | |||
) DECAF_API_VIS DECAF_NONNULL DECAF_WARN_UNUSED DECAF_NOINLINE; | |||
/** | |||
* @brief Multiply a point by the cofactor, then encode it like RFC 7748 | |||
* @brief Multiply a point by DECAF_X448_ENCODE_RATIO, | |||
* then encode it like RFC 7748. | |||
* | |||
* This function is mainly used internally, but is exported in case | |||
* it will be useful. | |||
* | |||
* The ratio is necessary because the internal representation doesn't | |||
* track the cofactor information, so on output we must clear the cofactor. | |||
* This would multiply by the cofactor, but in fact internally libdecaf's | |||
* points are always even, so it multiplies by half the cofactor instead. | |||
* | |||
* As it happens, this aligns with the base point definitions; that is, | |||
* if you pass the Decaf/Ristretto base point to this function, the result | |||
* will be DECAF_X448_ENCODE_RATIO times the X448 | |||
* base point. | |||
* | |||
* @param [out] out The scaled and encoded point. | |||
* @param [in] p The point to be scaled and encoded. | |||
*/ | |||
void decaf_448_point_mul_by_cofactor_and_encode_like_x448 ( | |||
void decaf_448_point_mul_by_ratio_and_encode_like_x448 ( | |||
uint8_t out[DECAF_X448_PUBLIC_BYTES], | |||
const decaf_448_point_t p | |||
) DECAF_API_VIS DECAF_NONNULL; | |||
@@ -64,9 +64,6 @@ static inline int bits() { return 448; } | |||
/** The curve's cofactor (removed, but useful for testing) */ | |||
static const int REMOVED_COFACTOR = 4; | |||
/** The curve's cofactor (removed, but useful for testing) */ | |||
static const int EDDSA_RATIO = 4; | |||
/** Residue class of field modulus: p == this mod 2*(this-1) */ | |||
static const int FIELD_MODULUS_TYPE = 3; | |||
@@ -263,6 +260,15 @@ public: | |||
/** Bytes required for EdDSA encoding */ | |||
static const size_t LADDER_BYTES = DECAF_X448_PUBLIC_BYTES; | |||
/** Ratio due to EdDSA encoding */ | |||
static const int EDDSA_ENCODE_RATIO = DECAF_448_EDDSA_ENCODE_RATIO; | |||
/** Ratio due to EdDSA decoding */ | |||
static const int EDDSA_DECODE_RATIO = DECAF_448_EDDSA_DECODE_RATIO; | |||
/** Ratio due to ladder decoding */ | |||
static const int LADDER_ENCODE_RATIO = DECAF_X448_ENCODE_RATIO; | |||
/** | |||
* Size of a stegged element. | |||
@@ -348,44 +354,49 @@ public: | |||
* @return DECAF_FAILURE the string was the wrong length, or wasn't the encoding of a point. | |||
* Contents of the point are undefined. | |||
*/ | |||
inline decaf_error_t DECAF_WARN_UNUSED decode_like_eddsa_and_ignore_cofactor_noexcept ( | |||
inline decaf_error_t DECAF_WARN_UNUSED decode_like_eddsa_and_mul_by_ratio_noexcept ( | |||
const FixedBlock<DECAF_EDDSA_448_PUBLIC_BYTES> &buffer | |||
) DECAF_NOEXCEPT { | |||
return decaf_448_point_decode_like_eddsa_and_ignore_cofactor(p,buffer.data()); | |||
return decaf_448_point_decode_like_eddsa_and_mul_by_ratio(p,buffer.data()); | |||
} | |||
inline void decode_like_eddsa_and_ignore_cofactor ( | |||
/** | |||
* Decode from EDDSA, multiply by EDDSA_DECODE_RATIO, and ignore any | |||
* remaining cofactor information. | |||
* @throw CryptoException if the input point was invalid. | |||
*/ | |||
inline void decode_like_eddsa_and_mul_by_ratio( | |||
const FixedBlock<DECAF_EDDSA_448_PUBLIC_BYTES> &buffer | |||
) /*throw(CryptoException)*/ { | |||
if (DECAF_SUCCESS != decode_like_eddsa_and_ignore_cofactor_noexcept(buffer)) throw(CryptoException()); | |||
if (DECAF_SUCCESS != decode_like_eddsa_and_mul_by_ratio_noexcept(buffer)) throw(CryptoException()); | |||
} | |||
/** Multiply out cofactor and encode like EdDSA. */ | |||
inline SecureBuffer mul_by_cofactor_and_encode_like_eddsa() const { | |||
/** Multiply by EDDSA_ENCODE_RATIO and encode like EdDSA. */ | |||
inline SecureBuffer mul_by_ratio_and_encode_like_eddsa() const { | |||
SecureBuffer ret(DECAF_EDDSA_448_PUBLIC_BYTES); | |||
decaf_448_point_mul_by_cofactor_and_encode_like_eddsa(ret.data(),p); | |||
decaf_448_point_mul_by_ratio_and_encode_like_eddsa(ret.data(),p); | |||
return ret; | |||
} | |||
/** Multiply out cofactor and encode like X25519/X448. */ | |||
inline SecureBuffer mul_by_cofactor_and_encode_like_ladder() const { | |||
SecureBuffer ret(LADDER_BYTES); | |||
decaf_448_point_mul_by_cofactor_and_encode_like_x448(ret.data(),p); | |||
return ret; | |||
} | |||
/** Multiply out cofactor and encode like EdDSA. */ | |||
inline void mul_by_cofactor_and_encode_like_eddsa( | |||
/** Multiply by EDDSA_ENCODE_RATIO and encode like EdDSA. */ | |||
inline void mul_by_ratio_and_encode_like_eddsa( | |||
FixedBuffer<DECAF_EDDSA_448_PUBLIC_BYTES> &out | |||
) const { | |||
decaf_448_point_mul_by_cofactor_and_encode_like_eddsa(out.data(),p); | |||
decaf_448_point_mul_by_ratio_and_encode_like_eddsa(out.data(),p); | |||
} | |||
/** Multiply by LADDER_ENCODE_RATIO and encode like X25519/X448. */ | |||
inline SecureBuffer mul_by_ratio_and_encode_like_ladder() const { | |||
SecureBuffer ret(LADDER_BYTES); | |||
decaf_448_point_mul_by_ratio_and_encode_like_x448(ret.data(),p); | |||
return ret; | |||
} | |||
/** Multiply out cofactor and encode like X25519/X448. */ | |||
inline void mul_by_cofactor_and_encode_like_ladder( | |||
/** Multiply by LADDER_ENCODE_RATIO and encode like X25519/X448. */ | |||
inline void mul_by_ratio_and_encode_like_ladder( | |||
FixedBuffer<LADDER_BYTES> &out | |||
) const { | |||
decaf_448_point_mul_by_cofactor_and_encode_like_x448(out.data(),p); | |||
decaf_448_point_mul_by_ratio_and_encode_like_x448(out.data(),p); | |||
} | |||
/** | |||
@@ -33,6 +33,8 @@ curve_data = { | |||
"trace": -0xa6f7cef517bce6b2c09318d2e7ae9f7a, | |||
"mont_base": 9, | |||
"rist_base": "e2f2ae0a6abc4e71a884a961c500515f58e30b6aa582dd8db6a65945e08d2d76", | |||
"eddsa_encode_ratio": 4, | |||
"x_encode_ratio": 4, | |||
"combs":comb_config(3,5,17), | |||
"wnaf":wnaf_config(5,3), | |||
@@ -44,6 +46,8 @@ curve_data = { | |||
"eddsa_sigma_iso": 1 | |||
}, | |||
"ed448goldilocks" : { | |||
"eddsa_encode_ratio": 4, | |||
"x_encode_ratio": 2, | |||
"altname": None, | |||
"name" : "Ed448-Goldilocks", | |||
"cofactor" : 4, | |||
@@ -1029,7 +1029,7 @@ decaf_error_t API_NS(direct_scalarmul) ( | |||
return succ; | |||
} | |||
void API_NS(point_mul_by_cofactor_and_encode_like_eddsa) ( | |||
void API_NS(point_mul_by_ratio_and_encode_like_eddsa) ( | |||
uint8_t enc[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES], | |||
const point_t p | |||
) { | |||
@@ -1122,7 +1122,7 @@ void API_NS(point_mul_by_cofactor_and_encode_like_eddsa) ( | |||
} | |||
decaf_error_t API_NS(point_decode_like_eddsa_and_ignore_cofactor) ( | |||
decaf_error_t API_NS(point_decode_like_eddsa_and_mul_by_ratio) ( | |||
point_t p, | |||
const uint8_t enc[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES] | |||
) { | |||
@@ -1341,13 +1341,16 @@ void decaf_x$(gf_shortname)_generate_key ( | |||
decaf_x$(gf_shortname)_derive_public_key(out,scalar); | |||
} | |||
void API_NS(point_mul_by_cofactor_and_encode_like_x$(gf_shortname)) ( | |||
void API_NS(point_mul_by_ratio_and_encode_like_x$(gf_shortname)) ( | |||
uint8_t out[X_PUBLIC_BYTES], | |||
const point_t p | |||
) { | |||
point_t q; | |||
#if COFACTOR == 8 | |||
point_double_internal(q,p,1); | |||
for (unsigned i=1; i<COFACTOR/4; i<<=1) point_double_internal(q,q,1); | |||
#else | |||
API_NS(point_copy)(q,p); | |||
#endif | |||
gf_invert(q->t,q->x,0); /* 1/x */ | |||
gf_mul(q->z,q->t,q->y); /* y/x */ | |||
gf_sqr(q->y,q->z); /* (y/x)^2 */ | |||
@@ -1373,24 +1376,13 @@ void decaf_x$(gf_shortname)_derive_public_key ( | |||
scalar_t the_scalar; | |||
API_NS(scalar_decode_long)(the_scalar,scalar2,sizeof(scalar2)); | |||
/* We're gonna isogenize by 2, so divide by 2. | |||
* | |||
* Why by 2, even though it's a 4-isogeny? | |||
* | |||
* The isogeny map looks like | |||
* Montgomery <-2-> Jacobi <-2-> Edwards | |||
* | |||
* Since the Jacobi base point is the PREimage of the iso to | |||
* the Montgomery curve, and we're going | |||
* Jacobi -> Edwards -> Jacobi -> Montgomery, | |||
* we pick up only a factor of 2 over Jacobi -> Montgomery. | |||
*/ | |||
for (unsigned i=1; i<COFACTOR; i<<=1) { | |||
/* Compensate for the encoding ratio */ | |||
for (unsigned i=1; i<DECAF_X$(gf_shortname)_ENCODE_RATIO; i<<=1) { | |||
API_NS(scalar_halve)(the_scalar,the_scalar); | |||
} | |||
point_t p; | |||
API_NS(precomputed_scalarmul)(p,API_NS(precomputed_base),the_scalar); | |||
API_NS(point_mul_by_cofactor_and_encode_like_x$(gf_shortname))(out,p); | |||
API_NS(point_mul_by_ratio_and_encode_like_x$(gf_shortname))(out,p); | |||
API_NS(point_destroy)(p); | |||
} | |||
@@ -29,12 +29,6 @@ const uint8_t NO_CONTEXT_POINTS_HERE = 0; | |||
const uint8_t * const DECAF_ED$(gf_shortname)_NO_CONTEXT = &NO_CONTEXT_POINTS_HERE; | |||
#endif | |||
/* EDDSA_BASE_POINT_RATIO = 1 or 2 | |||
* Because EdDSA25519 is not on E_d but on the isogenous E_sigma_d, | |||
* its base point is twice ours. | |||
*/ | |||
#define EDDSA_BASE_POINT_RATIO (1+EDDSA_USE_SIGMA_ISOGENY) | |||
static void clamp ( | |||
uint8_t secret_scalar_ser[DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES] | |||
) { | |||
@@ -120,14 +114,14 @@ void decaf_ed$(gf_shortname)_derive_public_key ( | |||
* the decaf base point is on Etwist_d, and when converted it effectively | |||
* picks up a factor of 2 from the isogenies. So we might start at 2 instead of 1. | |||
*/ | |||
for (unsigned int c = EDDSA_BASE_POINT_RATIO; c < COFACTOR; c <<= 1) { | |||
for (unsigned int c=1; c<$(C_NS)_EDDSA_ENCODE_RATIO; c <<= 1) { | |||
API_NS(scalar_halve)(secret_scalar,secret_scalar); | |||
} | |||
API_NS(point_t) p; | |||
API_NS(precomputed_scalarmul)(p,API_NS(precomputed_base),secret_scalar); | |||
API_NS(point_mul_by_cofactor_and_encode_like_eddsa)(pubkey, p); | |||
API_NS(point_mul_by_ratio_and_encode_like_eddsa)(pubkey, p); | |||
/* Cleanup */ | |||
API_NS(scalar_destroy)(secret_scalar); | |||
@@ -183,13 +177,13 @@ void decaf_ed$(gf_shortname)_sign ( | |||
/* 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) { | |||
for (unsigned int c = 2; c < $(C_NS)_EDDSA_ENCODE_RATIO; 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_mul_by_ratio_and_encode_like_eddsa)(nonce_point, p); | |||
API_NS(point_destroy)(p); | |||
API_NS(scalar_destroy)(nonce_scalar_2); | |||
} | |||
@@ -251,10 +245,10 @@ decaf_error_t decaf_ed$(gf_shortname)_verify ( | |||
uint8_t context_len | |||
) { | |||
API_NS(point_t) pk_point, r_point; | |||
decaf_error_t error = API_NS(point_decode_like_eddsa_and_ignore_cofactor)(pk_point,pubkey); | |||
decaf_error_t error = API_NS(point_decode_like_eddsa_and_mul_by_ratio)(pk_point,pubkey); | |||
if (DECAF_SUCCESS != error) { return error; } | |||
error = API_NS(point_decode_like_eddsa_and_ignore_cofactor)(r_point,signature); | |||
error = API_NS(point_decode_like_eddsa_and_mul_by_ratio)(r_point,signature); | |||
if (DECAF_SUCCESS != error) { return error; } | |||
API_NS(scalar_t) challenge_scalar; | |||
@@ -279,9 +273,10 @@ decaf_error_t decaf_ed$(gf_shortname)_verify ( | |||
&signature[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES], | |||
DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES | |||
); | |||
#if EDDSA_BASE_POINT_RATIO == 2 | |||
API_NS(scalar_add)(response_scalar,response_scalar,response_scalar); | |||
#endif | |||
for (unsigned c=1; c<$(C_NS)_EDDSA_DECODE_RATIO; c<<=1) { | |||
API_NS(scalar_add)(response_scalar,response_scalar,response_scalar); | |||
} | |||
/* pk_point = -c(x(P)) + (cx + k)G = kG */ | |||
@@ -26,6 +26,12 @@ $("extern const uint8_t * const DECAF_ED" + gf_shortname + "_NO_CONTEXT DECAF_AP | |||
#define decaf_ed$(gf_shortname)_prehash_update decaf_$(eddsa_hash)_update | |||
#define decaf_ed$(gf_shortname)_prehash_destroy decaf_$(eddsa_hash)_destroy | |||
/** EdDSA encoding ratio. */ | |||
#define $(C_NS)_EDDSA_ENCODE_RATIO $(eddsa_encode_ratio) | |||
/** EdDSA decoding ratio. */ | |||
#define $(C_NS)_EDDSA_DECODE_RATIO ($(cofactor) / $(eddsa_encode_ratio)) | |||
/** | |||
* @brief EdDSA key generation. This function uses a different (non-Decaf) | |||
* encoding. | |||
@@ -153,25 +159,43 @@ decaf_error_t decaf_ed$(gf_shortname)_verify_prehash ( | |||
/** | |||
* @brief EdDSA point encoding. Used internally, exposed externally. | |||
* Multiplies the point by the current cofactor first. | |||
* Multiplies by $(C_NS)_EDDSA_ENCODE_RATIO first. | |||
* | |||
* The multiplication is required because the EdDSA encoding represents | |||
* the cofactor information, but the Decaf encoding ignores it (which | |||
* is the whole point). So if you decode from EdDSA and re-encode to | |||
* EdDSA, the cofactor info must get cleared, because the intermediate | |||
* representation doesn't track it. | |||
* | |||
* The way libdecaf handles this is to multiply by | |||
* $(C_NS)_EDDSA_DECODE_RATIO when decoding, and by | |||
* $(C_NS)_EDDSA_ENCODE_RATIO when encoding. The product of these | |||
* ratios is always exactly the cofactor $(cofactor), so the cofactor | |||
* ends up cleared one way or another. But exactly how that shakes | |||
* out depends on the base points specified in RFC 8032. | |||
* | |||
* The upshot is that if you pass the Decaf/Ristretto base point to | |||
* this function, you will get $(C_NS)_EDDSA_ENCODE_RATIO times the | |||
* EdDSA base point. | |||
* | |||
* @param [out] enc The encoded point. | |||
* @param [in] p The point. | |||
*/ | |||
void $(c_ns)_point_mul_by_cofactor_and_encode_like_eddsa ( | |||
void $(c_ns)_point_mul_by_ratio_and_encode_like_eddsa ( | |||
uint8_t enc[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES], | |||
const $(c_ns)_point_t p | |||
) DECAF_API_VIS DECAF_NONNULL DECAF_NOINLINE; | |||
/** | |||
* @brief EdDSA point decoding. Remember that while points on the | |||
* EdDSA curves have cofactor information, Decaf ignores (quotients | |||
* out) all cofactor information. | |||
* @brief EdDSA point decoding. Multiplies by $(C_NS)_EDDSA_DECODE_RATIO, | |||
* and ignores cofactor information. | |||
* | |||
* See notes on $(c_ns)_point_mul_by_ratio_and_encode_like_eddsa | |||
* | |||
* @param [out] enc The encoded point. | |||
* @param [in] p The point. | |||
*/ | |||
decaf_error_t $(c_ns)_point_decode_like_eddsa_and_ignore_cofactor ( | |||
decaf_error_t $(c_ns)_point_decode_like_eddsa_and_mul_by_ratio ( | |||
$(c_ns)_point_t p, | |||
const uint8_t enc[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES] | |||
) DECAF_API_VIS DECAF_NONNULL DECAF_NOINLINE; | |||
@@ -40,6 +40,9 @@ typedef struct gf_$(gf_shortname)_s { | |||
/** The cofactor the curve would have, if we hadn't removed it */ | |||
#define $(C_NS)_REMOVED_COFACTOR $(cofactor) | |||
/** X$(gf_shortname) encoding ratio. */ | |||
#define DECAF_X$(gf_shortname)_ENCODE_RATIO $(x_encode_ratio) | |||
/** Number of bytes in an x$(gf_shortname) public key */ | |||
#define DECAF_X$(gf_shortname)_PUBLIC_BYTES $((gf_bits-1)//8 + 1) | |||
@@ -386,12 +389,26 @@ decaf_error_t decaf_x$(gf_shortname) ( | |||
) DECAF_API_VIS DECAF_NONNULL DECAF_WARN_UNUSED DECAF_NOINLINE; | |||
/** | |||
* @brief Multiply a point by the cofactor, then encode it like RFC 7748 | |||
* @brief Multiply a point by DECAF_X$(gf_shortname)_ENCODE_RATIO, | |||
* then encode it like RFC 7748. | |||
* | |||
* This function is mainly used internally, but is exported in case | |||
* it will be useful. | |||
* | |||
* The ratio is necessary because the internal representation doesn't | |||
* track the cofactor information, so on output we must clear the cofactor. | |||
* This would multiply by the cofactor, but in fact internally libdecaf's | |||
* points are always even, so it multiplies by half the cofactor instead. | |||
* | |||
* As it happens, this aligns with the base point definitions; that is, | |||
* if you pass the Decaf/Ristretto base point to this function, the result | |||
* will be DECAF_X$(gf_shortname)_ENCODE_RATIO times the X$(gf_shortname) | |||
* base point. | |||
* | |||
* @param [out] out The scaled and encoded point. | |||
* @param [in] p The point to be scaled and encoded. | |||
*/ | |||
void $(c_ns)_point_mul_by_cofactor_and_encode_like_x$(gf_shortname) ( | |||
void $(c_ns)_point_mul_by_ratio_and_encode_like_x$(gf_shortname) ( | |||
uint8_t out[DECAF_X$(gf_shortname)_PUBLIC_BYTES], | |||
const $(c_ns)_point_t p | |||
) DECAF_API_VIS DECAF_NONNULL; | |||
@@ -51,9 +51,6 @@ static inline int bits() { return $(gf_bits); } | |||
/** The curve's cofactor (removed, but useful for testing) */ | |||
static const int REMOVED_COFACTOR = $(cofactor); | |||
/** The curve's cofactor (removed, but useful for testing) */ | |||
static const int EDDSA_RATIO = $(cofactor/2 if eddsa_sigma_iso else cofactor); | |||
/** Residue class of field modulus: p == this mod 2*(this-1) */ | |||
static const int FIELD_MODULUS_TYPE = $(modulus &~ (modulus-3)); | |||
@@ -250,6 +247,15 @@ public: | |||
/** Bytes required for EdDSA encoding */ | |||
static const size_t LADDER_BYTES = DECAF_X$(gf_shortname)_PUBLIC_BYTES; | |||
/** Ratio due to EdDSA encoding */ | |||
static const int EDDSA_ENCODE_RATIO = $(C_NS)_EDDSA_ENCODE_RATIO; | |||
/** Ratio due to EdDSA decoding */ | |||
static const int EDDSA_DECODE_RATIO = $(C_NS)_EDDSA_DECODE_RATIO; | |||
/** Ratio due to ladder decoding */ | |||
static const int LADDER_ENCODE_RATIO = DECAF_X$(gf_shortname)_ENCODE_RATIO; | |||
/** | |||
* Size of a stegged element. | |||
@@ -335,44 +341,49 @@ public: | |||
* @return DECAF_FAILURE the string was the wrong length, or wasn't the encoding of a point. | |||
* Contents of the point are undefined. | |||
*/ | |||
inline decaf_error_t DECAF_WARN_UNUSED decode_like_eddsa_and_ignore_cofactor_noexcept ( | |||
inline decaf_error_t DECAF_WARN_UNUSED decode_like_eddsa_and_mul_by_ratio_noexcept ( | |||
const FixedBlock<DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES> &buffer | |||
) DECAF_NOEXCEPT { | |||
return $(c_ns)_point_decode_like_eddsa_and_ignore_cofactor(p,buffer.data()); | |||
return $(c_ns)_point_decode_like_eddsa_and_mul_by_ratio(p,buffer.data()); | |||
} | |||
inline void decode_like_eddsa_and_ignore_cofactor ( | |||
/** | |||
* Decode from EDDSA, multiply by EDDSA_DECODE_RATIO, and ignore any | |||
* remaining cofactor information. | |||
* @throw CryptoException if the input point was invalid. | |||
*/ | |||
inline void decode_like_eddsa_and_mul_by_ratio( | |||
const FixedBlock<DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES> &buffer | |||
) /*throw(CryptoException)*/ { | |||
if (DECAF_SUCCESS != decode_like_eddsa_and_ignore_cofactor_noexcept(buffer)) throw(CryptoException()); | |||
if (DECAF_SUCCESS != decode_like_eddsa_and_mul_by_ratio_noexcept(buffer)) throw(CryptoException()); | |||
} | |||
/** Multiply out cofactor and encode like EdDSA. */ | |||
inline SecureBuffer mul_by_cofactor_and_encode_like_eddsa() const { | |||
/** Multiply by EDDSA_ENCODE_RATIO and encode like EdDSA. */ | |||
inline SecureBuffer mul_by_ratio_and_encode_like_eddsa() const { | |||
SecureBuffer ret(DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES); | |||
$(c_ns)_point_mul_by_cofactor_and_encode_like_eddsa(ret.data(),p); | |||
$(c_ns)_point_mul_by_ratio_and_encode_like_eddsa(ret.data(),p); | |||
return ret; | |||
} | |||
/** Multiply out cofactor and encode like X25519/X448. */ | |||
inline SecureBuffer mul_by_cofactor_and_encode_like_ladder() const { | |||
SecureBuffer ret(LADDER_BYTES); | |||
$(c_ns)_point_mul_by_cofactor_and_encode_like_x$(gf_shortname)(ret.data(),p); | |||
return ret; | |||
} | |||
/** Multiply out cofactor and encode like EdDSA. */ | |||
inline void mul_by_cofactor_and_encode_like_eddsa( | |||
/** Multiply by EDDSA_ENCODE_RATIO and encode like EdDSA. */ | |||
inline void mul_by_ratio_and_encode_like_eddsa( | |||
FixedBuffer<DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES> &out | |||
) const { | |||
$(c_ns)_point_mul_by_cofactor_and_encode_like_eddsa(out.data(),p); | |||
$(c_ns)_point_mul_by_ratio_and_encode_like_eddsa(out.data(),p); | |||
} | |||
/** Multiply by LADDER_ENCODE_RATIO and encode like X25519/X448. */ | |||
inline SecureBuffer mul_by_ratio_and_encode_like_ladder() const { | |||
SecureBuffer ret(LADDER_BYTES); | |||
$(c_ns)_point_mul_by_ratio_and_encode_like_x$(gf_shortname)(ret.data(),p); | |||
return ret; | |||
} | |||
/** Multiply out cofactor and encode like X25519/X448. */ | |||
inline void mul_by_cofactor_and_encode_like_ladder( | |||
/** Multiply by LADDER_ENCODE_RATIO and encode like X25519/X448. */ | |||
inline void mul_by_ratio_and_encode_like_ladder( | |||
FixedBuffer<LADDER_BYTES> &out | |||
) const { | |||
$(c_ns)_point_mul_by_cofactor_and_encode_like_x$(gf_shortname)(out.data(),p); | |||
$(c_ns)_point_mul_by_ratio_and_encode_like_x$(gf_shortname)(out.data(),p); | |||
} | |||
/** | |||
@@ -70,7 +70,7 @@ void usage() { | |||
fprintf(stderr," -D: Display output in EdDSA format (times clearing ratio)\n"); | |||
fprintf(stderr," -R: Display raw xyzt\n"); | |||
fprintf(stderr," -C: Display output in X[25519|448] format\n"); | |||
fprintf(stderr," -H: ... divide by clearing ratio first\n"); | |||
fprintf(stderr," -H: ... divide by encoding ratio first\n"); | |||
fprintf(stderr,"\n"); | |||
fprintf(stderr," Ways to create points:\n"); | |||
fprintf(stderr," [hex]: Point from point data as hex\n"); | |||
@@ -97,7 +97,7 @@ public: | |||
uint8_t tmp[Group::Point::SER_BYTES]; | |||
typename Group::Point a,b; | |||
typename Group::Scalar s; | |||
bool plus=false, empty=true, elligator=false, mul=false, scalar=false, | |||
bool plus=false, empty=true, elligator=false, mul=false, scalar=false, div=false, torque=false, | |||
scalarempty=true, neg=false, einv=false, like_eddsa=false, like_x=false, decoeff=false, raw=false; | |||
if (done || error) return; | |||
for (int i=1; i<g_argc && !error; i++) { | |||
@@ -121,9 +121,14 @@ public: | |||
like_x = true; | |||
} else if (!strcmp(g_argv[i],"-H")) { | |||
decoeff = true; | |||
} else if (!strcmp(g_argv[i],"-T")) { | |||
torque = true; | |||
} else if (!strcmp(g_argv[i],"*")) { | |||
if (elligator || scalar || scalarempty) usage(); | |||
if (elligator || scalar || scalarempty || div) usage(); | |||
mul = true; | |||
} else if (!strcmp(g_argv[i],"/")) { | |||
if (elligator || scalar || scalarempty || mul) usage(); | |||
div = true; | |||
} else if (!strcmp(g_argv[i],"-s")) { | |||
if (elligator || scalar || !scalarempty) usage(); | |||
scalar = true; | |||
@@ -156,6 +161,8 @@ public: | |||
if (point) { | |||
if (neg) { b = -b; neg = false; } | |||
if (div) { b /= s; div=false; } | |||
if (torque) { b = b.debugging_torque(); torque=false; } | |||
if (mul) { b *= s; mul=false; } | |||
if (empty) { a = b; empty=false; } | |||
else if (plus) { a += b; plus=false; } | |||
@@ -164,7 +171,6 @@ public: | |||
} | |||
if (!error && !empty) { | |||
if (decoeff) a /= (Group::EDDSA_RATIO); | |||
if (einv) { | |||
uint8_t buffer[Group::Point::HASH_BYTES]; | |||
for (int h=0; h<1<<Group::Point::INVERT_ELLIGATOR_WHICH_BITS; h++) { | |||
@@ -179,11 +185,13 @@ public: | |||
printhex((const uint8_t *)&a, sizeof(a)); | |||
printf("\n"); | |||
} else if (like_eddsa) { | |||
SecureBuffer b = a.mul_by_cofactor_and_encode_like_eddsa(); | |||
if (decoeff) a /= (Group::Point::EDDSA_ENCODE_RATIO); | |||
SecureBuffer b = a.mul_by_ratio_and_encode_like_eddsa(); | |||
printhex(b.data(),b.size()); | |||
printf("\n"); | |||
} else if (like_x) { | |||
SecureBuffer b = a.mul_by_cofactor_and_encode_like_ladder(); | |||
if (decoeff) a /= (Group::Point::LADDER_ENCODE_RATIO); | |||
SecureBuffer b = a.mul_by_ratio_and_encode_like_ladder(); | |||
printhex(b.data(),b.size()); | |||
printf("\n"); | |||
} else { | |||
@@ -415,8 +415,8 @@ static void test_ec() { | |||
q=p; | |||
for (int j=1; j<Group::REMOVED_COFACTOR; j<<=1) q = q.times_two(); | |||
decaf_error_t error = r.decode_like_eddsa_and_ignore_cofactor_noexcept( | |||
p.mul_by_cofactor_and_encode_like_eddsa() | |||
decaf_error_t error = r.decode_like_eddsa_and_mul_by_ratio_noexcept( | |||
p.mul_by_ratio_and_encode_like_eddsa() | |||
); | |||
if (error != DECAF_SUCCESS) { | |||
test.fail(); | |||
@@ -552,7 +552,6 @@ static void test_eddsa() { | |||
SpongeRng rng(Block("test_eddsa"),SpongeRng::DETERMINISTIC); | |||
for (int i=0; i<NTESTS && test.passing_now; i++) { | |||
typename EdDSA<Group>::PrivateKey priv(rng); | |||
typename EdDSA<Group>::PublicKey pub(priv); | |||
@@ -569,7 +568,22 @@ static void test_eddsa() { | |||
} catch(CryptoException) { | |||
test.fail(); | |||
printf(" Signature validation failed on sig %d\n", i); | |||
} | |||
} | |||
/* Test encode_like and torque */ | |||
Point p(rng); | |||
SecureBuffer p1 = p.mul_by_ratio_and_encode_like_eddsa(); | |||
SecureBuffer p2 = p.debugging_torque().mul_by_ratio_and_encode_like_eddsa(); | |||
if (!memeq(p1,p2)) { | |||
test.fail(); | |||
printf(" Torque and encode like EdDSA failed\n"); | |||
} | |||
SecureBuffer p3 = p.mul_by_ratio_and_encode_like_ladder(); | |||
SecureBuffer p4 = p.debugging_torque().mul_by_ratio_and_encode_like_ladder(); | |||
if (!memeq(p3,p4)) { | |||
test.fail(); | |||
printf(" Torque and encode like ladder failed\n"); | |||
} | |||
} | |||
} | |||