void bii_binarymodpow_powerof2(bigint *dest, bigint base, bigint exp, uint32_t modpow){ //if the modulus is a power of 2, division and modular arithmetic is very fast. if(modpow==0){ bigint_setval32(dest, 0); return; } bigint res, B, E, tmp1; bigint_init(&res); bigint_init(&B); bigint_init(&E); bigint_init(&tmp1); bigint_setval32(&res,1); bigint_getsigbits(&B,base, modpow); bigint_setval(&E, exp); while(!bigint_isval(E,0)){ if(bigint_parity(E)==1){ bigint_multiply(&tmp1, res, B); bigint_getsigbits(&res, tmp1, modpow); } bigint_rightshift(&E,1); bigint_multiply(&tmp1, B,B); bigint_getsigbits(&B,tmp1,modpow); } bigint_setval(dest, res); bigint_free(&res); bigint_free(&B); bigint_free(&E); bigint_free(&tmp1); }
void bii_monproduct(bigint *dest, bigint abar, bigint bbar, bigint n, bigint nprime, uint32_t rpow){ bigint t, m, u, tmp1, tmp2; bigint_init(&t); bigint_init(&m); bigint_init(&u); bigint_init(&tmp1); bigint_init(&tmp2); bigint_multiply(&t, abar, bbar); bigint_multiply(&tmp1, t, nprime); bigint_getsigbits(&m, tmp1, rpow); bigint_multiply(&tmp1, m,n); bigint_add(&u,t,tmp1); bigint_rightshift(&u,rpow); if(bigint_cmp(u,n)>=0) bigint_subtract(dest,u,n); else bigint_setval(dest, u); bigint_free(&t); bigint_free(&m); bigint_free(&u); bigint_free(&tmp1); bigint_free(&tmp2); }
void bii_modexpodd(bigint *dest, bigint a, bigint e, bigint n){ /* * Modular exponentiation, returns a**e mod n * Uses the Mongtomery Product algorithm to speed up a standard repeated-squaring routine */ bigint r, nprime, tmp1, tmp2, abar, xbar; bigint_init(&r); bigint_init(&nprime); bigint_init(&tmp1); bigint_init(&tmp2); bigint_init(&abar); bigint_init(&xbar); //r is the least power of 2 which is larger than n. bigint_setval32(&r,1); uint32_t rpow = bii_sigbits(n)-1; bigint_leftshift(&r, rpow); if(bigint_cmp(r,n)==-1){ bigint_leftshift(&r,1); rpow++; } //r * r^{-1} - n*n' = 1. Use the euclidean algorithm to find n'. bigint_setval32(&tmp1, 1); bigint_egcd(r,n, tmp1, &tmp2, &nprime); bigint_setpos(&nprime); //abar = a * r mod n bigint_multiply(&tmp1,a,r); bigint_divide(&tmp2,&abar,tmp1,n); bigint_divide(&tmp1,&xbar,r,n); fflush(stdout); for(int i = bii_sigbits(e)-1; i>=0; i--){ bii_monproduct(&tmp1, xbar, xbar, n, nprime, rpow); bigint_setval(&xbar, tmp1); bigint_setval(&tmp2,e); bigint_rightshift(&tmp2,i); if(bigint_parity(tmp2)==1){ bii_monproduct(&tmp1,abar,xbar,n,nprime,rpow); bigint_setval(&xbar,tmp1); } } bigint_setval32(&tmp1, 1); bii_monproduct(dest, xbar, tmp1, n, nprime, rpow); bigint_free(&r); bigint_free(&nprime); bigint_free(&tmp1); bigint_free(&tmp2); bigint_free(&abar); bigint_free(&xbar); }
/** * Perform modular multiplication of big integers * * @v multiplicand0 Element 0 of big integer to be multiplied * @v multiplier0 Element 0 of big integer to be multiplied * @v modulus0 Element 0 of big integer modulus * @v result0 Element 0 of big integer to hold result * @v size Number of elements in base, modulus, and result * @v tmp Temporary working space */ void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, const bigint_element_t *modulus0, bigint_element_t *result0, unsigned int size, void *tmp ) { const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand = ( ( const void * ) multiplicand0 ); const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier = ( ( const void * ) multiplier0 ); const bigint_t ( size ) __attribute__ (( may_alias )) *modulus = ( ( const void * ) modulus0 ); bigint_t ( size ) __attribute__ (( may_alias )) *result = ( ( void * ) result0 ); struct { bigint_t ( size * 2 ) result; bigint_t ( size * 2 ) modulus; } *temp = tmp; int rotation; int i; /* Sanity check */ assert ( sizeof ( *temp ) == bigint_mod_multiply_tmp_len ( modulus ) ); /* Perform multiplication */ bigint_multiply ( multiplicand, multiplier, &temp->result ); /* Rescale modulus to match result */ bigint_grow ( modulus, &temp->modulus ); rotation = ( bigint_max_set_bit ( &temp->result ) - bigint_max_set_bit ( &temp->modulus ) ); for ( i = 0 ; i < rotation ; i++ ) bigint_rol ( &temp->modulus ); /* Subtract multiples of modulus */ for ( i = 0 ; i <= rotation ; i++ ) { if ( bigint_is_geq ( &temp->result, &temp->modulus ) ) bigint_subtract ( &temp->modulus, &temp->result ); bigint_ror ( &temp->modulus ); } /* Resize result */ bigint_shrink ( &temp->result, result ); /* Sanity check */ assert ( bigint_is_geq ( modulus, result ) ); }
void bigint_egcd(bigint a, bigint b, bigint c, bigint *x, bigint *y){ bigint r0, r1, r2, s1, s2, t1, t2, q, r, tmp1, tmp2; int revflag = 0; bigint_init(&r0); bigint_init(&r1); bigint_init(&r2); bigint_init(&s1); bigint_init(&s2); bigint_init(&t1); bigint_init(&t2); bigint_init(&q); bigint_init(&r); bigint_init(&tmp1); bigint_init(&tmp2); if(bigint_cmp(a,b)==-1){ revflag = 1; bigint_setval(&r0, b); bigint_setval(&r1, a); } else{ bigint_setval(&r0, a); bigint_setval(&r1, b); } bigint_divide(&q,&r2,r0,r1); bigint_setval32(&s1, 0); bigint_setval32(&s2, 1); bigint_setval32(&t1, 1); bigint_setval(&t2, q); bigint_negate(&t2); if(bigint_isval(r2,0)){ bigint_divide(&tmp1,&tmp2,c,b); if(bigint_isval(tmp2,0)){ if(revflag == 0){ bigint_setval32(x,0); bigint_setval(y,tmp1); return; } bigint_setval(x,tmp1); bigint_setval32(y,0); return; } bigint_setval32(x,0); bigint_setval32(y,0); return; } while(!bigint_isval(r2,0)){ bigint_divide(&q,&r,r1,r2); bigint_setval(&r1, r2); bigint_setval(&r2, r); bigint_multiply(&tmp1,s2,q); bigint_subtract(&tmp2,s1,tmp1); bigint_setval(&s1, s2); bigint_setval(&s2, tmp2); bigint_multiply(&tmp1,t2,q); bigint_subtract(&tmp2,t1,tmp1); bigint_setval(&t1, t2); bigint_setval(&t2, tmp2); } bigint_divide(&q,&r,c,r1); if(!bigint_isval(r,0)){ bigint_setval32(x,0); bigint_setval32(y,0); return; } if(revflag==1){ bigint_setval(&tmp1, s1); bigint_setval(&s1, t1); bigint_setval(&t1, tmp1); } if(s1.sign == BII_NEG){ bigint_setval(&tmp1, s1); bigint_setpos(&tmp1); bigint_divide(&tmp2,&r,tmp1,b); bigint_setval(&tmp1, tmp2); if(!bigint_isval(r,0)) bigint_incr(&tmp1); bigint_multiply(&tmp2,tmp1,b); bigint_plusequals(&s1,tmp2); bigint_multiply(&tmp2,tmp1,a); bigint_minusequals(&t1,tmp2); } bigint_multiply(x,q,s1); bigint_multiply(y,q,t1); bigint_free(&r0); bigint_free(&r1); bigint_free(&r2); bigint_free(&s1); bigint_free(&s2); bigint_free(&t1); bigint_free(&t2); bigint_free(&q); bigint_free(&r); bigint_free(&tmp1); bigint_free(&tmp2); }
void bii_modexpeven(bigint *dest, bigint a, bigint e, bigint n){ /* * Returns a**e mod n for the case when n is even. * This algorithm is from the paper: * Montgomery reduction with even modulus * Koc,C.K. * IEE Proceedings - Computers and Digital Techniques(1994),141(5):314 * http://dx.doi.org/10.1049/ip-cdt:19941291 */ bigint q, j, A, E, x1, x2, y, qinv, tmp1, tmp2; bigint_init(&q); bigint_init(&j); bigint_init(&A); bigint_init(&E); bigint_init(&x1); bigint_init(&x2); bigint_init(&y); bigint_init(&qinv); bigint_init(&tmp1); bigint_init(&tmp2); //n = q * (2**jpow) bigint_setval(&q,n); uint32_t jpow = 0; bigint_setval32(&j,1); while(bigint_parity(q)==0){ bigint_rightshift(&q,1); bigint_leftshift(&j,1); jpow++; } bigint_divide(&tmp1,&A,a,q); bii_modexpodd(&x1, A, e, q); bigint_getsigbits(&A,a,jpow); bigint_getsigbits(&E, e, jpow-1); bii_binarymodpow_powerof2(&x2,A,E,jpow); bigint_setval32(&tmp1, 1); bigint_egcd(q,j,tmp1, &qinv,&tmp2); bigint_subtract(&tmp1,x2,x1); bigint_multiply(&tmp2,tmp1,qinv); bigint_divide(&tmp1,&y,tmp2,j); bigint_multiply(&tmp1,q,y); bigint_add(dest,x1,tmp1); bigint_free(&q); bigint_free(&j); bigint_free(&A); bigint_free(&E); bigint_free(&x1); bigint_free(&x2); bigint_free(&y); bigint_free(&qinv); bigint_free(&tmp1); bigint_free(&tmp2); }