#include #include #include #include // modulus, encoded as big-endian bytes static const unsigned char modulus[] = {0x7f,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,0xff,0xff,0xff,0xed}; static const unsigned char a_minus_two_over_four[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xdb,0x41}; #define modulus_bytes (sizeof(modulus)) #define modulus_limbs ((8*sizeof(modulus) + GMP_LIMB_BITS-1)/GMP_LIMB_BITS) static void fe_print(mp_limb_t* fe) { printf("0x"); for (size_t i = modulus_limbs-1; i > 0; --i) { printf("%016lx", fe[i]); } printf("%016lx", fe[0]); } static void crypto_scalarmult(uint8_t *out, const uint8_t *secret, size_t secretbits, const uint8_t *point) { // curve constants mp_limb_t m[modulus_limbs+1]; mp_limb_t a24[modulus_limbs+1]; assert(mpn_set_str(m, modulus, modulus_bytes, 256) == (mp_size_t)modulus_limbs); assert(mpn_set_str(a24, a_minus_two_over_four, sizeof(a_minus_two_over_four), 256) <= (mp_size_t)modulus_limbs); // allocate scratch space for internal use by GMP. // as GMP _itch are documented as functions, not macros, we use a // variable-size stack allocation. hopefully the compiler will inline _itch // functions and figure out the correct stack frame size statically through // constant propagation. mp_size_t invscratch_sz = mpn_sec_invert_itch(modulus_limbs); mp_size_t scratch_sz = invscratch_sz; scratch_sz = (modulus_limbs > scratch_sz) ? modulus_limbs : scratch_sz; mp_limb_t scratch[scratch_sz]; for (size_t i = 0; i> (i%8))&1; // printf("%01d ", bit); // { mp_limb_t pr[modulus_limbs]; fe_inv(pr, nqz); fe_mul(pr, pr, nqx); fe_print(pr); } // printf(" "); // { mp_limb_t pr[modulus_limbs]; fe_inv(pr, nqpqz); fe_mul(pr, pr, nqpqx); fe_print(pr); } // printf("\n"); mpn_cnd_swap(bit, nqx, nqpqx, modulus_limbs); mpn_cnd_swap(bit, nqz, nqpqz, modulus_limbs); mp_limb_t *x2 = nqx2; mp_limb_t *z2 = nqz2; mp_limb_t *x3 = nqpqx2; mp_limb_t *z3 = nqpqz2; mp_limb_t *x = nqx; mp_limb_t *z = nqz; mp_limb_t *xprime = nqpqx; mp_limb_t *zprime = nqpqz; // fmonty(mp_limb_t *x2, mp_limb_t 0*z2, /* output 2Q */ // mp_limb_t *x3, mp_limb_t *z3, /* output Q + Q' */ // mp_limb_t *x, mp_limb_t *z, /* input Q */ // mp_limb_t *xprime, mp_limb_t *zprime, /* input Q' */ // const mp_limb_t *qmqp /* input Q - Q' */) { mp_limb_t origx[modulus_limbs], origxprime[modulus_limbs], zzz[modulus_limbs], xx[modulus_limbs], zz[modulus_limbs], xxprime[modulus_limbs], zzprime[modulus_limbs], zzzprime[modulus_limbs]; for (size_t i = 0; i> (i%GMP_LIMB_BITS))&1; out [i/8] |= bit<<(i%8); } } int main() { // { // uint8_t out[sizeof(modulus)] = {0}; // uint8_t point[sizeof(modulus)] = {9}; // uint8_t secret[sizeof(modulus)] = {1}; // crypto_scalarmult(out, point, secret, 256); // printf("0x"); for (int i = 31; i>=0; --i) { printf("%02x", out[i]); }; printf("\n"); // } { const uint8_t expected[32] = {0x89, 0x16, 0x1f, 0xde, 0x88, 0x7b, 0x2b, 0x53, 0xde, 0x54, 0x9a, 0xf4, 0x83, 0x94, 0x01, 0x06, 0xec, 0xc1, 0x14, 0xd6, 0x98, 0x2d, 0xaa, 0x98, 0x25, 0x6d, 0xe2, 0x3b, 0xdf, 0x77, 0x66, 0x1a}; const uint8_t basepoint[32] = {9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t a[32] = {0}, b[32] = {0}; uint8_t* in = a; uint8_t* out = b; a[0] = 1; for (int i = 0; i < 200; i++) { in[0] &= 248; in[31] &= 127; in[31] |= 64; crypto_scalarmult(out, in, 256, basepoint); uint8_t* t = out; out = in; in = t; } for (int i = 0; i < 32; i++) { if (in[i] != expected[i]) { return (i+1); } } return 0; } }