#include "uint2048.h" #include #include #define EOVERFLOW 75 int uint2048_init(uint2048_t* d, uint32_t n) { int i = 0; d->bucket[i++] = n; while (i < N_UINT2048) { d->bucket[i++] = 0; } return 0; } int uint2048_init_bytes(uint2048_t* d, const char* f, size_t n) { if (n > sizeof(uint2048_t)) { return -1; } memset(d->bucket, 0, sizeof(uint2048_t)); memcpy(d->bucket, f, n); return 0; } static inline uint32_t char_to_u32_safe_convert(char x) { return x >= 0 ? x : 256 + x; } int uint2048_init_bytes_be(uint2048_t* d, const char* f, size_t n) { if (n > sizeof(uint2048_t)) { return -1; } size_t i = 0; uint32_t bytes4 = 0; size_t dd = (n / 4) * 4; size_t dr = n - dd; for (int fi = n - 4; fi >= 0; fi -= 4) { bytes4 = 0; bytes4 |= char_to_u32_safe_convert(f[fi]) << 24; bytes4 |= char_to_u32_safe_convert(f[fi + 1]) << 16; bytes4 |= char_to_u32_safe_convert(f[fi + 2]) << 8; bytes4 |= char_to_u32_safe_convert(f[fi + 3]) << 0; d->bucket[i++] = bytes4; } bytes4 = 0; for (int remi = dr - 1; remi >= 0; remi--) { bytes4 |= char_to_u32_safe_convert(f[dd + remi]) << (remi * 8); } d->bucket[i++] = bytes4; while (i < N_UINT2048) { d->bucket[i++] = 0; } return 0; } int uint2048_copy(uint2048_t* dest, uint2048_t* src) { memcpy(dest, src, sizeof(uint2048_bucket_t) * N_UINT2048); return 0; } int uint2048_add(uint2048_t* a, uint2048_t* b, uint2048_t* c) { uint64_t carry = 0; uint64_t sum = 0; for (int i = 0; i < N_UINT2048; i++) { uint64_t ab = a->bucket[i]; uint64_t bb = b->bucket[i]; sum = ab + bb + carry; if (sum >= BASE_UINT2048U) { carry = 1; sum -= BASE_UINT2048U; } else { carry = 0; } c->bucket[i] = (uint2048_bucket_t)sum; } return carry ? -EOVERFLOW : 0; } int uint2048_sub(uint2048_t* a, uint2048_t* b, uint2048_t* c) { uint32_t carry = 0; uint64_t sum = 0; for (int i = 0; i < N_UINT2048; i++) { uint64_t ab = a->bucket[i]; uint64_t bb = b->bucket[i]; sum = carry + bb; if (ab >= sum) { ab = ab - (sum); carry = 0; } else { ab = ab + BASE_UINT2048U - (sum); carry = 1; } c->bucket[i] = (uint2048_bucket_t)ab; } if (carry) { uint2048_init(c, 0); } return carry ? -EOVERFLOW : 0; } int uint2048_shl(uint2048_t* a, int n) { int i; for (i = N_UINT2048 - 1; i >= n; i--) { a->bucket[i] = a->bucket[i - n]; } while (i >= 0) { a->bucket[i--] = 0; } return 0; } int uint2048_shr(uint2048_t* a, int n) { int i; for (i = 0; i < N_UINT2048 - n; i++) { a->bucket[i] = a->bucket[i + n]; } while (i < N_UINT2048) { a->bucket[i++] = 0; } return 0; } int uint2048_mult_by_digit(uint2048_t* a, uint2048_t* b, uint2048_bucket_t un) { uint64_t carry = 0; uint64_t tmp; uint64_t n = (uint64_t)un; for (int i = 0; i < N_UINT2048; i++) { uint64_t ab = a->bucket[i]; tmp = n * ab + carry; if (tmp >= BASE_UINT2048U) { carry = tmp / BASE_UINT2048U; tmp %= BASE_UINT2048U; } else { carry = 0; } b->bucket[i] = (uint2048_bucket_t)tmp; } return carry ? -EOVERFLOW : 0; } int uint2048_mult(uint2048_t* a, uint2048_t* b, uint2048_t* c) { uint2048_t p; uint2048_init(c, 0); for (int i = 0; i < N_UINT2048; i++) { if (!a->bucket[i]) { continue; } uint2048_mult_by_digit(b, &p, a->bucket[i]); uint2048_shl(&p, i); uint2048_add(c, &p, c); } return 0; } int uint2048_div(uint2048_t* a, uint2048_t* b, uint2048_t* dividend, uint2048_t* reminder) { uint2048_t tmp; if (dividend) { uint2048_init(dividend, 0); } uint2048_init(reminder, 0); for (int i = N_UINT2048 - 1; i >= 0; i--) { uint2048_shl(reminder, 1); reminder->bucket[0] = a->bucket[i]; uint64_t l = 0, r = BASE_UINT2048U; while (r - l > 1) { uint64_t m = (l + r) / 2; uint2048_mult_by_digit(b, &tmp, (uint2048_bucket_t)m); if (uint2048_less_equal(&tmp, reminder)) { l = m; } else { r = m; } } if (dividend) { dividend->bucket[i] = (uint2048_bucket_t)l; } uint2048_mult_by_digit(b, &tmp, (uint2048_bucket_t)l); uint2048_sub(reminder, &tmp, reminder); } return 0; } int uint2048_pow(uint2048_t* ua, uint2048_t* up, uint2048_t* mod, uint2048_t* ans) { uint2048_t tmp1; uint2048_t tmp2; uint2048_t const2; uint2048_t a; uint2048_t p; uint2048_copy(&a, ua); uint2048_copy(&p, up); uint2048_init(ans, 1); uint2048_init(&const2, 2); while (uint2048_is_not_zero(&p)) { if (uint2048_is_odd(&p)) { uint2048_mult(ans, &a, &tmp1); uint2048_div(&tmp1, mod, NULL, &tmp2); uint2048_copy(ans, &tmp2); } uint2048_mult(&a, &a, &tmp1); uint2048_div(&tmp1, mod, NULL, &tmp2); uint2048_copy(&a, &tmp2); uint2048_div(&p, &const2, &tmp1, &tmp2); uint2048_copy(&p, &tmp1); } return 0; } bool uint2048_less(uint2048_t* a, uint2048_t* b) { for (int i = N_UINT2048 - 1; i >= 0; i--) { if (a->bucket[i] < b->bucket[i]) { return true; } if (a->bucket[i] > b->bucket[i]) { return false; } } return false; } bool uint2048_less_equal(uint2048_t* a, uint2048_t* b) { for (int i = N_UINT2048 - 1; i >= 0; i--) { if (a->bucket[i] < b->bucket[i]) { return true; } if (a->bucket[i] > b->bucket[i]) { return false; } } return true; } bool uint2048_equal(uint2048_t* a, uint2048_t* b) { for (int i = 0; i < N_UINT2048; i++) { if (a->bucket[i] != b->bucket[i]) { return false; } } return true; } bool uint2048_is_not_zero(uint2048_t* a) { for (int i = 0; i < N_UINT2048; i++) { if (a->bucket[i] != 0) { return true; } } return false; } bool uint2048_is_odd(uint2048_t* a) { return (a->bucket[0] % 2) == 1; } int uint2048_dump(uint2048_t* a) { log("dumping"); for (int i = N_UINT2048 - 1; i >= 0; i--) { log(" %x", a->bucket[i]); } return 0; }