原提问在这里

笔者在使用到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,000999,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私钥对应同一个地址的更多相关文章

  1. C#比较两个对象是否为同一个对象。

    两个对象是否为同一个对象:是看两个对象是否指向堆中的同一块内存. 1.使用object.ReferenceEquals() class Program { static void Main(strin ...

  2. 判断两个控件在同一个Window上是否有重叠

    判断两个控件在同一个Window上是否有重叠 //对UIView写分类 - (BOOL)intersectWithView:(UIView *)view; - (BOOL)intersectWithV ...

  3. 通过调用C语言的库函数与在C代码中使用内联汇编两种方式来使用同一个系统调用来分析系统调用的工作机制

    通过调用C语言的库函数与在C代码中使用内联汇编两种方式来使用同一个系统调用来分析系统调用的工作机制 前言说明 本篇为网易云课堂Linux内核分析课程的第四周作业,我将通过调用C语言的库函数与在C代码中 ...

  4. Latex 初学者入门(四)-- 多个作者共享同一个地址

    又给老板改格式,其实感觉大多会议都是模板不同,不同主要在于注释,作者,摘要以及引用文献的不同,上次的那篇讲bib数据库的用法,真是倒腾了一整天,不知道为什么一定要使用这种东西,而且老板貌似对人家的风格 ...

  5. 比特币--私钥->公钥->钱包地址

    脑钱包-字符串SHA256散列成256bit当做私钥-彩虹表 脑钱包是开源的程序-->用户输入字符串当做密码-->经过SHA256散列算法-->256长bit位 (即是私钥)--&g ...

  6. visual studio 两个以上sln 引用同一个project ,生成时会改变projectguid问题

    当两个以上解决方案添加现有项,选择了同一个项目,那么在 sln 文件中,会自己带一个guid. 当打开两个解决方案,一个生成时,会影响另一个的project值,导致每次都看到了签出. 解决办法,打开共 ...

  7. 一个IP,一个linux服务器,两个项目,两个域名;如何将两个域名配置到同一个IP的两个项目中。

    一.现有资源: 1.阿里云centOS6.5服务器: 2.安装tomcat8.0+JDK: 3.两个不同maven项目的war包,项目名分别为cloud.am: 4.两个域名http://www.lu ...

  8. form-line 样式 让 两个控件在同一个水平位置

    <div class="row"> <div> <label class="form-inline">参加单位:<in ...

  9. 【tips】判断两个整数是否是同一个数量级

    leetcode刷题的时候,需要用到,已知整数A,B,且A>B,判断AB是否是同一数量级的. 第一想到的是不停地除以10,得到每个数字的数量级再进行比较,太麻烦: 转而向转化成字符串比较,还是麻 ...

随机推荐

  1. Activity初接触

    Activity中TextView的文字显示Hello Android: 1.直接显示:<TextView android:text="Hello Android" /> ...

  2. bzoj1039: [ZJOI2008]无序运动Movement

    Description D博士对物理有着深入的研究,经典物理.天体物理.量子物理都有着以他的名字命名的定理.最近D博士着迷于研究粒子运动的无规则性.对圣经深信不疑的他相信,上帝创造的任何事物必然是有序 ...

  3. 改变Web Browser控件IE版本

    默认的webbrowser控件使用的渲染模式版本似乎是IE7,想要更改更高版本,如下: 在注册表位置 HKEY_CURRENT_USER\Software\Microsoft\Internet Exp ...

  4. HDU 5113 Black And White 回溯+剪枝

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5113 Black And White Time Limit: 2000/2000 MS (Java/ ...

  5. Windows版 mysql 5.7.16安装

    MySQL 5.7版本安装教程-踩坑总结 下载 MySQL下载地址选择下载64位(看自己电脑是32位还是64位) 点击下载之后,它会让你登录,没有Oracle账户,跟着它的步骤注册一个就好了. 安装 ...

  6. 《高性能JavaScript》的新征程

    已经学了<JavaScript语言精粹>,现在学高性能. JS的出现是为了改善网页用户体验的,随着互联网通信速度的改善.计算机性能的提升,web越发丰富:但一段时间内,JS的引擎变化不大. ...

  7. 一篇关于PHP性能的文章

    一篇关于PHP性能的文章 昨晚清理浏览器收藏夹网址时,发现了http://www.phpbench.com/,想起来应该是2015年发现的一个比较性能的文章,我就点进去看了看,发现还是全英文耶,刚好最 ...

  8. [Kali_Metasploit]db_connect创建连接时无法连接的解决方案

    问题1复现路径: postgresql selected, no connection 第一步: db_connect postgres:toor@127.0.0.1/msfbook 连接成功不需要进 ...

  9. [Solution] JZOJ-5818 做运动

    [Solution] JZOJ-5818 做运动 Time Limits:2000ms Memory Limits:524288KB Description 一天,Y 君在测量体重的时候惊讶的发现,由 ...

  10. linux 更新yum源 改成阿里云源

    1.备份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2.下载新的CentOS-Base ...