题目描述

ECDSA

签名

假设我们的私钥为 d A d_A dA​而公钥为 Q A Q_A QA​, Q A = d A ⋅ G Q_A=d_A\cdot G QA​=dA​⋅G,接下来就是签名的过程,要签名的消息为 m m m

  1. 取 e = H A S H ( m ) e = HASH(m) e=HASH(m)
  2. 取 e e e的左边的 L n L_n Ln​个bit长度的值为 z z z, L n L_n Ln​即为前面提到的参数里 n n n的比特长度
  3. 从 [ 1 , n − 1 ] [1, n-1] [1,n−1]范围内,随机选择一个整数 k k k
  4. 利用 k k k得到椭圆曲线上的一点 ( x 1 , y 1 ) = k ⋅ G (x1,y1)=k \cdot G (x1,y1)=k⋅G
  5. 然后计算 r ≡ x 1 ( m o d n ) r \equiv x_1 (mod n) r≡x1​(modn),如果如果 r = 0 r=0 r=0则返回步骤3重新选择 k k k
  6. 计算 s = k − 1 ( z + r ⋅ d A ) ( m o d n ) s = k^{-1}(z + r\cdot d_A) (mod n) s=k−1(z+r⋅dA​)(modn),如果 s = 0 s=0 s=0则返回步骤3重新选择 k k k
  7. 得到的数字签名即为 ( r , s ) (r,s) (r,s)

验证

取点 P = ( X p , Y p ) = s − 1 ⋅ z ⋅ G + s − 1 ⋅ r ⋅ Q A P=(X_p,Y_p)= s ^ {-1} \cdot z \cdot G + s ^ {-1} \cdot r \cdot Q_A P=(Xp​,Yp​)=s−1⋅z⋅G+s−1⋅r⋅QA​
若 X p = r X_p=r Xp​=r,则签名有效,否则无效

Simple Proof
P = ( X p , Y p ) = s − 1 ⋅ z ⋅ G + s − 1 ⋅ r ⋅ Q A P=(X_p,Y_p)= s ^ {-1} \cdot z \cdot G + s ^ {-1} \cdot r \cdot Q_A P=(Xp​,Yp​)=s−1⋅z⋅G+s−1⋅r⋅QA​
因为 Q A = d A ⋅ G Q_A=d_A \cdot G QA​=dA​⋅G,故有
P = s − 1 ⋅ z ⋅ G + s − 1 ⋅ r ⋅ Q A P= s ^ {-1} \cdot z \cdot G + s ^ {-1} \cdot r \cdot Q_A P=s−1⋅z⋅G+s−1⋅r⋅QA​
= s − 1 ⋅ z ⋅ G + s − 1 ⋅ r ⋅ d A ⋅ G = s ^ {-1} \cdot z \cdot G + s ^ {-1} \cdot r \cdot d_A \cdot G =s−1⋅z⋅G+s−1⋅r⋅dA​⋅G
= s − 1 ⋅ G ⋅ ( z + r ⋅ d A ) = s ^ {-1} \cdot G \cdot {(z + r \cdot d_A)} =s−1⋅G⋅(z+r⋅dA​)
又有 s = k − 1 ( z + r ⋅ d A ) ( m o d n ) s = k^{-1}(z + r\cdot d_A) (mod n) s=k−1(z+r⋅dA​)(modn)
即 s − 1 = k ⋅ ( z + r ⋅ d A ) − 1 ( m o d n ) s^{-1} = k\cdot(z + r\cdot d_A)^{-1} (mod n) s−1=k⋅(z+r⋅dA​)−1(modn)
代入得到 P = k ⋅ G P=k \cdot G P=k⋅G

利用冲突的随机数恢复私钥

从上面的签名过程我们可以看到最关键的地方就在于随机数k,对于一个固定的椭圆曲线,一个确定的k就意味着一个确定的r,所以如果有两个相同的私钥签署的签名出现了相同的r就代表着在生成随机数时取到了相同的k,看到这里想必你也明白了我们题目的交易签名的问题出在哪了,这两笔交易的r值相同,代表在它们签名时使用的随机数k是相同的,而这就是我们恢复私钥的关键
我们不妨设这两个签名的 z z z与 s s s分别为 z 1 z_1 z1​, z 2 z_2 z2​与 s 1 s_1 s1​, s 2 s_2 s2​
则有
s 1 − s 2 = k − 1 ( z 1 + d A ⋅ r ) − k − 1 ( z 2 + d A ⋅ r ) s_1-s_2= k ^ {-1}(z_1 + d_A \cdot r)-k ^ {-1}(z_2+ d_A \cdot r) s1​−s2​=k−1(z1​+dA​⋅r)−k−1(z2​+dA​⋅r)
= k − 1 ( z 1 − z 2 ) = k ^ {-1}(z_1 - z_2) =k−1(z1​−z2​)
那么 k = ( z 1 − z 2 ) ( s 1 − s 2 ) k = \frac {(z_1-z_2)}{(s_1-s_2)} k=(s1​−s2​)(z1​−z2​)​
通过 k k k,可以计算出 d A = ( s ⋅ k − z ) / r d_A=(s \cdot k -z) /r dA​=(s⋅k−z)/r

P2PKH


PubkeyScript是一张记录了交易记录的指令列表,它控制了下一名使用者如何解锁已接收的比特币并传送。收款人会制造一个signature script,而该文件必须满足最后一个发送者创建的PubkeyScript的参数。
PubkeyScript的参数:

  1. 公钥哈希(Public Key Hash) (比特币地址)
  2. 电子签署(ScriptSig: (r,s)+pubkey)

ASM是汇编代码

  1. OP_PUSHBYTES_71指压入栈中一个71字节大小的数据
  2. nSequence用以记录该笔交易是否可以上链
  3. Previous output Script用以验证当前用于支付的比特币的来源
  4. ScriptPubKey是一个脚本,用以验证当前用户有能力使用这个UTXO中的比特币来支付,即证明身份
    OP_DUP复制栈顶数据
    OP_HASH160先后进行两种hash操作然后压入栈
    OP_PUSHBYTES_20将签名的hash值压入栈
    OP_EQUALVERIFY比较计算签名hash和刚压入栈的hash来验证有效性,有效返回1否则返回0
    OP_CHECKSIG检测栈顶的2个元素,pub key和signature是否能对应的上。对应的上,说明这个签名的私钥,和收款人的公钥可以对上。有资格花这笔钱
    OP_RETURN 用来当注释,携带一些信息
    Transaction hex则包含所有信息连接在一起

求解过程

提取r,s,z

脚本来源

# -*-coding:utf-8-*-
"""
@author: iceland
"""
import sys
import hashlib
import argparse
from urllib.request import urlopen# # ==============================================================================
# parser = argparse.ArgumentParser(
#     description='This tool helps to get ECDSA Signature r,s,z values from Bitcoin rawtx or txid',
#     epilog='Enjoy the program! :)    Tips BTC: bc1q39meky2mn5qjq704zz0nnkl0v7kj4uz6r529at')
#
# parser.add_argument("-txid", help="txid of the transaction. Automatically fetch rawtx from given txid", action="store")
# parser.add_argument("-rawtx", help="Raw Transaction on the blockchain.", action="store")
#
# if len(sys.argv) == 1:
#     parser.print_help()
#     sys.exit(1)
# args = parser.parse_args()
# # ==============================================================================
#
# txid = args.txid if args.txid else ''
# rawtx = args.rawtx if args.rawtx else ''
#
# if rawtx == '' and txid == '':
#     print('One of the required option missing -rawtx or -txid');
#     sys.exit(1)# ==============================================================================def get_rs(sig):rlen = int(sig[2:4], 16)r = sig[4:4 + rlen * 2]#    slen = int(sig[6+rlen*2:8+rlen*2], 16)s = sig[8 + rlen * 2:]return r, sdef split_sig_pieces(script):sigLen = int(script[2:4], 16)sig = script[2 + 2:2 + sigLen * 2]r, s = get_rs(sig[4:])pubLen = int(script[4 + sigLen * 2:4 + sigLen * 2 + 2], 16)pub = script[4 + sigLen * 2 + 2:]assert (len(pub) == pubLen * 2)return r, s, pub# Returns list of this list [first, sig, pub, rest] for each input
def parseTx(txn):if len(txn) < 130:print('[WARNING] rawtx most likely incorrect. Please check..')sys.exit(1)inp_list = []ver = txn[:8]if txn[8:12] == '0001':print('UnSupported Tx Input. Presence of Witness Data')sys.exit(1)inp_nu = int(txn[8:10], 16)first = txn[0:10]cur = 10for m in range(inp_nu):prv_out = txn[cur:cur + 64]var0 = txn[cur + 64:cur + 64 + 8]cur = cur + 64 + 8scriptLen = int(txn[cur:cur + 2], 16)script = txn[cur:2 + cur + 2 * scriptLen]  # 8b includedr, s, pub = split_sig_pieces(script)seq = txn[2 + cur + 2 * scriptLen:10 + cur + 2 * scriptLen]inp_list.append([prv_out, var0, r, s, pub, seq])cur = 10 + cur + 2 * scriptLenrest = txn[cur:]return [first, inp_list, rest]# ==============================================================================
def get_rawtx_from_blockchain(txid):try:htmlfile = urlopen("https://blockchain.info/rawtx/%s?format=hex" % txid, timeout=20)except:print('Unable to connect internet to fetch RawTx. Exiting..')sys.exit(1)else:res = htmlfile.read().decode('utf-8')return res# =============================================================================def getSignableTxn(parsed):res = []first, inp_list, rest = parsedtot = len(inp_list)for one in range(tot):e = firstfor i in range(tot):e += inp_list[i][0]  # prev_txide += inp_list[i][1]  # var0if one == i:e += '1976a914' + HASH160(inp_list[one][4]) + '88ac'else:e += '00'e += inp_list[i][5]  # seqe += rest + "01000000"z = hashlib.sha256(hashlib.sha256(bytes.fromhex(e)).digest()).hexdigest()res.append([inp_list[one][2], inp_list[one][3], z, inp_list[one][4], e])return res# ==============================================================================
def HASH160(pubk_hex):return hashlib.new('ripemd160', hashlib.sha256(bytes.fromhex(pubk_hex)).digest()).hexdigest()# ==============================================================================txn = '010000000153db4e56f159c0679818ef8ce814ce8fcaad12b854da7e582fb5f19266945f63000000006a47304402200e1e942f62d61cc25117d71bc2da4b523bd720dc7feec77551a0b152eb042cd7022030d7d78612b765dff96dd14fc5d723e06a8fa61b42a93410236273baf82f7f15012102572263bbac032e37cf96fe7664fb799f56353108c032807cc23ca557fb60b394ffffffff02d0070000000000001976a914b1c75a61c0461cd92c124e00ee275a600aa096b288ac0000000000000000056a0343544600000000'
# if rawtx == '':
#     rawtx = get_rawtx_from_blockchain(txid)print('\nStarting Program...')m = parseTx(txn)
e = getSignableTxn(m)for i in range(len(e)):print('=' * 70,f'\n[Input Index #: {i}]\n     R: {e[i][0]}\n     S: {e[i][1]}\n     Z: {e[i][2]}\nPubKey: {e[i][3]}')

