กฎพื้นฐานสี่ข้อของลายเซ็น ECDSA …
ในปี 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 = k ⋅ G
s = k ^{−1}( H ( M )+ r ⋅ ไพรเวต )
ลายเซ็นคือ ( r , s ) และโดยที่rคือพิกัด x ของจุดkG H ( M ) คือแฮช SHA-256 ของข้อความ ( M ) และแปลงเป็นค่าจำนวนเต็ม หาก ค่า kถูกเปิดเผยสำหรับลายเซ็นใด ๆ ผู้บุกรุกสามารถระบุคีย์ส่วนตัวได้โดยใช้:
priv = r ^{−1}×(( k ⋅ s )− H ( M ))
สิ่งนี้ใช้ได้เพราะ:
s ⋅ k = H ( M )+ r ⋅ ส่วนตัว
และอื่น ๆ:
r ⋅ ส่วนตัว = s ⋅ k − H ( M )
และสำหรับความเป็นส่วนตัว :
เอกชน = r −1( s ⋅ k − H ( 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 = k ⋅ G
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 = k ⋅ G
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 = k ⋅ G
s = k ^{−1}( h + r ⋅ d )
และโดยที่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
ค่าที่เราได้รับ:
s − sf = 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) อีอีซี