浅谈C语言的大整数库实现
前言
记录一手程序设计的实验作业,所使用的算法都是一些普通的算法,时间原因来不及做出太好的,只是稍微对几点想法说一下
函数体系及实现
核心是我们的头文件
|
内存管理
鉴于我们是进行大整数运算,可能会申请大量的内存,因此我设立了一系列函数帮助我在堆上管理内存
bn_err_t bn_init(bn_t *bn, int capacity); |
首先是
bn_err_t bn_init(bn_t *bn, int capacity); |
帮助我们初始化bn_t这个结构体,得到一个至少容量为1的dig容量,并且calloc会将内存清零便于我们快速使用
bn_err_t bn_init(bn_t *bn, int capacity) { |
方便我们申请一个bn_t结构体进行后续使用
bn_t temp; |
然后是
bn_err_t bn_init_copy(bn_t *bn, const dig_t *data, int digs); |
一样是初始化结构体,但是进一步实现了数的复制,并且可以通过参数设置复制的digs数
bn_err_t bn_init_copy(bn_t *bn, const dig_t *data, int digs) { |
然后是内存释放函数
bn_err_t bn_free(bn_t *bn); |
帮助我们释放内存
bn_err_t bn_free(bn_t *bn) { |
然后是动态内存调整
bn_err_t bn_resize(bn_t *bn, int new_capacity, bn_resize_mode_t mode); |
方便我们调整capacity的大小
bn_err_t bn_resize(bn_t *bn, int new_capacity, bn_resize_mode_t mode) { |
然后是capacity校验函数,防止出现内存不足的情况
bn_err_t bn_ensure_capacity(bn_t *bn, int required_digs); |
这里不可能发生截断,所以使用了BN_RESIZE_TRUNCATE
bn_err_t bn_ensure_capacity(bn_t *bn, int required_digs) { |
工具函数
对于大整数运算中,去判断或是设置某一特定位是1还是0便于我们操作,比如说设置一个
因此我们先设置这两个函数
static int bn_get_bit(const bn_t *bn, int bit) { |
然后我们设置一个用来判断数字有多少位的函数
int bn_get_bits(const bn_t *bn) { |
判断是否为0,是否为偶数(奇数)这类函数也顺便实现一下
int bn_is_zero(const bn_t *bn) { |
比较函数对于相减和模计算比较重要
int bn_cmp(const bn_t *a, const bn_t *b) { |
下面是几个比较常用的赋值函数
bn_err_t bn_set_zero(bn_t *bn) { |
清零函数高效清除数据
再设置一个置1的
bn_err_t bn_set_one(bn_t *bn) { |
然后是复制操作
bn_err_t bn_copy(bn_t *dst, const bn_t *src) { |
还有随机数生成器
bn_err_t bn_rand(bn_t *bn, int bits) { |
rand函数生成的随机数质量不高,我们使用BCryptGenRandom来生成高质量的随机数
bn_err_t bn_rand_security(bn_t *bn, int bits) { |
然后是打印函数
void bn_print(const bn_t *bn, const char *name) { |
AI帮我设计了一个debug的printf
void bn_print_debug(const bn_t *bn, const char *name) { |
然后是截断函数,对于模
这种是复制型的
bn_err_t bn_truncate_copy(bn_t *dst, const bn_t *src, int digs) { |
这种是对自身数据进行截断的
bn_err_t bn_truncate(bn_t *bn, int digs) { |
还有一种是对位截断的
bn_err_t bn_truncate_bits(bn_t *bn, int bits) { |
基础运算
加法就是简单的实现
bn_err_t bn_add(bn_t *r, const bn_t *a, const bn_t *b) { |
还有减法(a>b)
bn_err_t bn_sub(bn_t *r, const bn_t *a, const bn_t *b) { |
既然有得到正数的减法,如何实现一个得到负数的减法,毕竟拓展欧几里得算法中间是会出现负数的
于是灵光一闪,使用错误码返回代表是正数是负数,BN_SUCCESS代表非负数,BN_ERR_ALL_NEGATIVE_RESULT代表负数
bn_err_t bn_sub_signed(bn_t *r, const bn_t *a, const bn_t *b) { |
假如不使用错误码判断呢,那再拓展一下,传入一个变量来判断是否是正数
bn_err_t bn_sub_with_sign(bn_t *r, int *is_negative, const bn_t *a, const bn_t *b) { |
然后是乘法
bn_err_t bn_mul(bn_t *r, const bn_t *a, const bn_t *b) { |
平方运算
bn_err_t bn_sqr(bn_t *r, const bn_t *a) { |
左移和右移
bn_err_t bn_lsh(bn_t *r, const bn_t *a, int bits) { |
实现了大精度加法,为了加快小精度的速度,添加了对一个dig的特殊操作
dig_t bn_add_dig(bn_t *r, const bn_t *a, dig_t b) { |
然后是除法运算,这个主要是针对相差不大的数字
bn_err_t bn_div(bn_t *q, bn_t *r, const bn_t *a, const bn_t *b) { |
还有取模运算
bn_err_t bn_mod(bn_t *r, const bn_t *a, const bn_t *m) { |
模运算
一般的模加、模减、模乘
这里我没使用bn_mod是因为数比较接近,使用bn_mod的时间开销大,于是便使用了时间开销更小的bn_sub
bn_err_t bn_mod_add(bn_t *r, const bn_t *a, const bn_t *b, const bn_t *m) { |
还有模折半
bn_err_t bn_mod_hlv(bn_t *r, const bn_t *a, const bn_t *m) { |
进阶模运算
求逆元是模运算中比较常用的
有拓展欧几里得算法,但是这个好像在我的大整数运算中开销特别大,于是后来我改进成了牛顿迭代法,毕竟完成的模乘和模幂等等只需要求
首先是拓展欧几里得算法,因为我还没实现负数的运算,只能使用返回错误码来判断回溯是两个值的正负性
BN_SUCCESS = 0, |
也算是比较巧思了吧
bn_err_t extended_gcd(bn_t *gcd, bn_t *x, bn_t *y, const bn_t *a, const bn_t *b) { |
牛顿迭代法
bn_err_t bn_mod_inv_usedNewton(bn_t *inv, const bn_t *N, const bn_t *R, const int k){ |
蒙哥马利算法
使用一个结构体储存我们预计算的蒙哥马利上下文
bn_err_t mont_ctx_init(mont_ctx_t *ctx, const bn_t *N) { |
首先是计算我们的R的位数,使用bn_get_bits就可以了
bn_err_t mont_compute_R(bn_t *R, const bn_t *N, int *k) { |
然后是构造我们的R,使用bn_set_bit设置我们上面得到的位为1
然后是另一个很重要的参数
bn_err_t mont_compute_N_prime(bn_t *N_prime, const bn_t *N, const bn_t *R) { |
R2就是
转换为蒙哥马利形式
bn_err_t mont_map(bn_t *a_mont, const bn_t *a, const mont_ctx_t *ctx) { |
使用模约减返回
bn_err_t mont_reduce(bn_t *a, const bn_t *a_mont, const mont_ctx_t *ctx) { |
调用的函数是
bn_err_t mont_redc_internal(bn_t *r, const bn_t *T, const bn_t *N, const bn_t *N_prime, int k) { |
由于我们是按位截取的,所以循环减开销时间比较短,比起bn_mod速度快不少
然后就是我们的模乘和模幂的具体代码,都是经典算法
bn_err_t bn_mod_mul_mont(bn_t *r, const bn_t *a, const bn_t *b, const bn_t *m) { |
模幂算法也是
bn_err_t bn_mod_exp_mont(bn_t *r, const bn_t *a, const bn_t *e, const bn_t *m) { |
这就是我的代码啦
经过测试,速度如下,每一项都是随机的数据
+------------------------------------------------------------------------------+ |
感觉还是有点慢了,可以优化的地方还可以多一些,不过这里就告一段落了




