通过ECDSA签名获取以太坊上其他账户私钥的思路

前段时间看了一篇文章`利用随机数冲突的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()
}

如果有大佬的话可以帮我优化下代码,感激不尽

你可能感兴趣的:(区块链,eth)