區(qū)塊鏈研習(xí)社? ? ? (智博去快連)
本內(nèi)容引用自imtoken
通過(guò)區(qū)塊鏈,人類(lèi)歷史上首次通過(guò)技術(shù)徹底缅阳、純粹地保障「私有財(cái)產(chǎn)神圣不可侵犯」磕蛇。
讓人沉思,讓人興奮的一段話(huà)。 可在這背后的基礎(chǔ)技術(shù)「密碼學(xué)」是如何工作秀撇,以及保障數(shù)字資產(chǎn)的安全呢超棺?無(wú)論你是愛(ài)好者亦或投資客,應(yīng)該需要多少了解背后的原理呵燕,免得誤解棠绘,輕則鬧笑話(huà),重則損失資產(chǎn)再扭。因?yàn)槲覀兛倳?huì)聽(tīng)到一些鬼扯的故事(幫我找回密碼吧弄唧!私鑰發(fā)到群里了誒!)霍衫,皆是由于對(duì)錢(qián)包本質(zhì)的不了解候引。
本文僅談?wù)撳X(qián)包原型涉及的相關(guān)密碼學(xué),不包含 keystore敦跌,助記詞澄干,轉(zhuǎn)賬交易等。
錢(qián)包如何生成 這是以太坊黃皮書(shū)關(guān)于錢(qián)包(私鑰柠傍、公鑰麸俘、地址)的描述,僅僅 2 行文字惧笛。主要講解私鑰通過(guò) ECDSA(橢圓曲線(xiàn)簽名算法)推導(dǎo)出公鑰从媚,繼而經(jīng)過(guò) Keccak 單向散列函數(shù)推導(dǎo)出地址。 分解為 3 個(gè)步驟: 1. 創(chuàng)建隨機(jī)私鑰 (64 位 16 進(jìn)制字符 / 256 比特 / 32 字節(jié)) 2. 從私鑰推導(dǎo)出公鑰 (128 位 16 進(jìn)制字符 / 512 比特 / 64 字節(jié)) 3. 從公鑰推導(dǎo)出地址 (40 位 16 進(jìn)制字符 / 160 比特 / 20 字節(jié)) 這是我從 ethereumjs/keythereum 中剝離出來(lái)的 JavaScript 代碼患整,關(guān)于黃皮書(shū)上的公式的具體實(shí)現(xiàn)拜效,僅僅 6 行代碼。?
這是一件很奇妙的事情各谚,2 行文字紧憾,6 行代碼承載著億萬(wàn)級(jí)別的資產(chǎn),但往往越簡(jiǎn)單昌渤,越奧妙赴穗。以上的 6 行代碼,就已經(jīng)囊括密碼學(xué)中大多數(shù)技術(shù)膀息,比如隨機(jī)數(shù)生成器般眉、非對(duì)稱(chēng)加密,單向散列函數(shù)等潜支。以下我會(huì)為大家解剖這 6 行代碼甸赃,逐一介紹背后相關(guān)的密碼學(xué)知識(shí)。 隨機(jī)數(shù) 隨機(jī)數(shù)用于生成私鑰毁腿,若隨機(jī)數(shù)可以被預(yù)測(cè)或重現(xiàn)辑奈,則私鑰就會(huì)立刻形同虛設(shè)。所以保證隨機(jī)數(shù)擁有下列三項(xiàng)特征已烤,至關(guān)重要: 隨機(jī)性:不存在統(tǒng)計(jì)學(xué)偏差鸠窗,完全雜亂的數(shù)列 不可預(yù)測(cè)性:不能從過(guò)去的數(shù)列推測(cè)下一個(gè)出現(xiàn)的數(shù) 不可重現(xiàn)性:除非將數(shù)列保存下來(lái),否則不能重現(xiàn)相同的數(shù)列 軟件本身是無(wú)法生成具有不可重現(xiàn)性的隨機(jī)數(shù)胯究,因?yàn)檫\(yùn)行軟件的計(jì)算機(jī)本身僅具備有限的內(nèi)部狀態(tài)稍计。所以通過(guò)確定性的代碼,在周期足夠長(zhǎng)的情況下裕循,必然會(huì)出現(xiàn)相同的隨機(jī)數(shù)臣嚣。因此要生成具備不可重現(xiàn)性的隨機(jī)數(shù),需要從不確定的物理現(xiàn)象中獲取信息剥哑,比如周?chē)鷾囟裙柙颉h(huán)境噪音、鼠標(biāo)移動(dòng)株婴,鍵盤(pán)輸入間隔等怎虫。 在 Linux 內(nèi)核中維護(hù)了一個(gè)熵池用來(lái)收集來(lái)自設(shè)備驅(qū)動(dòng)程序和其它來(lái)源的環(huán)境噪音。熵(entropy)是描述系統(tǒng)混亂無(wú)序程度的物理量困介,一個(gè)系統(tǒng)的熵越大則說(shuō)明該系統(tǒng)的有序性越差大审,即不確定性越大。 所以在選擇生成私鑰的隨機(jī)數(shù)方法時(shí)座哩,需要選擇滿(mǎn)足密碼學(xué)強(qiáng)度的隨機(jī)數(shù)方法徒扶,比如 Node 中的 crypto.randomBytes。當(dāng)你調(diào)用 crypto.randomBytes(32) 方法時(shí)根穷,它會(huì)等待熵池搜集足夠的信息后姜骡,返回 64 位的隨機(jī)數(shù),即私鑰屿良。 const privateKey = crypto.randomBytes(32) // privateKey.toString('hex'): ea4692a11d962b249f8f0439d642a9013a1a0 8807649311d3672886d72d1fe51 另外溶浴,在以太坊中想要獲得隨機(jī)數(shù)是一件不容易的事情,因?yàn)榈V工需要得到同樣的結(jié)果管引,并經(jīng)過(guò)驗(yàn)證提交到區(qū)塊鏈上士败。但如果 EVM 存在 random opcode,礦工會(huì)生成不一致隨機(jī)數(shù)褥伴,無(wú)法達(dá)成共識(shí)谅将。 目前社區(qū)也提出相應(yīng)的方案,Mist 的作者 Alex van de Sande 提出使用 blockhashes 生成隨機(jī)數(shù)重慢,但由于礦工擁有操縱區(qū)塊數(shù)據(jù)的能力饥臂,如果有能力且愿意放棄 5 個(gè)區(qū)塊的獎(jiǎng)勵(lì),理論上可以間接影響隨機(jī)數(shù)似踱,所以不是完全足夠安全可靠隅熙。 為了解決礦工有可能作惡的問(wèn)題稽煤,國(guó)內(nèi)社區(qū)提出 RANDAO: A DAO working as RNG of Ethereum 項(xiàng)目,構(gòu)建一個(gè)人人可以參與的 DAO囚戚,通過(guò)經(jīng)濟(jì)激勵(lì)酵熙,由所有參與者共同決定一個(gè)隨機(jī)數(shù)。在 RANDAO 的基礎(chǔ)上驰坊,Vitalik Buterin 也提出 RANDAO++ 方案匾二,感興趣可以看看。 非對(duì)稱(chēng)加密 在對(duì)稱(chēng)密碼中拳芙,由于加密和解密的密鑰相同察藐,所以必須向接收者配送密鑰用于解密。但發(fā)送密鑰過(guò)程中舟扎,竊聽(tīng)者可以竊取密鑰解密分飞,不發(fā)送密鑰吧,接收者無(wú)法解密睹限,密鑰必須發(fā)送浸须,但又不能發(fā)送,這問(wèn)題稱(chēng)為密鑰配送問(wèn)題邦泄。一般采取事先共享密鑰删窒、密鑰分配中心、Diffie-Hellman 密鑰交換等方案來(lái)解決顺囊,但直到非對(duì)稱(chēng)加密方案的出現(xiàn)肌索,無(wú)需向接收者配送解密密鑰,密鑰配送問(wèn)題才完美解決特碳。 在非對(duì)稱(chēng)加密中诚亚,將密鑰分為加密密鑰和解密密鑰,也就是我們常說(shuō)的公鑰和私鑰午乓。公鑰和私鑰一一對(duì)應(yīng)站宗,由公鑰加密的密文,必須使用公鑰配對(duì)的私鑰才可以解密益愈。 看似有點(diǎn)復(fù)雜梢灭,我們祭出密碼學(xué)的男女主角 Alice 和 Bob,來(lái)通俗地梳理一下: 發(fā)送者: Bob蒸其,接收者:Alice敏释,竊聽(tīng)者:Eve 1. Alice 生成密鑰對(duì)(私鑰和公鑰),私鑰由 Alice 自身妥善保管 2. Alice 將自己的公鑰發(fā)送給 Bob摸袁,即使被 Eve 竊取也沒(méi)關(guān)系 3. Bob 使用 Alice 的公鑰對(duì)消息加密钥顽,發(fā)送給 Alice 4. 密文可能被 Eve 竊取,但他無(wú)法使用公鑰解密 5. Alice 使用自己的私鑰解密密文 當(dāng)我們調(diào)用 secp256k1.publicKeyCreate 獲得公鑰時(shí)靠汁,實(shí)際使用的是非對(duì)稱(chēng)加密中的橢圓曲線(xiàn)算法蜂大。通過(guò)該算法可以從私鑰推導(dǎo)出公鑰闽铐,這是一個(gè)不可逆的過(guò)程:K = k * G。給出常數(shù)點(diǎn) G 時(shí)奶浦,使用已知私鑰 k 求公鑰 K 的問(wèn)題并不困難兄墅,但反過(guò)來(lái),已知公鑰 K 求私鑰 k财喳,則非常困難。這就是橢圓曲線(xiàn)算法上的離散對(duì)數(shù)問(wèn)題斩狱,也是為什么你可以分享地址(或公鑰)給別人耳高,但不能暴露自己的私鑰。
const publicKey = secp256k1.publicKeyCreate(privateKey, false).slice(1) // publicKey.toString('hex'): 1e3f1532e3285b02...45d91a36a8d78cb6bef8
為了形象的表現(xiàn)橢圓曲線(xiàn)算法如何將私鑰推導(dǎo)出公鑰所踊,我們將使用簡(jiǎn)單的整數(shù)作為私鑰 k泌枪,找到公鑰 K = k * G,也就是 G 相加 k 次(數(shù)學(xué)原理一致)秕岛。在橢圓曲線(xiàn)中碌燕, 點(diǎn)的相加等同于從該點(diǎn)畫(huà)切線(xiàn)找到與曲線(xiàn)相交的另?點(diǎn), 然后映射到 x 軸继薛。下圖展示了從曲線(xiàn)上獲得 G修壕、2G、4G遏考、8G 的幾何操作慈鸠。 單向散列函數(shù) 單向散列函數(shù) (one-way hash function) 有一個(gè)輸入和一個(gè)輸出,其中輸入稱(chēng)為消息 (message) 灌具,輸出稱(chēng)為散列值 (hash value) 青团。散列值也稱(chēng)為消息摘要 (message digest) 或者指紋 (fingerprint) 。單向散列函數(shù)可以根據(jù)消息的內(nèi)容計(jì)算出散列值咖楣,而散列值就可以用來(lái)檢查消息的完整性督笆。 單向散列函數(shù)擁有下列四項(xiàng)特征: 1. 根據(jù)任意長(zhǎng)度的消息計(jì)算出固定長(zhǎng)度的散列值 2. 能夠快速計(jì)算出散列值 3. 具備單向性 4. 消息不同散列值也不同 當(dāng)我們調(diào)用 createKeccakHash("keccak256") 方法時(shí),Keccak 使用海綿函數(shù)诱贿,對(duì)公鑰與初始的內(nèi)部狀態(tài)做 XOR 運(yùn)算得到 32 字節(jié)散列值娃肿,取其后 20 字節(jié),轉(zhuǎn)成 40 位的 16 進(jìn)制字符珠十,即為地址咸作。 const address = createKeccakHash("keccak256"). update(publicKey).digest().slice(-20) // address.toString("hex"): 7a48ac1bf3943b2ca7a4ca4999cbcbb0e999950c
在以太坊中還有許多地方應(yīng)用了單向散列函數(shù),例如: 1. 礦工需要不斷計(jì)算特定數(shù)據(jù)的散列值宵睦,當(dāng)散列值滿(mǎn)足難度要求時(shí)记罚,礦工便可以廣播該區(qū)塊,獲得獎(jiǎng)勵(lì)壳嚎。 2. 根據(jù)默克爾樹(shù)根哈希的值前后是否一致來(lái)判斷區(qū)塊中的交易是否被篡改 題外話(huà)桐智,有一陣子我很好奇單向散列函數(shù)或哈希函數(shù)中的 ”Hash“ 代表什么意思呢末早?后來(lái)經(jīng)過(guò)查詢(xún)得知, ”Hash“ 在古法語(yǔ)中的原意時(shí)「斧頭」说庭,后來(lái)被引申為「剁碎」然磷,正好形象的比喻單向散列函數(shù),將消息剁碎刊驴,混合成固定長(zhǎng)度的散列值姿搜。后來(lái)通過(guò) Herbert Hellerman 的《Digital Computer System Principles》成為廣為流傳的術(shù)語(yǔ)。 最后 沒(méi)有最后了捆憎。 如果有幫助舅柜,可以考慮請(qǐng)我喝杯咖啡 > 無(wú)恥的 ENS 地址:liangzai.eth 參考: 圖解密碼技術(shù)(第3版 Mastering Bitcoin How are ethereum addresses generated? Random in Ethereum RANDAO: A DAO working as RNG of Ethereum RANDAO++ How asymmetric (public key) encryption works Elliptic Curve Cryptography: a gentle introduction Why it is called “hash table”, or “hash function”?