求dA

#-*-coding:utf-8-*-
r1 = 0x0e1e942f62d61cc25117d71bc2da4b523bd720dc7feec77551a0b152eb042cd7
s1 = 0x5611099541793c7681a9f8b48364d6e7088e16afe7b7b6244c52e94d28252a3b
z1 = 0x5ecd4154a2db20480d7715d6e47a772aaf596e11e6f16a4d58e9f0d260294660r2 = 0x0e1e942f62d61cc25117d71bc2da4b523bd720dc7feec77551a0b152eb042cd7
s2 = 0x30d7d78612b765dff96dd14fc5d723e06a8fa61b42a93410236273baf82f7f15
z2 = 0x50f1c6205aab5f8dac7b505f91dfc437b1b13cd00f12a492570a040a27c38e25assert r1 == r2
r = r1
def inverse_mod( a, m ):"""Inverse of a mod m."""if a < 0 or m <= a: a = a % mc, d = a, muc, vc, ud, vd = 1, 0, 0, 1while c != 0:q, c, d = divmod( d, c ) + ( c, )uc, vc, ud, vd = ud - q*uc, vd - q*vc, uc, vcassert d == 1if ud > 0: return udelse: return ud + mdef derivate_privkey(p, r, s1, s2, z1, z2):z = z1 - z2s = s1 - s2r_inv = inverse_mod(r, p)s_inv = inverse_mod(s, p)k = (z * s_inv) % pd = (r_inv * (s1 * k - z1)) % preturn d, kp  = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141privatekey,k=derivate_privkey(p,r,s1,s2,z1,z2)

利用私钥解密AES

import base64
cipher = base64.b64decode(b"4w/VLHqPZi/epoOGvjoY9TZWhDtYpL3iLsUTyvzghJM=")
privatekey = 0xF41AA419CB6BD43F322D403F40728CE9784CD0B465F409322A76A3DF0A984A29
from Crypto.Cipher import AES
from Crypto.Util.number import *
key = long_to_bytes(privatekey)[0:16]
iv = long_to_bytes(privatekey)[16:]
aes = AES.new(key=key,iv=iv,mode=AES.MODE_CBC)
flag = aes.decrypt(cipher.encode())
print(flag)

参考链接

