From 83c59a645a69d51f49cf59c8dfdd0c840121610a Mon Sep 17 00:00:00 2001 From: Michael Hamburg Date: Thu, 29 Jan 2015 13:52:16 -0800 Subject: [PATCH] decaf scalars work --- include/decaf.h | 73 +++++++++++++++++++++---- src/decaf.c | 65 ++++++++++++++++++++--- test/bench.c | 10 ++++ test/test_arithmetic.c | 117 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 248 insertions(+), 17 deletions(-) diff --git a/include/decaf.h b/include/decaf.h index f62ea68..7ebc2f1 100644 --- a/include/decaf.h +++ b/include/decaf.h @@ -22,6 +22,13 @@ #include +/* Goldilocks' build flags default to hidden and stripping executables. */ +#define API_VIS __attribute__((visibility("default"))) +#define WARN_UNUSED __attribute__((warn_unused_result)) +#define NONNULL1 __attribute__((nonnull(1))) +#define NONNULL2 __attribute__((nonnull(1,2))) +#define NONNULL3 __attribute__((nonnull(1,2,3))) + typedef uint64_t decaf_word_t, decaf_bool_t; /* TODO: prefix all these operations and factor to support multiple curves. */ @@ -34,6 +41,9 @@ typedef uint64_t decaf_word_t, decaf_bool_t; /** Number of bytes in a serialized point. One less bit than you'd think. */ #define DECAF_SER_BYTES ((DECAF_FIELD_BITS+6)/8) +/** Number of bytes in a serialized scalar. Two less bits than you'd think. */ +#define DECAF_SCALAR_BYTES ((DECAF_FIELD_BITS+5)/8) + /** Twisted Edwards (-1,d-1) extended homogeneous coordinates */ typedef struct decaf_point_s { decaf_word_t x[DECAF_LIMBS],y[DECAF_LIMBS],z[DECAF_LIMBS],t[DECAF_LIMBS]; @@ -50,25 +60,58 @@ static const decaf_bool_t DECAF_SUCCESS = -(decaf_bool_t)1 /*DECAF_TRUE*/, DECAF_FAILURE = 0 /*DECAF_FALSE*/; /** The identity point on the curve. */ -const decaf_point_t decaf_identity; +const decaf_point_t decaf_identity API_VIS; + +/** The prime p, for debugging purposes. + * FIXME: prevent this scalar from actually being used for non-debugging purposes? + */ +const decaf_scalar_t decaf_scalar_p API_VIS; + +/** A scalar equal to 1. */ +const decaf_scalar_t decaf_scalar_one API_VIS; + +/** A scalar equal to 0. */ +const decaf_scalar_t decaf_scalar_zero API_VIS; /** An arbitrarily chosen base point on the curve. TODO: define */ -const decaf_point_t decaf_basepoint; +const decaf_point_t decaf_basepoint API_VIS; #ifdef __cplusplus extern "C" { #endif -/* Goldilocks' build flags default to hidden and stripping executables. */ -#define API_VIS __attribute__((visibility("default"))) -#define WARN_UNUSED __attribute__((warn_unused_result)) -#define NONNULL1 __attribute__((nonnull(1))) -#define NONNULL2 __attribute__((nonnull(1,2))) -#define NONNULL3 __attribute__((nonnull(1,2,3))) - // TODO: ser, deser, inv?. // FIXME: scalar math is untested, and therefore probably wrong. + +/** + * @brief Read a scalar from wire format or from bytes. + * + * Return DECAF_SUCCESS if the scalar was in reduced form. This + * function is not WARN_UNUSED because eg challenges in signatures + * may need to be longer. + * + * TODO: create a decode long function. + * + * @param [in] ser Serialized form of a scalar. + * @param [out] out Deserialized form. + */ +decaf_bool_t decaf_decode_scalar( + decaf_scalar_t s, + const unsigned char ser[DECAF_SER_BYTES] +) API_VIS NONNULL2; + +/** + * @brief Serialize a scalar to wire format. + * + * @param [out] ser Serialized form of a scalar. + * @param [in] s Deserialized scalar. + */ +void decaf_encode_scalar( + unsigned char ser[DECAF_SER_BYTES], + const decaf_scalar_t s +) API_VIS NONNULL2; + /** * @brief Add two scalars. The scalars may use the same memory. * @param [in] a One scalar. @@ -81,6 +124,18 @@ void decaf_add_scalars ( const decaf_scalar_t b ) API_VIS NONNULL3; +/** + * @brief Compare two scalars. + * @param [in] a One scalar. + * @param [in] b Another scalar. + * @retval DECAF_TRUE The scalars are equal. + * @retval DECAF_FALSE The scalars are not equal. + */ +decaf_bool_t decaf_eq_scalars ( + const decaf_scalar_t a, + const decaf_scalar_t b +) API_VIS WARN_UNUSED NONNULL2; + /** * @brief Subtract two scalars. The scalars may use the same memory. * @param [in] a One scalar. diff --git a/src/decaf.c b/src/decaf.c index 5fa8029..e52d065 100644 --- a/src/decaf.c +++ b/src/decaf.c @@ -215,7 +215,7 @@ sv decaf_subx( } } -static const decaf_scalar_t DECAF_SCALAR_P = {{{ +const decaf_scalar_t decaf_scalar_p = {{{ 0x2378c292ab5844f3ull, 0x216cc2728dc58f55ull, 0xc44edb49aed63690ull, @@ -224,7 +224,9 @@ static const decaf_scalar_t DECAF_SCALAR_P = {{{ 0xffffffffffffffffull, 0x3fffffffffffffffull // TODO 32-bit clean -}}}, DECAF_SCALAR_R2 = {{{ +}}}, decaf_scalar_one = {{{1}}}, decaf_scalar_zero = {{{0}}}; + +static const decaf_scalar_t decaf_scalar_r2 = {{{ 0xe3539257049b9b60ull, 0x7af32c4bc1b195d9ull, 0x0d66de2388ea1859ull, @@ -235,7 +237,7 @@ static const decaf_scalar_t DECAF_SCALAR_P = {{{ // TODO 32-bit clean }}}; -static const decaf_word_t DECAF_MONTGOMERY_FACTOR = 0xfc42bbf0516e743b; +static const decaf_word_t DECAF_MONTGOMERY_FACTOR = 0x3bd440fae918bc5ull; sv decaf_montmul ( decaf_scalar_t out, @@ -254,7 +256,7 @@ sv decaf_montmul ( decaf_dword_t chain = 0; for (j=0; j>= WBITS; } @@ -282,8 +284,8 @@ void decaf_mul_scalars ( const decaf_scalar_t a, const decaf_scalar_t b ) { - decaf_montmul(out,a,b,DECAF_SCALAR_P,DECAF_MONTGOMERY_FACTOR); - decaf_montmul(out,out,DECAF_SCALAR_R2,DECAF_SCALAR_P,DECAF_MONTGOMERY_FACTOR); + decaf_montmul(out,a,b,decaf_scalar_p,DECAF_MONTGOMERY_FACTOR); + decaf_montmul(out,out,decaf_scalar_r2,decaf_scalar_p,DECAF_MONTGOMERY_FACTOR); } void decaf_sub_scalars ( @@ -291,7 +293,7 @@ void decaf_sub_scalars ( const decaf_scalar_t a, const decaf_scalar_t b ) { - decaf_subx(out, a->limb, b, DECAF_SCALAR_P, 0); + decaf_subx(out, a->limb, b, decaf_scalar_p, 0); } void decaf_add_scalars ( @@ -306,7 +308,19 @@ void decaf_add_scalars ( out->limb[i] = chain; chain >>= WBITS; } - decaf_subx(out, out->limb, b, DECAF_SCALAR_P, chain); + decaf_subx(out, out->limb, decaf_scalar_p, decaf_scalar_p, chain); +} + +decaf_bool_t decaf_eq_scalars ( + const decaf_scalar_t a, + const decaf_scalar_t b +) { + decaf_word_t diff = 0; + unsigned int i; + for (i=0; ilimb[i] ^ b->limb[i]; + } + return (((decaf_dword_t)diff)-1)>>WBITS; } /* *** API begins here *** */ @@ -451,6 +465,41 @@ void decaf_copy ( gf_cpy(a->t, b->t); } +decaf_bool_t decaf_decode_scalar( + decaf_scalar_t s, + const unsigned char ser[DECAF_SER_BYTES] +) { + unsigned int i,j,k=0; + for (i=0; ilimb[i] = out; + } + + decaf_sdword_t accum = 0; + for (i=0; ilimb[i] - decaf_scalar_p->limb[i]) >> WBITS; + } + + //decaf_mul_scalars(s,s,decaf_scalar_one); /* ham-handed reduce */ + + return accum; +} + +void decaf_encode_scalar( + unsigned char ser[DECAF_SER_BYTES], + const decaf_scalar_t s +) { + unsigned int i,j,k=0; + for (i=0; ilimb[i] >> (8*j); + } + } +} + void decaf_scalarmul ( decaf_point_t a, const decaf_point_t b, diff --git a/test/bench.c b/test/bench.c index 1ff0d60..c60569e 100644 --- a/test/bench.c +++ b/test/bench.c @@ -266,6 +266,16 @@ int main(int argc, char **argv) { when = now() - when; printf("barrett mac: %5.1fns\n", when * 1e9 / i); + decaf_scalar_t asc,bsc,csc; + memset(asc,0,sizeof(asc)); + memset(bsc,0,sizeof(bsc)); + when = now(); + for (i=0; i #include #include mpz_t mp_field; +mpz_t mp_scalar_field; + +void decaf_scalar_print ( + const char *descr, + const decaf_scalar_t scalar +) { + int j; + printf("%s = 0x", descr); + for (j=DECAF_SCALAR_LIMBS-1; j>=0; j--) { + printf(PRIxWORDfull, scalar->limb[j]); + } + printf("\n"); +} static mask_t mpz_to_field ( field_a_t out, @@ -20,6 +34,78 @@ static mask_t mpz_to_field ( return succ; } +static mask_t mpz_to_scalar ( + decaf_scalar_t out, + const mpz_t in +) { + uint8_t ser[DECAF_SCALAR_BYTES]; + mpz_t modded; + memset(ser,0,sizeof(ser)); + mpz_init(modded); + mpz_mod(modded, in, mp_scalar_field); + mpz_export(ser, NULL, -1, 1, -1, 0, modded); + mask_t succ = decaf_decode_scalar(out, ser); + return succ; +} + +static mask_t scalar_assert_eq_gmp( + const char *descr, + const decaf_scalar_t a, + const decaf_scalar_t b, + const decaf_scalar_t x, + const mpz_t ma, + const mpz_t mb, + const mpz_t y +) { + uint8_t xser[FIELD_BYTES], yser[FIELD_BYTES]; + mpz_t modded; + + memset(yser,0,sizeof(yser)); + + decaf_encode_scalar(xser, x); + + mpz_init(modded); + mpz_mod(modded, y, mp_scalar_field); + mpz_export(yser, NULL, -1, 1, -1, 0, modded); + + if (memcmp(xser,yser,FIELD_BYTES)) { + youfail(); + printf(" Failed arithmetic test %s\n", descr); + decaf_scalar_print(" a", a); + decaf_scalar_print(" b", b); + decaf_scalar_print(" decaf", x); + // printf(" gmpa = 0x"); + + int j; + // mpz_export(yser, NULL, -1, 1, -1, 0, ma); + // for (j=FIELD_BYTES-1; j>=0; j--) { + // printf("%02x", yser[j]); + // } + // printf("\n"); + // printf(" gmpb = 0x"); + // + // + // mpz_export(yser, NULL, -1, 1, -1, 0, mb); + // for (j=FIELD_BYTES-1; j>=0; j--) { + // printf("%02x", yser[j]); + // } + // printf("\n"); + (void)ma; (void)mb; + + printf(" gmpy = 0x"); + + mpz_export(yser, NULL, -1, 1, -1, 0, modded); + for (j=FIELD_BYTES-1; j>=0; j--) { + printf("%02x", yser[j]); + } + printf("\n"); + return MASK_FAILURE; + } + + mpz_clear(modded); + return MASK_SUCCESS; +} + static inline int BRANCH_ON_CONSTANT(int x) { __asm__ ("" : "+r"(x)); return x; @@ -127,6 +213,34 @@ static mask_t test_add_sub_RAW ( return succ; } +static mask_t test_scalar ( + const mpz_t x, + const mpz_t y +) { + decaf_scalar_t xx,yy,tt; + mpz_t t; + mask_t succ = MASK_SUCCESS; + succ = mpz_to_scalar(xx,x); + succ &= mpz_to_scalar(yy,y); + mpz_init(t); + + decaf_add_scalars(tt,xx,yy); + mpz_add(t,x,y); + succ &= scalar_assert_eq_gmp("scalar add",xx,yy,tt,x,y,t); + + decaf_sub_scalars(tt,xx,yy); + mpz_sub(t,x,y); + succ &= scalar_assert_eq_gmp("scalar sub",xx,yy,tt,x,y,t); + + decaf_mul_scalars(tt,xx,yy); + mpz_mul(t,x,y); + succ &= scalar_assert_eq_gmp("scalar mul",xx,yy,tt,x,y,t); + + mpz_clear(t); + + return succ; +} + static mask_t test_mul_sqr ( const mpz_t x, const mpz_t y, @@ -208,6 +322,8 @@ int test_arithmetic (void) { mpz_init(mp_field); mpz_import(mp_field, FIELD_BYTES, -1, 1, -1, 0, FIELD_MODULUS); + mpz_import(mp_scalar_field, DECAF_SCALAR_LIMBS, -1, sizeof(decaf_word_t), -1, 0, decaf_scalar_p); + mpz_t x,y; mpz_init(x); mpz_init(y); @@ -234,6 +350,7 @@ int test_arithmetic (void) { succ &= test_add_sub_RAW(x,y,word); succ &= test_mul_sqr(x,y,word); + succ &= test_scalar(x,y); if (j < 1000) succ &= test_isr(x);