void test_reduce_bigint(void){ bigint_t a, b, c; cli_putstr_P(PSTR("\r\nreduce test\r\n")); for (;;) { cli_putstr_P(PSTR("\r\nenter a:")); if (bigint_read_hex_echo(&a, 0)) { cli_putstr_P(PSTR("\r\n end reduce test")); return; } cli_putstr_P(PSTR("\r\nenter b:")); if (bigint_read_hex_echo(&b, 0)) { free(a.wordv); cli_putstr_P(PSTR("\r\n end reduce test")); return; } cli_putstr_P(PSTR("\r\n ")); bigint_print_hex(&a); cli_putstr_P(PSTR(" % ")); bigint_print_hex(&b); cli_putstr_P(PSTR(" = ")); memset(&c, 0, sizeof(c)); bigint_divide(NULL, &c, &a, &b); bigint_print_hex(&c); cli_putstr_P(PSTR("\r\n")); bigint_free(&c); bigint_free(&b); bigint_free(&a); } }
void test_div_bigint(void){ bigint_t a, b, c, d; printf_P(PSTR("\ndiv test\n")); for (;;) { printf_P(PSTR("\nenter a:")); if (bigint_read_hex_echo(&a, 0)) { printf_P(PSTR("\n end div test")); return; } printf_P(PSTR("\nenter b:")); if (bigint_read_hex_echo(&b, 0)) { free(a.wordv); printf_P(PSTR("\n end div test")); return; } printf_P(PSTR("\n ")); bigint_print_hex(&a); printf_P(PSTR(" / ")); bigint_print_hex(&b); printf_P(PSTR(" = ")); memset(&c, 0, sizeof(c)); memset(&d, 0, sizeof(d)); bigint_divide(&d, &c, &a, &b); bigint_print_hex(&d); printf_P(PSTR("; R = ")); bigint_print_hex(&c); printf_P(PSTR("\n")); bigint_free(&d); bigint_free(&c); bigint_free(&b); bigint_free(&a); } }
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); }
int bigint_multiply(bigint_s *dst, bigint_s *a, bigint_s *b) { if (!dst || !a || !b || !dst->bytes || !a->bytes || !b->bytes) return BIGINT_INVALID_ARGUMENT; if (a->bytes_alloced != b->bytes_alloced) return BIGINT_DIFFRENT_SIZE; // TODO: allow different sizes (padding) uint32_t buffer_size = dst->bytes_alloced; /* * multiply two big numbers (in columns with carry) * assuming that: * (b-number) first row * x (a-number) second row * ------------- * result */ bool add = false; for (uint32_t i = 0; i < a->bytes_used; i++) { // second row on paper bigint_s tmp; bigint_init(&tmp); uint32_t k = i; uint16_t rest = 0, carry = 0; for (uint32_t j = 0; j < b->bytes_used; j++) { uint16_t result = (uint16_t) a->bytes[i] * (uint16_t) b->bytes[j] + carry; carry = result/BIGINT_BASE; rest = result % BIGINT_BASE; if (k >= buffer_size) return BIGINT_OUT_OF_MEMORY; tmp.bytes[k++] = (uint8_t) rest; } if (k >= buffer_size) return BIGINT_OUT_OF_MEMORY; if (carry > 0) tmp.bytes[k++] = (uint8_t) carry; tmp.bytes_used = k; if (!add) { bigint_swap(dst, &tmp); add = true; } else { bigint_s r; bigint_init(&r); int rr = bigint_add(&r, dst, &tmp); if (rr != BIGINT_OK) return rr; bigint_swap(dst, &r); bigint_free(&r); } while (dst->bytes_used > 0 && dst->bytes[dst->bytes_used - 1] == 0) { dst->bytes_used--; } // sometimes result is prefixed with zeros, cutting them off bigint_free(&tmp); } return BIGINT_OK; }
void test_sub_bigint(void){ bigint_t a, b, c; printf_P(PSTR("\nadd test\n")); for (;;) { printf_P(PSTR("\nenter a:")); if (bigint_read_hex_echo(&a, 512)) { printf_P(PSTR("\n end add test")); return; } printf_P(PSTR("\nenter b:")); if (bigint_read_hex_echo(&b, 512)) { free(a.wordv); printf_P(PSTR("\n end add test")); return; } printf_P(PSTR("\n ")); bigint_print_hex(&a); printf_P(PSTR(" - ")); bigint_print_hex(&b); printf_P(PSTR(" = ")); memset(&c, 0, sizeof(c)); bigint_sub_u(&c, &a, &b); bigint_print_hex(&c); cli_putstr_P(PSTR("\r\n")); free(a.wordv); free(b.wordv); bigint_free(&c); } }
int bii_test_egcd(void){ bigint a; bigint b; bigint c; bigint x; bigint y; bigint_initrand(&a, 128); bigint_initrand(&b, 128); bigint_initrand(&c, 64); bigint_init(&x); bigint_init(&y); do{ bigint_egcd(a,b,c,&x,&y); }while(bigint_isval(x,0) && bigint_isval(y,0)); bigint_timesequals(&x,a); bigint_timesequals(&y,b); bigint_minusequals(&c,x); bigint_minusequals(&c,y); if(!bigint_isval(c,0)){ printf("egcd failed.\n"); return 1; } bigint_setval32(&a,4); bigint_setval32(&b,3); bigint_setval32(&c,1); bigint_egcd(a,b,c,&x,&y); if(!bigint_isval(x,1) || !(bigint_isval(y,1) && y.sign == BII_NEG)){ printf("egcd(4,3,1) failed.\n"); return 1; } bigint_free(&a); bigint_free(&b); bigint_free(&c); bigint_free(&x); bigint_free(&y); return 0; }
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); }
void test_gcdext_bigint(void){ bigint_t a, b, c, d, e; cli_putstr_P(PSTR("\r\ngcdext test\r\n")); for (;;) { cli_putstr_P(PSTR("\r\nenter a:")); if (bigint_read_hex_echo(&a, 0)) { cli_putstr_P(PSTR("\r\n end gcdext test")); return; } cli_putstr_P(PSTR("\r\nenter b:")); if (bigint_read_hex_echo(&b, 0)) { bigint_free(&a); cli_putstr_P(PSTR("\r\n end gcdext test")); return; } memset(&c, 0, sizeof(c)); memset(&d, 0, sizeof(d)); memset(&e, 0, sizeof(e)); cli_putstr_P(PSTR("\r\n gcdext( ")); bigint_print_hex(&a); cli_putstr_P(PSTR(", ")); bigint_print_hex(&b); cli_putstr_P(PSTR(") => ")); bigint_gcdext(&c, &d, &e, &a, &b); cli_putstr_P(PSTR("a = ")); bigint_print_hex(&d); cli_putstr_P(PSTR("; b = ")); bigint_print_hex(&e); cli_putstr_P(PSTR("; gcd = ")); bigint_print_hex(&c); cli_putstr_P(PSTR("\r\n")); bigint_free(&a); bigint_free(&b); bigint_free(&c); bigint_free(&d); bigint_free(&e); } }
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); }
struct bigint_t bigint_sub(const struct bigint_t * left, const struct bigint_t * right) { /* If the left is less than the right, bigint_sub always returns 0. */ if (left->len < right->len) return bigint_new_empty(); if (left->len == right->len && left->digits[left->len - 1] < right->digits[right->len - 1]) return bigint_new_empty(); /* Now, the following expressions holds at all times: * left.len >= right.len * left->digits[left->len - 1] >= right->digits[right->len - 1] */ struct bigint_t ret = bigint_new_empty(); size_t max_len = left->len; unsigned long *tmp = realloc(ret.digits, max_len * (sizeof (unsigned long))); ret.len = max_len; ret.digits = tmp; int carry_down = 0; for (int i = 0; i < max_len; ++i) { unsigned long left_digit = left->len < i + 1 ? 0 : left->digits[i]; unsigned long right_digit = right->len < i + 1 ? 0 : right->digits[i]; if (left_digit >= right_digit + carry_down) { unsigned long ret_digit = left_digit - right_digit - carry_down; ret.digits[i] = ret_digit; carry_down = 0; } else { unsigned long ret_digit = left_digit + bigint_max - right_digit - carry_down; ret.digits[i] = ret_digit; carry_down = 1; } } if (carry_down) { /* If left < right, */ bigint_free(&ret); return bigint_new_empty(); } int strip_len = 0; for (int i = 0; i < max_len - 1; ++i) { if (ret.digits[max_len - i - 1] != 0) break; ++strip_len; } tmp = realloc(ret.digits, (max_len - strip_len) * (sizeof (unsigned long))); ret.len = max_len - strip_len; ret.digits = tmp; return ret; }
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); }