Neo是個區塊鏈工程,地址,公鑰,私鑰,地址腳本,base58,sha256,ripemd160,ECCsa,secp256k1,secp25r1這些詞都是區塊鏈技術相關的,或是新東西或者有應用到html
經過學習後,記錄下本身的理解,若是是新接觸的話,須要找基礎的區塊鏈入門資料學習.git
參考資料http://www.javashuo.com/article/p-rfptnpjj-km.htmlgithub
ECCurve類文檔https://docs.microsoft.com/zh-cn/dotnet/api/system.security.cryptography.eccurve?view=netcore-2.2算法
一個區塊鏈開源項目,git:https://github.com/neo-project 區塊鏈的應用之一是數字加密貨幣.c#
私鑰是一個大整數,換成二進制是一個256位的數.私鑰相似於銀行帳戶,失去私鑰等於失去了資產.私鑰很是重要!api
例:用十六進制表示的私鑰 0d005d28cf3d62ec461770746ba42d4a30a638c73c6fbfa90fb3359dc7f72e6b學習
這個數是有限大的,取值範圍由位數和橢圓曲線有關.取256位的話,確定不會大於2^256-1.也和使用的橢圓曲線有關,但沒研究.區塊鏈
公鑰經過私鑰計算而來,NEO的計算辦法叫ECCsa,使用的是secp256r1曲線,固定的起始G點,通過私鑰次數的相加而獲得.簡單公式描述爲 公鑰=私鑰*G編碼
例: 022b03a16c8d16226618a7327226b4a073daef9ae259d7d884afce47353b51ee29加密
ecc加密算法有關的知識不少,若是要搞清楚,不太容易.尤爲在數學基礎很弱的狀況下更困難.這次學習也沒有懂,瞭解一些詞以下:
算法基於被證實過的數學理論,從一條在射影平面上的ecc橢圓曲線上的點開始,不停的作加法,作夠n次時,獲得的點的座標是公鑰.這個點位於曲線上,n次值就是私鑰
射影平面上,兩條平行線相交於無窮遠點.與中學時學的平面幾何(歐氏幾何)不一樣,這個平面是另外一門幾何,它們基於的公理不徹底同樣.例如,平行線不相交這點就不一樣
射影平面上,全部直線都有一個無窮遠點,任何兩條直線都有1個交點.若是兩行直線平行,那麼它們的交點是無窮遠點.若是不平行,則它們有各自的無窮遠點
一個射影平面上有且只有一條無窮遠直線,平面上全部的無窮遠點都在此條直線上.
射影平面是一個有限平面,而且是單面的,從平面上一點出發,能夠走到平面上任何一點,不存在平面的另外一面.這點,能夠參考默比烏斯帶特色
或者想象球面,不一樣於長方體有6個面,要走完6個面,必須跨過面與面之間的邊界,球只有一個面,不存在從一面到另外一面要跨過邊界的狀況.
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進制
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") } }
用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*私鑰=公鑰,能夠實現.