2021SC@SDUSC
目录
一、ECDSA介绍
二、代码分析
ECDSA的全名是Elliptic Curve DSA,即椭圆曲线DSA。它是Digital Signature Algorithm (DSA)应用了椭圆曲线加密算法的变种。椭圆曲线算法的原理很复杂,但是具有很好的公开密钥算法特性,通过公钥无法逆向获得私钥。
私钥:一个秘密号码,只有生成它的人知道。私钥本质上是一个随机生成的数字。在比特币中,一个人的私钥与区块链可以花这笔钱。在比特币中,私钥是单个无符号256位整数(32字节)。
公钥:与私钥相对应,但不需要保密的数字。公钥可以从私钥计算,但反之亦然。公钥可以用来确定签名是否是真实的(换句话说,用正确的密钥生成),而不需要泄露私钥。
ECDSA算法的两个优点:
1.在已知公钥的情况下,无法推导出该公钥对应的私钥。
2.可以通过某些方法来证明某人拥有一个公钥所对应的私钥,而此过程不会暴露关于私钥的任何信息。
ESCDA处理的实际上是消息的哈希值,而不是消息本身。哈希函数是可选择的,但这个哈希函数必须是一个
密码学安全的哈希函数。消息的哈希值需要截取一个固定的长度 Ln ,这个长度是 n (子群的阶)的二进制位数。截取后的哈希值是一个整数,我们记为 z。
ECDSA签名流程:
二元组(r,s)就是消息的签名
在多倍点运算中,已知多倍点与基点,求解倍数的问题称为椭圆曲线离散对数问题。对于一般椭圆曲线的离散对数问题,目前只存在指数级计算复杂度的求解方法。与大数分解问题及有限域上离散对数问题相比,椭圆曲线离散对数问题的求解难度要大得多。因此,在相同安全程度要求下,椭圆曲线密码较其他公钥密码所需的密钥规模要小得多。
1.在已知公钥的情况下,无法推导出该公钥对应的私钥。
假设随机取一个0-256位之间的值x,计算x*P,最后的结果一定会落在曲线上的一点。假设该点为X,在公开X以及具体曲线的方程的情况下,能否反推出最初的随机值x?
证:寻找x的过程只能通过暴力计算,的可能值为~中的一个,平均来说需要计算次能够找到一次值。那么问题来了,运行一次的计算需要多长的时间呢?
假设我们使用的是超级计算机,主频为(一秒钟可以进行一万亿次运算),从宇宙诞生的那一刻开始计算,到现在也就进行了次。找到值的概率为。这个概率和下一秒地球被巨型陨石撞击而毁灭的概率接近。
在上面的案例中,是~位的一个随机数,可以作为私钥。是随机椭圆曲线上的一个点,也就是由私钥生成的公钥,因此优点可以1得证。
但是密码学中,并不能使用上面介绍的实数域上的椭圆曲线。因为
1.实数域上的椭圆曲线是连续的,有无限个点,密码学要求有限点。
2.实数域上的椭圆曲线的运算有误差,不精确。密码学要求精确。
所以我们需要引入有限域上的椭圆曲线。
要证明优点2,还需要将随机椭圆曲线做一些改动:为了保证最后计算出来的点的坐标值相加是512位,secp256k1引入了一个对质数取模的机制。具体来说,随机椭圆曲线从变为了其中P=2256-232-29-28-27-26-24-1,是小于的最大质数。
2.可以通过某些方法来证明某人拥有一个公钥所对应的私钥,而此过程不会暴露关于私钥的任何信息。
这部分类似于零知识证明:我知道你能买得起这个东西,但是我不知道你到底有多少钱。
添加一个hash函数,简单修改可以得出:使,那么可知为。此时方程为:为了简单起见,我们记和。此时方程化简为:
假设:在已知的情况下,如果能够提供一个和满足上面的方程,就可以证明一个人拥有。这个假设有一个前提,如果一个人不知道x,那么他就无法提供和满足上面的等式。
详细探讨这个前提:如果一个人不知道x,又想计算出和,能够办到吗?结论是不能,首先我们无法从计算出(在有限时间内)。
还有一个问题:在已知和的情况下,能否计算出关于的任何信息?
根据公式:只要解出就可以了。
要想计算出x,就需要知道r,但是在r没有公开的情况下,能计算出r吗?我们知道R=r*P;但是根据这个公式无法倒推出r,所以x也是安全的。
(这部分是我在网上看到的相对好理解的证明了,来源ECDSA(椭圆曲线数字签名算法) - 简书)
static ECDSA_SIG *sm2_do_sign(const unsigned char *dgst, int dgstlen,
EC_KEY ecc算法中的秘钥结构体,里面包含私钥、公钥、曲线信息
一些返回空值,并直接结束的情况:
ec_group = EC_KEY_get0_group(ec_key);
priv_key = EC_KEY_get0_private_key(ec_key);
if (!ec_group || !priv_key) {
SM2err(SM2_F_SM2_DO_SIGN, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
if (!(ret = ECDSA_SIG_new())) {
SM2err(SM2_F_SM2_DO_SIGN, ERR_R_MALLOC_FAILURE);
return NULL;
}
ret->r = BN_new();
ret->s = BN_new();
ctx = BN_CTX_new();
order = BN_new();
e = BN_new();
bn = BN_new();
if (!ret->r || !ret->s || !ctx || !order || !e || !bn) {
SM2err(SM2_F_SM2_DO_SIGN, ERR_R_MALLOC_FAILURE);
goto end;
}
if (!EC_GROUP_get_order(ec_group, order, ctx)) {
SM2err(SM2_F_SM2_DO_SIGN, ERR_R_EC_LIB);
goto end;
}
/* convert dgst to e */
i = BN_num_bits(order);
#if 0
if (8 * dgstlen > i) {
dgstlen = (i + 7)/8;
}
#endif
if (!BN_bin2bn(dgst, dgstlen, e)) {
SM2err(SM2_F_SM2_DO_SIGN, ERR_R_BN_LIB);
goto end;
}
计算并判断随机数k
/* use or compute k and (kG).x */
if (!in_k || !in_x) {
if (!sm2_sign_setup(ec_key, ctx, &k, &ret->r)) {
SM2err(SM2_F_SM2_DO_SIGN, ERR_R_ECDSA_LIB);
goto end;
}
ck = k;
} else {
ck = in_k;
if (!BN_copy(ret->r, in_x)) {
SM2err(SM2_F_SM2_DO_SIGN, ERR_R_MALLOC_FAILURE);
goto end;
}
}
计算大整数r,并确保大整数r的合理性:如果 r=0 ,就重新选择一个k
/* r = e + x (mod n) */
if (!BN_mod_add(ret->r, ret->r, e, order, ctx)) {
SM2err(SM2_F_SM2_DO_SIGN, ERR_R_BN_LIB);
goto end;
}
if (!BN_mod_add(bn, ret->r, ck, order, ctx)) {
SM2err(SM2_F_SM2_DO_SIGN, ERR_R_BN_LIB);
goto end;
}
/* check r != 0 && r + k != n */
if (BN_is_zero(ret->r) || BN_is_zero(bn)) {
if (in_k && in_x) {
SM2err(SM2_F_SM2_DO_SIGN, SM2_R_NEED_NEW_SETUP_VALUES);
goto end;
} else
continue;
}
计算大整数s,并判断其合理性,如果s等于0,重新选择k
/* s = ((1 + d)^-1 * (k - rd)) mod n */
/* s = d'(k + r) - r mod n */
if (!BN_mod_mul(ret->s, EC_KEY_get_ex_data(ec_key, sm2_sign_idx),
bn, order, ctx)) {
SM2err(SM2_F_SM2_DO_SIGN, ERR_R_BN_LIB);
goto end;
}
if (!BN_mod_sub(ret->s, ret->s, ret->r, order, ctx)) {
SM2err(SM2_F_SM2_DO_SIGN, ERR_R_BN_LIB);
goto end;
}
#endif
/* check s != 0 */
if (BN_is_zero(ret->s)) {
if (in_k && in_x) {
SM2err(SM2_F_SM2_DO_SIGN, SM2_R_NEED_NEW_SETUP_VALUES);
goto end;
}
} else {
break;
}
结束:
end:
if (!ok) {
ECDSA_SIG_free(ret);
ret = NULL;
}
BN_free(k);
BN_CTX_free(ctx);
BN_free(order);
BN_free(e);
BN_free(bn);
return ret;
}