![](/img/trans.png)
[英]Generating Elliptic Curve Private Key in Python with the cryptography library
[英]How to get an elliptic curve public key from a private key
因此,我需要使用 ECC spec256k1 從相應的 256 位數字中獲取公鑰。
因此,假設我使用 sha256 從任何密碼中獲取私鑰,如下所示:
>>> import hashlib
>>> private_key = hashlib.sha3_256(b"Led Zeppelin - No Quarter").hexdigest()
>>> private_key
'c0b279f18074de51d075b152c8ce78b7bddb284e8cfde19896162abec0a0acce'
如何從該私鑰中獲取公鑰? 我需要將公鑰打印為字符串。
pip install fastecdsa
from fastecdsa import keys, curve,ecdsa
priv_key, pub_key = keys.gen_keypair(curve.secp256k1)
print(pub_key)
產生
X: 0xcc228e1a4c8e187a0deeabcd6e43bc8f7b6bdd91b8f823912f2de188fba054e6
Y: 0x7995a9d3866a8fa11a9af933c76216a908995ec5cec6ed7d3056b787fa7d39d7
支持的原語
素數場上的曲線-源
Name Class
P192 / secp192r1 fastecdsa.curve.P192
P224 / secp224r1 fastecdsa.curve.P224
P256 / secp256r1 fastecdsa.curve.P256
P384 / secp384r1 fastecdsa.curve.P384
P521 / secp521r1 fastecdsa.curve.P521
secp192k1 fastecdsa.curve.secp192k1
secp224k1 fastecdsa.curve.secp224k1
secp256k1 (bitcoin curve) fastecdsa.curve.secp256k1
brainpoolP160r1 fastecdsa.curve.brainpoolP160r1
brainpoolP192r1 fastecdsa.curve.brainpoolP192r1
brainpoolP224r1 fastecdsa.curve.brainpoolP224r1
brainpoolP256r1 fastecdsa.curve.brainpoolP256r1
brainpoolP320r1 fastecdsa.curve.brainpoolP320r1
brainpoolP384r1 fastecdsa.curve.brainpoolP384r1
brainpoolP512r1 fastecdsa.curve.brainpoolP512r1
當前接受的答案描述了如何生成一個新的對,並沒有解決這個問題。
任何隨機的 256 位 integer 都適合作為該曲線的私鑰,因此與例如 RSA 相比,生成私鑰非常快。
import hashlib
private_key = hashlib.sha3_256(b"Led Zeppelin - No Quarter").hexdigest()
print(private_key)
c0b279f18074de51d075b152c8ce78b7bddb284e8cfde19896162abec0a0acce
這與您的問題相同。
橢圓曲線密碼學中的公鑰是曲線上的點 - 一對 integer 坐標{X,Y}
位於曲線上。 我們可以像這樣計算
import fastecdsa.keys
import fastecdsa.curve
curve = fastecdsa.curve.secp256k1
private_key_raw = int(private_key, base=16)
pubkey = fastecdsa.keys.get_public_key(private_key_raw, curve)
print(pubkey)
X: 0xbaa41af234cb2744ddaa039929c6ff21f0d5ab5ebce045d4a7513236f9bd429a
Y: 0x30252bd111b42e5195355f7fbcb5d6586ae76facbb4b7118fa96a2e99b40f716
(On curve <secp256k1>)
值得注意的是,由於它們的特殊屬性,公共 EC 點也可以在 SEC1 編碼中“壓縮”為僅一個坐標加上奇偶校驗(奇數或偶數)位。 換言之,256 位私鑰的公鑰也可以表示為 25 位7位 integer 而不是兩個坐標:
import fastecdsa.encoding.sec1
compressed_pubkey = fastecdsa.encoding.sec1.SEC1Encoder().encode_public_key(pubkey)
print("0x" + compressed_pubkey.hex())
0x02baa41af234cb2744ddaa039929c6ff21f0d5ab5ebce045d4a7513236f9bd429a
也就是上面的X
坐標,以0x02
為前綴。 第一個字節將是0x02
(偶數Y
)或0x03
(奇數Y
)。
由於偶數/奇數對應於 SEC1 編碼中的pubkey.y % 2
,您甚至可以在沒有fastecdsa
幫助的情況下自己對其進行編碼:
compressed_pubkey = pubkey.x + ((2 if pubkey.y % 2 == 0 else 3) << 256)
print(hex(compressed_pubkey))
0x2baa41af234cb2744ddaa039929c6ff21f0d5ab5ebce045d4a7513236f9bd429a
最后但同樣重要的是,我們可以為您的密鑰對生成 PEM 編碼的 forms,這是許多使用公鑰的應用程序所期望的。 此外,將密鑰存儲在磁盤上是一種有效的方法。
pubkey_pem = fastecdsa.keys.export_key(pubkey, curve)
print(pubkey_pem)
-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEuqQa8jTLJ0TdqgOZKcb/IfDVq1684EXU
p1EyNvm9QpowJSvREbQuUZU1X3+8tdZYaudvrLtLcRj6lqLpm0D3Fg==
-----END PUBLIC KEY-----
privkey_pem = fastecdsa.keys.export_key(private_key_raw, curve)
print(privkey_pem)
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIMCyefGAdN5R0HWxUsjOeLe92yhOjP3hmJYWKr7AoKzOoAcGBSuBBAAK
oUQDQgAEuqQa8jTLJ0TdqgOZKcb/IfDVq1684EXUp1EyNvm9QpowJSvREbQuUZU1
X3+8tdZYaudvrLtLcRj6lqLpm0D3Fg==
-----END EC PRIVATE KEY-----
使用模塊fastecdsa的其他兩個答案是正確的,但您可能希望在沒有任何外部非標准模塊的情況下從頭開始實現橢圓曲線算術,出於教育目的和學習樂趣。
我也這樣做了,下面我展示了我的代碼,它從頭開始實現橢圓曲線點加法和乘法(閱讀鏈接的 Wiki,它有所有數學描述),而不使用任何非標准模塊。 橢圓曲線的數學非常簡單,只需 Python 中的幾十行代碼即可完全實現。
標准曲線secp256k1
的參數我取自比特幣維基頁面,這條曲線參數和其他曲線(如secp256r1
、 secp384r1
、 secp521r1
也取自公共SECG pdf 。 這些參數給出所謂基點的坐標和參數。
之后公鑰只是基點(標准曲線點)乘以私鑰(整數)。 私鑰是簡單的大 integer,而公鑰是由兩個 integer 坐標(X,Y)和標准不可修改參數(A,B,P,Q)表示的橢圓曲線點。
在我的代碼中,如果您出於某種原因想要使用外部gmpy2庫並通過python -m pip install gmpy2
安裝它,您可以取消注釋#import gmpy2
行。 該庫為所有曲線數學提供了大約2x
倍的加速。 但是你不需要取消注釋這一行,這個庫的使用是非強制性的,我的代碼只適用於標准 Python 模塊非常快。
下面的代碼作為示例計算您的問題中提供的私鑰,打印它,計算公鑰並打印公鑰的 X 和 Y 坐標。 如您所見,獲得的公鑰與其他答案中打印的公鑰相同,通過fastecdsa獲得。
代碼后可以看到我的程序的控制台output(打印的私鑰和公鑰)。
class ECPoint:
gmpy2 = None
#import gmpy2
import random
class InvError(Exception):
def __init__(self, *pargs):
self.value = pargs
@classmethod
def Int(cls, x):
return int(x) if cls.gmpy2 is None else cls.gmpy2.mpz(x)
@classmethod
def std_point(cls, t):
if t == 'secp256k1':
# https://en.bitcoin.it/wiki/Secp256k1
# https://www.secg.org/sec2-v2.pdf
p = 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFFC2F
a = 0
b = 7
x = 0x79BE667E_F9DCBBAC_55A06295_CE870B07_029BFCDB_2DCE28D9_59F2815B_16F81798
y = 0x483ADA77_26A3C465_5DA4FBFC_0E1108A8_FD17B448_A6855419_9C47D08F_FB10D4B8
q = 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_BAAEDCE6_AF48A03B_BFD25E8C_D0364141
elif t == 'secp256r1':
# https://www.secg.org/sec2-v2.pdf
p = 0xFFFFFFFF_00000001_00000000_00000000_00000000_FFFFFFFF_FFFFFFFF_FFFFFFFF
a = 0xFFFFFFFF_00000001_00000000_00000000_00000000_FFFFFFFF_FFFFFFFF_FFFFFFFC
b = 0x5AC635D8_AA3A93E7_B3EBBD55_769886BC_651D06B0_CC53B0F6_3BCE3C3E_27D2604B
x = 0x6B17D1F2_E12C4247_F8BCE6E5_63A440F2_77037D81_2DEB33A0_F4A13945_D898C296
y = 0x4FE342E2_FE1A7F9B_8EE7EB4A_7C0F9E16_2BCE3357_6B315ECE_CBB64068_37BF51F5
q = 0xFFFFFFFF_00000000_FFFFFFFF_FFFFFFFF_BCE6FAAD_A7179E84_F3B9CAC2_FC632551
elif t == 'secp384r1':
# https://www.secg.org/sec2-v2.pdf
p = 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFFFFF_00000000_00000000_FFFFFFFF
a = 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFFFFF_00000000_00000000_FFFFFFFC
b = 0xB3312FA7_E23EE7E4_988E056B_E3F82D19_181D9C6E_FE814112_0314088F_5013875A_C656398D_8A2ED19D_2A85C8ED_D3EC2AEF
x = 0xAA87CA22_BE8B0537_8EB1C71E_F320AD74_6E1D3B62_8BA79B98_59F741E0_82542A38_5502F25D_BF55296C_3A545E38_72760AB7
y = 0x3617DE4A_96262C6F_5D9E98BF_9292DC29_F8F41DBD_289A147C_E9DA3113_B5F0B8C0_0A60B1CE_1D7E819D_7A431D7C_90EA0E5F
q = 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_C7634D81_F4372DDF_581A0DB2_48B0A77A_ECEC196A_CCC52973
elif t == 'secp521r1':
# https://www.secg.org/sec2-v2.pdf
p = 2 ** 521 - 1
a = 2 ** 521 - 4
b = 0x0051_953EB961_8E1C9A1F_929A21A0_B68540EE_A2DA725B_99B315F3_B8B48991_8EF109E1_56193951_EC7E937B_1652C0BD_3BB1BF07_3573DF88_3D2C34F1_EF451FD4_6B503F00
x = 0x00C6_858E06B7_0404E9CD_9E3ECB66_2395B442_9C648139_053FB521_F828AF60_6B4D3DBA_A14B5E77_EFE75928_FE1DC127_A2FFA8DE_3348B3C1_856A429B_F97E7E31_C2E5BD66
y = 0x0118_39296A78_9A3BC004_5C8A5FB4_2C7D1BD9_98F54449_579B4468_17AFBD17_273E662C_97EE7299_5EF42640_C550B901_3FAD0761_353C7086_A272C240_88BE9476_9FD16650
q = 0x01FF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFA_51868783_BF2F966B_7FCC0148_F709A5D0_3BB5C9B8_899C47AE_BB6FB71E_91386409
else:
assert False
return ECPoint(a, b, p, x, y, q = q)
def __init__(self, A, B, N, x, y, *, q = 0, prepare = True):
if prepare:
N = self.Int(N)
A, B, x, y, q = [self.Int(e) % N for e in [A, B, x, y, q]]
assert (4 * A ** 3 + 27 * B ** 2) % N != 0
assert (y ** 2 - x ** 3 - A * x - B) % N == 0, (hex(N), hex((y ** 2 - x ** 3 - A * x) % N))
assert N % 4 == 3
assert y == pow(x ** 3 + A * x + B, (N + 1) // 4, N)
self.A, self.B, self.N, self.x, self.y, self.q = A, B, N, x, y, q
def __add__(self, other):
A, B, N = self.A, self.B, self.N
Px, Py, Qx, Qy = self.x, self.y, other.x, other.y
if Px == Qx and Py == Qy:
s = ((Px * Px * 3 + A) * self.inv(Py * 2, N)) % N
else:
s = ((Py - Qy) * self.inv(Px - Qx, N)) % N
x = (s * s - Px - Qx) % N
y = (s * (Px - x) - Py) % N
return ECPoint(A, B, N, x, y, prepare = False)
def __rmul__(self, other):
other = self.Int(other - 1)
r = self
while True:
if other & 1:
r = r + self
if other == 1:
return r
other >>= 1
self = self + self
@classmethod
def inv(cls, a, n):
a %= n
if cls.gmpy2 is None:
try:
return pow(a, -1, n)
except ValueError:
import math
raise cls.InvError(math.gcd(a, n), a, n)
else:
g, s, t = cls.gmpy2.gcdext(a, n)
if g != 1:
raise cls.InvError(g, a, n)
return s % n
def __repr__(self):
return str(dict(x = self.x, y = self.y, A = self.A, B = self.B, N = self.N, q = self.q))
def __eq__(self, other):
for i, (a, b) in enumerate([(self.x, other.x), (self.y, other.y), (self.A, other.A),
(self.B, other.B), (self.N, other.N), (self.q, other.q)]):
if a != b:
return False
return True
def get_pub(priv_key):
bp = ECPoint.std_point('secp256k1')
pub = priv_key * bp
return pub.x, pub.y
def main():
import hashlib
priv_key = int(hashlib.sha3_256(b"Led Zeppelin - No Quarter").hexdigest(), 16)
print('priv key :', hex(priv_key))
pubx, puby = get_pub(priv_key)
print('pub key x:', hex(pubx))
print('pub key y:', hex(puby))
main()
Output:
priv key : 0xc0b279f18074de51d075b152c8ce78b7bddb284e8cfde19896162abec0a0acce
pub key x: 0xbaa41af234cb2744ddaa039929c6ff21f0d5ab5ebce045d4a7513236f9bd429a
pub key y: 0x30252bd111b42e5195355f7fbcb5d6586ae76facbb4b7118fa96a2e99b40f716
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.