title | tags | ||||||
---|---|---|---|---|---|---|---|
40. 常用椭圆曲线 |
|
这一讲,我们将介绍以太坊上常用的三条椭圆曲线:secp256k1
,bn128
,和 bls12_381
,其中 secp256k1
也被比特币采用。
我们在介绍椭圆曲线离散对数问题(ECDLP)的时候介绍了 secp256k1
曲线,这里再简单介绍一遍。secp256k1
由SECG(Standards for Efficient Cryptography Group)标准化,也是它名字的由来。
secp256k1
的椭圆曲线方程为:
它定义在一个特定的有限域
secp256k1
椭圆曲线上的点群形成了一个循环群,阶为 115792089237316195423570985008687907852837564279074904382605163141518161494337
,包含的点非常多,保障了算法的安全性。点 secp256k1
的一个基点/生成元,可以生成所有点,其中:
Gx = 55066263022277343669578718895168534326250603453777863175500187360389116729240
Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424
secp256k1
被用于比特币和以太坊的公钥生成和数字签名,下面我们利用 py_ecc
库给出代码示例。
使用 secp256k1
进行公钥生成非常简单,我们先随机生成一个私钥
# 椭圆曲线 secp256k1 示例
# 利用标量乘法,从私钥生成公钥
from py_ecc.secp256k1 import secp256k1
import os
def generate_public_key(private_key):
"""
使用secp256k1椭圆曲线,根据给定的私钥生成公钥。
参数:
private_key (int): 私钥,一个大整数。
返回:
(int, int): 公钥,椭圆曲线上的点。
"""
# secp256k1的基点
G = secp256k1.G
# 计算公钥
public_key = secp256k1.multiply(G, private_key)
return public_key
# 示例:使用一个随机的私钥
private_key = int(os.urandom(32).hex(), 16)
# 生成公钥
public_key = generate_public_key(private_key)
# 打印结果
print(f"Private Key: {private_key}")
print(f"Public Key: {public_key}")
# 示例输出
# Private Key: 40871478222817722377012551921323657605236631423958081783403470740144884256441
# Public Key: (18814187692496112820586797121940816605467606938301853840004393937958984136992, 72833048843328294920821861725991661253504985018641366317346599320677058633891)
我们可以利用 py_ecc.secp256k1
中的 ecdsa_raw_sign
和 ecdsa_raw_recover
来实现椭圆曲线数字签名算法(ECDSA)。我们之后会更详细的介绍 ECDSA 算法。
# secp256k1 数字签名
from py_ecc.secp256k1 import secp256k1
import os
import hashlib
def sign_message(private_key, message):
"""
使用私钥对消息进行签名。
"""
message_hash = hashlib.sha256(message.encode()).digest()
private_key_bytes = private_key.to_bytes(32, "big")
signature = secp256k1.ecdsa_raw_sign(message_hash, private_key_bytes)
return signature
def verify_signature(message, signature, public_key):
"""
使用公钥验证消息的签名。
"""
message_hash = hashlib.sha256(message.encode()).digest()
recovered_public_key = secp256k1.ecdsa_raw_recover(message_hash, signature)
return recovered_public_key == public_key
# 示例使用
private_key = int.from_bytes(os.urandom(32), 'big')
public_key = secp256k1.multiply(secp256k1.G, private_key) # 计算公钥
print(f"Private Key: {private_key}")
print(f"Public Key: {public_key}")
message = "Hello, blockchain world!"
signature = sign_message(private_key, message) # 签名消息
is_valid = verify_signature(message, signature, public_key) # 尝试从签名恢复公钥
# 比较原始公钥和恢复的公钥
print(f"Signature valid: {is_valid}")
# 示例输出
# Private Key: 100160191408028635805410835424804882729758587641862022398559246101084514055515
# Public Key: (94753041202778772986386517607721465828067708966050249355074253521404789962176, 108824044826657285606250531715029407748756362423778933890891533480553307901806)
# Signature valid: True
bn_128
曲线,全称 Barreto-Naehrig 128位曲线,是一种在密码学中广泛使用的配对友好椭圆曲线。它的嵌入度为 12,兼顾加密安全与配对效率,常被用于零知识证明算法中。
bn_128
的椭圆曲线
它定义在一个特定的有限域 p
是一个大素数。
p = 21888242871839275222246405745257275088548364400416034343698204186575808495617
bn_128
椭圆曲线上的点群形成了一个循环群,阶为 21888242871839275222246405745257275088548364400416034343698204186575808495617
,包含的点非常多,保障了算法的安全性。点 bn_128
的一个基点/生成元,可以生成所有点。
在构造 Ate 配对时,配对映射
a = 10857046999023057138634570762232829481370756359578518086990519993285655852781
b = 11559732032986387107991004021392285783925812861821192530917403151452391805634
c = 8495653923123431417604973247489272438418190587263600148770280649306958101930
d = 4082367875863433681332203403145435568316851327593401208105741076214120093531
使用 bn128
曲线生成公钥的过程和 secp256k1
类似。
# bn128 生成公钥
from py_ecc.bn128 import bn128_curve
import os
def generate_bn128_public_key(private_key):
"""
使用bn_128曲线和给定的私钥生成公钥。
参数:
private_key (int): 私钥,一个大整数。
返回:
(int, int): 公钥,bn_128曲线上的点。
"""
# BN128_G1是bn_128曲线的基点
public_key = bn128_curve.multiply(bn128_curve.G1, private_key)
return public_key
# 示例:使用一个随机的私钥
private_key = int.from_bytes(os.urandom(32), 'big')
# 生成公钥
public_key = generate_bn128_public_key(private_key)
# 打印结果
print(f"Private Key: {private_key}")
print(f"Public Key: {public_key}")
# 示例输出
# Private Key: 98359178994781335595533648854802231427270090895769248482397491373685555850978
# Public Key: (3661113004864472419130070831996330893639690693841499262022550248113059694488, 16647856845341024716707355890250833951196099189567973816478113518219363325204)
我们在第38讲中介绍了如何用 bn128
实现配对,要注意一点是配对是在
# bn128 双线性配对
from py_ecc.bn128 import G1, G2, pairing, add, multiply, eq
print(G1)
print(G2)
print("\n")
a = 69
b = 420
c = a * b
A = multiply(G2, a)
B = multiply(G1, b)
pair_A_B = pairing(A, B)
print("Pairing of points A and B: ",pair_A_B)
print("\n")
C = multiply(G2, c)
pair_G2_C = pairing(C, G1)
print("Pairing of points G2 and C: ",pair_G2_C)
print("\n")
print("Is pair_A_B == pair_G2_C? ", pair_A_B == pair_G2_C)
# 输出
# (1, 2)
# ((10857046999023057138634570762232829481370756359578518086990519993285655852781, 11559732032986387107991004021392285783925812861821192530917403151452391805634), (8495653923123431417604973247489272438418190587263600148770280649306958101930, 4082367875863433681332203403145435568316851327593401208105741076214120093531))
# Pairing of points A and B: (19735667940922659777402175920395455799125563888708961631093487249968872129612, 1976543863057094994989237517814173599120655827589866703826517845909315612857, 19686523416572620016989349096902944934819162198495809257491045534399198954254, 5826646852844954420149583478015267673527445979905768896060072350584178989060, 2064185964405234542610947637037132798744921024553195185441592358018988389207, 8341934863294343910133492936755210611939463215146220944606211376003151106114, 12807669762027938768857302676393862225355612177677457846751491105239425227277, 5741126950795831539169012545403256931813076395529913201048083937620822856065, 11074901068523180915867722424807487877141140784438044188857570704539589417315, 19327019285776193278582429402961044775129507055467003359023290900912857119476, 17306986078986604236447922180440988200852103029519452658980599808670992125088, 13188937242065601189938233945175869194113210620973903647453917247887073581439)
# Pairing of points G2 and C: (19735667940922659777402175920395455799125563888708961631093487249968872129612, 1976543863057094994989237517814173599120655827589866703826517845909315612857, 19686523416572620016989349096902944934819162198495809257491045534399198954254, 5826646852844954420149583478015267673527445979905768896060072350584178989060, 2064185964405234542610947637037132798744921024553195185441592358018988389207, 8341934863294343910133492936755210611939463215146220944606211376003151106114, 12807669762027938768857302676393862225355612177677457846751491105239425227277, 5741126950795831539169012545403256931813076395529913201048083937620822856065, 11074901068523180915867722424807487877141140784438044188857570704539589417315, 19327019285776193278582429402961044775129507055467003359023290900912857119476, 17306986078986604236447922180440988200852103029519452658980599808670992125088, 13188937242065601189938233945175869194113210620973903647453917247887073581439)
# Is pair_A_B == pair_G2_C? True
bls12_381
属于 Barreto-Lynn-Scott (BLS) 曲线族的一员,是一种配对友好的椭圆曲线。它的嵌入度为 12,配对高效且安全,被以太坊广泛采用,比如POS的节点签名。
bls12_381
的椭圆曲线
它定义在一个特定的有限域 p
是一个大素数。
p = 21888242871839275222246405745257275088696311157297823662689037894645226208583
bls12_381
椭圆曲线上的点群形成了一个循环群,阶为 52435875175126190479447740508185965837690552500527637822603658699938581184513
,包含的点非常多,保障了算法的安全性。点 bls12_381
的一个基点/生成元,可以生成所有点。
其中:
x1 = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507
x2 = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569
在构造 Ate 配对时,配对映射
a = 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160
b = 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758
c = 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905
d = 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582
使用 bls12_381
曲线生成公钥的过程和 bn128
类似。
# bls12_381 生成公钥
from py_ecc.bls12_381 import bls12_381_curve
import os
def generate_bn12_381_public_key(private_key):
"""
使用bn_128曲线和给定的私钥生成公钥。
参数:
private_key (int): 私钥,一个大整数。
返回:
(int, int): 公钥,bn_128曲线上的点。
"""
# BN128_G1是bn_128曲线的基点
public_key = bls12_381_curve.multiply(bls12_381_curve.G1, private_key)
return public_key
# 示例:使用一个随机的私钥
private_key = int.from_bytes(os.urandom(32), 'big')
# 生成公钥
public_key = generate_bn12_381_public_key(private_key)
# 打印结果
print(f"Private Key: {private_key}")
print(f"Public Key: {public_key}")
# 示例输出
# Private Key: 56832202591799069674370871859151631253659339730808373097707650526306669655451
# Public Key: (2672943242084458229690202553507767493858110823696659228443909079186365919837314837610879707240986236828893077890320, 1516123302208562362629191397278119903430202415903098718379575356530260147717671392463098304288800407793122740332702)
bls12_381
的配对实现和 bn128
类似,同样要注意一点是配对是在
# bls12_381 双线性配对
from py_ecc.bls12_381 import G1, G2, pairing, add, multiply, eq
print(G1)
print(G2)
print("\n")
a = 69
b = 420
c = a * b
A = multiply(G2, a)
B = multiply(G1, b)
pair_A_B = pairing(A, B)
print("Pairing of points A and B: ",pair_A_B)
print("\n")
C = multiply(G2, c)
pair_G2_C = pairing(C, G1)
print("Pairing of points G2 and C: ",pair_G2_C)
print("\n")
print("Is pair_A_B == pair_G2_C? ", pair_A_B == pair_G2_C)
# 输出
# (3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507, 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569)
# ((352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160, 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758), (1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905, 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582))
# Pairing of points A and B: (559875907953044229256999964908655596470329614681804657067074917348889299656574983763205735263906508658423626306192, 3251387332700024622230711712327939415422447046055926038630362608193945095062996827680637432749053965474170688846803, 1858978301495685148589092187900391308425211794249943939941796868269658435530364461212323465553496690057506398710958, 2821404563389658506867792213698964607416184520400354580766817454079710851304957653749944402097411780097914172680501, 3371394908151563362208243796489511825354821020573987752522791881868987441291678825694507113985550194783443672326288, 2297984649797609740520111469542560058998637859756636710986648527547199863538622957148043186058263511759636104385884, 3480762570907741510541555641785158658308333937734941283300383364697580261225975907843679022209374260264933745191828, 3240728397255321363427476858948130370605249287048803384220203355573990507150386888156524321441752887099266166133108, 2376364160413810038009747479244195484637259359228646277111417852748902100064937901534264975269224589631629799823776, 505616797063036550970852124247959597244795697098930755073121309023649013438395471915981324345265013483679297150493, 283646809217572597374969288842854659843926065997224794730305413934017744924705963601539908633134851567640611976585, 208748941951544416005406635656082534817221797560780462964136211816030039051269393961107822344678318294491041226308)
# Pairing of points G2 and C: (559875907953044229256999964908655596470329614681804657067074917348889299656574983763205735263906508658423626306192, 3251387332700024622230711712327939415422447046055926038630362608193945095062996827680637432749053965474170688846803, 1858978301495685148589092187900391308425211794249943939941796868269658435530364461212323465553496690057506398710958, 2821404563389658506867792213698964607416184520400354580766817454079710851304957653749944402097411780097914172680501, 3371394908151563362208243796489511825354821020573987752522791881868987441291678825694507113985550194783443672326288, 2297984649797609740520111469542560058998637859756636710986648527547199863538622957148043186058263511759636104385884, 3480762570907741510541555641785158658308333937734941283300383364697580261225975907843679022209374260264933745191828, 3240728397255321363427476858948130370605249287048803384220203355573990507150386888156524321441752887099266166133108, 2376364160413810038009747479244195484637259359228646277111417852748902100064937901534264975269224589631629799823776, 505616797063036550970852124247959597244795697098930755073121309023649013438395471915981324345265013483679297150493, 283646809217572597374969288842854659843926065997224794730305413934017744924705963601539908633134851567640611976585, 208748941951544416005406635656082534817221797560780462964136211816030039051269393961107822344678318294491041226308)
# Is pair_A_B == pair_G2_C? True
这一讲,我们介绍了比特币和以太坊上的常用椭圆曲线:secp256k1
,bn128
,和bls12_381
,并基于ecc_py
写了简单示例。secp256k1
主要用于比特币和以太坊上的公钥生成和数字签名,而bn128
和bls12_381
是配对友好的曲线,可以被用于签名和零知识证明算法。