static int base58_decode(mrb_state *mrb, char *dst, const char *data, int length, const char *chars) { int leading_zero = 0; int i; Bignum *result = bignum_alloc_char(mrb, 0); Bignum *base = bignum_alloc_char(mrb, 1); int b_length; for (i = 0; i < length; ++i) { if (data[i] == chars[0]) { leading_zero++; } else { break; } } memset(dst, 0, leading_zero); for (i = length - 1; i > leading_zero - 1; --i) { Bignum *f = bignum_alloc_char(mrb, 0); int j, c = -1; for (j = 0; j < 58; ++j) { if (data[i] == chars[j]) { c = j; break; } } if (c == -1) return -1; for (j = 0; j < c; ++j) bignum_add(result, base); for (j = 0; j < 58; ++j) bignum_add(f, base); bignum_free(base); base = f; } bignum_free(base); b_length = bignum_length(result); memcpy(dst + leading_zero, result->data + result->len - b_length , b_length); bignum_free(result); return leading_zero + b_length; }
bignum* bignum_sub(bignum a, bignum b) { b.sign = !b.sign; bignum* sum = bignum_add(a, b); return sum; }
main(int argc, char** argv) { char bignum_1[1000]; char bignum_2[1000]; int i, j = 0, k = 0; zero(bignum_1, 1000); zero(bignum_2, 1000); bignum_1[999] = 1; printf("NOTE: there's a limit of 1000 digits\n"); printf("calculate factorial of: "); scanf("%d", &i); while(i--){ /* memcpy(bignum_2, bignum_1, 1000); */ wannabe_memcpy(bignum_2, bignum_1, 1000); for(j = i; j>0; j--) bignum_add(bignum_1, bignum_2); } bignum_put(bignum_1); return 0; }
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); }
int find_nth_first_nbits_fibonacci(int nbits) { int i, nth, idx; struct bignum num[2] = {0}; nth = 3; num[0].d[0] = 1; num[1].d[0] = 1; while (1) { idx = ((nth & 0x1) ^ 0x1); bignum_add(&num[idx], &num[(idx ^ 0x1)]); if (((num[idx].used + 1) * 5) >= nbits) { int tmp = ((num[idx].used + 1) * 5); for (i = 10000; i > 0; i /= 10) { if (num[idx].d[num[idx].used] / i == 0) tmp--; } if (tmp >= nbits) break; } nth++; } return nth; }
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]]); }
void comb_sum(bignum_t* sum, const byte* comb_set) { int i; bignum_clear(sum); for (i = 0; i < 70; i++) if (comb_set[i / 8] & (1 << (i % 8))) bignum_add(sum, &nums[i]); }
/* Examples: 82000 (base 3) = 11011111001 = 1*3**0 + 0*3**1 + 0*3**2 + 1*3**3 +3**4 +3**5 +3**6 +3**7 +0*3**8 +3**9 +3**10 82000 (base 5) = 10111000 = 0*5**0 + 0*5**1 + 0*5**2 + 1*5**3 + 1*5**4 + 1*5**5 + 0*5**6 + 1*5**7 */ void bignum_from_string_binary(bignum *n, char const* s, size_t base) { char const *end_of_s = s + strlen(s) - 1; bignum_from_int(n, 0); bignum multiplier; bignum_init(&multiplier); bignum_from_int(&multiplier, 1); while (end_of_s != s) { assert((*end_of_s == '1') || (*end_of_s == '0')); if (*end_of_s == '1') { bignum_add(n, &multiplier); } bignum_mul_int(&multiplier, base); --end_of_s; } bignum_add(n, &multiplier); bignum_free(&multiplier); }
Bool bignum_div3(BigNum b1, BigNum b2, BigNum *b3, BigNum *b4) { //---- 局所宣言 BigNum low; // 下端 BigNum hig; // 上端 BigNum mid; // 中央 BigNum val; // 計算値(除数と仮整商の積) BigNum t; // 一時変数 int sft; // 上端の節数 int cmp; // 大小比較の結果 //---- 事前処理 // 除数の吟味(0除算の禁止) if ( bignum_zero(b2) == TRUE ) { return FALSE; } //---- 初期処理 bignum_init(&low, 0); // 下端の初期化(0) bignum_init(&hig, 1); // 上端の仮値(1) sft = b1.uni-b2.uni+1; // 上端の節数 bignum_shift(&hig, sft); // 上端の初期化(節移動) //---- 計算処理 //-- 整商の計算 while ( bignum_near(low, hig, 1) == 0 ) { // 上端と下端の中点として中央値をmidに格納 bignum_add(low, hig, &mid); bignum_half(&mid); // 中央値midとb2の乗算をvalに格納l if ( bignum_mlt(mid, b2, &val) == FALSE ) { return FALSE; } // b1とvalが等しければ脱出 cmp = bignum_cmp(val, b1); if ( cmp == 0 ) { low = mid; break; } // 異なれば上端または下端を更新 else if ( cmp > 0 ) { hig = mid; } else { low = mid; } } //-- 整商の格納と剰余の計算 // 下端値lowを整商*b3として格納 *b3 = low; // 整商*b3とb2の乗算をvalに格納l bignum_mlt(*b3, b2, &val); // b1とvalの差を剰余として*b4に格納 bignum_sub(b1, val, b4); //---- 事後処理 bignum_chk(b3); // 節数の更新 bignum_chk(b4); //---- 返却処理 return TRUE; // 正常に処理完了 }
bignum* bignum_add(bignum a, bignum b) { char carry = 0; /* Indique l'opération à faire en valeur absolue 1 si les deux nombres sont additionnés en valeur absolue -1 s'il s'agit d'une soustraction */ char op = 1; int i = 0; int size_a = bignum_len(a), size_b = bignum_len(b), max_size = MAX(size_a, size_b); bignum* sum = bignum_init(); bigdigit* digit = NULL; bigdigit** da = &a.first; bigdigit** db = &b.first; bigdigit** next = &sum->first; if(a.sign == b.sign) { sum->sign = a.sign; } else { // Assure que |a| >= |b| par la suite if(bignum_absgt(b, a)) { bignum_destoroyah(sum); return bignum_add(b, a); } sum->sign = a.sign; op = -1; } for(i = 0; i < max_size + 1; i++) { digit = bigdigit_init(); digit->value = carry; if(i < size_a) { digit->value += (*da)->value; da = &(*da)->next; } if(i < size_b) { digit->value += op * (*db)->value; db = &(*db)->next; } carry = op * (digit->value >= 10 || digit->value < 0); digit->value = (digit->value + 10) % 10; *next = digit; next = &digit->next; } *next = NULL; bignum_clean(sum); return sum; }
bignum_t * bignum_add_to_ (bignum_t * a, bignum_t * b, bool clear_flag) { bignum_t * c = bignum_add (a, b); bignum_delete (a); if (clear_flag) bignum_delete (b); return c; }
// 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); }
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; }
Bool bignum_sqrt(BigNum b1, BigNum *b0) { //---- 局所宣言 BigNum low; // 下端 BigNum hig; // 上端 BigNum mid; // 中央 BigNum val; // 二乗値 int sft; // 上端の節数 int cmp; // 大小比較の結果 //---- 初期処理 // lowを最下端0に初期化 bignum_init(&low, 0); // higを最上端に初期化 // 最上端は結果が含まれる範囲でキリの良い値 // 1で初期化し、適当な節だけ左シフト sft = (UNI-1)/2; bignum_init(&hig, 1); bignum_shift(&hig, sft); //---- 計算処理 while ( bignum_near(hig, low, 1) == FALSE ) { // 上端と下端の中点として中央値midの計算 bignum_add(low, hig, &mid); bignum_half(&mid); // 中央値midの二乗値val bignum_mlt(mid, mid, &val); // 二乗値valが入力値b1と等しければ脱出 cmp = bignum_cmp(val, b1); if ( cmp == 0 ) { break; }// 異なれば上端または下端を更新 else if ( cmp > 0 ) { hig = mid; } else { low = mid; } } //---- 事後処理 // 中央値midを結果b0に格納 *b0 = mid; // 節数と桁数の更新 bignum_chk(b0); //---- 返却処理 return TRUE; // 正常に処理完了 }
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; }
int main(int argc, const char *argv[]) { #ifdef DB fp = fopen("input", "r"); #endif int i, idx; int digits = 1; fibo[0].arr[0] = 1; fibo[1].arr[0] = 2; for (i = 2; i <= 5000; ++i) { digits = bignum_add(i, digits); } while (scanf("%d", &idx) != EOF) { if (!idx) {puts("1"); continue;} bignum_print(idx); putchar('\n'); } return 0; }
Bool bignum_div4(BigNum b1, BigNum b2, BigNum *b3, BigNum *b4) { //---- 局所宣言 int uni; // 節数の差 BigNum t, p; // 一時変数 int a; // 各節の整商 int k; // 反復変数 //---- 事前処理 // 除数の吟味(0除算の禁止) if ( bignum_zero(b2) == TRUE ) { return FALSE; } //---- 初期処理 bignum_init(b3, 0); // 整商の初期化(0) bignum_init(b4, 0); // 剰余の初期化(0) uni = b1.uni - b2.uni +1; // 節数の差(整商の節数) //---- 計算処理 for ( k = uni; k >= 0; k-- ) { bignum_scl(b4, RAD); bignum_add(b1, *b4, &t); b1 = t; b2 = t; bignum_shift(&t, k); bignum_output(b1); bignum_output(t); bignum_div1(b1, t, &a, b4); bignum_scl(&t, a); bignum_sub(b1, t, &p); b1 = p; b3->num[k] = a; } //---- 事後処理 bignum_chk(b3); bignum_chk(b4); //---- 返却処理 return TRUE; // 正常に処理完了 }
Bool bignum_plrt(BigNum b1, int e, BigNum *b0) { //---- 局所宣言 BigNum low; // 下端 BigNum hig; // 上端 BigNum mid; // 中央 BigNum val; // 累乗値 int sft; // 上端の節数 int cmp; // 大小比較の結果 //---- 初期処理 bignum_init(&low, 0); bignum_init(&hig, 1); sft = (UNI-1)/e; bignum_shift(&hig, sft); //---- 計算処理 while ( bignum_near(low, hig, 1) == 0 ) { bignum_add(low, hig, &mid); bignum_half(&mid); bignum_pow(mid, e, &val); cmp = bignum_cmp(val, b1); if ( cmp == 0 ) { break; } else if ( cmp > 0 ) { hig = mid; } else { low = mid; } } //---- 事後処理 *b0 = mid; bignum_chk(b0); //---- 返却処理 return TRUE; // 正常に処理完了 }
static int get_ipv6_lease(main_server_st* s, struct proc_st* proc) { struct sockaddr_storage tmp, mask, network, rnd; unsigned i, max_loops = MAX_IP_TRIES; int ret; const char* c_network, *c_netmask; char buf[64]; if (proc->config.ipv6_network && proc->config.ipv6_netmask) { c_network = proc->config.ipv6_network; c_netmask = proc->config.ipv6_netmask; } else { c_network = s->config->network.ipv6; c_netmask = s->config->network.ipv6_netmask; } if (c_network && c_netmask) { ret = inet_pton(AF_INET6, c_network, SA_IN6_P(&network)); if (ret != 1) { mslog(s, NULL, LOG_ERR, "error reading IP: %s", c_network); return -1; } ret = inet_pton(AF_INET6, c_netmask, SA_IN6_P(&mask)); if (ret != 1) { mslog(s, NULL, LOG_ERR, "error reading mask: %s", c_netmask); return -1; } proc->ipv6 = calloc(1, sizeof(*proc->ipv6)); if (proc->ipv6 == NULL) return ERR_MEM; /* mask the network */ for (i=0;i<sizeof(struct in6_addr);i++) SA_IN6_U8_P(&network)[i] &= (SA_IN6_U8_P(&mask)[i]); ((struct sockaddr_in6*)&network)->sin6_family = AF_INET6; ((struct sockaddr_in6*)&network)->sin6_port = 0; memcpy(&tmp, &network, sizeof(tmp)); ((struct sockaddr_in6*)&tmp)->sin6_family = AF_INET6; ((struct sockaddr_in6*)&tmp)->sin6_port = AF_INET6; ((struct sockaddr_in6*)&rnd)->sin6_family = AF_INET6; ((struct sockaddr_in6*)&rnd)->sin6_port = AF_INET6; do { if (max_loops == 0) { mslog(s, NULL, LOG_ERR, "could not figure out a valid IPv6 IP."); ret = ERR_NO_IP; goto fail; } if (max_loops == MAX_IP_TRIES) { uint32_t t = hash_any(proc->username, strlen(proc->username), 0); memset(SA_IN6_U8_P(&rnd), 0, sizeof(struct in6_addr)); memcpy(SA_IN6_U8_P(&rnd)+sizeof(struct in6_addr)-5, &t, 4); } else gnutls_rnd(GNUTLS_RND_NONCE, SA_IN6_U8_P(&rnd), sizeof(struct in6_addr)); max_loops--; /* Mask the random number with the netmask */ for (i=0;i<sizeof(struct in6_addr);i++) SA_IN6_U8_P(&rnd)[i] &= ~(SA_IN6_U8_P(&mask)[i]); SA_IN6_U8_P(&rnd)[sizeof(struct in6_addr)-1] &= 0xFE; /* Now add the network to the masked random number */ for (i=0;i<sizeof(struct in6_addr);i++) SA_IN6_U8_P(&rnd)[i] |= (SA_IN6_U8_P(&network)[i]); /* check if it exists in the hash table */ if (ip_lease_exists(s, &rnd, sizeof(struct sockaddr_in6)) != 0) { mslog(s, proc, LOG_DEBUG, "cannot assign local IP %s to '%s'; it is in use.", human_addr((void*)&rnd, sizeof(struct sockaddr_in6), buf, sizeof(buf)), proc->username); continue; } proc->ipv6->lip_len = sizeof(struct sockaddr_in6); memcpy(&proc->ipv6->lip, &rnd, proc->ipv6->lip_len); /* RIP = LIP + 1 */ memcpy(&tmp, &proc->ipv6->lip, proc->ipv6->rip_len); bignum_add(SA_IN6_U8_P(&tmp), sizeof(struct in6_addr), 1); /* check if it exists in the hash table */ if (ip_lease_exists(s, &tmp, sizeof(struct sockaddr_in6)) != 0) { mslog(s, proc, LOG_DEBUG, "cannot assign remote IP %s to '%s'; it is in use.", human_addr((void*)&tmp, sizeof(struct sockaddr_in6), buf, sizeof(buf)), proc->username); continue; } proc->ipv6->rip_len = sizeof(struct sockaddr_in6); memcpy(&proc->ipv6->rip, &tmp, proc->ipv6->rip_len); /* mask the last IP with the netmask */ for (i=0;i<sizeof(struct in6_addr);i++) SA_IN6_U8_P(&tmp)[i] &= (SA_IN6_U8_P(&mask)[i]); /* the result should match the network */ if (memcmp(SA_IN6_U8_P(&network), SA_IN6_U8_P(&tmp), sizeof(struct in6_addr)) != 0) { continue; } mslog(s, proc, LOG_DEBUG, "selected IP for '%s': %s", proc->username, human_addr((void*)&proc->ipv6->lip, proc->ipv6->lip_len, buf, sizeof(buf))); if (icmp_ping6(s, (void*)&proc->ipv6->lip, (void*)&proc->ipv6->rip) == 0) break; } while(1); } return 0; fail: free(proc->ipv6); proc->ipv6 = NULL; return ret; }
// assign n from s, treat s as being in base 'base' void bignum_base_convert(bignum *n, bignum* s) { bignum_from_int(n, 0); for (int i = 0; i < s->size; ++i) { bignum_add(n, &sum_lut[i][s->data[i]]); } }
/** * crypto_rsa_exptmod - RSA modular exponentiation * @in: Input data * @inlen: Input data length * @out: Buffer for output data * @outlen: Maximum size of the output buffer and used size on success * @key: RSA key * @use_private: 1 = Use RSA private key, 0 = Use RSA public key * Returns: 0 on success, -1 on failure */ int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen, struct crypto_rsa_key *key, int use_private) { struct bignum *tmp, *a = NULL, *b = NULL; int ret = -1; size_t modlen; if (use_private && !key->private_key) return -1; tmp = bignum_init(); if (tmp == NULL) return -1; if (bignum_set_unsigned_bin(tmp, in, inlen) < 0) goto error; if (bignum_cmp(key->n, tmp) < 0) { /* Too large input value for the RSA key modulus */ goto error; } if (use_private) { /* * Decrypt (or sign) using Chinese remainer theorem to speed * up calculation. This is equivalent to tmp = tmp^d mod n * (which would require more CPU to calculate directly). * * dmp1 = (1/e) mod (p-1) * dmq1 = (1/e) mod (q-1) * iqmp = (1/q) mod p, where p > q * m1 = c^dmp1 mod p * m2 = c^dmq1 mod q * h = q^-1 (m1 - m2) mod p * m = m2 + hq */ a = bignum_init(); b = bignum_init(); if (a == NULL || b == NULL) goto error; /* a = tmp^dmp1 mod p */ if (bignum_exptmod(tmp, key->dmp1, key->p, a) < 0) goto error; /* b = tmp^dmq1 mod q */ if (bignum_exptmod(tmp, key->dmq1, key->q, b) < 0) goto error; /* tmp = (a - b) * (1/q mod p) (mod p) */ if (bignum_sub(a, b, tmp) < 0 || bignum_mulmod(tmp, key->iqmp, key->p, tmp) < 0) goto error; /* tmp = b + q * tmp */ if (bignum_mul(tmp, key->q, tmp) < 0 || bignum_add(tmp, b, tmp) < 0) goto error; } else { /* Encrypt (or verify signature) */ /* tmp = tmp^e mod N */ if (bignum_exptmod(tmp, key->e, key->n, tmp) < 0) goto error; } modlen = crypto_rsa_get_modulus_len(key); if (modlen > *outlen) { *outlen = modlen; goto error; } if (bignum_get_unsigned_bin_len(tmp) > modlen) goto error; /* should never happen */ *outlen = modlen; os_memset(out, 0, modlen); if (bignum_get_unsigned_bin( tmp, out + (modlen - bignum_get_unsigned_bin_len(tmp)), NULL) < 0) goto error; ret = 0; error: bignum_deinit(tmp); bignum_deinit(a); bignum_deinit(b); return ret; }
/** * 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; }
/** * 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); }