主页 > 下载官方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()
}

如果有大佬能帮我优化一下代码,感激不尽