1 简介
⽐特币基于椭圆曲线加密的椭圆曲线数字签名算法(ECDSA),特定的椭圆曲线称为secp256k1。其公式定义如下
y2=x3+ax+b mod p
其中:p = 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F = 2256-232-29-28-27-26-24-1 = 2256-232-977,a = 0, b=7
基点G为:x=0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,y=0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
G的阶为:n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
secp256k1的命名出自一个密码协议标准,每一个字母和数字都代表着特定含义,下面分别进行介绍
1.1 密码协议标准
第一部分是「sec」,sec是Standards for Efficient Cryptography 的简称,是SECG发布的一种密码学协议标准。SECG发布的「SEC 1」和「SEC 2」两个关于椭圆曲线的协议标准,在「SEC 2」中有详细说明secp256k1以及其他曲线的参数定义。除了「sec」,还有众多其他关于椭圆曲线的协议标准,从SafeCurve中可以看到有下列不同类型的标准。
「SafeCurve」此处较久没有更新,有些标准已经更新了多次,例如NIST关于数字签名的标准 FIPS 186目前在用的是第四版,第五版也在起草中了,从「NIST」官网中可见。
1.2 有限域
第二部分是「p」,p表示该椭圆曲线是基于素数有限域Fp。有限域是离散数学中的概念,它是一个由有限数量元素组成的集合,元素之间可以进行加法和乘法计算。密码学中使用椭圆曲线都是基于有限域的,除了素数有限域Fp之外,还有另一种特征为2的有限域F2m,Fp的大小(元素个数)为p,F2m的大小为2m。基于Fp的椭圆曲线为:
基于F2m的椭圆曲线为:
在「SEC 2」中还定义了sect163k1、sect163r1等曲线,其中,t表示的是该曲线基于F2m。在「NIST FIPS 186-4」中定了P-256、B-163等曲线,P-表示基于Fp,B-表示基于F2m。
1.3 有限域大小
每个椭圆曲线E都有若干关键参数,包括阶为n的基点G和协因子h等,其中,n为一个大素数,n*h为椭圆曲线上点的数量。为了计算效率考虑,h通常设置为1、2或4。通俗地讲,如果椭圆曲线上的点数量越多,那么这条椭圆曲线的安全度就越高,因此n的取值是影响曲线安全的关键。椭圆曲线又都是基于有限域的,曲线上的点都是有限域中的元素,因此,有限域大小决定了曲线安全度。第三部分「256」就是有限域大小的表现形式,还有更多其他如192、224、384等,在「NIST FIPS 186-4」中有个表格展现了Fp 和F2m两个域的各种不同大小配置。
SEC标准在这块的设置和NIST标准类似,我们会看到p系列的曲线有p192、p224、p256(secp256k1就是其中一种)、p384和p521,t/B系列有t163/B-163、t233/B-233等。
1.4 Koblitz Curve
第四部分「k」表示该曲线是Koblitz Curve(科布利兹曲线),从「SEC 2」中可以看到还有此处标记为r的曲线(如secp256r1),r表示该曲线是伪随机曲线Pseudo-Random Curve。Koblitz Curve命名源自数学家「Neal Koblitz」,它是一种特殊的曲线,它的一些参数是精心挑选设置的。Koblitz Curve具有自同态的性质,可以通过优化大幅提升计算效率。相比之下,Pesudo-Random Curve的对应参数是通过随机种子计算出来的,有标准的检验算法可以检测所有参数是随机种子产生而来。在「NIST FIPS 186-4」中Koblitz Curve曲线以「K-」标记开头,分别有K-163、K-233等。
1.5 末位标记
到了第五部分「1」,这是代表在前4个条件下提供了多种推荐参数设置,在SEC标准中大部分该位都是1,即只提供一种推荐参数,sect163r2是一个例外。下面把SEC和NIST两个标准推荐的曲线分别列一下,二者有较大部分是相同的参数设置。
上述表格中,同一行中SEC和NIST都出现的,两个曲线虽然名字不同,但参数完全相同,也就是说其实一样的。橙色底纹的几个SEC曲线没有对应的NIST曲线,因此SEC标准包含的曲线比NIST多一些,如这里secp256k1就是SEC标准单独存在的。说到这里,不得不提一个正经八卦。据说,NIST推荐的Pesudo-Random Curve,也就是P和B系列,并没有公布随机数挑选规则,外界存在一种疑虑,可能NSA(美国国家安全局)掌握了后门,能够轻易破解这些密码协议。
2 源码及编译
secp256k1源码可以从以下地址下载:https://github.com/bitcoin-core/secp256k1
用git下载源码- git clone https://github.com/bitcoin-core/secp256k1
复制代码 Check out最新release版本2.1 Linux下编译
在Linux下可以使用Autotools进行编译- $ ./autogen.sh # Generate a ./configure script
- $ ./configure # Generate a build system
- $ make # Run the actual build process
- $ make check # Run the test suite
- $ sudo make install # Install the library into the system (optional)
复制代码 可以用./configure --prefix=指定安装路径,如我将编译结果安装到buildout目录下,其目录结构如下:
2.2 Windows编译
在Windows下,使用CMake+VS2019进行编译,编译配置如下:
Generate时使用默认配置,完成后用VS2019打开生成好的工程,进行编译,结果如下:
运行其中的tests项目输出如下:
由于内容比较多,所以运行花费时间较长。
3 应用
用VS2019创建控制台应用程序secp256k1Test,并将include和之前编译生成lib库及dll库放到工程目录下
按照以上目录结构,修改项目C/C++中的包含路径及链接器中的配置
主程序secp256k1Test.c如下
- 1 #include <stdlib.h>
- 2 #include <stdio.h>
- 3 #include <string.h>
- 4 #include <stdint.h>
- 5 #include "secp256k1.h"
- 6
- 7 #define bswap_16(value) \
- 8 ((((value) & 0xff) << 8) | ((value) >> 8))
- 9
- 10 #define bswap_32(value) \
- 11 (((uint32_t)bswap_16((uint16_t)((value) & 0xffff)) << 16) | \
- 12 (uint32_t)bswap_16((uint16_t)((value) >> 16)))
- 13
- 14 #define bswap_64(value) \
- 15 (((uint64_t)bswap_32((uint32_t)((value) & 0xffffffff)) \
- 16 << 32) | \
- 17 (uint64_t)bswap_32((uint32_t)((value) >> 32)))
- 18
- 19 int main()
- 20 {
- 21 int ret;
- 22 secp256k1_context* pCtx = NULL;
- 23 secp256k1_pubkey pubkey;
- 24 unsigned char rand32[32] = { 0 };
- 25 printf("this is for secp256k1 testing\n");
- 26
- 27 pCtx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
- 28 if (pCtx) {
- 29 for (int i = 0; i < sizeof(rand32) / 4; i++) {
- 30 int r = rand();
- 31 memcpy(rand32 + i * 4, &r, 4);
- 32 }
- 33 if (!secp256k1_context_randomize(pCtx, rand32))
- 34 printf("secp256k1_context_randomize failed\n");
- 35 else {
- 36 printf("secp256k1_context_randomize success\n");
- 37 }
- 38
- 39 memset(rand32, 0, sizeof(rand32));
- 40 rand32[31] = 1;
- 41 ret = secp256k1_ec_pubkey_create(pCtx, &pubkey, rand32);
- 42 if (ret) {
- 43 printf("private key\n0x");
- 44 for (int i = 0; i < 32; i++)
- 45 printf("%02x", rand32[i]);
- 46 printf("\n");
- 47 printf("secp256k1_ec_pubkey_create success\n");
- 48 printf("0x");
- 49 for (int i = 0; i < 32; i++)
- 50 printf("%02x", pubkey.data[31-i]);
- 51 printf("\n0x");
- 52 for (int i = 0; i < 32; i++)
- 53 printf("%02x", pubkey.data[63-i]);
- 54 printf("\n");
- 55 }
- 56 else {
- 57 printf("secp256k1_ec_pubkey_create failed\n");
- 58 }
- 59
- 60 // order N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
- 61 unsigned int* pData = (unsigned int*)rand32;
- 62 pData[0] = bswap_32(0xFFFFFFFF);
- 63 pData[1] = bswap_32(0xFFFFFFFF);
- 64 pData[2] = bswap_32(0xFFFFFFFF);
- 65 pData[3] = bswap_32(0xFFFFFFFE);
- 66 pData[4] = bswap_32(0xBAAEDCE6);
- 67 pData[5] = bswap_32(0xAF48A03B);
- 68 pData[6] = bswap_32(0xBFD25E8C);
- 69 pData[7] = bswap_32(0xD0364140);
- 70 ret = secp256k1_ec_pubkey_create(pCtx, &pubkey, rand32);
- 71 if (ret) {
- 72 printf("private key\n0x");
- 73 for (int i = 0; i < 32; i++)
- 74 printf("%02x", rand32[i]);
- 75 printf("\n");
- 76 printf("secp256k1_ec_pubkey_create success\n");
- 77 printf("0x");
- 78 for (int i = 0; i < 32; i++)
- 79 printf("%02x", pubkey.data[31 - i]);
- 80 printf("\n0x");
- 81 for (int i = 0; i < 32; i++)
- 82 printf("%02x", pubkey.data[63 - i]);
- 83 printf("\n");
- 84 }
- 85 else {
- 86 printf("secp256k1_ec_pubkey_create failed\n");
- 87 }
- 88
- 89 secp256k1_context_destroy(pCtx);
- 90 }
- 91
- 92 return 1;
- 93 }
复制代码 secp256k1Test.c程序第40,41行,以0x1为私钥产生公钥,即椭圆曲线生成元G。程序第62~70行, 以阶n-1为私钥产生公钥,即(n-1)*G,这里仅为测试,所以两次取的私钥都是特殊值,正常情况下私钥要随机产生,程序最终运行结果如下- this is for secp256k1 testing
- secp256k1_context_randomize success
- private key
- 0x0000000000000000000000000000000000000000000000000000000000000001
- secp256k1_ec_pubkey_create success
- 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
- 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
- private key
- 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140
- secp256k1_ec_pubkey_create success
- 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
- 0xb7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777
复制代码 有椭圆曲线理论可知两次产生的公钥点互为逆元,它们关于x轴对称,x坐标相同,y坐标互为相反数(在有限域内y坐标之和为模数p)。
参考:
https://cloud.tencent.com/developer/news/586021
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |