กฎพื้นฐานสี่ข้อของลายเซ็น ECDSA …

May 10 2023
ในปี 1999 Don Johnson Alfred Menezes (1999) ได้ตีพิมพ์บทความคลาสสิกเรื่อง “The Elliptic Curve Digital Signature Algorithm (ECDSA)” โดยพื้นฐานแล้ว จะใช้ DSA (Digital Signature Algorithm) ซึ่งสร้างโดย David W. Kravitz และแปลงเป็น การแสดงเส้นโค้งวงรี
ภาพถ่ายโดย Signature Pro บน Unsplash

ในปี 1999 Don Johnson Alfred Menezes (1999) ได้ตีพิมพ์บทความคลาสสิกเรื่อง “The Elliptic Curve Digital Signature Algorithm (ECDSA)”:

โดยพื้นฐานแล้ว จะใช้ DSA (Digital Signature Algorithm) ซึ่งสร้างโดย David W. Kravitz และแปลงเป็นการแสดงเส้นโค้งวงรี และเนื่องจากท่อนซุงที่แยกจากกันมีขนาดใหญ่ขึ้น วิธีการแบบ Elliptic Curve จึงมีประสิทธิภาพมากขึ้น

จากนั้นในปี 2550 Satoshi Nakamoto เริ่มเขียนโค้ดสำหรับการใช้งาน Bitcoin ของเขา/เธอ และเลือก ECDSA เป็นวิธีลายเซ็นหลัก และใช้เส้นโค้ง secp256k1 สำหรับ Ethereum ก็เช่นกัน วิธีธรรมชาติในการใช้คือวิธีลายเซ็น ECDSA แต่ลายเซ็น ECDSA มีแนวโน้มที่จะถูกโจมตีหากใช้งานไม่ถูกต้อง ดังนั้น มาดูกฎพื้นฐานสี่ข้อกัน

ความมหัศจรรย์ที่แท้จริงของ ECDSA คือเราไม่ต้องเก็บพับลิกคีย์ แต่สามารถตรวจสอบลายเซ็นได้จากไพรเวตคีย์เวอร์ชันแฮช ด้วยวิธีนี้ บล็อกเชนจึงไม่จำเป็นต้องเก็บคีย์สาธารณะของผู้ที่ใช้มัน และนี่เป็นหนึ่งในครั้งแรกที่เราสร้างโครงสร้างพื้นฐานข้อมูลแบบกระจายอำนาจอย่างแท้จริง

หากคุณต้องการทำความเข้าใจวิธีการทำงานของลายเซ็น ECDSA ลองที่นี่

อย่ารั่ว Nonce

ตัวอย่าง: ถอดรหัส ECDSA จากการรั่วไหลของ nonce (SECP256k1 ) ECDSA กับ nonce . ข้อมูลนี้สรุป ECDSA ว่าสามารถกู้คืนคีย์ส่วนตัวได้อย่างไรด้วยการรั่วไหลของค่า nonce สำหรับ SECP256k1

ด้วยลายเซ็น ECDSA เราจะเซ็นข้อความด้วยคีย์ส่วนตัว ( priv ) และพิสูจน์ลายเซ็นด้วยคีย์สาธารณะ ( pub ) จากนั้นจะใช้ค่าสุ่ม (ไม่มีค่า) เพื่อสุ่มลายเซ็น ทุกครั้งที่เราลงนาม เราจะสร้างค่า nonce แบบสุ่มและจะสร้างลายเซ็นที่แตกต่างกัน (แต่ตรวจสอบได้) โดยรวมแล้วผู้ลงนามจะต้องเปิดเผยองค์ประกอบของลายเซ็นและรหัสสาธารณะเท่านั้น ไม่ใช่ค่าที่ไม่มีค่า หากผู้ลงนามเปิดเผยค่า nonce เพียงค่าเดียวโดยไม่ได้ตั้งใจ ผู้บุกรุกสามารถค้นพบคีย์ส่วนตัวได้ ในกรณีนี้ เราจะเปิดเผยค่า nonce และกำหนดคีย์ส่วนตัว และใช้เส้นโค้ง secp256k1 (เหมือนกับที่ใช้กับ Bitcoin)

ใน ECDSA Bob จะสร้างคีย์ส่วนตัวแบบสุ่ม ( priv ) จากนั้นจึงสร้างคีย์สาธารณะจาก:

ผับ = ส่วนตัว × G

ถัดไป เพื่อสร้างลายเซ็นสำหรับข้อความของMเขาสร้างตัวเลขสุ่ม ( k ) และสร้างลายเซ็นของ:

r = kG

s = k ^{−1}( H ( M )+ rไพรเวต )

ลายเซ็นคือ ( r , s ) และโดยที่rคือพิกัด x ของจุดkG H ( M ) คือแฮช SHA-256 ของข้อความ ( M ) และแปลงเป็นค่าจำนวนเต็ม หาก ค่า kถูกเปิดเผยสำหรับลายเซ็นใด ๆ ผู้บุกรุกสามารถระบุคีย์ส่วนตัวได้โดยใช้:

priv = r ^{−1}×(( ks )− H ( M ))

สิ่งนี้ใช้ได้เพราะ:

sk = H ( M )+ rส่วนตัว

และอื่น ๆ:

rส่วนตัว = skH ( M )

และสำหรับความเป็นส่วนตัว :

เอกชน = r −1( skH ( M ))

นี่คือรหัสบางส่วนที่ค้นพบคีย์ส่วนตัว หากมีการเปิดเผย nonce ( k ) [ ที่นี่ ]:

import ecdsa
import random
import libnum
import hashlib
import sys

G = ecdsa.SECP256k1.generator
order = G.order()
print ("Curve detail")
print (G.curve())
print ("Order:",order)
print ("Gx:",G.x())
print ("Gy:",G.y())

priv = random.randrange(1,order)
 
Public_key = ecdsa.ecdsa.Public_key(G, G * priv)
Private_key = ecdsa.ecdsa.Private_key(Public_key, priv)
 
k1 = random.randrange(1, 2**127)
msg1="Hello"
if (len(sys.argv)>1):
 msg1=(sys.argv[1])
m1 = int(hashlib.sha256(msg1.encode()).hexdigest(),base=16)
 
sig1 = Private_key.sign(m1, k1)

print ("\nMessage 1: ",msg1)
print ("Sig 1 r,s: ",sig1.r,sig1.s)
r1_inv = libnum.invmod(sig1.r, order)
s1 = sig1.s
 
try_private_key = (r1_inv * ((k1 * s1) - m1)) % order
print ()
print ("Found Key: ",try_private_key)
print ()
print ("Key: ",priv)
if (ecdsa.ecdsa.Public_key(G, G * try_private_key) == Public_key):
 print("\nThe private key has been found")
 print (try_private_key)

Curve detail
CurveFp(p=115792089237316195423570985008687907853269984665640564039457584007908834671663, a=0, b=7, h=1)
Order: 115792089237316195423570985008687907852837564279074904382605163141518161494337
Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240
Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424

Message 1:  hello
Sig 1 r,s:  31110256322898237264490243973699731757547476866639597679936653478826981616940 39826373609221276498318363598911660764943881869513002749160966300292770474312
Found Key:  95525957745036960168874600860927089941985475618074755510253043724286299804190
Key:  95525957745036960168874600860927089941985475618074755510253043724286299804190
The private key has been found
95525957745036960168874600860927089941985475618074755510253043724286299804190

ตัวอย่าง: ถอดรหัส ECDSA ด้วย nonces ที่อ่อนแอ (sepc256k1 ) ECDSA : เปิดเผยคีย์ส่วนตัวจาก nonce เดียวกัน ข้อมูลนี้สรุป ECDSA ว่าสามารถกู้คืนคีย์ส่วนตัวด้วยค่า nonce ที่ไม่รัดกุมได้อย่างไร

ด้วยลายเซ็น ECDSA เราจะเซ็นข้อความด้วยคีย์ส่วนตัว ( priv ) และพิสูจน์ลายเซ็นด้วยคีย์สาธารณะ ( pub ) จากนั้นจะใช้ค่าสุ่ม (ไม่มีค่า) เพื่อสุ่มลายเซ็น ทุกครั้งที่เราลงนาม เราจะสร้างค่า nonce แบบสุ่มและจะสร้างลายเซ็นที่แตกต่างกัน (แต่ตรวจสอบได้) อย่างไรก็ตาม คีย์ส่วนตัวสามารถค้นพบได้หากอลิซเซ็นชื่อสองข้อความที่แตกต่างกันด้วย nonce เดียวกัน [1]

ใน ECDSA Bob จะสร้างคีย์ส่วนตัวแบบสุ่ม ( priv ) จากนั้นจึงสร้างคีย์สาธารณะจาก:

ผับ = ส่วนตัว × G

ถัดไป เพื่อสร้างลายเซ็นสำหรับข้อความของMเขาสร้างตัวเลขสุ่ม ( k ) และสร้างลายเซ็นของ:

r = kG

s = k ^{−1}( H ( M )+ rไพรเวต )

ลายเซ็นคือ ( r , s ) และโดยที่rคือพิกัด x ของจุดkG H ( M ) คือแฮช SHA-256 ของข้อความ ( M ) และแปลงเป็นค่าจำนวนเต็ม

สมมติว่าเรามีข้อความสองข้อความ ( ม. 1 และม. 2) และมีแฮชของ:

ชั่วโมง 1= ชั่วโมง ( ม. 1)

ชั่วโมง 2= ชั่วโมง ( ม. 2)

สมมติว่าอลิซลงนามในข้อความด้วยรหัสส่วนตัวเดียวกัน ( priv)และ nonce เดียวกัน ( k)จากนั้นเราสามารถกู้คืนรหัสส่วนตัวด้วย:

เรายังสามารถกู้คืน nonce ได้ด้วย:

ต่อไปนี้คือโค้ดบางส่วนที่ค้นหาคีย์ส่วนตัว และโค้ด nonce ( k ) ถ้าเราใช้ค่า nonce เดียวกัน [ here ]:

import ecdsa
import random
import libnum
import hashlib
import sys

G = ecdsa.SECP256k1.generator
order = G.order()
priv1 = random.randrange(1,order)
 
Public_key = ecdsa.ecdsa.Public_key(G, G * priv1)
x1 = ecdsa.ecdsa.Private_key(Public_key, priv1)
k = random.randrange(1, 2**127)
msg1="Hello"
msg2="Hello1"
if (len(sys.argv)>1):
 msg1=(sys.argv[1])
if (len(sys.argv)>2):
 msg2=(sys.argv[2]) 

h1 = int(hashlib.sha256(msg1.encode()).hexdigest(),base=16)
h2 = int(hashlib.sha256(msg2.encode()).hexdigest(),base=16)
 
sig1 = x1.sign(h1, k)
sig2 = x1.sign(h2, k)
r1,s1 = sig1.r,sig1.s
r2,s2 = sig2.r,sig2.s
valinv = libnum.invmod( r1*(s1-s2),order)
x1rec = (   (s2*h1-s1*h2) * (valinv)) % order
print ("Message 1: ",msg1)
print (f"Signature r={r1}, s={s1}")
print ("\nMessage 2: ",msg2)
print (f"Signature r={r2}, s={s2}")

print ("\nPrivate key",priv1)
print ("\nPrivate recovered ",x1rec)
valinv = libnum.invmod( (s1-s2),order)
k1rec = (   (h1-h2) * valinv) % order
print ("\nK: ",k)
print ("\nK recovered ",k1rec)

