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版本

git checkout v0.6.0

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

secp256k1算法详解一的更多相关文章

  1. BM算法  Boyer-Moore高质量实现代码详解与算法详解

    Boyer-Moore高质量实现代码详解与算法详解 鉴于我见到对算法本身分析非常透彻的文章以及实现的非常精巧的文章,所以就转载了,本文的贡献在于将两者结合起来,方便大家了解代码实现! 算法详解转自:h ...

  2. kmp算法详解

    转自:http://blog.csdn.net/ddupd/article/details/19899263 KMP算法详解 KMP算法简介: KMP算法是一种高效的字符串匹配算法,关于字符串匹配最简 ...

  3. 机器学习经典算法详解及Python实现--基于SMO的SVM分类器

    原文:http://blog.csdn.net/suipingsp/article/details/41645779 支持向量机基本上是最好的有监督学习算法,因其英文名为support vector  ...

  4. [转] KMP算法详解

    转载自:http://www.matrix67.com/blog/archives/115 KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段.    我们这里说的K ...

  5. 【转】AC算法详解

    原文转自:http://blog.csdn.net/joylnwang/article/details/6793192 AC算法是Alfred V.Aho(<编译原理>(龙书)的作者),和 ...

  6. KMP算法详解(转自中学生OI写的。。ORZ!)

    KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段. 我们这里说的KMP不是拿来放电影的(虽然我很喜欢这个软件),而是一种算法.KMP算法是拿来处理字符串匹配的.换句 ...

  7. EM算法详解

    EM算法详解 1 极大似然估计 假设有如图1的X所示的抽取的n个学生某门课程的成绩,又知学生的成绩符合高斯分布f(x|μ,σ2),求学生的成绩最符合哪种高斯分布,即μ和σ2最优值是什么? 图1 学生成 ...

  8. Tarjan算法详解

    Tarjan算法详解 今天偶然发现了这个算法,看了好久,终于明白了一些表层的知识....在这里和大家分享一下... Tarjan算法是一个求解极大强联通子图的算法,相信这些东西大家都在网络上百度过了, ...

  9. 安全体系(二)——RSA算法详解

    本文主要讲述RSA算法使用的基本数学知识.秘钥的计算过程以及加密和解密的过程. 安全体系(零)—— 加解密算法.消息摘要.消息认证技术.数字签名与公钥证书 安全体系(一)—— DES算法详解 1.概述 ...

  10. 安全体系(三)——SHA1算法详解

    本文主要讲述使用SHA1算法计算信息摘要的过程. 安全体系(零)—— 加解密算法.消息摘要.消息认证技术.数字签名与公钥证书 安全体系(一)—— DES算法详解 安全体系(二)——RSA算法详解 为保 ...

随机推荐

  1. 头晕的android SDK Manager and 找不到真机

    这张图很完美!可是出问题就头晕了. 问题场景:执行Andriod.bat出现下面界面后,然后跳出Andriod SDK的界面: android SDK Manager的界面就孤零零的几条记录挂在那里. ...

  2. MySurvey 问卷调查, 一个简单的Biwen.QuickApi示例项目

    MySurvey 项目 很久没更新我的博客了,之前开发的Biwen.QuickApi微框架 一直没有开发一个示例项目,最近有点时间,写了一个示例项目稍微介绍下 项目简介 这是一个基于 Biwen.Qu ...

  3. 不同数据库Oracle、PostgreSQL、Vertical、Mysql常用操作

    不同数据库Oracle.PostgreSQL.Vertical.Mysql常用操作 授权语句用于管理数据库用户的权限,常见的授权语句如下: 1.授权用户对表的SELECT权限 GRANT SELECT ...

  4. Java连接Redis常用操作

    1.去重 package Data; import redis.clients.jedis.Jedis; public class TestRedisUniq { public static Jedi ...

  5. c++指针传递与引用传递

    c 不支持引用传递的! 在 C++中,指针传递和引用传递是两种常用的参数传递方式,它们各自有不同的特点和适用场景.下面是两者之间的主要区别: 1. 语法和使用 指针传递 定义和调用:函数参数是一个指针 ...

  6. nginx代理静态页面添加二级目录

    location /wash { # root html; alias /home/cxq/wash-html/dist; index index.html index.htm; try_files ...

  7. selenium IDE简单使用

    selenium IDE可理解为录制操作浏览器的过程,然后回放实现UI级的自动化 一,首先安装,本案例主要在谷歌浏览器上使用,所以用的是支持谷歌的IDE文件 下载,打开https://www.crx4 ...

  8. 如何在 MySQL 中实现读写分离?

    如何在 MySQL 中实现读写分离? 在 MySQL 中实现读写分离主要目的是为了提升数据库的性能和扩展性,将读请求和写请求分配到不同的服务器上,减轻主数据库的压力.通常,写请求会发送到主库,而读请求 ...

  9. MySQL 中如果发生死锁应该如何解决?

    MySQL 中如果发生死锁应该如何解决? 死锁是指多个事务在执行过程中因资源争用形成的循环等待,导致无法继续执行.MySQL 会自动检测死锁并选择一个事务进行回滚,但我们可以通过优化设计和操作来避免和 ...

  10. 一、Java语言介绍

    1.硬件知识介绍 2.常用dos命令以及快捷键 1 /** 2 *@desc: 复习 3 *@Description: 4 * dir:列出当前文件目录下的所有文件; 5 * md:创建一个新目录; ...