/** * Encode the message of given length, using the public key (exponent, modulus) * The resulting array will be of size len/bytes, each index being the encryption * of "bytes" consecutive characters, given by m = (m1 + m2*128 + m3*128^2 + ..), * encoded = m^exponent mod modulus */ bignum *encodeMessage(int len, int bytes, char *message, bignum *exponent, bignum *modulus) { /* Calloc works here because capacity = 0 forces a realloc by callees but we should really * bignum_init() all of these */ int i, j; bignum *encoded = calloc(len/bytes, sizeof(bignum)); bignum *num128 = bignum_init(), *num128pow = bignum_init(); bignum *x = bignum_init(), *current = bignum_init(); bignum_fromint(num128, 128); bignum_fromint(num128pow, 1); for(i = 0; i < len; i += bytes) { bignum_fromint(x, 0); bignum_fromint(num128pow, 1); /* Compute buffer[0] + buffer[1]*128 + buffer[2]*128^2 etc (base 128 representation for characters->int encoding)*/ for(j = 0; j < bytes; j++) { bignum_fromint(current, message[i + j]); bignum_imultiply(current, num128pow); bignum_iadd(x, current); /*x += buffer[i + j] * (1 << (7 * j)) */ bignum_imultiply(num128pow, num128); } encode(x, exponent, modulus, &encoded[i/bytes]); #ifndef NOPRINT bignum_print(&encoded[i/bytes]); printf(" "); #endif } return encoded; }
/** * 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); }
Bool bignum_div4(BigNum b1, BigNum b2, BigNum *b3, BigNum *b4) { //---- 局所宣言 int uni; // 節数の差 BigNum t; // 一時変数 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; // 節数の差(整商の節数) t = b2; bignum_shift(&t, uni-1); //---- 計算処理 for ( k = uni-1; k >= 0; k-- ) { bignum_div1(b1, t, &a, b4); b1 = *b4; bignum_shift(&t, -1); b3->num[k] = a; } //---- 事後処理 bignum_chk(b3); bignum_chk(b4); //---- 返却処理 return TRUE; // 正常に処理完了 }
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); }
Bool bignum_div5(BigNum b1, BigNum b2, BigNum *b3, BigNum *b4) { //---- 局所宣言 BigNum t; int a; int uni; int k; //---- 事前処理 if ( bignum_zero(b2) == TRUE ) { return FALSE; } //---- 初期処理 bignum_init(b3, 0); bignum_init(b4, 0); uni = b1.uni - b2.uni+1; bignum_shift(&b2, uni); //---- 計算処理 for ( k = uni; k >= 0; k-- ) { bignum_div3(b1, b2, &t, b4); b1 = *b4; bignum_shift(&b2, -1); b3->num[k] = t.num[0]; } //---- 事後処理 bignum_chk(b3); bignum_chk(b4); //---- 返却処理 return TRUE; // 正常に処理完了 }
/** * 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); }
int crypto_mod_exp(const u8 *base, size_t base_len, const u8 *power, size_t power_len, const u8 *modulus, size_t modulus_len, u8 *result, size_t *result_len) { struct bignum *bn_base, *bn_exp, *bn_modulus, *bn_result; int ret = 0; bn_base = bignum_init(); bn_exp = bignum_init(); bn_modulus = bignum_init(); bn_result = bignum_init(); if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL || bn_result == NULL) goto error; if (bignum_set_unsigned_bin(bn_base, base, base_len) < 0 || bignum_set_unsigned_bin(bn_exp, power, power_len) < 0 || bignum_set_unsigned_bin(bn_modulus, modulus, modulus_len) < 0) goto error; if (bignum_exptmod(bn_base, bn_exp, bn_modulus, bn_result) < 0) goto error; ret = bignum_get_unsigned_bin(bn_result, result, result_len); error: bignum_deinit(bn_base); bignum_deinit(bn_exp); bignum_deinit(bn_modulus); bignum_deinit(bn_result); return ret; }
/** * 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); }
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; // 正常に処理完了 }
Bool bignum_sub(BigNum b1, BigNum b2, BigNum *b0) { //---- 局所宣言 int c; // 節の繰下り int v; // 当該の節値 int k; // 反復変数 //---- 初期処理 bignum_init(b0, 0); // 和の初期化 c = 0; // 繰下りを0に //---- 減算 for ( k = 0; k < UNI; k++ ) { // 下位節から v = b1.num[k] - b2.num[k] - c; // 節同士の加算(繰上り付) c = 0; // 繰下りの初期化 while ( v < 0 ) { v += RAD; c++; } // 繰下りの計算(剰余による) b0->num[k] = v; // 節値の格納 } //---- 事後処理 if ( c != 0 ) { return FALSE; } // 最上位桁での繰下りの吟味 bignum_chk(b0); // 節数と桁数の格納 //---- 返却処理 return TRUE; // 正常に処理完了 }
Bool bignum_div2(BigNum b1, int a2, BigNum *b3, int *a4) { //---- 局所宣言 int k; // 反復変数 //---- 事前処理 // 除数の吟味(0除算の禁止) //---- 初期処理 bignum_init(b3, 0); // 整商の初期化 *a4 = 0; // 剰余の初期化 //---- 計算処理 // 多倍長の各節をa2で除算 for ( k = b1.uni-1; k > 0; k-- ) { // 整商を各節に格納し、剰余を更新 b3->num[k] = b1.num[k] / a2; b1.num[k-1] += (b1.num[k] % a2) * RAD; } b3->num[0] = b1.num[k]/a2; *a4 = b1.num[k] % a2; //---- 事後処理 bignum_chk(b3); // 節数と桁数の格納 //---- 返却処理 return TRUE; // 正常に処理完了 }
Bool bignum_gcd1(BigNum b1, BigNum b2, BigNum *b0) { //---- 局所宣言 BigNum e; BigNum t; int a; bignum_init(&e, 1); //---- 計算処理 while ( 1 ) { if ( bignum_zero(b1) ) { bignum_mlt(b2, e, b0);return; } if ( bignum_zero(b2) ) { bignum_mlt(b1, e, b0);return; } if ( bignum_cmp(b1, b2) == 0 ) { bignum_mlt(b1, e, b0);return; } if ( b1.num[0]%2 == 0 && b2.num[0]%2 == 0 ) { bignum_div2(b1, 2, &t, &a); b1 = t; bignum_div2(b2, 2, &t, &a); b2 = t; bignum_scl(&e, 2); continue; } if ( b1.num[0]%2 == 0 ) { bignum_div2(b1, 2, &t, &a); b1 = t; continue; } if ( b2.num[0]%2 == 0 ) { bignum_div2(b2, 2, &t, &a); b2 = t; continue; } if ( bignum_cmp(b1, b2) == 1 ) { bignum_sub(b1, b2, &t); b1 = t; } else { bignum_sub(b2, b1, &t); b2 = t; } } //---- 返却処理 return TRUE; // 正常に処理完了 }
bignum_t * bignum_get_str (const char * value) { bignum_t * num = x_malloc (sizeof (bignum_t)); bignum_init (num); while (isblank (*value)) value++; if (*value == '-') num->sign = true; const char * tail_ptr = NULL; if (!*value) tail_ptr = value; else tail_ptr = value + strlen (value) - 1; while (tail_ptr > value && isspace (*tail_ptr)) tail_ptr--; while (tail_ptr >= value && isdigit (*tail_ptr)) { ensure_allocation (num); num->digits[num->used++] = *tail_ptr - '0'; tail_ptr--; } if (num->allocated == 0) { free (num); return bignum_get (0); } return num; }
// 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); }
Bool bignum_pow1(BigNum b1, int e, BigNum *b0) { //---- 局所宣言 // 一時変数 BigNum bt; //---- 事前処理 // 計算範囲の吟味 if ( e < 0 ) { return FALSE; } if ( b1.dig * e > UNI*LEV ) { return FALSE; } //---- 初期処理 // 結果*b0を1に初期化 bignum_init(b0, 1); //---- 計算処理 // 素朴法による累乗計算 while ( e-- > 0 ) { bt = *b0; bignum_mlt(b1, bt, b0); } //---- 事後処理 // 節数と桁数の格納 bignum_chk(b0); //---- 返却処理 return TRUE; // 正常に処理完了 }
// 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); }
/** * Construit un bignum avec le code ASCII du char c */ bignum* bignum_fromchar(char c) { int i; bignum* num = bignum_init(); num->sign = BIGNUM_POSITIVE; bigdigit* digit = NULL; bigdigit** next = &num->first; for(i = 0; c; i++) { digit = bigdigit_init(); digit->value = (c % 10); c /= 10; *next = digit; next = &digit->next; } *next = NULL; bignum_clean(num); return num; }
/** * Construit un bignum avec les digits de num inversés */ bignum* bignum_rev(bignum num) { bignum* rev = bignum_init(); bigdigit* rev_digit = NULL; bigdigit** digit_addr = &num.first; bigdigit* prev_addr = NULL; // Construit le nouveau bignum à l'envers while(*digit_addr != NULL) { rev_digit = bigdigit_init(); please_dont_segfault(rev_digit); rev_digit->next = prev_addr; rev_digit->value = (*digit_addr)->value; prev_addr = rev_digit; digit_addr = &(*digit_addr)->next; } rev->sign = num.sign; rev->first = prev_addr; rev->refs = 1; // Attention : les trailing zéros sont importants dans le contexte d'un bignum inversé return rev; }
Bool bignum_input(BigNum *n) { //---- 局所宣言 int u; // 多倍長の節数 int t; // 一時変数 int k; // 反復変数 //---- 初期処理 bignum_init(n, 0); // 結果を0に初期化 //---- 節数の入力と確認 scanf("%d", &u); // 節数の入力 if ( u > UNI ) { return FALSE; } // 節数の超上なら打切 //---- 各節の入力と確認 for ( k = u-1; k >= 0; k-- ) { // 上位節から scanf("%d", &t); // 入力値の各格納 if ( t >= RAD ) { return FALSE; } // 節値が基数の以上なら打切 (*n).num[k] = t; // 構造体の配列メンバに節値を格納 } //---- 事後処理 bignum_chk(n); // 実際の桁数の計算 //---- 返却処理 return TRUE; // 処理が正常に完了 }
Bool bignum_add(BigNum b1, BigNum b2, BigNum *b0) { //---- 局所宣言 int c; // 節の繰上り int v; // 当該の節値 int k; // 反復変数 //---- 初期処理 bignum_init(b0, 0); // 和を0に c = 0; // 繰上りを0に //---- 計算処理 for ( k = 0; k < UNI; k++ ) { // 下位節から v = b1.num[k] + b2.num[k] + c; // 節同士の加算(繰上り付) c = v / RAD; // 繰上りの計算(整商による) b0->num[k] = v % RAD; // 繰上りの清算(剰余による) } //---- 事後処理 if ( c != 0 ) { return FALSE; } // 最上位桁での繰上りの吟味 bignum_chk(b0); // 節数と桁数の格納 //---- 返却処理 return TRUE; // 正常に処理完了 }
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; // 正常に処理完了 }
/** * 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); }
/** * 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_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; }
/** * Decode the cryptogram of given length, using the private key (exponent, modulus) * Each encrypted packet should represent "bytes" characters as per encodeMessage. * The returned message will be of size len * bytes. */ int *decodeMessage(int len, int bytes, bignum *cryptogram, bignum *exponent, bignum *modulus) { int *decoded = malloc(len * bytes * sizeof(int)); int i, j; bignum *x = bignum_init(), *remainder = bignum_init(); bignum *num128 = bignum_init(); bignum_fromint(num128, 128); for(i = 0; i < len; i++) { decode(&cryptogram[i], exponent, modulus, x); for(j = 0; j < bytes; j++) { bignum_idivider(x, num128, remainder); if(remainder->length == 0) decoded[i*bytes + j] = (char)0; else decoded[i*bytes + j] = (char)(remainder->data[0]); #ifndef NOPRINT printf("%c", (char)(decoded[i*bytes + j])); #endif } } return decoded; }
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_pow1(BigNum b1, int e, BigNum *b0) { //---- 局所宣言 // 一時変数 int k1, k2; BigNum bt; int c; //---- 事前処理 // 計算範囲の吟味 if ( e < -1 ) { return FALSE; } if ( b1.dig * e > UNI*LEV ) { return FALSE; } //---- 初期処理 // 結果*b0を1に初期化 bignum_init(b0, 1); //---- 計算処理 // 素朴法による累乗計算 while ( e-- > 0 ) { bt = *b0; bignum_init(b0, 0); for ( k1 = 0; k1 < b1.uni; k1++ ) { for ( k2 = 0; k2 < bt.uni; k2++ ) { if ( k1 + k2 >= UNI ) { continue; } // 添字の範囲外 b0->num[k1+k2] += b1.num[k1] * bt.num[k2]; // 桁ごとの加算 } } // 繰上りの清算 c = 0; for ( k1 = 0; k1 < UNI; k1++ ) { // 下位桁から b0->num[k1] += c; // 桁同士の加算 c = b0->num[k1] / RAD; b0->num[k1] %= RAD; // 繰上りの清算 } bignum_chk(b0); } //---- 事後処理 // 節数と桁数の格納 //---- 返却処理 return TRUE; // 正常に処理完了 }
// 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); }
/** * 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); }