| @@ -22,6 +22,13 @@ | |||||
| #include <stdint.h> | #include <stdint.h> | ||||
| /* 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; | typedef uint64_t decaf_word_t, decaf_bool_t; | ||||
| /* TODO: prefix all these operations and factor to support multiple curves. */ | /* 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. */ | /** Number of bytes in a serialized point. One less bit than you'd think. */ | ||||
| #define DECAF_SER_BYTES ((DECAF_FIELD_BITS+6)/8) | #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 */ | /** Twisted Edwards (-1,d-1) extended homogeneous coordinates */ | ||||
| typedef struct decaf_point_s { | typedef struct decaf_point_s { | ||||
| decaf_word_t x[DECAF_LIMBS],y[DECAF_LIMBS],z[DECAF_LIMBS],t[DECAF_LIMBS]; | 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*/; | DECAF_FAILURE = 0 /*DECAF_FALSE*/; | ||||
| /** The identity point on the curve. */ | /** 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 */ | /** 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 | #ifdef __cplusplus | ||||
| extern "C" { | extern "C" { | ||||
| #endif | #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?. | // TODO: ser, deser, inv?. | ||||
| // FIXME: scalar math is untested, and therefore probably wrong. | // 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. | * @brief Add two scalars. The scalars may use the same memory. | ||||
| * @param [in] a One scalar. | * @param [in] a One scalar. | ||||
| @@ -81,6 +124,18 @@ void decaf_add_scalars ( | |||||
| const decaf_scalar_t b | const decaf_scalar_t b | ||||
| ) API_VIS NONNULL3; | ) 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. | * @brief Subtract two scalars. The scalars may use the same memory. | ||||
| * @param [in] a One scalar. | * @param [in] a One scalar. | ||||
| @@ -215,7 +215,7 @@ sv decaf_subx( | |||||
| } | } | ||||
| } | } | ||||
| static const decaf_scalar_t DECAF_SCALAR_P = {{{ | |||||
| const decaf_scalar_t decaf_scalar_p = {{{ | |||||
| 0x2378c292ab5844f3ull, | 0x2378c292ab5844f3ull, | ||||
| 0x216cc2728dc58f55ull, | 0x216cc2728dc58f55ull, | ||||
| 0xc44edb49aed63690ull, | 0xc44edb49aed63690ull, | ||||
| @@ -224,7 +224,9 @@ static const decaf_scalar_t DECAF_SCALAR_P = {{{ | |||||
| 0xffffffffffffffffull, | 0xffffffffffffffffull, | ||||
| 0x3fffffffffffffffull | 0x3fffffffffffffffull | ||||
| // TODO 32-bit clean | // TODO 32-bit clean | ||||
| }}}, DECAF_SCALAR_R2 = {{{ | |||||
| }}}, decaf_scalar_one = {{{1}}}, decaf_scalar_zero = {{{0}}}; | |||||
| static const decaf_scalar_t decaf_scalar_r2 = {{{ | |||||
| 0xe3539257049b9b60ull, | 0xe3539257049b9b60ull, | ||||
| 0x7af32c4bc1b195d9ull, | 0x7af32c4bc1b195d9ull, | ||||
| 0x0d66de2388ea1859ull, | 0x0d66de2388ea1859ull, | ||||
| @@ -235,7 +237,7 @@ static const decaf_scalar_t DECAF_SCALAR_P = {{{ | |||||
| // TODO 32-bit clean | // 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 ( | sv decaf_montmul ( | ||||
| decaf_scalar_t out, | decaf_scalar_t out, | ||||
| @@ -254,7 +256,7 @@ sv decaf_montmul ( | |||||
| decaf_dword_t chain = 0; | decaf_dword_t chain = 0; | ||||
| for (j=0; j<DECAF_SCALAR_LIMBS; j++) { | for (j=0; j<DECAF_SCALAR_LIMBS; j++) { | ||||
| chain += (decaf_dword_t)mand*mier[j] + accum[j]; | |||||
| chain += ((decaf_dword_t)mand)*mier[j] + accum[j]; | |||||
| accum[j] = chain; | accum[j] = chain; | ||||
| chain >>= WBITS; | chain >>= WBITS; | ||||
| } | } | ||||
| @@ -282,8 +284,8 @@ void decaf_mul_scalars ( | |||||
| const decaf_scalar_t a, | const decaf_scalar_t a, | ||||
| const decaf_scalar_t b | 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 ( | void decaf_sub_scalars ( | ||||
| @@ -291,7 +293,7 @@ void decaf_sub_scalars ( | |||||
| const decaf_scalar_t a, | const decaf_scalar_t a, | ||||
| const decaf_scalar_t b | 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 ( | void decaf_add_scalars ( | ||||
| @@ -306,7 +308,19 @@ void decaf_add_scalars ( | |||||
| out->limb[i] = chain; | out->limb[i] = chain; | ||||
| chain >>= WBITS; | 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; i<DECAF_SCALAR_LIMBS; i++) { | |||||
| diff |= a->limb[i] ^ b->limb[i]; | |||||
| } | |||||
| return (((decaf_dword_t)diff)-1)>>WBITS; | |||||
| } | } | ||||
| /* *** API begins here *** */ | /* *** API begins here *** */ | ||||
| @@ -451,6 +465,41 @@ void decaf_copy ( | |||||
| gf_cpy(a->t, b->t); | 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; i<DECAF_SCALAR_LIMBS; i++) { | |||||
| decaf_word_t out = 0; | |||||
| for (j=0; j<sizeof(decaf_word_t); j++,k++) { | |||||
| out |= ((decaf_word_t)ser[k])<<(8*j); | |||||
| } | |||||
| s->limb[i] = out; | |||||
| } | |||||
| decaf_sdword_t accum = 0; | |||||
| for (i=0; i<DECAF_SCALAR_LIMBS; i++) { | |||||
| accum = (accum + s->limb[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; i<DECAF_SCALAR_LIMBS; i++) { | |||||
| for (j=0; j<sizeof(decaf_word_t); j++,k++) { | |||||
| ser[k] = s->limb[i] >> (8*j); | |||||
| } | |||||
| } | |||||
| } | |||||
| void decaf_scalarmul ( | void decaf_scalarmul ( | ||||
| decaf_point_t a, | decaf_point_t a, | ||||
| const decaf_point_t b, | const decaf_point_t b, | ||||
| @@ -266,6 +266,16 @@ int main(int argc, char **argv) { | |||||
| when = now() - when; | when = now() - when; | ||||
| printf("barrett mac: %5.1fns\n", when * 1e9 / i); | 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<nbase*10; i++) { | |||||
| decaf_mul_scalars(csc,asc,bsc); | |||||
| } | |||||
| when = now() - when; | |||||
| printf("decaf mulsc: %5.1fns\n", when * 1e9 / i); | |||||
| memset(&ext,0,sizeof(ext)); | memset(&ext,0,sizeof(ext)); | ||||
| memset(&niels,0,sizeof(niels)); /* avoid assertions in p521 even though this isn't a valid ext or niels */ | memset(&niels,0,sizeof(niels)); /* avoid assertions in p521 even though this isn't a valid ext or niels */ | ||||
| @@ -1,10 +1,24 @@ | |||||
| #include "field.h" | #include "field.h" | ||||
| #include "test.h" | #include "test.h" | ||||
| #include "decaf.h" | |||||
| #include <gmp.h> | #include <gmp.h> | ||||
| #include <string.h> | #include <string.h> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| mpz_t mp_field; | 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 ( | static mask_t mpz_to_field ( | ||||
| field_a_t out, | field_a_t out, | ||||
| @@ -20,6 +34,78 @@ static mask_t mpz_to_field ( | |||||
| return succ; | 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) { | static inline int BRANCH_ON_CONSTANT(int x) { | ||||
| __asm__ ("" : "+r"(x)); | __asm__ ("" : "+r"(x)); | ||||
| return x; | return x; | ||||
| @@ -127,6 +213,34 @@ static mask_t test_add_sub_RAW ( | |||||
| return succ; | 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 ( | static mask_t test_mul_sqr ( | ||||
| const mpz_t x, | const mpz_t x, | ||||
| const mpz_t y, | const mpz_t y, | ||||
| @@ -208,6 +322,8 @@ int test_arithmetic (void) { | |||||
| mpz_init(mp_field); | mpz_init(mp_field); | ||||
| mpz_import(mp_field, FIELD_BYTES, -1, 1, -1, 0, FIELD_MODULUS); | 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_t x,y; | ||||
| mpz_init(x); | mpz_init(x); | ||||
| mpz_init(y); | mpz_init(y); | ||||
| @@ -234,6 +350,7 @@ int test_arithmetic (void) { | |||||
| succ &= test_add_sub_RAW(x,y,word); | succ &= test_add_sub_RAW(x,y,word); | ||||
| succ &= test_mul_sqr(x,y,word); | succ &= test_mul_sqr(x,y,word); | ||||
| succ &= test_scalar(x,y); | |||||
| if (j < 1000) | if (j < 1000) | ||||
| succ &= test_isr(x); | succ &= test_isr(x); | ||||