BlockChain-Account_TakeOver相关推荐

  1. 世界上最大的超级计算机,科学网—区块链(blockchain)如何能造出世界上最大的超级计算机? - 刘进平的博文...

    区块链(blockchain)如何能造出世界上最大的超级计算机? Technology As our desktop computers, laptops, mobile devices, etc.  ...

  2. Blockchain实现详细手册

    Bill Caraher预见到有一天blockchain技术"将会证实,并且会无疑问地证明"法律行业所使用的文档和合同的来源.对于Caraher来说,他是von Briesen & ...

  3. 区块链论文: Bitcoin-NG: A Scalable Blockchain Protocol

    本文首发于 https://zhuanlan.zhihu.com/blockchain-top-paper 发现已有几篇中文博客描述这篇论文,但是本文跟它们的不同点在于,希望站在高层视角,结合图片来理 ...

  4. IBM推出实时跨境支付解决方案Blockchain World Wire

    \ 计算巨头 IBM 公司现已推出基于区块链技术的金融解决方案,据称其有望彻底颠覆现有全球支付与汇款体系的运作方式. \这套全新解决方案名为"IBM Blockchain World Wir ...

  5. blockchain 区块链200行代码:在JavaScript实现的一个简单的例子

    blockchain 区块链200行代码:在JavaScript实现的一个简单的例子 了解blockchain的概念很简单(区块链,交易链块):它是分布式的(即不是放置在同一台机器上,不同的网络设备上 ...

  6. 微软宣布推出Azure Blockchain Tokens加密代币平台

    美国东部时间11月4日~8日,一年一度的微软IT大会Ignite在美国奥兰多举行.作为微软最重要的技术会议之一,每年微软都会在Iginite大会上宣布一系列的产品及服务的升级,也会发布一些新的技术解决 ...

  7. BaaS(区块链即服务Blockchain as a Service)

    BaaS(区块链即服务Blockchain as a Service)  BaaS(区块链即服务Blockchain as a Service) 1. 什么是区块链服务? 区块链服务是指利用区块链 ...

  8. BlockChain:区块链技术基础概念综合理解——个人总结

    BlockChain:区块链技术基础概念综合理解--个人总结 目录 区块链的进阶与意义 1.区块链技术的进阶 2.区块链技术三大意义-传递价值.建立可信用环境.提高效率和降低成本 1.传递价值 2.建 ...

  9. BlockChain:BlockChain周边概念详解+个人理解

    BlockChain:BlockChain周边概念详解+个人理解 目录 1.拜占庭将军问题 2.共识机制 1.区块链的共识机制目前有以下几种 PoW PoS DPoS 其他共识机制 1.拜占庭将军问题 ...

  10. BlockChain:《Blockchain Gate》听课笔记——区块链的1.0架构 VS 区块链3.0架构+个人理解

    BlockChain:<Blockchain Gate>听课笔记--区块链的1.0架构 VS  区块链3.0架构+个人理解 相关文章 BlockChain:<Blockchain G ...

最新文章

  1. 人工智能:第二章 知识表示方法
  2. pythonmax对字符_(MAX第五篇)Python--字符串操作(三)
  3. 团队阅读——怎样学习软件工程
  4. 图片马可以直接连接吗_商标买来可以直接使用吗?
  5. avenir字体可以商用吗_顶级公司的顶级logo设计原来用的这些字体!附字体下载...
  6. 单片机设计时钟程序c语言,单片机电子时钟程序设计
  7. Java快速入门学习笔记9 | Java语言中的方法
  8. python中dtype什么意思_浅谈python 中的 type(), dtype(), astype()的区别
  9. Delphi 2010 新增功能之: Rtti 单元(5): 获取方法的更多信息
  10. Android 面试(四):Android Service 你真的能应答自如了吗?
  11. 一个.NET通用JSON解析/构建类的实现(c#)
  12. 高清人脸数据集汇总 (主要用于人脸生成、分割任务)
  13. 进销存excel_超实用Excel完整进销存管理系统,多功能实现,轻松套用赶GET
  14. 神秘邻居把我的信息卖给了诈骗团伙
  15. banner设圆角_Banner设计技巧!
  16. 无纸化会议系统连接服务器失败,无纸化会议系统使用注意事项及注册/更新流程...
  17. 鸿蒙系统8月9日登场,华为自研鸿蒙系统将于8月9日正式登场,还有全新的鸿鹄芯片...
  18. 怎样让小孩变成机灵顾客
  19. 尼尔·唐纳德·沃尔什《与神对话》
  20. tensorflow踩坑

热门文章

  1. 《向死而生-我修的死亡学分》-李开复先生
  2. 第四章 常见 Android 文件格式(二)(classes.dex)
  3. 实战落地!电力巡检目标检测和推理部署
  4. PS2经典射击(FPS)游戏推荐
  5. Arcgis出图时提示未能加载文件或程序集stdole, Version=7.0.3300.0错误
  6. 南京理工计算机学院考研真题,南京理工大学计算机考研历年真题
  7. 广电运通:现有银行自助设备需要针对数字货币兑换进行升级
  8. STM32CUBEMX_STM32F030F4P6_TIM1_CH3_PWM
  9. Android Studio、Git 解决合并冲突
  10. Win10创建原始套接字失败原因及解决方法