/* Copyright (c) 2014 Cryptography Research, Inc. * Released under the MIT License. See LICENSE.txt for license information. */ #include #include "scalarmul.h" #include "string.h" #include "barrett_field.h" mask_t p448_montgomery_ladder( struct p448_t *out, const struct p448_t *in, const uint64_t *scalar, int nbits, int n_extra_doubles ) { struct montgomery_t mont; p448_sqr(&mont.z0,in); p448_copy(&mont.za,&mont.z0); p448_set_ui(&mont.xa,1); p448_set_ui(&mont.zd,0); p448_set_ui(&mont.xd,1); int i,j,n=(nbits-1)&63; mask_t pflip = 0; for (j=(nbits+63)/64-1; j>=0; j--) { uint64_t w = scalar[j]; for (i=n; i>=0; i--) { mask_t flip = -((w>>i)&1); p448_cond_swap(&mont.xa,&mont.xd,flip^pflip); p448_cond_swap(&mont.za,&mont.zd,flip^pflip); montgomery_step(&mont); pflip = flip; } n = 63; } p448_cond_swap(&mont.xa,&mont.xd,pflip); p448_cond_swap(&mont.za,&mont.zd,pflip); for (j=0; ja, &n->b, doNegate); p448_cond_neg(&n->c, doNegate); } static __inline__ void cond_negate_tw_pniels( struct tw_pniels_t *n, mask_t doNegate ) { cond_negate_tw_niels(&n->n, doNegate); } void constant_time_lookup_tw_pniels( struct tw_pniels_t *out, const struct tw_pniels_t *in, int nin, int idx ) { big_register_t big_one = 1, big_i = idx; big_register_t *o = (big_register_t *)out; const big_register_t *i = (const big_register_t *)in; int j; unsigned int k; memset(out, 0, sizeof(*out)); for (j=0; j>= 1; if (i> (i%64) & 0xF, inv = (bits>>3)-1; bits ^= inv; constant_time_lookup_tw_pniels(&pn, multiples, 8, bits&7); cond_negate_tw_pniels(&pn, inv); convert_tw_pniels_to_tw_extensible(working, &pn); for (i-=4; i>=0; i-=4) { double_tw_extensible(working); double_tw_extensible(working); double_tw_extensible(working); double_tw_extensible(working); bits = scalar2[i/64] >> (i%64) & 0xF; inv = (bits>>3)-1; bits ^= inv; constant_time_lookup_tw_pniels(&pn, multiples, 8, bits&7); cond_negate_tw_pniels(&pn, inv); add_tw_pniels_to_tw_extensible(working, &pn); } } void edwards_scalar_multiply_vlook( struct tw_extensible_t *working, const uint64_t scalar[7] ) { const int nbits=448; /* HACK? */ word_t prepared_data[14] = { 0x9595b847fdf73126ull, 0x9bb9b8a856af5200ull, 0xb3136e22f37d5c4full, 0x0000000189a19442ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x4000000000000000ull, 0x721cf5b5529eec33ull, 0x7a4cf635c8e9c2abull, 0xeec492d944a725bfull, 0x000000020cd77058ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull }; /* TODO: split off */ uint64_t scalar2[7]; convert_to_signed_window_form(scalar2,scalar,prepared_data,7); struct tw_extensible_t tabulator; copy_tw_extensible(&tabulator, working); double_tw_extensible(&tabulator); struct tw_pniels_t pn, multiples[8]; convert_tw_extensible_to_tw_pniels(&pn, &tabulator); convert_tw_extensible_to_tw_pniels(&multiples[0], working); int i; for (i=1; i<8; i++) { add_tw_pniels_to_tw_extensible(working, &pn); convert_tw_extensible_to_tw_pniels(&multiples[i], working); } i = nbits - 4; int bits = scalar2[i/64] >> (i%64) & 0xF, inv = (bits>>3)-1; bits ^= inv; copy_tw_pniels(&pn, &multiples[bits&7]); cond_negate_tw_pniels(&pn, inv); convert_tw_pniels_to_tw_extensible(working, &pn); for (i-=4; i>=0; i-=4) { double_tw_extensible(working); double_tw_extensible(working); double_tw_extensible(working); double_tw_extensible(working); bits = scalar2[i/64] >> (i%64) & 0xF; inv = (bits>>3)-1; bits ^= inv; copy_tw_pniels(&pn, &multiples[bits&7]); cond_negate_tw_pniels(&pn, inv); add_tw_pniels_to_tw_extensible(working, &pn); } } void edwards_comb( struct tw_extensible_t *working, const word_t scalar[7], const struct tw_niels_t *table, int n, int t, int s ) { word_t prepared_data[14] = { 0xebec9967f5d3f5c2ull, 0x0aa09b49b16c9a02ull, 0x7f6126aec172cd8eull, 0x00000007b027e54dull, 0x0000000000000000ull, 0x0000000000000000ull, 0x4000000000000000ull, 0xc873d6d54a7bb0cfull, 0xe933d8d723a70aadull, 0xbb124b65129c96fdull, 0x00000008335dc163ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull }; /* TODO: split off. Above is for 450 bits */ word_t scalar2[7]; convert_to_signed_window_form(scalar2,scalar,prepared_data,7); /* const int n=3, t=5, s=30; */ int i,j,k; struct tw_niels_t ni; for (i=0; i> (bit%WORD_BITS) & 1) << k; } } mask_t invert = (tab>>(t-1))-1; tab ^= invert; tab &= (1<<(t-1)) - 1; constant_time_lookup_tw_niels(&ni, table + (j<<(t-1)), 1<<(t-1), tab); cond_negate_tw_niels(&ni, invert); if (i||j) { add_tw_niels_to_tw_extensible(working, &ni); } else { convert_tw_niels_to_tw_extensible(working, &ni); } } } } void simultaneous_invert_p448( struct p448_t *out, const struct p448_t *in, int n ) { if (!n) return; p448_copy(&out[1], &in[0]); int i; for (i=1; i0; i--) { p448_mul(&tmp, &out[i], &out[0]); p448_copy(&out[i], &tmp); p448_mul(&tmp, &out[0], &in[i]); p448_copy(&out[0], &tmp); } } mask_t precompute_for_combs( struct tw_niels_t *out, const struct tw_extensible_t *const_base, int n, int t, int s ) { if (s < 1) return 0; struct tw_extensible_t working, start; copy_tw_extensible(&working, const_base); struct tw_pniels_t pn_tmp; struct tw_pniels_t *doubles = (struct tw_pniels_t *) malloc(sizeof(*doubles) * (t-1)); struct p448_t *zs = (struct p448_t *) malloc(sizeof(*zs) * (n<<(t-1))); struct p448_t *zis = (struct p448_t *) malloc(sizeof(*zis) * (n<<(t-1))); if (!doubles || !zs || !zis) { free(doubles); free(zs); free(zis); return 0; } int i,j,k; for (i=0; i>1); int idx = ((i+1)<<(t-1))-1 ^ gray; convert_tw_extensible_to_tw_pniels(&pn_tmp, &start); copy_tw_niels(&out[idx], &pn_tmp.n); p448_copy(&zs[idx], &pn_tmp.z); if (j >= (1<<(t-1)) - 1) break; int delta = (j+1) ^ ((j+1)>>1) ^ gray; for (k=0; delta>1; k++) delta >>=1; if (gray & (1< 0) { double_tw_extensible(&base); convert_tw_extensible_to_tw_pniels(&twop, &base); add_tw_pniels_to_tw_extensible(&base, &tmp); convert_tw_extensible_to_tw_pniels(&tmp, &base); p448_copy(&zs[1], &tmp.z); copy_tw_niels(&out[1], &tmp.n); for (i=2; i < 1<= -2 - tableBits; i--) { int bit = (i >= 0) ? (scalar[i/WORD_BITS] >> (i%WORD_BITS)) & 1 : 0; current = 2*current + bit; /* * Sizing: |current| >= 2^(tableBits+1) -> |current| = 2^0 * So current loses (tableBits+1) bits every time. It otherwise gains * 1 bit per iteration. The number of iterations is * (nbits + 2 + tableBits), and an additional control word is added at * the end. So the total number of control words is at most * ceil((nbits+1) / (tableBits+1)) + 2 = floor((nbits)/(tableBits+1)) + 2. * There's also the stopper with power -1, for a total of +3. */ if (current >= (2<> 1; current = -(current & 1); int j; for (j=i; (delta & 1) == 0; j++) { delta >>= 1; } control[position].power = j+1; control[position].addend = delta; position++; assert(position <= nbits/(tableBits+1) + 2); } } control[position].power = -1; control[position].addend = 0; return position; } static void prepare_wnaf_table( struct tw_pniels_t *output, struct tw_extensible_t *working, int tbits ) { convert_tw_extensible_to_tw_pniels(&output[0], working); if (tbits == 0) return; double_tw_extensible(working); struct tw_pniels_t twop; convert_tw_extensible_to_tw_pniels(&twop, working); add_tw_pniels_to_tw_extensible(working, &output[0]); convert_tw_extensible_to_tw_pniels(&output[1], working); for (int i=2; i < 1< 0) { assert(control[0].addend > 0); assert(control[0].power >= 0); convert_tw_pniels_to_tw_extensible(working, &precmp[control[0].addend >> 1]); } else { set_identity_tw_extensible(working); return; } int conti = 1, i; for (i = control[0].power - 1; i >= 0; i--) { double_tw_extensible(working); if (i == control[conti].power) { assert(control[conti].addend); if (control[conti].addend > 0) { add_tw_pniels_to_tw_extensible(working, &precmp[control[conti].addend >> 1]); } else { sub_tw_pniels_from_tw_extensible(working, &precmp[(-control[conti].addend) >> 1]); } conti++; assert(conti <= control_bits); } } } void edwards_scalar_multiply_vt_pre( struct tw_extensible_t *working, const uint64_t scalar[7], const struct tw_niels_t *precmp, int table_bits ) { /* HACK: not 448? */ const int nbits=448; struct smvt_control control[nbits/(table_bits+1)+3]; int control_bits = recode_wnaf(control, scalar, nbits, table_bits); if (control_bits > 0) { assert(control[0].addend > 0); assert(control[0].power >= 0); convert_tw_niels_to_tw_extensible(working, &precmp[control[0].addend >> 1]); } else { set_identity_tw_extensible(working); return; } int conti = 1, i; for (i = control[0].power - 1; i >= 0; i--) { double_tw_extensible(working); if (i == control[conti].power) { assert(control[conti].addend); if (control[conti].addend > 0) { add_tw_niels_to_tw_extensible(working, &precmp[control[conti].addend >> 1]); } else { sub_tw_niels_from_tw_extensible(working, &precmp[(-control[conti].addend) >> 1]); } conti++; assert(conti <= control_bits); } } } void edwards_combo_var_fixed_vt( struct tw_extensible_t *working, const uint64_t scalar_var[7], const uint64_t scalar_pre[7], const struct tw_niels_t *precmp, int table_bits_pre ) { /* HACK: not 448? */ const int nbits_var=448, nbits_pre=448, table_bits_var = 3; struct smvt_control control_var[nbits_var/(table_bits_var+1)+3]; struct smvt_control control_pre[nbits_pre/(table_bits_pre+1)+3]; int ncb_var = recode_wnaf(control_var, scalar_var, nbits_var, table_bits_var); int ncb_pre = recode_wnaf(control_pre, scalar_pre, nbits_pre, table_bits_pre); (void)ncb_var; (void)ncb_pre; struct tw_pniels_t precmp_var[1< control_pre[0].power) { convert_tw_pniels_to_tw_extensible(working, &precmp_var[control_var[0].addend >> 1]); contv++; } else if (i == control_pre[0].power && i >=0 ) { convert_tw_pniels_to_tw_extensible(working, &precmp_var[control_var[0].addend >> 1]); add_tw_niels_to_tw_extensible(working, &precmp[control_pre[0].addend >> 1]); contv++; contp++; } else { i = control_pre[0].power; convert_tw_niels_to_tw_extensible(working, &precmp[control_pre[0].addend >> 1]); contp++; } if (i < 0) { set_identity_tw_extensible(working); return; } for (i--; i >= 0; i--) { double_tw_extensible(working); if (i == control_var[contv].power) { assert(control_var[contv].addend); if (control_var[contv].addend > 0) { add_tw_pniels_to_tw_extensible(working, &precmp_var[control_var[contv].addend >> 1]); } else { sub_tw_pniels_from_tw_extensible(working, &precmp_var[(-control_var[contv].addend) >> 1]); } contv++; } if (i == control_pre[contp].power) { assert(control_pre[contp].addend); if (control_pre[contp].addend > 0) { add_tw_niels_to_tw_extensible(working, &precmp[control_pre[contp].addend >> 1]); } else { sub_tw_niels_from_tw_extensible(working, &precmp[(-control_pre[contp].addend) >> 1]); } contp++; } } assert(contv == ncb_var); assert(contp == ncb_pre); }