JavaScript開發簽名和多重簽名解析

JavaScript開發簽名和多重簽名解析,加密貨幣是一種數字資產,隨著區塊鏈等相關技術的創新和突破,很多有形或無形資產實現瞭去中心化。比如我們這裡分享的 億書 就是要把數字出版物版權進行保護,實現去中心化,解決業界多年來版權保護不力的難題。

無論數字資產,還是數字出版版權,都是有明確所有權的,當前實現數字資產所屬的技術手段就是本篇要介紹的簽名。而多重簽名是對簽名的擴展使用,給數字資產轉移提供瞭安全保障和技術手段。本篇,從基本概念入手,詳細瞭解簽名多重簽名的作用和代碼實現。

源碼

主要源碼地址:

signatures.js https://github.com/Ebookcoin/ebookcoin/blob/v0.1.3/modules/signatures.js

multisignatures.js https://github.com/Ebookcoin/ebookcoin/blob/v0.1.3/modules/multisignatures.js

解讀

簽名

(1)簽名的作用和特點

名字的解釋簽名是什麼?有人第一反應是日常生活中的用筆簽名,那麼我會說,你的直覺是對的。不過,當很多小夥伴看到網上的很多解釋,卻又迷惑瞭,事實上不同概念在不同領域的表述是有差別的,但本質相同。我堅信生活是一切創作的源泉,任何一個概念都能從生活中找到原型,這裡的“簽名”也是如此。

簽名的作用。日常生活中,凡是需要確認歸屬的(是簽名人的,不是其他的),都需要所有者進行簽名。比如,我簽名瞭一份文件,出瞭問題,責任我負,我簽名瞭一個支票,就代表將由我支付。我們普通老百姓最常見的場景,就是去銀行辦業務,銀行職員會讓你反復簽一大堆的單據,想必每個人都會有深刻的印象。

簽名的特點。人的筆跡是很個性化的,越熟練的字體,個性特征越固定,因此一個人的名字,不同的人寫出完全相同筆跡的概率非常小,即便是專業模仿也可以通過技術鑒別出來,這樣一來,人的簽名就具有唯一性、可驗證的特點,並被法律認可。

簽名的驗證如果,你拿著一張支票去銀行兌換,銀行職員會對支票上的簽名和印章仔細比對,確保印章大小、樣式,以及付款人簽名等,與銀行留存的信息一致,才會給你兌付,這就是簽名驗證。

(2)比特幣客戶端簽名功能

數字資產需要簽名。類比人類簽名,比特幣也有簽名功能。如果瞭解比特幣錢包(客戶端軟件),就會發現它提供瞭一個消息簽名的功能,可以用來對其他用戶通過比特幣網絡之外的信息進行簽名和驗證。我個人使用的是 比特幣官方網站 提供的比太錢包,如圖:

bither-wallet-sign.pngvcyotrzVxs7Vo6zIzrrO0ru3vbP2z9bG29Wpo6y2vNDo0qrNqLn9z/LGvcyozbbL38C0veK+9qGj08O7p9Do0qq21LXayP23vca9zKi++LbU0MXIzqOssqLNqLn9zv7J/Lj2yMvQxc+isLLIq7vxtcO9u9LXtcS7+bG+saPVz6GjPC9wPg0KPHA+o6gzo6m159fTx6nD+zwvcD4NCjxwPs2ouf3Jz8r2t9bO9qOsv8nS1MDtveK1xMrHo6w8Y29kZT7HqcP7PC9jb2RlPrXE1/fTw8rHyLe2qNfKsvrL+cr0o6zG5MzY1ffKx7zytaWhorCyyKuhor/J0enWpKGjsNHV4rj2uMXE7rPpz/Oz9sC0o6zTptPDtb28xsvju/rPtc2zwO+jrM6qwcvIt7aoyv3X1tfKsvrL+cr0o6zSstDo0qq9+NDQPGNvZGU+x6nD+zwvY29kZT6jrNXivs3Kx7TzvNK+rbOjv7S1vbXEJmxkcXVvO7Xn19PHqcP7JnJkcXVvO7XEuMXE7qGj1NrN+MLnysC958Dvo6w8Y29kZT7HqcP7PC9jb2RlPr/J0tS21MjOus7Q6NKqyLfIz7XEyv3X1tfKsvq9+NDQtKbA7aOsscjI57HIzNix0rXY1rehorXn19PK6bDmyKi1yKOssqLS1LTLwLTQ+7jm1tjSqtfKsvq1xMv5yvSjrNXiyMPO3tDovOC53LXEyKXW0NDEu6+9u9LXs8nOqr/JxNyhozwvcD4NCjxwPr7fzOW/qreiyei8xtbQo6y+zcrHvNPD3Ly8yvW0+szmyMu1xLHKvKOjrLK7yLvIzrrOx6nD+7e9t6i2vLvhsbvEo7fCo6y2+MfSxKO3wrXEs8mxvryrtc2jrM/gt7SjrNHp1qS1xLPJsb7ItLrcuN+ho77fzOW1xLzTw9y78tHp1qS8vMr1o6zH67LOv7zHsMPmtcTVwr3ao6zV4sDvztLDx73pydzS2srpysfI57rOyrnTw8epw/u8vMr1tcShozwvcD4NCjxwPtLayunSsr7fsbjHqcP7xNzBpqOs1ruyu7n9o6zEv8eww7vT0LWltsDM4bmpPGNvZGU+x6nD+9DFz6I8L2NvZGU+tcSy2df3uanTw7unyrnTw6OstvjKx82ouf3HqcP7o6zM7bzTwcs8Y29kZT7Wp7i2w9zC6zwvY29kZT65psTco6y21NPDu6fVyrrF18qy+te3vNPBy9K7suOxo7ukoaM8L3A+DQo8cD6jqDSjqdLayum1xNanuLbD3MLrPC9wPg0KPHA+PGNvZGU+x6nD+zwvY29kZT63vbeo1No8Y29kZT5tb2R1bGVzL3NpZ25hdHVyZXMuanM8L2NvZGU+zsS8/sDvo6zA4M28yOfPwqO6PC9wPg0KPHA+PGltZyBhbHQ9″signatures-class.png” src=”/uploadfile/Collfiles/20160629/20160629091342456.png” title=”\” />

我們還是從Api開始,代碼如下:

// modules/signatures.js文件
// 179行
router.map(shared, {
  "get /fee": "getFee",
  "put /": "addSignature"
});

// 188行
library.network.app.use('/api/signatures', router);

通過上面的代碼,可以瞭解簽名提供瞭兩個簡單的公共接口:

get /api/signatures/fee -> shared.getFee
put /api/signatures/ -> shared.addSignature //簽名操作

顯然,最核心的方法也就是shared.addSignature,代碼:

// 215行
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, // 297行
                                sender: account,
                                keypair: keypair,
                                requester: keypair,
                                secondKeypair: secondKeypair,

                            });
                        } catch (e) {
                            return cb(e.toString());
                        }
            ...         
}

毫無疑問,支付密碼也是一個簡單的交易(交易類型TransactionTypes.SIGNATURE,見297行)。基於此,我們不難想象,添加類似比特幣的簽名功能也是件非常簡單的事情,我們會在億書下一個版本裡添加這項功能,具體請關註 億書幣版本庫 最新進展。

多重簽名

上面我們提到,比特幣的匿名性,使交易處於不可信之中,最終導致用戶不敢交易。有瞭簽名功能,就有瞭確認雙方信息的有效手段,問題總算有瞭解決方案。聰明的小夥伴會發現,簽名和驗證過程除瞭繁瑣,並沒有讓我們覺得比使用第三方平臺更有效、更安全。有沒有更好的解決方案呢?回答是:有,那就是多重簽名。

(1)基本概念

多重簽名,可以簡單的理解為一個數字資產的多個簽名。簽名標定的是數字資產所屬和權限,多重簽名預示著數字資產可由多人支配和管理。在加密貨幣領域,如果要動用一個加密貨幣地址的資金,通常需要該地址的所有人使用他的私鑰(由用戶專屬保護)進行簽名。那麼,多重簽名,就是動用這筆資金需要多個私鑰簽名,通常這筆資金或數字資產會保存在一個多重簽名的地址或帳號裡。這就好比,我們工作中有一份文件,需要多個部門簽署才能生效一樣。

在實際的操作過程中,一個多重簽名地址可以關聯n個私鑰,在需要轉賬等操作時,隻要其中的m個私鑰簽名就可以把資金轉移瞭,其中m要小於等於n,也就是說m/n小於1,可以是2/3, 3/5等等,是要在建立這個多重簽名地址的時候確定好的。

(2)工作原理

數字資產在某種情況下,需要多人支配。換句話說,在某些特定條件下,數字資產如果無法確認歸屬某個特定的人,那麼最好讓相關人共同簽署它的所有權。

仍然舉上面的例子,在Alice發貨之後,Imfly收到貨之前,這筆錢應該由第三方信用比較高的中介暫時保存,這個階段,這筆錢要麼是Alice的,要麼是Imfly的,最終的歸屬要看Imfly是否收到貨。所以,這個第三方,無論如何都是應該有的,不然Imfly就要承擔大部分風險(因為比特幣的單向不可逆,Imfly發送之後就沒有辦法收回瞭)

這樣一來,這筆錢的所屬關系,在交易過程中涉及到Alice、Imfly和平臺第三方(雖然不屬於它,但它有權裁定資金去向),那麼就應該由他們三方簽名,因此網上購物就是典型的多重簽名的例子。其多重簽名模型就是2/3,也就是說隻要他們中的兩個簽名,資金就可以被轉移。

具體到這個例子,Imfly把錢打給一個關聯三方私鑰的多重簽名地址,如果整個交易過程順利,隻要Alice和Imfly兩個簽名,這筆錢就會順利到達Alice手裡。如果不順利,他們任何一人提出仲裁,平臺第三方調查之後,通過簽名就能把這筆錢轉給Alice或退回Imfly。這非常類似淘寶和京東的模式,但是比他們更加便捷和安全,至少不用擔心第三方倒閉、挪用資金或攜款跑路。

(3)應用場景

很顯然,多重簽名給瞭加密貨幣騰飛的翅膀,讓它單一單項支付的能力更具吸引力,讓加密貨幣技術應用到各行各業成為可能。這裡簡單的羅列幾個應用場景,供探索和思考:

電子商務。比較常見的是2/3的模式。上面電子商務網站的例子,就是最典型的場景之一,目前已經有成功的案例瞭。延伸一下,這類應用本質就是中介,所以還可用在各類中介機構性質的服務上。 財產分割。比如夫妻雙方共有財產,可以使用1/2的模式,一個賬戶誰都可以使用,跟各自擁有帳號一樣,好處是系統忠實記錄瞭每個人的花銷,鬧掰的時候很容易清算。擴展到公司合夥經營,可以使用1/n模式,n個人合夥人,都可以直接支配共有資金,具體清算時,一目瞭然。 資金監管。其實,這是多重簽名的最直接作用,一筆錢需要多個人簽名才能使用,任何一個人都無法直接動用資金,這在生活中太常見瞭,隻要靈活設置多重簽名的比重模式,就能解決生活中很多問題。比如,接著上面夫妻的例子,夫妻要儲備一筆資金,供孩子上大學使用,在這之前誰都不能動,那麼把模式改為2/2,不僅限制瞭夫妻雙方,也給黑客攻擊增加瞭難度。

