目录
简介
比特币的所有权是通过数字密钥(私钥、公钥)、比特币地址和数字签名来确立的。
数字密钥不存储在网络中,而是由用户生成并存储在一个文件或简单数据库中,称为钱包。
存储在用户钱包中的数字密钥完全独立于比特币协议,可由用户的钱包软件生成并管理,而无需区块链或网络连接。
密钥实现了比特币的许多特性:去中心化信任和控制、所有权认证和基于密码学证明的安全模型。
每笔比特币交易都需要一个有效的签名才会被鵆在区块链。只有有效的数字密钥才能产生有效的数字签名,拥有了比特币的密钥副本就拥有了该账户的比特币控制权。密钥成对出现:公钥、私钥。
在比特币交易的支付环节,收件人的公钥是通过其数字指纹标识的,称为比特币地址,一般情况下,比特币地址由一个公钥生成并对应于这个公钥。然而,并非所有比特币地址都是公钥。
公钥加密和加密货币
公钥加密发明与20世纪70年代。自此,一些合适的数学函数被提出。譬如:素数幂和椭圆曲线乘法。这些数学函数是不可逆的。基于这些数学函数的密码学,使得生成数字密钥和不可伪造的数字签名成为可能。
比特币正是使用椭圆曲线乘法作为其公钥加密的基础算法。
在比特币系统中,我们用公钥加密创建一个密钥对,用于控制比特币的获取。密钥对包括一个私钥,和由其衍生出的唯一的公钥。公钥用于接收比特币,而私钥用户比特币支付时的交易签名。
支付比特币时,比特币的当前所有者需要在交易中提交其公钥和签名(每次的签名都不同,但均从同一个私钥生成)。比特币网络中的所有人都可以通过所提交的公钥和签名进行验证,并确认该消息是否有效,即确认支付者在该时刻对所交易的比特币拥有所有权。
私钥和公钥
私钥(k)是一个数字,通常是随机选出的。有了私钥,就可以使用椭圆曲线乘法这个单向加密函数产生一个公钥(K)。
有了公钥,我们就可以使用一个单向加密哈希函数生成比特币地址(A)。
●私钥(k):一个数字,随机选出。
●公钥(K):私钥使用椭圆曲线乘法算法生成。
●比特币地址(A):公钥通过单向加密哈希函数生成。
从一个随机数生成私钥
生成密钥的第一步也是最重要的一步,就是找到足够安全的熵源,即随机性来源。生成一个比特币私钥在本质上与“在1和2^256之间选一个数字”无异。比特币软件使用操作系统底层的随机数生成器来生成256位的熵(随机性)。通常,操作系统随机数生成器由人工的随机源进行初始化,也可能需要通过几秒钟内不停晃动鼠标等方式进行初始化。
更准确的说,私钥可以是1和n-1之间的任何数字,其中n是一个常数(n=1.158*10^77,略小于2^256),并由比特币所使用的椭圆曲线的阶所定义。要生成这样一个私钥,我们随机选择一个256位的数字,并检查它是否小于n-1。从编程角度看,一般是通过在一个密码学安全的随机源中取出一长串随机字节,对其使用SHA256哈希算法进行运算,这样就可以方便产生一个256位的数字。如果运算结果小于n-1,我们就有了一个合适的私钥。否则,就用另一个随机数再重复一次。
比特币私钥空间大小是2^256,用十进制表示大约是10^77。而可见宇宙被估计只含有10^80个原子。
公钥
通过椭圆曲线乘法可以从私钥计算得到公钥,这是不可逆转的过程: K = k * G。
k是私钥,G是被称为生成点的常数点,而K是所得公钥。
其反向运算,被称为“寻找离散对数”--已知公钥K来求出私钥k非常困难。
椭圆曲线密码学解释
椭圆曲线加密算法是一种基于离散对数问题的非对称(或公钥)加密法,可以用对椭圆曲线上的点进行加法或乘法运算来表达。
须知概念
自然数:自然数是大于或等于0的整数,也就是非负整数,正整数.(如:0、100)
整数:任意自然数(如1,2,3,4,5)以及它们的负数或0.(如3,0,-5)
有理数:有理数是整数和分数(如2/3)的统称.(能精确地表示为两个整数之比的数)
无理数:也称为无限不循环小数,不能写作两整数之比。若将它写成小数形式,小数点之后的数字有无限多个,并且不会循环。 常见的无理数有非完全平方数的平方根、π和e(其中后两者均为超越数)等。
实数:实数是是有理数和无理数的总称(不存在虚数部分的数).
虚数:在数学中,虚数就是形如a+b*i的数,其中a,b是实数,且b≠0,i² = - 1。虚数这个名词是17世纪著名数学家笛卡尔创立,因为当时的观念认为这是真实不存在的数字。后来发现虚数a+b*i的实部a可对应平面上的横轴,虚部b与对应平面上的纵轴,这样虚数a+b*i可与平面内的点(a,b)对应。
质数(素数):质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数。
质数又称素数。一个大于1的自然数,除了1和它自身外,不能整除其他自然数的数叫做质数;否则称为合数。
合数:除1,0以外不是质数的正整数就是合数。
互质:互质是公约数只有1的两个整数,叫做互质整数。公约数只有1的两个自然数,叫做互质自然数,后者是前者的特殊情形。
对数:在数学中,对数是对求幂的逆运算。
如果a的x次方等于N(a>0,且a不等于1),那么数x叫做以a为底N的对数(logarithm),记作x=logaN。其中,a叫做对数的底数,N叫做真数。
同余运算:如果 a 和 b 除以 p 的余数相同,则说 a 和 b 关于模 p 同余。
a≡b(mod p) ÍÎ a mod p = b mod p
参考:https://blog.csdn.net/qq_35546304/article/details/53025685,http://www.matrix67.com/blog/archives/236
原根:原根是一种数学符号,设m是正整数,a是整数,若a模m的阶等于φ(m),则称a为模m的一个原根。(其中φ(m)表示m的欧拉函数)
假设一个数g是P的原根,那么g^i mod P的结果两两不同,且有 1
g^(P-1) 和1是关于P的同余。
g^i mod p ≠ g^j mod p (p为素数),其中i≠j且i, j介于1至(p-1)之间,则g为p的原根。
同阶:等价商为一,同阶商为一个常数。
阶:
设 (a,m)=1, 满足 ax≡1(mod m) 的最小的 x,称为a对m的阶,记为ordm(a)。
当 ordm(a)=ϕ(m) 时称为a为m的原根。
离散对数:在整数中,离散对数(英语:Discrete logarithm)是一种基于同余运算和原根的一种对数运算。而在实数中对数的定义 logba是指对于给定的a和b,有一个数x,使得bx=a。相同地在任何群G中可为所有整数k定义一个幂数为bx,而离散对数logba是指使得bx=a的整数k。
离散对数和原根:参考:https://blog.csdn.net/dylan_frank/article/details/70249110
算法解释
上图是一个椭圆曲线示例,类似于比特币所用的曲线。
比特币使用了secp256k1标准所定义的一条特殊的椭圆曲线和一些列数字常数。该标准由国美国家标准与技术研究院(NIST)设立。secp256k1曲线由下述函数定义,该函数可产生一条椭圆曲线:
因为这条曲线被定义在一个素数介的有限域内,而不是定义在实数范围,它的函数图形看起来像分散在两个维度上的散点图,因此很难画图表示。不过其中的数学原理与实数范围的椭圆曲线相似。作为一个例子,下图显示了在一个小了很多的素数阶17的有限域内的椭圆曲线,其形式为网络上的一系列散点。而specp256k1的比特币椭圆曲线可以被想象成一个极大的网格上一系列更为复杂的散点。
图为:椭圆曲线密码学F(p)上的椭圆曲线,其中p=17。
在椭圆曲线的数学原理中,有一个点被称为“无穷远点”,这大致对应于0在加法中的作用。计算机中,它有时表示为X=Y=0(虽然这不满足椭圆曲线方程,但可作为特殊情况进行校验)。还有一个+运算符,被称为“加法”,就像实数相加。给定椭圆曲线上的两个点P1和P2,则椭圆曲线上必定有第三个点P3=P1+P2。
几何图形中,该第三点P3可以在P1和P2之间画一条线来确定。这条直线恰好与椭圆曲线上的一点相交,此点记为P3'=(x,y)。然后,在x轴做映射获得P3 = (x,-y)。
可以解释“无穷远点”之存在需要的特殊情况:
- 若P1和P2是同一点,P1和P2间的连线则为P1的切线。曲线上有且只有一个新的点与该切线相交。该切线的斜率可用微分求得。即使限制曲线点为两个整数坐标也可求得斜率!
- 在某些情况下(即,如果P1和P2具有相同x值,但不同y值),则切线完全垂直,在这种情况改下,P3=“无穷远点”。
- 若P1就是“无穷远点”,那么P1+P2=P2。类似P2是无穷远点,则P1+P2 = P1。这是把无穷远点类似于0的作用。
事实证明,在这里+运算复合结合律,这意味着(A+B)C = A (B+C).这就是说我们可以直接不加括号书写A+B+C,而不至于混淆。
我们已经定义了椭圆加法,为了扩展加法,我们对乘法进行标准定义。给定椭圆曲线上的点P,如果k是整数,则kP = P+P+...+P(k次)。注意,k有时被混淆而称为“指数”。
生成公钥
以一个随机生成的私钥k为起点,我们将其与曲线上已定义的生成点G相乘已获得曲线上的另一点,也就是相应的公钥K。生成点是secp256k1标准的一部分,比特币密钥的生成点都是相同的:
K = k * G
所有比特币用户的生成点是相同的,一个私钥k乘以G将得到相同的公钥K。k和K之间的关系是固定的,但只能单向运算,即从k得到K。这就是可以吧比特币地址(k的衍生)与任何人共享而不会泄露私钥(k)的原因。
为实现椭圆曲线乘法,我们将之前生成的私钥k和与生成点G相乘得到公钥K:
K = 1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD * G
公钥K被定义为一个点K = (x,y):
K = (x, y)
其中:
x = F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A
y = 07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB
为了展示整数点的乘法,我们将使用较为简单的实数范围的椭圆曲线。目标是找到生成点G的倍数kG。也就是将G相加k次。
在椭圆曲线中,点的相加等同于从该点画切线找到与曲线相交的另一点,然后映射到x轴。
上图显示了在曲线上得到G、2G、4G的几何操作。
大多数比特币程序使用OpenSSL加密库进行椭圆曲线计算。例如,调用EC_POINT_mul()函数,可以计算得到公钥。
比特币地址
比特币地址是一个由数字和字母组成的字符串。由公钥(一个同样由数字和字母组成的字符串)生成的比特币地址以数字“1”开头。例如:
1J7mdg5rbQyUHENYdx39WVWK7fsLpEoXZy
比特币地址可由公钥经过单向的加密哈希算法得到。哈希算法是一种单向函数,接收任意长度的输入产生指纹摘要。
加密哈希函数在比特币中被广泛使用:比特币地址、脚本地址以及在挖矿中的工作量证明算法。(私钥、地址均是使用SHA256生成,而公钥是私钥通过椭圆算法生成)
由公钥生成比特币地址时使用的算法是(SHA)和(RIPEMD),别特是SHA256和RIPEMD160。
以公钥K为输入,计算其SHA256哈希值,并以此结果计算RIPEMD160哈希值,得到一个长度为160比特(20字节)的数字:
A = RIPEMD160(SHA256(K))
比特币地址与公钥不同,比特币地址时由公钥经过单向的哈希函数生成的。
通常用户看到的比特币地址是经过Base58Check编码的,这种编码使用了58个字符(一种Base58数字系统)和校验码,提高了可读性、避免歧义并有效防止了在地址转录和输入中产生的错误。
Base58和Base58Check编码
Base64
使用了26个小写字母、26个大写字母、10个数字以及两个符号(例如“+”和"/"),用于在电子邮件这样的基于文本的没接找那个传递二进制数据。Base64通常用于编码邮件中的附件。
Base58
是一种基于文本的二进制编码格式,用在比特币和其他的加密货币中。
这种编码格式不仅实现了数据压缩,保证了易读性,还具有错误诊断功能。
Base58是Base64的子集,同样使用大小写字母和10个数字,但舍弃了一些容易错读和在特定字体中容易混淆的字符。
具体的,Base58不含Base64中的0(数字0)、O(大写字母O)、l(小写字母L)、I(大写字母i)、以及"+"和"/"两个字符。简而言之,Base58就是不包括(0,O,l,I)的大小写字母和数字组成。
例:比特币的Base58字母表:123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
Base58Check
一种Base58格式的、有版本的、经过校验的格式,可以明确的对比特币数据编码的编码格式。
是一种常用在比特币中的Base58编码格式,增加了错误校验码来检查数据在转录中出现的错误。
检验码长4个字节,添加到需要编码的数据之后。校验码是从需要编码的数据的哈希值中得到的,所以可以用来检测并避免转录和输入中产生的错误。
使用Base58check编码格式时,编码软件会计算原始数据的校验码并和结果数据中自带的检验码进行对比。二者不匹配则表明有错误产生,那么这个Base58Check格式的数据就是无效的。
实现是:在encode前,在输入流尾部加入输入内容的hash值(4个字节)。然后再对输入流进行 Base58Encode。
在 decode 时候:先 Base58Decode, 然后拆成两部分(内容和校验值),判断对内容计算的校验值和校验值字段是否一致。
为了使用Base58Check编码格式对数据(数字)进行编码,首先我们要对数据添加一个称作“版本字节”的前缀,这个前缀用来明确需要编码的数据的类型。例如,比特币地址的前缀是0(十六进制0x00),而对私钥编码时前缀是128(十六进制是0x80)。
接下来,我们计算“双哈希”校验码,意味着要对之前的结果(前缀和数据)进行两次SHA256哈希算法:
checksum = SHA256(SHA256(prefix+data))
在产生的长32个字节的哈希值(两次哈希运算)中,我们只取前4个字节。这4个字节就作为校验码。校验码会添加到数据之后。
结果由三部分组成:前缀、数据和校验码。这个结果采用之前描述的Base58字母表编码。
下图描述了Base58Check编码的过程:
在比特币中,大多数需要向用户展示的数据都是用Base58Check编码,可以实现数据压缩,易读而且有错误校验。
Base58Check编码中的版本前缀是数据的格式易于辨别,编码之后的数据头包含了明确的属性。这些属性使用户可以轻松明确被编码的数据的类型以及如何使用它们。
Base58Check编码的比特币地址时1开头的;
Baase58Check编码的私钥WIF是以5开头的。
Base58Check版本前缀和编码后的结果:
私钥(SHA256)-> 公钥(椭圆曲线上的某个点)-> 两次哈希(SHA256)的校验码+Base58Check格式的比特币地址。
密钥的格式
私钥的格式
私钥可以以许多不同的格式表示,所有这些都对应于相同的256位的数字。如下有三种常见格式:
如下展示了上面三种格式所生成的私钥:Hex是16进制的32位=16*32=256位
每种格式之间可以相互转换。
公钥的格式
公钥格式分为非压缩格式或压缩格式公钥两种。
公钥是椭圆曲线上的一个点,由一对坐标(x,y)组成。
公钥通常为前缀04紧接着两个256比特(位)的数字。其中一个256比特数字是公钥的x坐标,另一个是y坐标。前缀04用来区分非压缩格式,02或03开头是压缩格式。
压缩格式公钥
引入压缩格式公钥是为了减少比特币交易的字节数,从而可以节省那些运行区块链数据库的节点磁盘空间。
大部分比特币交易包含了公钥,用于验证用户的凭据和支付比特币。
每个公钥有520比特(包括前缀、x坐标,y坐标)。
一个公钥是一个椭圆曲线的的点(x,y)。而椭圆去选实际是一个数学方程,曲线上的点实际是该方程的解。
因此,如果我们知道x坐标,就可以通过方程:
得到y坐标。这种方案可以让我们只存储公钥的x坐标,略去y坐标。从而将公钥的大小和存储空间减少了256比特。每个交易所需的字节数减少了近一半。
未压缩格式公钥使用04座位前缀,压缩格式公钥是以02或03作为前缀。
需要两种不同前缀的原因:因为椭圆曲线加密的共识左边是y^2,也就是说y的解来自一个平方根,可能是正值也可能是负值。更形象说,y坐标可能在x坐标轴上面或者下面。当给定x,我们需要知道y值在x轴上还是下,因为它们代表椭圆曲线上不同的点,即不同的公钥。当我们在素数(质数)P阶的有限域上使用二进制算术计算椭圆曲线时,y坐标可能是奇数或者偶数,分别对应y的正负符号。因此,为了区分y坐标两种可能值,在生成压缩格式公钥时,如果y是偶数,就用02作为前缀;如果是奇数,就用03 作为前缀。
下图阐述了公钥压缩:
压缩格式公钥和非压缩格式公钥对应同一个私钥。但是使用双哈希函数(RIPEMD160(SHA256(K)))将压缩格式公钥转化为比特币地址得到的值和非压缩格式公钥转化出的比特币地址不同。两个地址都合法。
压缩格式公钥逐渐成为大部分比特币客户端的默认格式。但是如果出现新老客户端兼容问题(有的支持压缩,有的不支持压缩,那么同一个私钥对应两个不同的比特币地址,而且两个地址都合法)。
为了解决这个问题,当私钥从钱包中被导出时,较新的比特币客户端将使用一种不同的钱包导入格式(Wallet import Format)。这种新的钱包导入格式可以用来表名该私钥已经被用来生成压缩的公钥,同时生成比特币地址也是基于该压缩公钥。
压缩格式私钥
“压缩格式私钥”是一种名称上的误导,因为当一个私钥被使用WIF压缩格式导出,不但没有压缩,而且比“非压缩格式私钥”长一个字节。这个多出来的一个字节是私钥被加了后缀01,用以表示该私钥是来自一个较新的钱包,只能被用来生成压缩的公钥。私钥是非压缩的,也不能被压缩。“压缩的私钥”实际上只是表示“用于生成压缩格式公钥的私钥”。
另外,这些格式并不是刻意互换使用的。在较新的实现了压缩格式公钥的钱包中,私钥只能且永远被导出为WIF压缩格式(以K或L为前缀)。对于较老的没有实现压缩格式公钥的钱包,私钥将只能被导出为WIF格式(以5为前缀)导出。
如果一个比特币钱包实现了压缩格式公钥,那么它将会在所有交易中使用该压缩格式公钥。钱包中的私钥将会被用来生成压缩格式公钥,压缩格式公钥然后被用来生成交易中的比特币地址。当一个实现了压缩格式公钥的比特币钱包导出私钥时,钱包导入格式(WIF)将会被改为WIF压缩格式,该格式将会在私钥后面附加一个字节大小的后缀01。
最终的Base58Check编码格式的私钥被称作WIF(“压缩”)私钥,以字母“K”或“L”开头。
同样的私钥,不同的格式: