主页 > 下载官方imtoken钱包 > 通过ECDSA签名获取以太坊其他账户私钥的思路
通过ECDSA签名获取以太坊其他账户私钥的思路
下载官方imtoken钱包 2023-03-08 06:44:53
前段时间看过一篇文章《利用随机数冲突的ECDSA签名还原以太坊私钥》
据说当同一交易发送方和接收方的两次交易的随机数K相同时被公布的以太坊私钥,可以推断出交易发送方的私钥。
我想能不能通过遍历整个以太坊上所有交易的签名信息中的R值,找到满足上述条件的两笔或多笔交易。
思路是:从第0块到最新块读取每个块中交易中的R值,然后存入数据库。 然后通过查看数据库的工具被公布的以太坊私钥,很容易找到相同数据的两个r。 数据库中记录了r的值和R当前所在区块的值。 然后恢复私钥。 我相信还是有可能在整个链条中找到满足上述条件的800W块的。
代码附在下面:
package main
import (
"fmt"
"github.com/ethereum/go-ethereum/rpc"
"strconv"
"os"
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
//区块高度
var Height string
//当前区块交易数量
var BlockTransactionCountByNumber string
//10进制显示区块高度因为获取到的区块高度为16进制,方便打印查看
var DecHeight uint64
//每个区块的结构
type BlockTransactionObject struct{
Number string `json:"number"` //块编号,挂起块为null
Hash string `json:"hash"` //块哈希,挂起块为null
ParentHash string `json:"parentHash"` //父块的哈希
Nonce string `json:"nonce"` //生成的pow哈希,挂起块为null
Sha3Uncles string `json:"sha3Uncles"` //块中叔伯数据的SHA3哈希
LogsBloom string `json:"logsBloom"` //快日志的bloom过滤器,挂起块为null
TransactionsRoot string `json:"transactionsRoot"` //块中的交易树根节点
StateRoot string `json:"stateRoot"` //块最终状态树的根节点
ReceiptsRoot string `json:"receiptsRoot"` //块交易收据树的根节点
Miner string `json:"miner"` //挖矿奖励的接收账户
Difficulty string `json:"difficulty"` //块难度,整数
TotalDifficulty string `json:"totalDifficulty"` //截止到本块的链上总难度
ExtraData string `json:"extraData"` //块额外数据
Size string `json:"size"` //本块字节数
GasLimit string `json:"gasLimit"` //本块允许的最大gas用量
GasUsed string `json:"gasUsed"` //本块中所有交易使用的总gas用量
Timestamp string `json:"timestamp"` //块时间戳
Transactions []Transaction `json:"transactions"` //交易对象数组,或32字节长的交易哈希数组
Uncles []string `json:"uincles"` //叔伯哈希数组
}
//每笔交易的结构
type Transaction struct {
Hash string `json:"hash"`
Nonce string `json:"nonce"`
BlockHash string `json:"blockHash"`
BlockNumber string `json:"blockNumber"`
TransactionIndex string `json:"transactionIndex"`
From string `json:"from"`
To string `json:"to"`
Value string `json:"value"`
Gas string `json:"gas"`
GasPrice string `json:"gasPrice"`
Input string `json:"input"`
V string `json:"v"`
R string `json:"r"`
S string `json:"s"`
}
//实例化区块对象
var BlockTransactionObjects BlockTransactionObject
//声明一个数据库句柄,接受后面的操作赋值
var conn *sql.DB
func main() {
//连接数据库
conn,err :=sql.Open("mysql","root:zxc@tcp(127.0.0.1:3306)/ethsig?charset=utf8")
if err !=nil{
fmt.Println("链接数据库错误:",err)
}
//进入数据库ethsig
_,err = conn.Exec("USE ethsig")
if err != nil {
panic(err)
}
//连接以太坊主网接口,没有的可以自己去申请 https://infura.io
client,err:=rpc.Dial("https://mainnet.infura.io/v3/xxxxxxxxxxx")
if err!=nil{
fmt.Println("错误:",err)
}
defer client.Close()
DecHeight=GetHeight(client)
fmt.Println("当前区块高度:",DecHeight,"十六进制:",Height)
for i:=3750;i<=int(DecHeight);i++{
j:=fmt.Sprintf("0x%x",i)
getBlockTransactionCountByNumber(client,j)
}
}
//获取以太坊最新区块高度,转成10进制返回
func GetHeight(client *rpc.Client)(uint64) {
err:=client.Call(&Height,"eth_blockNumber","latest")
if err!=nil{
fmt.Println("错误:",err)
}
n, _ := strconv.ParseUint(Height[2:],16,32)
return n
}
//获取当前区块交易数
func getBlockTransactionCountByNumber(client *rpc.Client,j string)() {
err:=client.Call(&BlockTransactionCountByNumber,"eth_getBlockTransactionCountByNumber",j)
if err!=nil{
fmt.Println("错误:",err)
}
heights, _ := strconv.ParseUint(j[2:],16,32)
BlockTransactionCountByNumbers, _ := strconv.ParseUint(BlockTransactionCountByNumber[2:],16,32)
fmt.Println("当前块:",heights,"当前块交易数量:",BlockTransactionCountByNumbers)
GetBlockByNumber(client,j)
}
//依次遍历区块里交易信息并且写入数据库
func GetBlockByNumber(client *rpc.Client,heights string){
err:=client.Call(&BlockTransactionObjects,"eth_getBlockByNumber",heights,true)
if err!=nil{
fmt.Println("错误:",err)
}
for key,_ :=range BlockTransactionObjects.Transactions{
fmt.Println("----------------------------------------")
fmt.Println("当前块第个",key,"交易",)
SetDatabases(conn,BlockTransactionObjects.Transactions[key].R,heights)
fmt.Println("----------------------------------------")
}
fmt.Println()
}
//写数据库操作,保存r值和当前r所在区块高度
func SetDatabases(conn *sql.DB,r string,index string){
//_,err = conn.Exec("CREATE TABLE example2 ( id integer, r text ,index text)")
stmt, err := conn.Prepare("INSERT INTO `sig` (`r`,`index`) values (?,?)")
if err!=nil{
fmt.Println("预处理失败:",err)
}
res, err := stmt.Exec(r,index)
id, err := res.LastInsertId()
fmt.Println(id)
if err != nil {
fmt.Println(err)
panic(err)
}
defer conn.Close()
}
如果有大佬能帮我优化一下代码,感激不尽