山东大学软件工程应用与实践——GMSSL开源库(十)——重要的大整数
2021SC@SDUSC
文章标题
- BIGNUM的结构
- 大整数的加减法(绝对值加减)
- 绝对值加减
- 带符号加减
- 大整数的乘法
- 经典乘法
- 递归和comba乘法
- 小结
无论是SM2、SM9等国密算法还是以RSA为代表的国际标准算法或者任何其他密码算法,对于大整数都有一定的要求,例如RSA中公钥的生成,需要用到大素数的乘法模幂等运算。而像1024位这种大整数的运算,肯定不能用普通的整数的加减乘除运算方法,一个是int类型的变量不能容纳这么长的数,另一个是考虑到计算机的计算效率问题。既能实现大整数“big number”加减乘除乘方模幂等运算,还需要保证效率,是对大整数运算程序实现的要求。因为GMSSL是在OPENSSL之上进行的扩充,本篇分析了OPENSSL中bn文件夹中针对大整数的运算方法。
BIGNUM的结构
首先认识一下BIGNUM的结构,源代码来自\openssl-master\crypto\bn\bn_local.h
#define BN_ULONG unsigned long
struct bignum_st {BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit* chunks. */int top; /* Index of last used d +1. *//* The next are internal book keeping for bn_expand. */int dmax; /* Size of the d array. */int neg; /* one if the number is negative */int flags;
};
typedef struct bignum_st BIGNUM;
其中
BN_ULONG 32比特无符号数,简称为“字”;
d 指针,指向表示大整数的数组;
dmax 数组的最大长度;
top 大整数的最高字,0≤top≤dmax-1;
neg 标记了大整数的符号,neg为1表示负数,为0则表示正数;
flags 大整数的属性,这一点后面提到时再详细说明。
举个简单的例子进行说明。比如定义一个最长可以表示4个字的大整数,则dmax=4;但是这个数可能只有低2个字有效,高2个字都为0,即d[3]=d[2]=0,d[1]≠0,则此时top=1。
原文链接:https://blog.csdn.net/samsho2/article/details/85772221
大整数的加减法(绝对值加减)
openssl-master\crypto\bn\bn_add.c
绝对值加减
int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)//绝对值加
{int max, min, dif;const BN_ULONG *ap, *bp;BN_ULONG *rp, carry, t1, t2;bn_check_top(a);bn_check_top(b);if (a->top < b->top) {const BIGNUM *tmp;tmp = a;a = b;b = tmp;}max = a->top;min = b->top;dif = max - min;if (bn_wexpand(r, max + 1) == NULL)return 0;r->top = max;ap = a->d;bp = b->d;rp = r->d;carry = bn_add_words(rp, ap, bp, min);rp += min;ap += min;while (dif) {dif--;t1 = *(ap++);t2 = (t1 + carry) & BN_MASK2;*(rp++) = t2;carry &= (t2 == 0);}*rp = carry;r->top += carry;r->neg = 0;bn_check_top(r);
return 1;
}
int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)//绝对值减
{int max, min, dif;BN_ULONG t1, t2, borrow, *rp;const BN_ULONG *ap, *bp;bn_check_top(a);bn_check_top(b);max = a->top;min = b->top;dif = max - min;if (dif < 0) { /* hmm... should not be happening */ERR_raise(ERR_LIB_BN, BN_R_ARG2_LT_ARG3);return 0;}if (bn_wexpand(r, max) == NULL)return 0;ap = a->d;bp = b->d;rp = r->d;borrow = bn_sub_words(rp, ap, bp, min);ap += min;rp += min;while (dif) {dif--;t1 = *(ap++);t2 = (t1 - borrow) & BN_MASK2;*(rp++) = t2;borrow &= (t1 == 0);}while (max && *--rp == 0)max--;r->top = max;r->neg = 0;bn_pollute(r);return 1;
}
其中BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int n)与BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int n)函数实现了低位的齐字加减法,并返回进位值赋给carry\borrow。算法思想主要利用了整数的加法进位时只可能进一位或者不进位,两大整数相加减时,位数少的与位数多的相同位数进行齐字加减,高位与carry\borrow相加减后放到高位,完成绝对值加减法。
带符号加减
int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)//大整数加
{int ret, r_neg, cmp_res;bn_check_top(a);bn_check_top(b);if (a->neg == b->neg) {r_neg = a->neg;ret = BN_uadd(r, a, b);} else {cmp_res = BN_ucmp(a, b);if (cmp_res > 0) {r_neg = a->neg;ret = BN_usub(r, a, b);} else if (cmp_res < 0) {r_neg = b->neg;ret = BN_usub(r, b, a);} else {r_neg = 0;BN_zero(r);ret = 1;}}r->neg = r_neg;bn_check_top(r);return ret;
}
int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)//大整数减
{int ret, r_neg, cmp_res;bn_check_top(a);bn_check_top(b);if (a->neg != b->neg) {r_neg = a->neg;ret = BN_uadd(r, a, b);} else {cmp_res = BN_ucmp(a, b);if (cmp_res > 0) {r_neg = a->neg;ret = BN_usub(r, a, b);} else if (cmp_res < 0) {r_neg = !b->neg;ret = BN_usub(r, b, a);} else {r_neg = 0;BN_zero(r);ret = 1;}}r->neg = r_neg;bn_check_top(r);return ret;
}
有了绝对值相加减后,带符号的大整数进行加减运算就变得比较简单了。
先进行判定a、b是否同号,若同号,结果r的符号赋上a的符号,然后进行绝对值加减;否则,进行绝对值比较,r的符号赋上绝对值大的数的符号,然后进行绝对值相减。
大整数的乘法
以下源代码来自openssl-master\crypto\bn\bn_mul.c
经典乘法
Openssl首先实现了最基本的经典乘法方式,也就是类似小学中学到的“竖式计算”的方法,在void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b, int nb)中实现了该方法。
void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b, int nb)
{BN_ULONG *rr;if (na < nb) {int itmp;BN_ULONG *ltmp;itmp = na;na = nb;nb = itmp;ltmp = a;a = b;b = ltmp;}rr = &(r[na]);if (nb <= 0) {(void)bn_mul_words(r, a, na, 0);return;} elserr[0] = bn_mul_words(r, a, na, b[0]);for (;;) {if (--nb <= 0)return;rr[1] = bn_mul_add_words(&(r[1]), a, na, b[1]);if (--nb <= 0)return;rr[2] = bn_mul_add_words(&(r[2]), a, na, b[2]);if (--nb <= 0)return;rr[3] = bn_mul_add_words(&(r[3]), a, na, b[3]);if (--nb <= 0)return;rr[4] = bn_mul_add_words(&(r[4]), a, na, b[4]);rr += 4;r += 4;b += 4;}
}
递归和comba乘法
Openssl使用的环境一般是对信息的加解密,故对大整数的使用一定是不能用int、long等类型进行直接表示的,也就是说普通的数乘方法无法直接在实际场景中使用。上述的bn_mul_normal函数只起到最顶层的作用,实际对大整数的乘法运算使用到了递归乘法和comba乘法。
当然,openssl也实现了大整数的递归乘法和comba乘法。对于大整数来说,递归乘法的时间复杂度要比普通数乘要小。同时,对大整数乘法问题进行分而治之,逐步变成可以解决的数乘问题。
void bn_mul_recursive
void bn_mul_part_recursive
void bn_mul_low_recursive
三个函数实现了对大整数的递归乘法。
void bn_mul_comba8
void bn_mul_comba4
函数实现了对大整数的comba乘法,有关comba算法的具体内容,不在此详细介绍。
通过ctx,使程序自己判断使用递归乘法还是comba乘法:
int bn_mul_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
{int ret = 0;int top, al, bl;BIGNUM *rr;
#if defined(BN_MUL_COMBA) || defined(BN_RECURSION)int i;
#endif
#ifdef BN_RECURSIONBIGNUM *t = NULL;int j = 0, k;
#endifbn_check_top(a);bn_check_top(b);bn_check_top(r);al = a->top;bl = b->top;if ((al == 0) || (bl == 0)) {BN_zero(r);return 1;}top = al + bl;BN_CTX_start(ctx);if ((r == a) || (r == b)) {if ((rr = BN_CTX_get(ctx)) == NULL)goto err;} elserr = r;#if defined(BN_MUL_COMBA) || defined(BN_RECURSION)i = al - bl;
#endif
#ifdef BN_MUL_COMBAif (i == 0) {# if 0if (al == 4) {if (bn_wexpand(rr, 8) == NULL)goto err;rr->top = 8;bn_mul_comba4(rr->d, a->d, b->d);goto end;}
# endifif (al == 8) {if (bn_wexpand(rr, 16) == NULL)goto err;rr->top = 16;bn_mul_comba8(rr->d, a->d, b->d);goto end;}}
#endif /* BN_MUL_COMBA */
#ifdef BN_RECURSIONif ((al >= BN_MULL_SIZE_NORMAL) && (bl >= BN_MULL_SIZE_NORMAL)) {if (i >= -1 && i <= 1) {/** Find out the power of two lower or equal to the longest of the* two numbers*/if (i >= 0) {j = BN_num_bits_word((BN_ULONG)al);}if (i == -1) {j = BN_num_bits_word((BN_ULONG)bl);}j = 1 << (j - 1);assert(j <= al || j <= bl);k = j + j;t = BN_CTX_get(ctx);if (t == NULL)goto err;if (al > j || bl > j) {if (bn_wexpand(t, k * 4) == NULL)goto err;if (bn_wexpand(rr, k * 4) == NULL)goto err;bn_mul_part_recursive(rr->d, a->d, b->d,j, al - j, bl - j, t->d);} else { /* al <= j || bl <= j */if (bn_wexpand(t, k * 2) == NULL)goto err;if (bn_wexpand(rr, k * 2) == NULL)goto err;bn_mul_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d);}rr->top = top;goto end;}}
#endif /* BN_RECURSION */if (bn_wexpand(rr, top) == NULL)goto err;rr->top = top;bn_mul_normal(rr->d, a->d, al, b->d, bl);#if defined(BN_MUL_COMBA) || defined(BN_RECURSION)end:
#endifrr->neg = a->neg ^ b->neg;rr->flags |= BN_FLG_FIXED_TOP;if (r != rr && BN_copy(r, rr) == NULL)goto err;ret = 1;err:bn_check_top(r);BN_CTX_end(ctx);return ret;
}
最后是大整数乘法中最上层的函数,对外只留下了一个乘法的接口,对外只需要输入两个大整数和上下文环境,就返回r=a*b。
int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
{int ret = bn_mul_fixed_top(r, a, b, ctx);bn_correct_top(r);bn_check_top(r);return ret;
}
小结
本篇文章主要对大整数的加减法和乘法运算进行了分析。和大整数相关的运算函数一直是底层代码中较为重要的一部分,下面将会对大整数的其他运算的实现进行代码方向的分析与学习。
对于大整数的运算操作,属于openssl甚至是密码学编程较为底层的内容。现阶段使用的密码,大部分都依赖于大整数的产生和运算。理解底层的运算内容可以更好地认识上层的函数实现,同时也进一步了解了底层的算法。
山东大学软件工程应用与实践——GMSSL开源库(十)——重要的大整数相关推荐
- 山东大学软件工程应用与实践——GMSSL开源库(四)——SM9数字签名算法及验证的源代码分析
2021SC@SDUSC 目录 一.引言 二.密钥的生成数字签名与签名验证相关代码 1.判定函数 2.签名的初始化函数 3.签名执行函数 4.真正的签名函数 5.签名验证初始化函数 6.签名验证执行函 ...
- 山东大学软件工程应用与实践——GMSSL开源库(一) ——WINDOWS下GMSSL的安装与编译的超详细保姆级攻略
2021SC@SDUSC GMSSL简介 GmSSL是一个开源的密码工具箱,支持SM2/SM3/SM4/SM9/ZUC等国密(国家商用密码)算法.SM2国密数字证书及基于SM2证书的SSL/TLS安全 ...
- 山东大学软件工程应用与实践——GMSSL开源库(九)——SM9密钥封装与公钥加密的源代码分析
2021SC@SDUSC 文章目录 int SM9_wrap_key(密钥的封装) int SM9_unwrap_key(密钥的解封) int SM9_encrypt(公钥加密算法) int SM9_ ...
- 山东大学软件工程应用与实践——GMSSL开源库(二)——浅尝SM9
2021SC@SDUSC 概述 为了降低公开密钥系统中密钥和证书管理的复杂性,以色列科学家.RSA算法发明人之一Adi Shamir在1984年提出了标识密码(Identity-Based Crypt ...
- 山东大学软件工程应用与实践——Pig代码综述
2021SC@SDUSC 目录 一.Pig是什么? 二.Pig的特点 三.Pig安装部署 四.组内分工 一.Pig是什么? Pig 是Apache平台下的一个免费开源项目,是MapReduce的一个抽 ...
- <2021SC@SDUSC>博客(5)山东大学软件工程应用与实践JPress代码分析(四)
2021SC@SDUSC 前言 在前面三篇文章中,我对 JPress 项目的基础框架 JFinal 和 JBoot 在使用层面进行了拆解与分析.在接下来的文章中,我将在代码层面对 JPress 项目中 ...
- <2021SC@SDUSC>博客(9)山东大学软件工程应用与实践Jpress代码分析(8)
2021SC@SDUSC Lucene和ElasticSearch 在上一篇博客中提到的Elasticsearch是一个基于Lucene搜索引擎为核心构建的开源,分布式,RESTful搜索服务器.这里 ...
- 山东大学软件工程应用与实践——WeaselTSF(一)
2021SC@SDUSC 文章目录 简单介绍 WeaselTSF.h 从本篇博客开始分析WeaselTFS这个包中的代码. 简单介绍 WeaselTSF.vcproj This is the main ...
- 山东大学软件工程应用与实践——使用CUDA/GPU技术加速密码运算(第五周)
2021SC@SDUSC 很抱歉由于自身身体原因,本来打算这周对AES算法进行CPU和GPU的实际检测比较分析进行推迟.我决定对于SHA.AES.RSA三个算法在CPU和GPU性能对比放在最后几周. ...
最新文章
- 2017年第八届蓝桥杯省赛试题(JavaA组)
- Swift Playgrounds Learn to Code 2 final project Pyramid
- oracle case when exists()
- 白话科普系列——网站靠什么提升加载速度?
- 快速上手sqlserver profiler
- 分析一下shell(转)
- linux怎样自制库_如何制作自己的LINUX系统?
- 一、Objective-C之Runtime的概念
- hdf5文件和csv的区别_使用HDF5文件并创建CSV文件
- mysql重置密码报错,吐血整理
- linux pm2 权限,pm2 部署 node的三种方法示例
- 浏览器Firefox新标签页默认打开地址设置
- 联想y470上三代cpu_联想Y470笔记本i3处理器能换i5或者i7处理器嘛?
- 最优秀的开源库之GPUImage
- win10弹出计算机的内存不足,Win10系统提示“计算机内存不足”的解决方法
- Frida学习之旅(一)--Google Pixel手机的ROOT
- 计算机毕设(附源码)JAVA-SSM基于web的社团管理系统
- Required request body is missing: public错误
- 远程控制电脑会不会泄露隐私
- Linux网卡固件,CentOS下X710网卡升级驱动和固件脚本 | 聂扬帆博客
热门文章
- 2. 饶明新 校示范课六年级上册《数学广角-数与形》照片
- 【python】3分钟搞定音频剪辑,进阶版
- 从系统架构理解Spring Cloud Gateway的作用
- 居然嘲笑我们没有Excel的这个功能,呵呵
- 2021年国开专科计算机应用基础终结性考试试题 内附word和ppt答案 (文尾直接下载)
- excel如何绘制三线表头?
- 基于javaweb+jsp的宠物领养信息管理系统(JavaWeb JSP MySQL Servlet SSM SpringBoot Layui Ajax)
- 小学五年级计算机课评课,小学五年级英语评课稿
- ubuntu分区设置
- 2021-12-05 vue移动端卖座电影项目(六) 为详情页面Detail.vue获取后台数据并设置样式