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); }
/* Allocates some memory for a brainfuck program */ Memory *make_memory(void) { int i; Memory *mem; mem = malloc(sizeof(Memory)); mem->mp = 0; if(wrap) { /* memory cells are unsigned char */ mem->pos_mem = malloc(INIT_MEM_SIZE); mem->pos_len = INIT_MEM_SIZE; memset(mem->pos_mem, 0, INIT_MEM_SIZE); mem->neg_mem = malloc(INIT_MEM_SIZE); mem->neg_len = INIT_MEM_SIZE; memset(mem->neg_mem, 0, INIT_MEM_SIZE); } else { /* memory cells are bigint */ mem->pos_mem = malloc(INIT_MEM_SIZE * sizeof(bigint)); mem->pos_len = INIT_MEM_SIZE; /* we have to cast to "bigint *" here for the pointer arithmetic to work */ for(i = 0; i < mem->pos_len; i++) bigint_init((bigint *)mem->pos_mem + i); mem->neg_mem = malloc(INIT_MEM_SIZE * sizeof(bigint)); mem->neg_len = INIT_MEM_SIZE; for(i = 0; i < mem->neg_len; i++) bigint_init((bigint *)mem->neg_mem + i); } return mem; }
int bii_test_modexp(void){ bigint dest, base, exp, mod; bigint_init(&dest); bigint_init(&base); bigint_init(&exp); bigint_init(&mod); bigint_setval32(&base, 375); bigint_setval32(&exp, 249); bigint_setval32(&mod, 388); buf = calloc(1, sizeof(char)); bigint_modexp(&dest, base, exp, mod); if(!bigint_isval(dest, 175)){ printf("Failed.\n"); return 1; } bigint_setval32(&base,2); bigint_setvalhex(&mod, "444291e51b3ea5fd16673e95674b01e7b"); //bigint_setval32(&mod, 0x25); bigint_setvalrand(&exp, 400); bigint_modequals(&exp,mod); bigint_tohex(base,&buf); printf("modexp(%s, ",buf); bigint_tohex(exp, &buf); printf("%s, ", buf); bigint_tohex(mod, &buf); printf("%s)\n ", buf); fflush(stdout); bigint_modexp(&dest, base, exp, mod); printf("done.\n");fflush(stdout); bigint_tohex(base,&buf); printf("%s",buf); printf(" ** "); bigint_tohex(exp, &buf); printf("%s", buf); printf(" %% "); bigint_tohex(mod, &buf); printf("%s == ", buf); bigint_tohex(dest, &buf); printf("%s\n", buf); free(buf); return 0; }
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; }
/** Multiply two big integers. * * The big integers @a a and @a b are multiplied and the result is stored in * @a dest. * * @param a First factor. * @param b Second factor. * @param dest Destination bigint. */ void bigint_mul(bigint_t *a, bigint_t *b, bigint_t *dest) { size_t idx; bigint_t dprod; bigint_t sum; bigint_t tmp; #ifdef DEBUG_BIGINT_TRACE printf("Multiply bigints.\n"); #endif bigint_init(&sum, 0); for (idx = 0; idx < b->length; ++idx) { bigint_shift_mul_dig(a, b->digit[idx], idx, &dprod); bigint_add(&dprod, &sum, &tmp); bigint_destroy(&dprod); bigint_destroy(&sum); bigint_shallow_copy(&tmp, &sum); } if (b->negative) sum.negative = !sum.negative; bigint_shallow_copy(&sum, dest); }
/** Get value of big integer. * * Allows to obtain the value of big integer, provided that it fits * into a small integer. * * @param bigint Bigint to obtain value from. * @param dval Place to store value. * @return EOK on success, ELIMIT if bigint is too big to fit * to @a dval. */ int bigint_get_value_int(bigint_t *bigint, int *dval) { bigint_t vval, diff; size_t idx; int val; bool_t zf; #ifdef DEBUG_BIGINT_TRACE printf("Get int value of bigint.\n"); #endif val = 0; for (idx = 0; idx < bigint->length; ++idx) { val = val * BIGINT_BASE + bigint->digit[idx]; } if (bigint->negative) val = - val; /* If the value did not fit @c val now contains garbage. Verify. */ bigint_init(&vval, val); bigint_sub(bigint, &vval, &diff); zf = bigint_is_zero(&diff); bigint_destroy(&vval); bigint_destroy(&diff); /* If the difference is not zero, the verification failed. */ if (zf != b_true) return EINVAL; *dval = val; return EOK; }
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; }
/* Returns a pointer to the current cell of memory in mem. Sorts out the growing of memory where necessary */ static inline void *get_cell(Memory *memory) { int i; int *len; void **mem; int mp; /* positive or negative address? */ if(memory->mp >= 0) { len = &(memory->pos_len); mp = memory->mp; mem = &(memory->pos_mem); } else { if(noneg) { fprintf(stderr, "%s: negative memory, perhaps you need to stop using " "the --no-negative option or fix a memory leak in your " "program.\n", program_name); stop_program = 1; return NULL; } len = &(memory->neg_len); mp = -memory->mp; mem = &(memory->neg_mem); } /* check that mp is within range */ if(maxmem && mp > maxmem) { fprintf(stderr, "%s: memory overflow, perhaps you need to adjust the " "--max-mem option or fix a memory leak in your program.\n", program_name); stop_program = 1; return NULL; } /* double the size of memory until we are within range */ while(mp >= *len) { if(wrap) { *mem = realloc(*mem, *len * 2); memset(*mem + *len, 0, *len); } else { *mem = realloc(*mem, *len * 2 * sizeof(bigint)); /* the cast is to make the pointer arithmetic happy */ for(i = 0; i < *len; i++) bigint_init((bigint *)*mem + *len + i); } *len *= 2; } if(wrap) return *mem + mp; else return *(bigint **)mem + mp; }
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); }
/* Read input to the current cell */ void input(Memory *mem) { void *cell; bigint input; int c; char buf[1024]; char *p; if(!(cell = get_cell(mem))) return; if(chario) { /* character io */ fflush(stdout); c = fgetc(stdin); if(c == EOF) goto handle_eof; else { if(wrap) *(unsigned char *)cell = c; else bigint_from_int(cell, c); } } else { /* number io */ bigint_init(&input); /* use bigint for input even if we're reading to wrapping cells */ do { if(prompt) { fprintf(stderr, "Input: "); fflush(stderr); } if(!(fgets(buf, 1024, stdin))) goto handle_eof; if((p = strchr(buf, '\n'))) *p = '\0'; } while(bigint_from_string(&input, buf) == BIGINT_ILLEGAL_PARAM); if(wrap) *(unsigned char *)cell = bigint_to_int(&input); else bigint_copy(cell, &input); bigint_release(&input); } return; handle_eof: if(strcasecmp(eof_value, "nochange") != 0) { bigint_from_string(cell, eof_value); } }
/** * Perform modular exponentiation of big integers * * @v base0 Element 0 of big integer base * @v modulus0 Element 0 of big integer modulus * @v exponent0 Element 0 of big integer exponent * @v result0 Element 0 of big integer to hold result * @v size Number of elements in base, modulus, and result * @v exponent_size Number of elements in exponent * @v tmp Temporary working space */ void bigint_mod_exp_raw ( const bigint_element_t *base0, const bigint_element_t *modulus0, const bigint_element_t *exponent0, bigint_element_t *result0, unsigned int size, unsigned int exponent_size, void *tmp ) { const bigint_t ( size ) __attribute__ (( may_alias )) *base = ( ( const void * ) base0 ); const bigint_t ( size ) __attribute__ (( may_alias )) *modulus = ( ( const void * ) modulus0 ); const bigint_t ( exponent_size ) __attribute__ (( may_alias )) *exponent = ( ( const void * ) exponent0 ); bigint_t ( size ) __attribute__ (( may_alias )) *result = ( ( void * ) result0 ); size_t mod_multiply_len = bigint_mod_multiply_tmp_len ( modulus ); struct { bigint_t ( size ) base; bigint_t ( exponent_size ) exponent; uint8_t mod_multiply[mod_multiply_len]; } *temp = tmp; static const uint8_t start[1] = { 0x01 }; memcpy ( &temp->base, base, sizeof ( temp->base ) ); memcpy ( &temp->exponent, exponent, sizeof ( temp->exponent ) ); bigint_init ( result, start, sizeof ( start ) ); while ( ! bigint_is_zero ( &temp->exponent ) ) { if ( bigint_bit_is_set ( &temp->exponent, 0 ) ) { bigint_mod_multiply ( result, &temp->base, modulus, result, temp->mod_multiply ); } bigint_ror ( &temp->exponent ); bigint_mod_multiply ( &temp->base, &temp->base, modulus, &temp->base, temp->mod_multiply ); } }
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); }