比特币使用了椭圆曲线数字签名算法(ECDSA),是一种基于椭圆曲线的密码学算法。这中椭圆曲线被广泛称为secp256k1.它的曲线方程式是 y² = x³ + 7 在一个有限域上取值。示例图形如下:
平面上椭圆曲线上的加法是根据在几何上定义的直线与曲线的截距,我们这里不讨论几何学,只是说它可以归结为一组涉及实数的方程。但我们不是研究实数,而是研究有限域。
当你不是在实数上工作,而是在另一个域上工作时,使用平几何这些方程来定义加法。在secp256k1的情况下,该字段是整数mod p的有限字段,其中
p = 2256 – 232 – 977
这里的p被选择为相对接2256。它不是小2256的最大素数,在p到2256之间有很多素数。其他因素也进入了选择p。注意,我们不是在整数mod p中工作;我们是在Abelian群中工作,其加法定律由整数mod p上的椭圆曲线定义。
基点:
接下来,我们在椭圆曲线上选取一个基点g。定义secp256k1的标准是g是
压缩格式:0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
非压缩格式:
040x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
基点是椭圆曲线上的一个特殊选择点,所以它是一对mod p数,而不是一个数。如何从这些压缩或未压缩的表单中提取x和y?
压缩格式:
压缩的表单只给出x,你应该为y求解。未压缩的表单给出x和y。但是,数字是稍微编码的。在压缩格式中,字符串以“o2”或“o3”开头,其余字符串是x的十六进制表示形式。将有两个y值满足
y² = x³ + 7 mod p
“o2”或“03”告诉你该选哪一个。如果压缩表单以02开头,请选择最低有效位为偶数的根。如果压缩后的表单以03开头,则选择最低有效位为奇数的根。
(这两个根加在p上,p是奇数,所以其中一个根是偶数,另一个是奇数。)
未压缩格式:
未压缩的表单将始终以04开头。在此之后,将x和y的十六进制表示连接在一起。
举例说明,假如有
x = 79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
y = 483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
我们可以用一小段python代码来验证:
x = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
y = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
assert((yy - xx*x - 7) % p == 0)
从我们的基点g开始,将kg定义为g自加次。再次注意,这里的“加法”是椭圆曲线上的加法,而不是整数域中的加法mod p
椭圆曲线密码体制的关键是能有效地计算kg,而从kg的乘积开始求解k则不能。可以使用快速指数算法计算kg,但求解k需要计算离散对数。
(这是ECDLP:椭圆曲线离散对数问题。)
为什么这叫做“指数化”而不是“乘法”?椭圆曲线上的算法是可交换的,在可交换(即交换)群中,群运算通常表示为加法。重复加法叫做乘法。
但在一般群论中,群运算表示为乘法,而群运算的重复应用称为指数运算。使用一般术语“指数化”是很普遍的,尽管在阿贝尔群上,称之为乘法更有意义。
通过取对数来撤消指数运算,因此求解k的过程称为离散对数问题。椭圆曲线密码的安全性取决于离散对数的计算难度 。
在一组n大小的离散对数问题中,目前最好的算法需要O(n)运算。在我们的情况下n有多大?
选择基点g有一个大的阶,实际上它的阶大约为2256。具体来说,用十六进制表示的g的阶是
n = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141.
这意味着我们得到大约256/2=128位的安全性,因为\qquad $ 2^{256} $ \qquad 2256=2128。