void bignum_init_base_convert(size_t size, int base) { bignum multiplier; bignum_init(&multiplier); bignum_from_int(&multiplier, 1); mul_lut = malloc(size * sizeof(bignum)); mul_lut_size = size; for (int i = 0; i < size; ++i) { bignum_init(&mul_lut[i]); bignum_copy(&mul_lut[i], &multiplier); bignum_mul_int(&multiplier, base); } bignum_free(&multiplier); bignum sum; bignum_init(&sum); for (int i = 0; i < SUMSZ; ++i) { for (int j = 0; j < 256; ++j) { int m = i*8; bignum_from_int(&sum, 0); for (uint8_t mask = 1; mask != 0; mask <<= 1) { if (j & mask) { bignum_add(&sum, &mul_lut[m]); } ++m; } bignum_init(&sum_lut[i][j]); bignum_copy(&sum_lut[i][j], &sum); } } bignum_free(&sum); }
/** * Perform an in place divide of source, also producing a remainder. * source = source/div and remainder = source - source/div. */ void bignum_idivider(bignum* source, bignum* div, bignum* remainder) { bignum *q = bignum_init(), *r = bignum_init(); bignum_divide(q, r, source, div); bignum_copy(q, source); bignum_copy(r, remainder); bignum_deinit(q); bignum_deinit(r); }
// a *= b void bignum_mul_int(bignum *a, unsigned int b) { bignum tmp; bignum_init(&tmp); uint8_t b_bytes[] = { b & 0x000000ff, (b & 0x0000ff00) >> 8, (b & 0x00ff0000) >> 16, (b & 0xff000000) >> 24, }; int b_size = 3; while (b_size > 1 && b_bytes[b_size] == 0) --b_size; for (int bi = 0; bi < b_size; ++bi) { int carry = 0; for (int ai = 0; ai < a->size; ++ai) { int prod = carry + a->data[ai] * b_bytes[bi]; carry = prod / 256; tmp.data[ai + bi] = prod % 256; } tmp.data[bi + a->size] = carry; } tmp.size = a->size + b_size; while (tmp.size > 0 && tmp.data[tmp.size - 1] == 0) { --tmp.size; } if (tmp.size == 0) { tmp.size = 1; } bignum_copy(a, &tmp); bignum_free(&tmp); }
/** * Modulate the source by the modulus. source = source % modulus */ void bignum_imodulate(bignum* source, bignum* modulus) { bignum *q = bignum_init(), *r = bignum_init(); bignum_divide(q, r, source, modulus); bignum_copy(r, source); bignum_deinit(q); bignum_deinit(r); }
void comb_fast_sum(bignum_t* sum, const byte* comb_set) { int i; bignum_copy(sum, &all_sums_by_word_and_pos[0][*(uint16_t*)comb_set]); for (i = 1; i < 5; i++) bignum_add(sum, &all_sums_by_word_and_pos[i][((uint16_t*)comb_set)[i]]); }
// a %= b void bignum_mod(bignum *a, bignum *b) { bignum tmp; bignum_init(&tmp); bignum_div_mod(a, b, &tmp); bignum_copy(a, &tmp); bignum_free(&tmp); }
/** * Perform an in place divide of source. source = source/div. */ void bignum_idivide(bignum *source, bignum *div) { bignum *q = bignum_init(), *r = bignum_init(); bignum_divide(q, r, source, div); bignum_copy(q, source); bignum_deinit(q); bignum_deinit(r); }
/** * Compute the inverse of a mod m. Or, result = a^-1 mod m. */ void bignum_inverse(bignum* a, bignum* m, bignum* result) { bignum *remprev = bignum_init(), *rem = bignum_init(); bignum *auxprev = bignum_init(), *aux = bignum_init(); bignum *rcur = bignum_init(), *qcur = bignum_init(), *acur = bignum_init(); bignum_copy(m, remprev); bignum_copy(a, rem); bignum_fromint(auxprev, 0); bignum_fromint(aux, 1); while(bignum_greater(rem, &NUMS[1])) { bignum_divide(qcur, rcur, remprev, rem); /* Observe we are finding the inverse in a finite field so we can use * a modified algorithm that avoids negative numbers here */ bignum_subtract(acur, m, qcur); bignum_imultiply(acur, aux); bignum_iadd(acur, auxprev); bignum_imodulate(acur, m); bignum_copy(rem, remprev); bignum_copy(aux, auxprev); bignum_copy(rcur, rem); bignum_copy(acur, aux); } bignum_copy(acur, result); bignum_deinit(remprev); bignum_deinit(rem); bignum_deinit(auxprev); bignum_deinit(aux); bignum_deinit(rcur); bignum_deinit(qcur); bignum_deinit(acur); }
int bignum_is_lychrel(const bignum *a, int tries) { bignum *b, *c; int i, result = 1; b = bignum_copy(a); for (i = 0; i < tries; i++) { c = bignum_copy(b); bignum_reverse_digits(b); bignum_add(b, c); bignum_delete(c); if (bignum_is_palindrome(b)) { result = 0; break; } } bignum_delete(b); return result; }
// a *= b void bignum_mul_int_silly_loop(bignum *a, unsigned int b) { bignum tmp; bignum_init(&tmp); bignum_copy(&tmp, a); --b; // XXX: this loop is probably quite inefficient, think of something better while (b > 0) { bignum_add(a, &tmp); --b; } bignum_free(&tmp); }
/** * Compute the jacobi symbol, J(ac, nc). */ int bignum_jacobi(bignum* ac, bignum* nc) { bignum *remainder = bignum_init(), *twos = bignum_init(); bignum *temp = bignum_init(), *a = bignum_init(), *n = bignum_init(); int mult = 1, result = 0; bignum_copy(ac, a); bignum_copy(nc, n); while(bignum_greater(a, &NUMS[1]) && !bignum_equal(a, n)) { bignum_imodulate(a, n); if(bignum_leq(a, &NUMS[1]) || bignum_equal(a, n)) break; bignum_fromint(twos, 0); /* Factor out multiples of two */ while(a->data[0] % 2 == 0) { bignum_iadd(twos, &NUMS[1]); bignum_idivide(a, &NUMS[2]); } /* Coefficient for flipping */ if(bignum_greater(twos, &NUMS[0]) && twos->data[0] % 2 == 1) { bignum_remainder(n, &NUMS[8], remainder); if(!bignum_equal(remainder, &NUMS[1]) && !bignum_equal(remainder, &NUMS[7])) { mult *= -1; } } if(bignum_leq(a, &NUMS[1]) || bignum_equal(a, n)) break; bignum_remainder(n, &NUMS[4], remainder); bignum_remainder(a, &NUMS[4], temp); if(!bignum_equal(remainder, &NUMS[1]) && !bignum_equal(temp, &NUMS[1])) mult *= -1; bignum_copy(a, temp); bignum_copy(n, a); bignum_copy(temp, n); } if(bignum_equal(a, &NUMS[1])) result = mult; else result = 0; bignum_deinit(remainder); bignum_deinit(twos); bignum_deinit(temp); bignum_deinit(a); bignum_deinit(n); return result; }
/** * Perform modular exponentiation by repeated squaring. This will compute * result = base^exponent mod modulus */ void bignum_modpow(bignum* base, bignum* exponent, bignum* modulus, bignum* result) { bignum *a = bignum_init(), *b = bignum_init(), *c = bignum_init(); bignum *discard = bignum_init(), *remainder = bignum_init(); bignum_copy(base, a); bignum_copy(exponent, b); bignum_copy(modulus, c); bignum_fromint(result, 1); while(bignum_greater(b, &NUMS[0])) { if(b->data[0] & 1) { bignum_imultiply(result, a); bignum_imodulate(result, c); } bignum_idivide(b, &NUMS[2]); bignum_copy(a, discard); bignum_imultiply(a, discard); bignum_imodulate(a, c); } bignum_deinit(a); bignum_deinit(b); bignum_deinit(c); bignum_deinit(discard); bignum_deinit(remainder); }
/** * Check whether a is a Euler witness for n. That is, if a^(n - 1)/2 != Ja(a, n) mod n */ int solovayPrime(int a, bignum* n) { bignum *ab = bignum_init(), *res = bignum_init(), *pow = bignum_init(); bignum *modpow = bignum_init(); int x, result; bignum_fromint(ab, a); x = bignum_jacobi(ab, n); if(x == -1) bignum_subtract(res, n, &NUMS[1]); else bignum_fromint(res, x); bignum_copy(n, pow); bignum_isubtract(pow, &NUMS[1]); bignum_idivide(pow, &NUMS[2]); bignum_modpow(ab, pow, n, modpow); result = !bignum_equal(res, &NUMS[0]) && bignum_equal(modpow, res); bignum_deinit(ab); bignum_deinit(res); bignum_deinit(pow); bignum_deinit(modpow); return result; }
/** * Print a bignum to stdout as base 10 integer. This is done by * repeated division by 10. We can make it more efficient by dividing by * 10^9 for example, then doing single precision arithmetic to retrieve the * 9 remainders */ void bignum_print(bignum* b) { int cap = 100, len = 0, i; char* buffer = malloc(cap * sizeof(char)); bignum *copy = bignum_init(), *remainder = bignum_init(); if(b->length == 0 || bignum_iszero(b)) printf("0"); else { bignum_copy(b, copy); while(bignum_isnonzero(copy)) { bignum_idivider(copy, &NUMS[10], remainder); buffer[len++] = remainder->data[0]; if(len >= cap) { cap *= 2; buffer = realloc(buffer, cap * sizeof(char)); } } for(i = len - 1; i >= 0; i--) printf("%d", buffer[i]); } bignum_deinit(copy); bignum_deinit(remainder); free(buffer); }
/** * Compute the gcd of two bignums. result = gcd(b1, b2) */ void bignum_gcd(bignum* b1, bignum* b2, bignum* result) { bignum *a = bignum_init(), *b = bignum_init(), *remainder = bignum_init(); bignum *temp = bignum_init(), *discard = bignum_init(); bignum_copy(b1, a); bignum_copy(b2, b); while(!bignum_equal(b, &NUMS[0])) { bignum_copy(b, temp); bignum_imodulate(a, b); bignum_copy(a, b); bignum_copy(temp, a); } bignum_copy(a, result); bignum_deinit(a); bignum_deinit(b); bignum_deinit(remainder); bignum_deinit(temp); bignum_deinit(discard); }
bignum* bignum_dumb_mul(bignum a, bignum b) { // Optimisation if(bignum_absgt(b, a)) return bignum_dumb_mul(b, a); bignum* prod = bignum_fromstr("0"); bignum* zero = bignum_fromstr("0"); bignum* dec = bignum_fromstr("-1"); char sign = a.sign != b.sign; bignum* b_copy = bignum_copy(&b); b_copy->sign = 0; bignum* add_result = NULL; bignum* prod_result = NULL; a.sign = 0; while(!bignum_eq(*b_copy, *zero)) { add_result = bignum_add(*b_copy, *dec); bignum_destoroyah(b_copy); b_copy = add_result; prod_result = bignum_add(*prod, a); bignum_destoroyah(prod); prod = prod_result; } bignum_destoroyah(b_copy); bignum_destoroyah(zero); bignum_destoroyah(dec); prod->sign = sign; return prod; }
/** * Algo de karatsuba pour la multiplication de grands entiers */ bignum* bignum_mul(bignum a, bignum b) { int len_a = bignum_len(a); int len_b = bignum_len(b); // Multiplication stupide pour les petits nombres if(len_a < 2 || len_b < 2) { return bignum_dumb_mul(a, b); } int max = MAX(len_a, len_b); int max_middle = max/2; bignum* high_a = bignum_init(); bignum* high_b = bignum_init(); bignum* low_a = bignum_init(); bignum* low_b = bignum_init(); bignum_split(a, max-max_middle, high_a, low_a); bignum_split(b, max-max_middle, high_b, low_b); bignum* z2 = bignum_mul(*high_a, *high_b); bignum* z0 = bignum_mul(*low_a, *low_b); // Je voudrais de l'operator overloading : (z2*10^(max))+((z1-z2-z0)*10^(max_middle))+(z0) bignum* sum_a = bignum_add(*low_a, *high_a); bignum* sum_b = bignum_add(*low_b, *high_b); bignum_destoroyah(high_a); bignum_destoroyah(high_b); bignum_destoroyah(low_a); bignum_destoroyah(low_b); // z1 = (sum_a*sum_b) - z2 - z0 bignum* mul_of_sum = bignum_mul(*sum_a, *sum_b); bignum* diff_a = bignum_sub(*mul_of_sum,*z2); bignum* z1 = bignum_sub(*diff_a, *z0); bignum_destoroyah(mul_of_sum); bignum_destoroyah(diff_a); bignum_destoroyah(sum_a); bignum_destoroyah(sum_b); //arrondir pour avoir la bonne puissance de 10 dans les shifts. float inter = (float)max; inter = inter/2.0f; inter += 0.5f; max_middle = (int) inter; if(max%2 == 1){ max++; } //r1 = z2*10^(max) bignum* r1 = bignum_copy(z2); bignum_shift_left(r1, max); //r2 = z1 bignum* r2 = bignum_copy(z1); //r2 = r2*10^(max_middle) bignum_shift_left(r2, max_middle); //r3 = r2 + z0 bignum* r3 = bignum_add(*r2, *z0); //bignum_destoroyah(z0); bignum_destoroyah(r2); //rf = r1+r3 bignum* rf = bignum_add(*r1, *r3); bignum_destoroyah(r1); bignum_destoroyah(r3); bignum_destoroyah(z0); bignum_destoroyah(z1); bignum_destoroyah(z2); return rf; }
int main(int argc, const char * argv[]) { char *p=(char*)malloc(BUF_SIZE*sizeof(char)); printf("\n请输入选择的大素数p:\n"); scanf("%s",p); bignum *p1 = bignum_init(); bignum_fromstring(p1, p); free(p); if(probablePrime(p1, ACCURACY)) { printf("p合理"); bignum *yz = bignum_init(); bignum_fromint(yz, 3); if (bignum_equal(yz,p1)) { printf("但p太小不适用!\n"); return 1; } }else{ printf("p不是素数!\n"); return 1; } bignum *p2 = bignum_init(); bignum *temp = bignum_init(); bignum_fromint(temp, 1); bignum_subtract(p2, p1, temp); printf("\n请输入选择的本原元α:\n"); char *a=(char*)malloc(BUF_SIZE*sizeof(char)); scanf("%s",a); bignum *a1 = bignum_init(); bignum_fromstring(a1, a); free(a); printf("\n请输入选择的随机整数d:(2<=d<=p-2)\n"); char *d=(char*)malloc(BUF_SIZE*sizeof(char)); scanf("%s",d); bignum *d1 = bignum_init(); bignum_fromstring(d1, d); free(d); bignum *yz0 = bignum_init(); bignum_fromint(yz0, 2); bignum *yz1 = bignum_init(); bignum_subtract(yz1, p1, yz0); if( (bignum_greater(d1, yz0)||bignum_equal(d1, yz0))&&(bignum_greater(yz1,d1)||bignum_equal(yz1,d1)) ) { printf("d合理"); }else{ printf("d不合要求!\n"); return 1; } printf("\n请输入您的消息x:\n"); char *x=(char*)malloc(BUF_SIZE*sizeof(char)); scanf("%s",x); bignum *x1 = bignum_init(); bignum_fromstring(x1, x); free(x); printf("\n请输入您选择的k:(2<=k<=p-2且k应与p-1互质)\n"); char *k=(char*)malloc(BUF_SIZE*sizeof(char)); scanf("%s",k); bignum *k1 = bignum_init(); bignum_fromstring(k1, k); free(k); if( (bignum_greater(k1, yz0)||bignum_equal(k1, yz0))&&(bignum_greater(yz1,k1)||bignum_equal(yz1,k1)) ) { bignum *yz2 = bignum_init(); bignum_gcd(k1, p2, yz2); if (!bignum_equal(yz2,temp)) { printf("k不合要求!\n"); return 1; } printf("k合理"); }else{ printf("k不合要求!\n"); return 1; } bignum *b1 = bignum_init(); bignum_modpow(a1,d1,p1,b1); printf("\n\n所以\n您生成的公钥(p,α,β)为:\t("); bignum_print(p1); printf(","); bignum_print(a1); printf(","); bignum_print(b1); printf(")\n"); printf("您的私钥为:"); bignum_print(d1); printf("\n"); printf("您发出的消息(x(r,s))为:\t("); bignum_print(x1); printf(",("); bignum *r1 = bignum_init(); bignum_modpow(a1,k1,p1,r1); bignum_print(r1); printf(","); bignum *s1=bignum_init(); bignum_multiply(temp, d1, r1); bignum *temp2 = bignum_init(); bignum *x2 = bignum_init(); bignum_copy(x1, x2); while (bignum_less(x2, temp)) { bignum *add = bignum_init(); bignum_copy(p2, add); bignum_iadd(x2, add) ; } bignum_subtract(temp2, x2, temp); // printf("\ntemp2:"); // bignum_print(temp2); // printf("\t"); // bignum_print(x2); // printf("\t"); // bignum_print(temp); // printf("\n"); bignum_inverse(k1, p2, temp);//计算a的逆元result = a^-1 mod m bignum_multiply(s1, temp, temp2); bignum_imodulate(s1, p2);//source = source % modulus bignum_print(s1); printf("))\n"); bignum *t0 = bignum_init(); bignum_modpow(a1,x1,p1,t0); bignum *t1 = bignum_init(); bignum_modpow(b1,r1,p1,t1); bignum *t2 = bignum_init(); bignum_modpow(r1,s1,p1,t2); bignum *t3 = bignum_init(); bignum_multiply(t3, t1, t2); bignum_imodulate(t3, p1); printf("按t=(α^x)mod p,结果为:"); bignum_print(t0); printf("\n按t=(β^r*r^s)mod p,结果为:"); bignum_print(t3); printf("\n"); if (bignum_equal(t0, t3)) { printf("此签名正确有效~\n\n"); }else{ printf("此签名错误无效!\n\n"); } }
/** * Divide two bignums by naive long division, producing both a quotient and remainder. * quotient = floor(b1/b2), remainder = b1 - quotient * b2. If b1 < b2 the quotient is * trivially 0 and remainder is b2. */ void bignum_divide(bignum* quotient, bignum* remainder, bignum* b1, bignum* b2) { bignum *b2copy = bignum_init(), *b1copy = bignum_init(); bignum *temp = bignum_init(), *temp2 = bignum_init(), *temp3 = bignum_init(); bignum* quottemp = bignum_init(); word carry = 0; int n, m, i, j, length = 0; unsigned long long factor = 1; unsigned long long gquot, gtemp, grem; if(bignum_less(b1, b2)) { /* Trivial case, b1/b2 = 0 iff b1 < b2. */ quotient->length = 0; bignum_copy(b1, remainder); } else if(bignum_iszero(b1)) { /* 0/x = 0.. assuming b2 is nonzero */ quotient->length = 0; bignum_fromint(remainder, 0); } else if(b2->length == 1) { /* Division by a single limb means we can do simple division */ if(quotient->capacity < b1->length) { quotient->capacity = b1->length; quotient->data = realloc(quotient->data, quotient->capacity * sizeof(word)); } for(i = b1->length - 1; i >= 0; i--) { gtemp = carry * RADIX + b1->data[i]; gquot = gtemp / b2->data[0]; quotient->data[i] = (unsigned)gquot; if(quotient->data[i] != 0 && length == 0) length = i + 1; carry = gtemp % b2->data[0]; } bignum_fromint(remainder, carry); quotient->length = length; } else { /* Long division is neccessary */ n = b1->length + 1; m = b2->length; if(quotient->capacity < n - m) { quotient->capacity = n - m; quotient->data = realloc(quotient->data, (n - m) * sizeof(word)); } bignum_copy(b1, b1copy); bignum_copy(b2, b2copy); /* Normalize.. multiply by the divisor by 2 until MSB >= HALFRADIX. This ensures fast * convergence when guessing the quotient below. We also multiply the dividend by the * same amount to ensure the result does not change. */ while(b2copy->data[b2copy->length - 1] < HALFRADIX) { factor *= 2; bignum_imultiply(b2copy, &NUMS[2]); } if(factor > 1) { bignum_fromint(temp, (unsigned)factor); bignum_imultiply(b1copy, temp); } /* Ensure the dividend is longer than the original (pre-normalized) divisor. If it is not * we introduce a dummy zero word to artificially inflate it. */ if(b1copy->length != n) { b1copy->length++; if(b1copy->length > b1copy->capacity) { b1copy->capacity = b1copy->length; b1copy->data = realloc(b1copy->data, b1copy->capacity * sizeof(word)); } b1copy->data[n - 1] = 0; } /* Process quotient by long division */ for(i = n - m - 1; i >= 0; i--) { gtemp = RADIX * b1copy->data[i + m] + b1copy->data[i + m - 1]; gquot = gtemp / b2copy->data[m - 1]; if(gquot >= RADIX) gquot = UINT_MAX; grem = gtemp % b2copy->data[m - 1]; while(grem < RADIX && gquot * b2copy->data[m - 2] > RADIX * grem + b1copy->data[i + m - 2]) { /* Should not overflow... ? */ gquot--; grem += b2copy->data[m - 1]; } quottemp->data[0] = (unsigned)gquot % RADIX; quottemp->data[1] = (gquot / RADIX); if(quottemp->data[1] != 0) quottemp->length = 2; else quottemp->length = 1; bignum_multiply(temp2, b2copy, quottemp); if(m + 1 > temp3->capacity) { temp3->capacity = m + 1; temp3->data = realloc(temp3->data, temp3->capacity * sizeof(word)); } temp3->length = 0; for(j = 0; j <= m; j++) { temp3->data[j] = b1copy->data[i + j]; if(temp3->data[j] != 0) temp3->length = j + 1; } if(bignum_less(temp3, temp2)) { bignum_iadd(temp3, b2copy); gquot--; } bignum_isubtract(temp3, temp2); for(j = 0; j < temp3->length; j++) b1copy->data[i + j] = temp3->data[j]; for(j = temp3->length; j <= m; j++) b1copy->data[i + j] = 0; quotient->data[i] = (unsigned)gquot; if(quotient->data[i] != 0) quotient->length = i; } if(quotient->data[b1->length - b2->length] == 0) quotient->length = b1->length - b2->length; else quotient->length = b1->length - b2->length + 1; /* Divide by factor now to find final remainder */ carry = 0; for(i = b1copy->length - 1; i >= 0; i--) { gtemp = carry * RADIX + b1copy->data[i]; b1copy->data[i] = (unsigned)gtemp/factor; if(b1copy->data[i] != 0 && length == 0) length = i + 1; carry = (unsigned)gtemp % factor; } b1copy->length = length; bignum_copy(b1copy, remainder); } bignum_deinit(temp); bignum_deinit(temp2); bignum_deinit(temp3); bignum_deinit(b1copy); bignum_deinit(b2copy); bignum_deinit(quottemp); }
/** * Perform an in place add into the source bignum. That is source += add */ void bignum_iadd(bignum* source, bignum* add) { bignum* temp = bignum_init(); bignum_add(temp, source, add); bignum_copy(temp, source); bignum_deinit(temp); }
/** * Perform an in place subtract from the source bignum. That is, source -= sub */ void bignum_isubtract(bignum* source, bignum* sub) { bignum* temp = bignum_init(); bignum_subtract(temp, source, sub); bignum_copy(temp, source); bignum_deinit(temp); }
/** * Perform an in place multiplication into the source bignum. That is source *= mult */ void bignum_imultiply(bignum* source, bignum* mult) { bignum* temp = bignum_init(); bignum_multiply(temp, source, mult); bignum_copy(temp, source); bignum_deinit(temp); }