是否可能两个ETH私钥对应同一个地址
原提问在这里。
笔者在使用到neon-js
中的私钥生成方法时发现其使用了getRandomValues方法来生成64字符长度的私钥,进而考虑到其随机性,若是调用足够多次,依然有可能生成两个完全一样的私钥,这也就是在暴力破解区块链中的账户了。然后就找到了最前面的这个提问,对其整理翻译得到此文。
概述
在以太坊中,一个私钥长度为256位(64字符,32字节),而从私钥得到的地址长度位160位(40字符,20字节)。依据"Pigeonhole Principle"(一句话概括就是10个大师球抓11只皮卡丘的话至少有一个大师球得装两只皮卡丘),当私钥总数足够多时必然会有相同私钥出现。所以理论上来说,共有2256个私钥对应2160个ETH地址,那么就至少有296个私钥对应的地址会重复,也就是这么多只皮卡丘得和另外2160只共享大师球了。(相对的公钥长度则为512位,与私钥的对应就溢出了许多,不过在NEO中公钥长度与私钥一致,所以最极端情况下可以刚好一一对应)
问题
如果两个私钥指向的是同一个地址,那他俩是否都有对此地址的所有权,是否都能操作这一地址的转账(签名)?更夸张的设想,如果连私钥都重复生成了,那岂不是一笔可能存在的巨款可以被共享了?
被采纳回答
并不是完全有 2^256个私钥能被生成(看来私钥碰撞的难度降低了)。而是FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141
个。这一数值在ETH源码中被定义为N
,是ETH密钥对生成使用的secp256k1椭圆曲线的依照。
回到你的问题,确实,对应同一地址的私钥都能够花费这个地址中的余额,并依照先到先服务进行。他们将会生成同一个公钥,这是椭圆曲线数字签名算法想要避免的,并且,两者生成的签名也同时对这个地址有效。在go-ethereum/accounts/key.go中我们从S256(secp256k1的曲线)生成一个私钥,这意味着私钥的值默认会小于N
。
func newKeyFromECDSA(privateKeyECDSA *ecdsa.PrivateKey) *Key {
id := uuid.NewRandom()
key := &Key{
Id: id,
Address: crypto.PubkeyToAddress(privateKeyECDSA.PublicKey),
PrivateKey: privateKeyECDSA,
}
return key
}
func newKey(rand io.Reader) (*Key, error) {
privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), rand)
if err != nil {
return nil, err
}
return newKeyFromECDSA(privateKeyECDSA), nil
}
go-ethereum/crypto/secp256k1/secp256中也使用了稍微不同的方法生成密钥对。
对于这个N究竟意味着什么的很酷的解释
想象私钥是你的车子的车速,而公钥是你的车子的仪表盘,而仪表盘最多显示000,000
到999,999
,那如果实际车速为1,000,001
时仪表盘显示速度就会是1,也就是两个速度与一个显示(两个私钥与一个地址)。
椭圆曲线的组算法与这颇为相似,只不过不是999,999
而是看起来很随意的这个N
。由于这个原因,就算你有了不同的私钥,你也有可能创建同一公钥的合法的签名并因此花费同一ETH地址的余额。
较枯燥的数学解释
私钥是个256位数值,为了从一个私钥计算出公钥,将它与一个椭圆曲线组(g
)相乘,在ETH中这个值是定义在secp256k1库中的一个变量,它本身也是一个椭圆曲线点,由于椭圆曲线本身是循环的,所以存在一个n
使得n.g = 1
,这被称作generator order
。
根据这一方程我们可以知道,如果我们有一个私钥k
,k大于n,我们将有k.g = (k-1).g = k'.g
,这个k'
就是另一个私钥了,所以我们的私钥必须小于n
,而不是2^256
。
另外两个你可能有兴趣的问题:
个人总结
生成重复私钥和生成对应同一地址的私钥是两个问题,后者可以通过限制私钥生成范围来避免,但前者反而会因为了避免后者而增加发生几率(从1/2^256
增加到1/某个限制值
)。
从这个提问来看,至少go-ethereum
中通过限制私钥生成的范围来保证不会有两个私钥对应同一公钥,也就是不超出椭圆曲线的周期范围(仍不能避免理论上生成两个相同私钥的可能)。
不过,仍然可能存在某次生成新私钥时这个私钥是全网中曾经生成过的,这虽然难度很高,但耐不住区块链完全公开,完全可能有比较无聊又恶趣味的人不停碰撞私钥。虽然说这个私钥机制被推翻的那天密码学跟区块链必然都会有较大冲击,但至少目前这事情也只是理论上可行。
深入目前最新的go-ethereum
源码,在中可以看到私钥是这么创建的:
privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), reader)
也就是调用了crypto/ecdsa
库的GenerateKey
方法,给的范围是crypto.S256()
,这个值在curve.go中可以找到:
var theCurve = new(BitCurve)
func init() {
// See SEC 2 section 2.7.1
// curve parameters taken from:
// http://www.secg.org/collateral/sec2_final.pdf
theCurve.P = math.MustParseBig256("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F")
theCurve.N = math.MustParseBig256("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141")
theCurve.B = math.MustParseBig256("0x0000000000000000000000000000000000000000000000000000000000000007")
theCurve.Gx = math.MustParseBig256("0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798")
theCurve.Gy = math.MustParseBig256("0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")
theCurve.BitSize = 256
}
// S256 returns a BitCurve which implements secp256k1.
func S256() *BitCurve {
return theCurve
}
并在crypto.go中定义了如下变量用于限制范围,超过此范围的就视为非法私钥:
var (
secp256k1_N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
secp256k1_halfN = new(big.Int).Div(secp256k1_N, big.NewInt(2))
)
不过回到笔者一开始的目的,使用neon-js
中的私钥生成方法来创建一个NEO私钥,这货直接使用的是js中的encrypt.getRandomValues
,其随机性以及对双重私钥(对应同一地址)的防御能力又有多少呢?答案看来得去追踪NEO-CLI
自己的私钥生成算法了。如果没找错的话是下面这段:
public WalletAccount CreateAccount()
{
byte[] privateKey = new byte[32];
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
{
rng.GetBytes(privateKey);
}
WalletAccount account = CreateAccount(privateKey);
Array.Clear(privateKey, 0, privateKey.Length);
return account;
}
仅通过C#自带的库生成,没找到范围限制,也就是跟neon-js
的做法一样,把随机程度压力交给大佬了,这样来看不知是好消息还是坏消息,可以放心使用neon-js
来创建私钥了,反正没比neo
核心的创建方法差到哪里去。
再提出个大胆的想法,如果集齐一万甚至更多的志愿者,每天也不挖矿,每人整个超级计算机就碰撞某个范围的ETH私钥(可以看作是难度巨大的挖矿),协商如果谁遇到了巨额存款地址就平摊,哲学角度这就是在挑战区块链核心的信仰了。
是否可能两个ETH私钥对应同一个地址的更多相关文章
- C#比较两个对象是否为同一个对象。
两个对象是否为同一个对象:是看两个对象是否指向堆中的同一块内存. 1.使用object.ReferenceEquals() class Program { static void Main(strin ...
- 判断两个控件在同一个Window上是否有重叠
判断两个控件在同一个Window上是否有重叠 //对UIView写分类 - (BOOL)intersectWithView:(UIView *)view; - (BOOL)intersectWithV ...
- 通过调用C语言的库函数与在C代码中使用内联汇编两种方式来使用同一个系统调用来分析系统调用的工作机制
通过调用C语言的库函数与在C代码中使用内联汇编两种方式来使用同一个系统调用来分析系统调用的工作机制 前言说明 本篇为网易云课堂Linux内核分析课程的第四周作业,我将通过调用C语言的库函数与在C代码中 ...
- C#比较两个对象是否为同一个对象。 Visual Studio调试器指南---多线程应用程序调试(一)
两个对象是否为同一个对象:是看两个对象是否指向堆中的同一块内存. 1.使用object.ReferenceEquals() class Program { static void Main(strin ...
- Latex 初学者入门(四)-- 多个作者共享同一个地址
又给老板改格式,其实感觉大多会议都是模板不同,不同主要在于注释,作者,摘要以及引用文献的不同,上次的那篇讲bib数据库的用法,真是倒腾了一整天,不知道为什么一定要使用这种东西,而且老板貌似对人家的风格 ...
- 比特币--私钥->公钥->钱包地址
脑钱包-字符串SHA256散列成256bit当做私钥-彩虹表 脑钱包是开源的程序-->用户输入字符串当做密码-->经过SHA256散列算法-->256长bit位 (即是私钥)--&g ...
- visual studio 两个以上sln 引用同一个project ,生成时会改变projectguid问题
当两个以上解决方案添加现有项,选择了同一个项目,那么在 sln 文件中,会自己带一个guid. 当打开两个解决方案,一个生成时,会影响另一个的project值,导致每次都看到了签出. 解决办法,打开共 ...
- 一个IP,一个linux服务器,两个项目,两个域名;如何将两个域名配置到同一个IP的两个项目中。
一.现有资源: 1.阿里云centOS6.5服务器: 2.安装tomcat8.0+JDK: 3.两个不同maven项目的war包,项目名分别为cloud.am: 4.两个域名http://www.lu ...
- form-line 样式 让 两个控件在同一个水平位置
<div class="row"> <div> <label class="form-inline">参加单位:<in ...
随机推荐
- Python第二话 初识复杂数据类型(list、dictionary、tuple)
上一篇我们简单认识了数据类型:数字number和字符串string,这篇我们就来隆重介绍一下重量级的数据类型:列表list.字典dictionary和元组tuple. 一.列表List: ①列表是什么 ...
- JavaScript简史
JavaScript诞生于1995年. 当时的web正在日益兴起,人们对客户端语言的需求也越来越强烈.当时走在技术革新最前沿的Netscape公司决定开发一种客户端语言,用来处理简单的输入验证. 当时 ...
- Leetcode 3——Palindrome Number(回文数)
Problem: Determine whether an integer is a palindrome. Do this without extra space. 简单的回文数,大一肯定有要求写过 ...
- 配置 CSV Data Set Config 来参数化新增客户信息操作
1.首先根据新增客户信息的http请求,来确定需要参数化的变量,选取符合测试需求且经常变化或未来会变化的变量为需要参数化的变量,如本文中的客户端名称(sys_name).描述(description) ...
- alpha冲刺第六天
一.合照 二.项目燃尽图 三.项目进展 主界面首页内容呈现 我的栏目之我的问题完成 我的栏目之我的提问完成 还是插不进去,然后打算先放一放,一直在一个地方纠结那么久脑子太乱 四.明日规划 问答界面问题 ...
- 201621123043《java程序设计》第五周学习总结
1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 接口. Comparable接口 .Comparator接口.compareTo. 1.2 尝试使用思维导图将这些关键词组织起来 ...
- C语言:第0次作业
问题1: 你为什么选择计算机专业?你认为你的条件如何?和这些博主比呢? 感性地讲,高中时意外看到了电影<社交网络>,自那时起就将将马克扎克伯格视为偶像,他天才的智慧和长远的眼光深深吸引了我 ...
- Django SNS 微博项目开发
1.功能需求 一个人可以follow很多人 一个用户如果发了新weibo会自动推送所有关注他的人 可以搜索.关注其它用户 可以分类关注 用户可以发weibo, 转发.收藏.@其它人 发微博时可选择公开 ...
- JFinal项目发送邮件——jfinal-mail-plugin
JFianl框架: JFinal 是基于 Java 语言的极速 WEB + ORM 框架,其核心设计目标是开发迅速.代码量少.学习简单.功能强大.轻量级.易扩展.Restful.在拥有Java语言所有 ...
- PostgreSQL 客户端乱码问题
关于客户端和服务器端的乱码问题, POSTGRESQL字符集问题总结 总结的很详细, 特别棒. 这里让我头痛了很久的问题在于 终端 上字符编码的问题, 由于我的mbp上的 iterm2 的默认编码为 ...