Message 1:  hello
Signature r=16163824871702315365636544754327339671279830383115616072776286071644348532176, s=78942102071383249892109282228339664393041099900407940222266026023142592864884
Message 2:  hello1
Signature r=16163824871702315365636544754327339671279830383115616072776286071644348532176, s=83502523167965149244641473202679268630845178075816922294718909855670078364206
Private key 6542179820561127199468453109220159836323733777364616770035873205004743487369
Private recovered  6542179820561127199468453109220159836323733777364616770035873205004743487369
K:  109308891778201478280270581205739604663
K recovered  109308891778201478280270581205739604663

ตัวอย่าง: การเปิดเผยคีย์ส่วนตัวจากสองคีย์และ nonces ที่ใช้ร่วมกัน (SECP256k1 ) ECDSA: การเปิดเผยคีย์ส่วนตัวจากสองคีย์และ nonces ที่ใช้ร่วมกัน (SECP256k1 ) ข้อมูลนี้สรุป ECDSA ว่าเราสามารถเปิดเผยคีย์ส่วนตัวสองคีย์จากข้อความที่เซ็นชื่อสี่รายการได้อย่างไร

ด้วยลายเซ็น ECDSA เราจะเซ็นข้อความด้วยคีย์ส่วนตัว ( priv ) และพิสูจน์ลายเซ็นด้วยคีย์สาธารณะ ( pub ) จากนั้นจะใช้ค่าสุ่ม (ไม่มีค่า) เพื่อสุ่มลายเซ็น ทุกครั้งที่เราลงนาม เราจะสร้างค่า nonce แบบสุ่มและจะสร้างลายเซ็นที่แตกต่างกัน (แต่ตรวจสอบได้) อย่างไรก็ตาม คีย์ส่วนตัวสามารถค้นพบได้หากอลิซลงนามสี่ข้อความด้วยสองคีย์และสอง nonce [2] ในกรณีนี้ เธอจะเซ็นข้อความ 1 ด้วยคีย์ส่วนตัวแรก ( x 1) เซ็นข้อความ 2 ด้วยคีย์ส่วนตัวที่สอง ( x 2) เซ็นข้อความ 3 ด้วยคีย์ส่วนตัวแรก ( x 1) และเซ็นข้อความ 4 ด้วย รหัสส่วนตัวที่สอง ( x 2) nonce เดียวกัน ( k1) ใช้ในการลงนามสำหรับข้อความ 1 และ 2 และอีก nonce ( k 2) ใช้ในการลงนามข้อความ 3 และ 4

ใน ECDSA Bob จะสร้างคีย์ส่วนตัวแบบสุ่ม ( priv ) จากนั้นจึงสร้างคีย์สาธารณะจาก:

ผับ = ส่วนตัว × G

ถัดไป เพื่อสร้างลายเซ็นสำหรับข้อความของMเขาสร้างตัวเลขสุ่ม ( k ) และสร้างลายเซ็นของ:

r = kG

s = k −1( H ( M )+ rไพรเวต )

ลายเซ็นคือ ( r , s ) และโดยที่rคือพิกัด x ของจุดkG H ( M ) คือแฮช SHA-256 ของข้อความ ( M ) และแปลงเป็นค่าจำนวนเต็ม

ในกรณีนี้ อลิซจะมีคู่คีย์สองคู่ และมีคีย์ส่วนตัวสองคีย์ ( x 1 และx 2) เธอจะเซ็นข้อความ 1 ( ม. 1) ด้วยรหัสส่วนตัวแรก ( x 1), ลงชื่อข้อความ 2 ( ม. 2) ด้วยรหัสส่วนตัวที่สอง ( x 2), ลงชื่อข้อความ 3 ( ม. 3) ด้วยรหัสส่วนตัวแรก ( x 1) และเซ็นข้อความ 4 ( ม. 4) ด้วยรหัสส่วนตัวที่สอง ( x 2) nonce เดียวกัน ( k 1) ใช้ในการเซ็นข้อความ 1 และ 2 และ nonce อีกอัน ( k 2) ใช้ในการเซ็นข้อความ 3 และ 4 ตอนนี้สมมติว่าเรามีสี่ข้อความ ( m 1 .. m4) และมีแฮชของ:

