Files
Custom-Operating-System/boot/libboot/crypto/uint2048.c

300 lines
6.6 KiB
C

#include "uint2048.h"
#include <libboot/log/log.h>
#include <libboot/mem/mem.h>
#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;
}