多重簽名的設計,讓各種業務去中心化充滿無限可能。

(4)億書的多重簽名

多重簽名方法在modules/multisignatures.js文件裡,類圖如下:

multisignatures-class.png

實現Api的代碼如下:

// 318行
router.map(shared, {
  "get /pending": "pending", // Get pending transactions
  "post /sign": "sign", // Sign transaction
  "put /": "addMultisignature", // Add multisignature
  "get /accounts": "getAccounts"
});

// 329行
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方法,對應的自然是更新操作,不查看代碼也可以猜想到,該功能應該是在已有帳號基礎上的操作,從客戶端錢包設置菜單裡,可以看到如圖操作:

addMultisignature.png

看看shared.addMultisignature的源代碼如下:

// modules/multisignatures.js文件
shared.addMultisignature = function (req, cb) {
    var body = req.body;
    library.scheme.validate(body, {
        ...

    // 732行
        required: ['min', 'lifetime', 'keysgroup', 'secret']
    }, function (err) {
      ...

        library.balancesSequence.add(function (cb) {
            modules.accounts.getAccount({publicKey: keypair.publicKey.toString('hex')}, function (err, account) {
                ...

        // 767行
                try {
                    var transaction = library.logic.transaction.create({
                        type: TransactionTypes.MULTI, // 769行
                        sender: account,
                        keypair: keypair,
                        secondKeypair: secondKeypair,
                        min: body.min,
                        keysgroup: body.keysgroup,
                        lifetime: body.lifetime
                    });
                } catch (e) {
                    return cb(e.toString());
                }

                ...
};

從732行可知,創建一個多重簽名,必須’min’, ‘lifetime’, ‘keysgroup’, ‘secret’這四參數(其實,一個默認參數就是當前帳號),min代表上面講到的m值,即需要確認的人數;lifetime代表生命周期;keysgroup包含多重簽名關聯的全部帳號,它是數組類型,包含的元素個數就是n;secret是用戶密碼,與用戶私鑰對應。

經過一系列的驗證之後,作為一個交易(交易類型TransactionTypes.MULTI,769行)保存到數據庫(區款鏈)裡。創建成功的帳號,可以顯示多重帳號菜單,對交易進行操作。接下來,自然應該能夠查看全部關聯的帳號(請看shared.getAccounts方法),查看待確認的交易(請看shared.pending方法),這兩個方法僅僅是簡單的查詢,沒什麼難度,這裡不再浪費篇幅。

如果用戶同意交易,就可以對待確認的交易進行簽名(shared.sign方法),這個方法的源碼如下:

// 586行
shared.sign = function (req, cb) {
    var body = req.body;
    library.scheme.validate(body, {
        ...
        required: ['transactionId', 'secret']
    }, function (err) {
        ...

    // 632行
        function done(cb) {
            library.balancesSequence.add(function (cb) {
        // 634行
                var transaction = modules.transactions.getUnconfirmedTransaction(body.transactionId);

                if (!transaction) {
                    return cb("Transaction not found");
                }

        // 640行
                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});
            });
        }

        ...
};

這個方法,相比單獨的簽名方法,不同的是單獨的簽名方法相當於一個新建交易,而這裡的多重簽名的用戶簽名,顯然僅僅是對未確認交易(634行)進行簽名確認(640行維護瞭一個簽名數組,641行的push方法把用戶簽名寫入數組)。而且,相比獨立簽名,驗證也更復雜,我們將在下一篇《交易》一文中集中討論驗證問題。您也可以結合下一篇的內容,閱讀和理解這裡的簽名方法。

總結

在加密貨幣裡,每一個交易都涉及到使用私鑰簽名,用於確認每筆資金所有人。確定瞭所有人,自然就確定瞭資金轉移的條件、目標和方向,就為我們下一步進行資金轉移操作奠定瞭基礎。

You May Also Like