ชั่วโมง 1= ชั่วโมง ( ม. 1)

ชั่วโมง 2= ชั่วโมง ( ม. 2)

ชั่วโมง 3= ชั่วโมง ( ม. 3)

ชั่วโมง 4= ชั่วโมง ( ม. 4)

ลายเซ็นสำหรับข้อความจะเป็น ( s 1, r 1), ( s 2, r 1), ( s 3, r 2) และ ( s 4, r 2):

s 1= k 1−1( ชั่วโมง 1+ r 1⋅ x 1)(mod p )

s 2= k 1−1( ชั่วโมง 2+ r 1⋅ x 2)(mod p )

s 3= k 2−1( ชั่วโมง 3+ r 2⋅ x 1)(mod p )

s 4= k 2−1( ชั่วโมง 4+ r 2⋅ x 2)(mod p )

ด้วยการใช้ Gaussian elimination เรายังสามารถกู้คืนคีย์ส่วนตัวได้ด้วย:

และ:

นี่คือรหัสบางส่วนที่ค้นพบคีย์ส่วนตัว [ ที่นี่ ]:

import ecdsa
import random
import libnum
import hashlib
import sys
G = ecdsa.SECP256k1.generator
order = G.order()
priv1 = random.randrange(1,order)
Public_key = ecdsa.ecdsa.Public_key(G, G * priv1)
x1 = ecdsa.ecdsa.Private_key(Public_key, priv1)
priv2 = random.randrange(1,order)
Public_key2 = ecdsa.ecdsa.Public_key(G, G * priv2)
x2 = ecdsa.ecdsa.Private_key(Public_key2, priv2)
k1 = random.randrange(1, 2**127)
k2 = random.randrange(1, 2**127)
msg1="Hello"
msg2="Hello1"
msg3="Hello3"
msg4="Hello4"
if (len(sys.argv)>1):
 msg1=(sys.argv[1])
if (len(sys.argv)>2):
 msg2=(sys.argv[2]) 
if (len(sys.argv)>3):
 msg3=(sys.argv[3]) 
if (len(sys.argv)>4):
 msg4=(sys.argv[4]) 

h1 = int(hashlib.sha256(msg1.encode()).hexdigest(),base=16)
h2 = int(hashlib.sha256(msg2.encode()).hexdigest(),base=16)
h3 = int(hashlib.sha256(msg3.encode()).hexdigest(),base=16)
h4 = int(hashlib.sha256(msg4.encode()).hexdigest(),base=16)
 
sig1 = x1.sign(h1, k1)
sig2 = x2.sign(h2, k1)
sig3 = x1.sign(h3, k2)
sig4 = x2.sign(h4, k2)
r1,s1 = sig1.r,sig1.s
r1_1,s2 = sig2.r,sig2.s
r2,s3 = sig3.r,sig3.s
r2_1,s4 = sig4.r,sig4.s
valinv = libnum.invmod( r1*r2*(s1*s4-s2*s3),order)
x1rec = ((h1*r2*s2*s3-h2*r2*s1*s3-h3*r1*s1*s4+h4*r1*s1*s3    ) * valinv)  % order
x2rec = ((h1*r2*s2*s4-h2*r2*s1*s4-h3*r1*s2*s4+h4*r1*s2*s3    ) * valinv)  % order

