zoukankan      html  css  js  c++  java
  • Neo私钥到地址

    基础名词

    Neo是个区块链工程,地址,公钥,私钥,地址脚本,base58,sha256,ripemd160,ECCsa,secp256k1,secp25r1这些词都是区块链技术相关的,或是新东西或者有应用到

    通过学习后,记录下自己的理解,如果是新接触的话,需要找基础的区块链入门资料学习.

    参考资料https://www.cnblogs.com/crazylights/p/8166690.html

    ECCurve类文档https://docs.microsoft.com/zh-cn/dotnet/api/system.security.cryptography.eccurve?view=netcore-2.2

    Neo区块链

    一个区块链开源项目,git:https://github.com/neo-project 区块链的应用之一是数字加密货币.

    私钥

    私钥是一个大整数,换成二进制是一个256位的数.私钥类似于银行账户,失去私钥等于失去了资产.私钥非常重要!

    例:用十六进制表示的私钥 0d005d28cf3d62ec461770746ba42d4a30a638c73c6fbfa90fb3359dc7f72e6b

    这个数是有限大的,取值范围由位数和椭圆曲线有关.取256位的话,肯定不会大于2^256-1.也和使用的椭圆曲线有关,但没研究.

    公钥

    公钥通过私钥计算而来,NEO的计算办法叫ECCsa,使用的是secp256r1曲线,固定的起始G点,经过私钥次数的相加而得到.简单公式描述为 公钥=私钥*G

    例: 022b03a16c8d16226618a7327226b4a073daef9ae259d7d884afce47353b51ee29

    ecc加密算法有关的知识很多,如果要搞清楚,不太容易.尤其在数学基础很弱的情况下更困难.此次学习也没有懂,了解一些词如下:

    私钥到公钥算法相关知识

    算法基于被证明过的数学理论,从一条在射影平面上的ecc椭圆曲线上的点开始,不停的做加法,做够n次时,得到的点的坐标是公钥.这个点位于曲线上,n次值就是私钥

    射影平面

    射影平面上,两条平行线相交于无穷远点.与中学时学的平面几何(欧氏几何)不同,这个平面是另一门几何,它们基于的公理不完全一样.例如,平行线不相交这点就不同

    射影平面上,所有直线都有一个无穷远点,任何两条直线都有1个交点.如果两行直线平行,那么它们的交点是无穷远点.如果不平行,则它们有各自的无穷远点

    一个射影平面上有且只有一条无穷远直线,平面上所有的无穷远点都在此条直线上.

    射影平面是一个有限平面,并且是单面的,从平面上一点出发,可以走到平面上任何一点,不存在平面的另一面.这点,可以参考默比乌斯带特点

    或者想象球面,不同于长方体有6个面,要走完6个面,必须跨过面与面之间的边界,球只有一个面,不存在从一面到另一面要跨过边界的情况.

    ecc曲线加法

    ecc椭圆曲线位于射影平面上,有一些数学计算规则.这个规则就是ecc加密用到的算法之一.对比下图,算法大至逻辑如下:

    加法定义:曲线上一点与另一点之和,等于这两点所在直线与曲线的交点的X轴对称点.如果这个点是同一点,那么和等于该点所在切线与曲线交点的X轴对称点.

    例如图上G点,它的和就是2G,2G正是G点切线与曲线交点G的X轴对称点.继续做加法,从2G点开始得到4G...

    做N次加法之后,得到一个点Q,这个点就是公钥,而N就是私钥.

    算法特点

    采用这种算法计算有个特点,G是固定的,私钥(N)是个随机大整数,公钥(Q)是一个坐标(X,Y).那么,给定N时,通过将G相加N次,就得到了公钥Q.

    那么反过来,给定Q时,却很难计算出N,也就是说,从G点开始,不知道是相加了多少次而得到Q的.那么,有私钥好计算公钥,而反过来则不行.

    如果将ecc曲线加法换成简单的加法,也能得出相似的结论.例如2+2+2=6,一眼看出,是2相加3次得到的.那么公钥是6,私钥是3,基点是2

    那么,2+2+.?.+2=2744584774030027284458040387221349021599708342405734667783110002634902555648 这个人工算要很久,要靠计算机算.

    如果以现有计算能力,破解一个密码要很久,比如几百年.那么这个加密手段肯定是有效的,因为人已经死了几个世纪了,你却还不能破解密码.

    地址脚本

    脚本是一段程序代码,地址脚本也是程序代码.由公钥计算得到地址脚本.

    例如这个地址脚本: cc8e9da86d4c81663d52b5baf9d1c2a2d935013f 计算方法如下

    公钥的形式

    上文讲述曲线时提到,公钥是一个坐标,是一个椭圆曲线上的点,它有X,Y两个值.十六进制表示格式如:04XY,看起来有些误解.它是04开头接着X坐标和Y坐标的十六进制值

    X,Y都是一个32字节的数,那么整个O4XY一共是65个字节.这种表示形式是非压缩的.压缩的形式如下

    022b03a16c8d16226618a7327226b4a073daef9ae259d7d884afce47353b51ee29 这是个33字节的数据,开始的02表示Y为偶数,如果Y是奇数,那么是03开头.后面是X值

    选用压缩形式表示公钥,因为短.由于椭圆曲线的特点,只需要知道X坐标和Y坐标的奇偶性,就能推算出Y坐标.所以能这样干.至于这特点,并未深入研究,所以没懂.

    压缩公钥算出地址脚本

    在公钥前面加0x21,后面加oxac,然后做一次sha256,再做一次ripemd160,最后得到20字节的数据,就是地址脚本

    21022b03a16c8d16226618a7327226b4a073daef9ae259d7d884afce47353b51ee29ac 0x21=33,而压缩公钥的长度是33字节.

    地址

    地址由地址脚本计算得到,计算办法如下:

    将地址脚本,前面加17变成21个字节,然后将其做两次sha256,取得到的数据前4字节,加到这21个字节后面 简单的讲,地址是地址脚本加了摘要,可以验证.

    17cc8e9da86d4c81663d52b5baf9d1c2a2d935013f1234abcd 类似这样,然后用base58编码成如下形式

    AXdWU5vYe3Ja9n778RpgJrrCUjAsfQgT1r

    区块链的数字账户,通过此地址发生交易.类似于银行账号,转账时需要双方的银行卡号.有了对方地址,就能向对方转加密货币.

    小结

    转换过程: 私钥 ==> 公钥 ==> 地址脚本 ==> 地址

    账户相关这些都源于私钥.WIF是一种私钥形式,由私钥到WIF的计算如下:

    私钥前面加0x80后面加0x01,一共34字节,将这34字节做两次SHA256,取结果前4字节,放到34个字节后面,变成38字节.然后base58编码得到WIF.和地址类似,能验证

    080d005d28cf3d62ec461770746ba42d4a30a638c73c6fbfa90fb3359dc7f72e6b011234abcd

    写代码时,需要用到的一些库:

    摘要相关: System.Security.Cryptography命名空间下, SHA256 , RIPEMD160(这个在.netcore上还没有,framework上有)

    ecc曲线相关: System.Security.Cryptography命名空间下 ECCurve ECDsa ECParameters

    大整数: System.Numerics命名空间下 BigInteger

    base58,这个没有库,但是比较简单,可以自己实现.算法类同于将2进制转为16进制.58编码就是将2进制转为58进制

    其它

    Neo ECC曲线参数

                NeoSecp256r1 = new ECCurve
                {
                    // 选择曲线 y^2 = x^ + ax + b
                    CurveType = ECCurve.ECCurveType.PrimeShortWeierstrass,
    
                    A = hex2ByteArray("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"),
    
                    B = hex2ByteArray("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"),
    
                    // 所谓"阶",没搞明白
                    Prime = hex2ByteArray("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"),
    
                    // 私钥必须小于n n对应是Order这个属性
                    Order = hex2ByteArray("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"),
    
                    Cofactor = hex2ByteArray("01"),
    
                    // 加法起点G
                    G=new ECPoint
                    {
                        X=hex2ByteArray("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"),
                        Y=hex2ByteArray("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5")
                    }
                }
            

    ECCurve

    用c#的这个类,可以得到一对私钥和公钥.如下

                // secp2561曲线,相关参数是neo特定的
                var secp256r1 = NeoSecp256r1;
    
                ECDsa sa = ECDsa.Create();
    
                // 随机生成密钥对,私钥和公钥
                sa.GenerateKey(secp256r1);
    
                // 导出的对象里包含私钥和公钥
                ECParameters ecpE = sa.ExportParameters(true);
    
                // 如果不异常,则生成成功
                ecpE.Validate();
    
                // 私钥
                ecpE.D
    
                // 公钥
                ecpE.Q
            

    在这个类中,没有找到给定私钥求公钥的方法.NEO源码中有ECC加密的代码,有这样的方法,G*私钥=公钥,可以实现.

  • 相关阅读:
    最小的linux发行版TinyCore Linux 系统,从分区安装系统开始
    目标世界上最小的Linux系统—ttylinux体验
    在虚拟机上安装树莓派系统
    天气预报查询
    树莓派做服务器,搭建Typecho博客和Owncloud云盘
    超好用的C#控制台应用模板
    一个简单好用的日志框架NLog
    让编写的单元测试同时支持 NUnit/MSTest
    使用MSTest进行单元测试入门
    C#开源日志文件实时监控工具Tail
  • 原文地址:https://www.cnblogs.com/mirrortom/p/11096200.html
Copyright © 2011-2022 走看看