隨着區塊鏈相關技術的創新和突破,不少有形或無形資產都將實現去中心化,數字資產將無處不在。要保護數字出版物版權,實現去中心化,解決業界多年來版權保護不力的難題。不管數字資產,仍是數字出版版權,都是有明確全部權的,當前實現數字資產所屬的技術手段就是本期《區塊鏈100講》要介紹的數字簽名。而多重簽名是對數字簽名的擴展使用,給數字資產轉移提供了安全保障和技術手段。本期內容從基本概念入手,詳細瞭解數字簽名和多重簽名的做用和代碼實現。算法
什麼是數字簽名?數據庫
不少人的第一反應是用筆簽名。生活中咱們常常須要用筆簽名:借條要簽名,合同要簽名,去銀行辦理業務也要簽名。簽下名字,就表示對這件事負責。人的筆跡是很個性的,幾乎不可能複製,即使是專業模仿也能夠經過技術鑑別出來,所以簽名就具備惟一性的特色,並被法律承認。數字簽名的原理跟用筆簽名相似,用於確認身份。api
數字簽名有兩個做用:數組
一是能肯定消息確實是由發送方簽名併發出來的;安全
二是數字簽名能肯定消息的完整性。bash
然而,在沒有筆跡驗證的狀況下,數字簽名如何保持惟一性和可驗證性呢?網絡
**簽名的驗證。**若是,你拿着一張支票去銀行兌換,銀行職員會對支票上的簽名和印章仔細比對,確保印章大小、樣式,以及付款人簽名等,與銀行留存的信息一致,纔會給你兌付,這就是簽名驗證。併發
簡單地講,就是加密技術代替人的筆跡,數字簽名涉及一個哈希函數、發送者的公鑰、發送者的私鑰。app
其操做方法是:函數
在區塊鏈系統中發送一條廣播時,發送方用一個哈希函數從廣播文本中生成摘要,而後用本身的私鑰對摘要進行加密,加密後的摘要將做爲廣播的數字簽名和廣播一塊兒發送給接收方,接收方首先用與發送方同樣的哈希函數從接收到的原始廣播中計算出報文摘要,接着再用發送方的公鑰來對廣播附加的數字簽名進行解密。若是這兩個摘要相同,那麼接收方就能確認該數字簽名是發送方的。
比特幣客戶端簽名功能
數字資產須要簽名。類比人類簽名,比特幣也有簽名功能。若是瞭解比特幣錢包(客戶端軟件),就會發現它提供了一個簽名消息的功能,能夠用來對其餘用戶經過比特幣網絡以外的信息進行簽名和驗證。我我的使用的是 比特幣官方網站 提供的比太錢包,如圖:
**這個功能幹什麼用的呢?**有好多小夥伴不清楚,這裏舉個簡單的例子解釋一下,具體使用的時候毫不限於這些應用。
Alice開了一個網店,但沒有直接接入比特幣網絡,不能自動確認和驗證支付者。客戶Imfly購買了她的產品,並用比特幣支付了所有貨款。由於比特幣地址和交易都是公開匿名的,爲了防止冒充冒領,Alice須要確認Imfly提供的那個付款地址確實是imfly本人的,不然不能發貨。這時候,就須要Imfly先把支付貨款的比特幣地址和相關交易簽名信息(如圖),而後經過QQ或郵件傳給Alice,Alice使用客戶端驗證信息簽名,才能確認交易確實是Imfly的。
想象一下,若是沒有簽名功能會怎麼樣呢?由於比特幣僅是一個匿名、安全的支付手段,但卻沒法確認支付方或收款方是誰,信息的不肯定性,將使得比特幣網絡以外的交易沒法達成。在中心化的世界裏,這個問題是經過運營平臺這個第三方達成的,好比支付寶等,雙方的所有信息,平臺都掌握,任何一方出現欺詐,都須要經過向平臺投訴來解決。用戶須要對第三方平臺絕對信任,並經過犧牲我的信息安全得到交易的基本保障。
電子簽名
經過上述分析,能夠理解的是,簽名的做用是肯定資產所屬,其特徵是簡單、安全、可驗證。把這個概念抽象出來,應用到計算機系統裏,爲了肯定數字資產所屬,也須要進行簽名,這就是你們常常看到的「電子簽名」的概念。在網絡世界裏,簽名能夠對任何須要確認的數字資產進行處理,好比比特幣地址、電子書版權等,並以此來宣告重要資產的所屬,這讓無需監管的去中心化交易成爲可能。
具體開發設計中,就是用加密技術代替人的筆跡,否則任何簽名方法都會被模仿,並且模仿的成本極低,相反,驗證的成本卻很高。這也是當前數字出版行業版權保護不力的緣由之一,各大平臺僅僅經過用戶權限來限制用戶使用數字出版物,並無對出版物自己採起數字簽名等加密措施,一旦被盜版,驗證和取證工做耗費不少人力物力。下面那某個項目爲例:
支付密碼
簽名方法在modules/signatures.js文件裏,類圖以下:
咱們仍是從Api開始,代碼以下:
// modules/signatures.js文件
router.map(shared, {
"get /fee": "getFee",
"put /": "addSignature"
});
library.network.app.use('/api/signatures', router);
複製代碼
經過上面的代碼,能夠了解簽名提供了兩個簡單的公共接口:
get /api/signatures/fee -> shared.getFee
put /api/signatures/ -> shared.addSignature //簽名操做
複製代碼
顯然,最核心的方法也就是shared.addSignature,代碼:
shared.addSignature = function (req, cb) {
...
library.scheme.validate(body, {
properties: {
...
},
required: ["secret", "secondSecret"] },
function (err) {
...
library.balancesSequence.add(function (cb) {
if (body.multisigAccountPublicKey && body.multisigAccountPublicKey != keypair.publicKey.toString('hex')) { modules.accounts.getAccount({publicKey: body.multisigAccountPublicKey}, function (err, account) {
...
try {
var transaction = library.logic.transaction.create({
type: TransactionTypes.SIGNATURE,
sender: account,
keypair: keypair,
requester: keypair,
secondKeypair: secondKeypair,
});
} catch (e) {
return cb(e.toString());
}
... }
複製代碼
毫無疑問,支付密碼也是一個簡單的交易(交易類型TransactionTypes.SIGNATURE)。基於此,咱們不難想象,添加相似比特幣的簽名功能也是件很是簡單的事情。
再簡單一點:
發送方把hello kitty的信息進行雙重處理。首先是經過接收方公鑰來進行加密。
爲何要接收方的公鑰來加密? 由於只有接收方的私鑰能夠解開接受方公鑰加過的密,因此只有接受方能夠解密。
而後hello kitty還要經過哈希值獲得摘要,接要再通過發送方私匙進行簽名,簽名後得出的原文密文和發送方簽名一塊兒發給接受方。
接收方用本身的私匙解開密文,獲得hello kitty.
而後經過哈希獲得摘要。
另外則是經過發送方的公鑰解開發送方簽名,獲得摘要,而且經過解密原文密文的摘要和解密發送方簽名的摘要進行對比,最後的摘要一致,則認爲摘要是對的。
經過這樣的方式,接受方完成了對發送方簽名過的hello kitty信息的認證。
這裏要記一個口訣,公鑰加密,私鑰解密,私鑰簽名,公鑰解密。
再短一點,則是公鑰加,私鑰解,私鑰籤,公鑰解。
有個問題,爲何用接收方的公鑰加密hello kitty?由於經過這種方式,只有接受方的私鑰才能解開。
爲何要用發送方的私鑰簽名,不用其它人的私鑰簽名?由於這種方式,才能讓接收方確認這條信息是發送方發出來的。只有發送方的公鑰才能解開發送方的簽名。
什麼是多重簽名
比特幣的匿名性,使交易處於不可信之中,最終致使用戶不敢交易。有了簽名功能,就有了確認雙方信息的有效手段。那麼,什麼是多重簽名呢?
多重簽名,能夠簡單地理解爲一個數字資產的多個簽名。多重簽名預示着數字資產可由多人支配和管理。多重簽名,就表示動用這筆資金須要多個私鑰簽名,一般這筆資金或數字資產會保存在一個多重簽名的地址或帳號裏。相似於生活中有一份文件須要多個部門簽署才能生效同樣。
**多重簽名是數字簽名的升級,它讓區塊鏈相關技術應用到各行各業成爲可能。**在實際的操做過程當中,一個多重簽名地址能夠關聯n個私鑰,在須要轉帳等操做時,只要其中的m個私鑰簽名就能夠把資金轉移了,其中m要小於等於n,也就是說m/n小於1,能夠是2/3, 3/5等等,是要在創建這個多重簽名地址的時候肯定好的。
例如,電子商務、財產分割、資金監管等。例如,一對夫妻要儲備一筆資金,供孩子上大學使用,在這以前誰都不能動,那麼把簽名模式改成2/2,不只限制了夫妻雙方,也給黑客攻擊增長了難度。多重簽名的設計,讓各類業務去中心化充滿無限可能。
工做原理
數字資產在某種狀況下,須要多人支配。換句話說,在某些特定條件下,數字資產若是沒法確認歸屬某個特定的人,那麼最好讓相關人共同簽署它的全部權。
仍然舉上面的例子,在Alice發貨以後,Imfly收到貨以前,這筆錢應該由第三方信用比較高的中介暫時保存,這個階段,這筆錢要麼是Alice的,要麼是Imfly的,最終的歸屬要看Imfly是否收到貨。因此,這個第三方,不管如何都是應該有的,否則Imfly就要承擔大部分風險(由於比特幣的單向不可逆,Imfly發送以後就沒有辦法收回了)
這樣一來,這筆錢的所屬關係,在交易過程當中涉及到Alice、Imfly和平臺第三方(雖然不屬於它,但它有權裁定資金去向),那麼就應該由他們三方簽名,所以網上購物就是典型的多重簽名的例子。其多重簽名模型就是2/3,也就是說只要他們中的兩個簽名,資金就能夠被轉移。
具體到這個例子,Imfly把錢打給一個關聯三方私鑰的多重簽名地址,若是整個交易過程順利,只要Alice和Imfly兩個簽名,這筆錢就會順利到達Alice手裏。若是不順利,他們任何一人提出仲裁,平臺第三方調查以後,經過簽名就能把這筆錢轉給Alice或退回Imfly。這很是相似淘寶和京東的模式,可是比他們更加便捷和安全,至少不用擔憂第三方倒閉、挪用資金或攜款跑路。
應用場景
很顯然,多重簽名給了加密貨幣騰飛的翅膀,讓它單一單項支付的能力更具吸引力,讓加密貨幣技術應用到各行各業成爲可能。這裏簡單的羅列幾個應用場景,供探索和思考:
**電子商務。**比較常見的是2/3的模式。上面電子商務網站的例子,就是最典型的場景之一,目前已經有成功的案例了。延伸一下,這類應用本質就是中介,因此還可用在各種中介機構性質的服務上。
財產分割。好比夫妻雙方共有財產,可使用1/2的模式,一個帳戶誰均可以使用,跟各自擁有賬號同樣,好處是系統忠實記錄了每一個人的花銷,鬧掰的時候很容易清算。擴展到公司合夥經營,可使用1/n模式,n我的合夥人,均可以直接支配共有資金,具體清算時,一目瞭然。
資金監管。其實,這是多重簽名的最直接做用,一筆錢須要多我的簽名才能使用,任何一我的都沒法直接動用資金,這在生活中太常見了,只要靈活設置多重簽名的比重模式,就能解決生活中不少問題。好比,接着上面夫妻的例子,夫妻要儲備一筆資金,供孩子上大學使用,在這以前誰都不能動,那麼把模式改成2/2,不只限制了夫妻雙方,也給黑客攻擊增長了難度.
多重簽名的設計,讓各類業務去中心化充滿無限可能。
多重簽名
多重簽名方法在modules/multisignatures.js文件裏,類圖以下:
實現Api的代碼以下:
router.map(shared, {
"get /pending": "pending",
// Get pending
transactions "post /sign": "sign",
// Sign transaction
"put /": "addMultisignature",
// Add multisignature
"get /accounts": "getAccounts" });
library.network.app.use('/api/multisignatures', router);
複製代碼
解析一下,最後產生的Api以下:
get /api/multisignatures/pending -> shared.pending // 查詢等待中的交易
post /api/multisignatures/sign -> shared.sign // 簽名交易
put /api/multisignatures/ -> shared.addMultisignature // 建立多重簽名賬號
get /api/multisignatures/accounts -> shared.getAccounts // 得到關聯的賬號(對應者用戶私鑰)
提供的功能很顯然,包括:待交易查詢、關聯賬號列表查詢,用戶簽名交易,建立多重簽名賬號等4個核心功能。咱們先從建立多重簽名賬號開始,這個Api使用的是http的put方法,對應的天然是更新操做,不查看代碼也能夠猜測到,該功能應該是在已有賬號基礎上的操做,從客戶端錢包設置菜單裏,能夠看到如圖操做:
看看shared.addMultisignature的源代碼以下:
// modules/multisignatures.js文件
shared.addMultisignature = function (req, cb) {
var body = req.body;
library.scheme.validate(body, {
... required: ['min', 'lifetime', 'keysgroup', 'secret'] },
function (err) {
...
library.balancesSequence.add(function (cb) {
modules.accounts.getAccount({publicKey: keypair.publicKey.toString('hex')}, function (err, account) {
...
try {
var transaction = library.logic.transaction.create({
type: TransactionTypes.MULTI,
sender: account,
keypair: keypair,
secondKeypair: secondKeypair,
min: body.min,
keysgroup: body.keysgroup,
lifetime: body.lifetime
});
} catch (e) {
return cb(e.toString());
}
... };
複製代碼
建立一個多重簽名,必須'min', 'lifetime', 'keysgroup', 'secret'這四參數(其實,一個默認參數就是當前賬號),min表明上面講到的m值,即須要確認的人數;lifetime表明生命週期;keysgroup包含多重簽名關聯的所有賬號,它是數組類型,包含的元素個數就是n,secret是用戶密碼,與用戶私鑰對應。
通過一系列的驗證以後,做爲一個交易(交易類型TransactionTypes.MULTI)保存到數據庫(區塊鏈)裏。建立成功的賬號,能夠顯示多重賬號菜單,對交易進行操做。接下來,天然應該可以查看所有關聯的賬號(請看shared.getAccounts方法),查看待確認的交易(請看shared.pending方法),這兩個方法僅僅是簡單的查詢,沒什麼難度,這裏再也不浪費篇幅。
若是用戶贊成交易,就能夠對待確認的交易進行簽名(shared.sign方法),這個方法的源碼以下:
shared.sign = function (req, cb) {
var body = req.body;
library.scheme.validate(body, {
...
required: ['transactionId', 'secret'] },
function (err) {
...
function done(cb) {
library.balancesSequence.add(function (cb) {
var transaction = modules.transactions.getUnconfirmedTransaction(body.transactionId);
if (!transaction) {
return cb("Transaction not found"); }
transaction.signatures = transaction.signatures || [];
transaction.signatures.push(sign);
library.bus.message('signature', {
signature: sign,
transaction: transaction.id
}, true);
cb();
}, function (err) {
if (err) {
return cb(err.toString());
}
cb(null, {transactionId: transaction.id});
});
}
... };
複製代碼
這個方法,相比單獨的簽名方法,不一樣的是單獨的簽名方法至關於一個新建交易,而這裏的多重簽名的用戶簽名,顯然僅僅是對未確認交易進行簽名確認(640行維護了一個簽名數組,push方法把用戶簽名寫入數組)。
延伸閱讀:區塊鏈100講:梅克爾樹保障區塊鏈數據不可篡改,想換根就要砍樹!
內容來源:圖書--機械工業出版社華章分社《連接將來:迎接區塊鏈與數字資產的新時代》;公衆號--區塊鏈研究實驗室、鏈社區
做者:許子敬、鏈三豐、社長等
整理:Cynthia
活動推薦
掃描下圖中二維碼或點擊「閱讀原文」便可報名參加