print ("Message 1: ",msg1)
print (f"Signature r={r1}, s={s1}")
print ("\nMessage 2: ",msg2)
print (f"Signature r={r1_1}, s={s2}")
print ("\nMessage 3: ",msg3)
print (f"Signature r={r2}, s={s3}")
print ("\nMessage 4: ",msg4)
print (f"Signature r={r2_1}, s={s4}")
print ("\nPrivate key (x1):",priv1)
print ("\nPrivate recovered (x1): ",x1rec)
print ("\nPrivate key (x2):",priv2)
print ("\nPrivate recovered (x2):",x2rec)

Message 1:  hello
Signature r=96094994597103916506348675161520648758285225187589783433159767384063221853577, s=11930786632149881397940019723063699895405239832076777367931993614016265847425
Message 2:  hello1
Signature r=96094994597103916506348675161520648758285225187589783433159767384063221853577, s=86716405197525298580208026914311340731533780839926210284720464080897845438167
Message 3:  hello2
Signature r=12047241901687561506156261203581292367663176900884185151523104379030284412704, s=42453302255950972549884862083375617752595228510622859389343928824741407916152
Message 4:  hello3
Signature r=12047241901687561506156261203581292367663176900884185151523104379030284412704, s=64279036158699242111613174757286438038132181593159757823380636958768174455517
Private key (x1): 82160419381684073393977402015108188969157550419795710258656483526045067388858
Private recovered (x1):  82160419381684073393977402015108188969157550419795710258656483526045067388858
Private key (x2): 114347697544140976184770951847100304992433696701232754239964044576164337336942
Private recovered (x2): 114347697544140976184770951847100304992433696701232754239964044576164337336942

ตัวอย่าง: Fault Attack . ECDSA : การโจมตีผิดพลาด ในการโจมตีข้อบกพร่องใน ECDSA เราต้องการเพียงสองลายเซ็นเท่านั้น หนึ่งถูกสร้างขึ้นโดยไม่มีข้อผิดพลาด ( r , s ) และอีกอันหนึ่งมีข้อบกพร่อง ( rf , sf ) จากสิ่งเหล่านี้เราสามารถสร้างรหัสส่วนตัวได้

ในการโจมตีข้อบกพร่องใน ECDSA เราต้องการเพียงสองลายเซ็นเท่านั้น หนึ่งถูกสร้างขึ้นโดยไม่มีข้อผิดพลาด ( r , s ) และอีกอันหนึ่งมีข้อบกพร่อง ( rf , sf ) จากสิ่งเหล่านี้ เราสามารถสร้างรหัสส่วนตัว [3,4]

ใน ECDSA Bob จะสร้างคีย์ส่วนตัวแบบสุ่ม ( priv ) จากนั้นจึงสร้างคีย์สาธารณะจาก:

ผับ = ส่วนตัว × G

ถัดไป เพื่อสร้างลายเซ็นสำหรับข้อความของMเขาสร้างตัวเลขสุ่ม ( k ) และสร้างลายเซ็นของ:

r = kG

s = k ^{−1}( h + rd )

และโดยที่dคือคีย์ส่วนตัวและh = H ( M ) ลายเซ็นคือ ( r , s )และโดยที่rคือพิกัด x ของจุดkG hคือแฮช SHA-256 ของข้อความ ( M ) และแปลงเป็นค่าจำนวนเต็ม

สมมติว่าเรามีสองลายเซ็น หนึ่งมีข้อผิดพลาดและอีกอันหนึ่งถูกต้อง จากนั้นเรามี ( r , s ) สำหรับข้อผิดพลาดที่ถูกต้อง และ ( rf , sf ) สำหรับข้อผิดพลาด สิ่งเหล่านี้จะเป็น:

sf = k^{ −1}.( h + d . rf )(mod p )

s = k ^{−1}.( h + d . r )(mod p )

และที่ไหนh

เป็นแฮชของข้อความ ทีนี้ ถ้าเราลบสองตัวs

ค่าที่เราได้รับ:

ssf = k ^{−1}.( h + d . r )− k^{ −1}.( h + d . rf )

แล้ว:

จากนั้นสามารถแทนที่ใน:

s = k^{ −1}( h + r . d )(mod p )

สิ่งนี้ให้:

จากนั้นเราสามารถจัดเรียงใหม่เพื่อรับรหัสส่วนตัว ( d ) จาก:

นี่คือรหัสที่จะใช้สิ่งนี้ [ ที่นี่ ]:

import ecdsa
import random
import libnum
import hashlib
import sys

G = ecdsa.SECP256k1.generator
order = G.order()
priv1 = random.randrange(1,order)
 
Public_key = ecdsa.ecdsa.Public_key(G, G * priv1)
d = ecdsa.ecdsa.Private_key(Public_key, priv1)
k = random.randrange(1, 2**127)
msg="Hello"
if (len(sys.argv)>1):
 msg=(sys.argv[1])

h = int(hashlib.sha256(msg.encode()).hexdigest(),base=16)
sig = d.sign(h, k)

r,s = sig.r,sig.s
# Now generate a fault
rf = sig.r+1
sf=(libnum.invmod(k,order)*(h+priv1*rf)) % order
k = h*(s-sf) * libnum.invmod(sf*r-s*rf,order)

valinv = libnum.invmod( (sf*r-s*rf),order)
dx =(h*(s-sf)* valinv) % order
print(f"Message: {msg}")
print(f"k: {k}")
print(f"Sig 1 (Good): r={r}, s={s}")
print(f"Sig 2 (Faulty): r={rf}, s={sf}")
print (f"\nGenerated private key: {priv1}")
print (f"\nRecovered private key: {dx}")

Message: hello
k: 15613459045461464441268016329920647751876410646419944753875923461028663912505625338208127533545920850138128660754322530221814353295370007218638086487275174473446354362246611811506735710487039390917643920660108528521515014507889120
Sig 1 (Good): r=84456595696494933440514821180730426741490222897895228578549018195243892414625, s=68818602365739991134541263302679449117335025608295087929401907013433000993001
Sig 2 (Faulty): r=84456595696494933440514821180730426741490222897895228578549018195243892414626, s=58598513613070973829759520121438538694005185742306423466103492198584643742545
Generated private key: 15195234419506006831576867959209365250058907799872905479943949602323611654898
Recovered private key: 15195234419506006831576867959209365250058907799872905479943949602323611654898

ECDSA นั้นยอดเยี่ยม แต่ต้องจัดการด้วยความระมัดระวัง!

อ้างอิง

[1] Brengel, M., & Rossow, C. (2018, กันยายน). ระบุการรั่วไหลของคีย์ของผู้ใช้ bitcoin ในการประชุมวิชาการนานาชาติว่าด้วยการวิจัยการโจมตี การบุกรุก และการป้องกัน (หน้า 623–643) สปริงเกอร์, จาม [ ที่นี่ ].

[2] Brengel, M., & Rossow, C. (2018, กันยายน). ระบุการรั่วไหลของคีย์ของผู้ใช้ bitcoin ในการประชุมวิชาการนานาชาติว่าด้วยการวิจัยการโจมตี การบุกรุก และการป้องกัน (หน้า 623–643) สปริงเกอร์, จาม [ ที่นี่ ].

[3] Sullivan, GA, Sippe, J., Heninger, N., & Wustrow, E. (2022) เปิดสู่ข้อผิดพลาด: ในการประนีประนอมคีย์ {TLS} แบบพาสซีฟผ่านข้อผิดพลาดชั่วคราว ใน USENIX Security Symposium ครั้งที่ 31 (USENIX Security 22) (หน้า 233–250)

[4] Poddebniak, D., Somorovsky, J., Schinzel, S., Lochter, M., & Rösler, P. (2018, เมษายน). โจมตีโครงร่างลายเซ็นที่กำหนดขึ้นโดยใช้การโจมตีข้อบกพร่อง ในปี 2018 IEEE European Symposium on Security and Privacy (EuroS&P) (หน้า 338–352) อีอีซี