比特币签名(bitcoinjs)

签名

如果一个人持有私钥,他就可以使用私钥对任意的消息进行签名。即通过私钥sk对消息message进行签名,得到signature

let signature = sign(message, sk);

签名的目的是为了证明,该消息确实是由持有私钥sk的人发出的,任何其他人都可以对签名进行验证。验证方法是,由私钥持有人公开对应的公钥pk,其他人用公钥pk对消息message和签名signature进行验证:

let result = verify(message, signature, pk);

如果验证通过,则可以证明该消息确实是由持有私钥sk的人发出的,并且未经过篡改。

数字签名算法在电子商务、在线支付这些领域有非常重要的作用,因为它能通过密码学理论证明:

  1. 签名不可伪造,因为私钥只有签名人自己知道,所以其他人无法伪造签名;
  2. 消息不可篡改,如果原始消息被人篡改了,对签名进行验证将失败;
  3. 签名不可抵赖,如果对签名进行验证通过了,签名人不能抵赖自己曾经发过这一条消息。

简单地说来,数字签名可以防伪造,防篡改,防抵赖。

对消息进行签名,实际上是对消息的哈希进行签名,这样可以使任意长度的消息在签名前先转换为固定长度的哈希数据。对哈希进行签名相当于保证了原始消息的不可伪造性。

我们来看看使用ECDSA如何通过私钥对消息进行签名。关键代码是通过sign()方法签名,并获取一个ECSignature对象表示签名:

const bitcoin = require('bitcoinjs-lib');

let
    message = 'a secret message!',
    hash = bitcoin.crypto.sha256(message),
    wif = 'L16zYACWmkQXMUhYAzLA1dWEg95yv8VokSVFcadgpMFeTQoDzMPz',
    keyPair = bitcoin.ECPair.fromWIF(wif);
// 用私钥签名:
let signature = keyPair.sign(hash).toDER(); // ECSignature对象
// 打印签名:
console.log(signature.toString('hex'));
// 打印公钥以便验证签名:
console.log(keyPair.getPublicKeyBuffer().toString('hex'));

 

Run

3045022100d3fcd05aed64d7f7684dd921b11f3b4a10fb07c1418e458a43aaef64bf19d48802205a3bbe9a69b83a00c855b4a882b71c7af9c9ef03e1f62ff7f683378d42b2a994
0319e2c444740d73d54387d711306356bbc89c7a31b87749bedc6f8f07d5810004

ECSignature对象可序列化为十六进制表示的字符串。

在获得签名、原始消息和公钥的基础上,可以对签名进行验证。验证签名需要先构造一个不含私钥的ECPair,然后调用verify()方法验证签名:

const bitcoin = require('bitcoinjs-lib');

let signAsStr = '3045022100d3fcd05aed64d7f7684dd9'
              + '21b11f3b4a10fb07c1418e458a43aaef'
              + '64bf19d48802205a3bbe9a69b83a00c8'
              + '55b4a882b71c7af9c9ef03e1f62ff7f6'
              + '83378d42b2a994';

let
    signAsBuffer = Buffer.from(signAsStr, 'hex'),
    signature = bitcoin.ECSignature.fromDER(signAsBuffer), // ECSignature对象
    message = 'a secret message!',
    hash = bitcoin.crypto.sha256(message),
    pubKeyAsStr = '0319e2c444740d73d54387d711306356bbc89c7a31b87749bedc6f8f07d5810004',
    pubKeyAsBuffer = Buffer.from(pubKeyAsStr, 'hex'),
    pubKeyOnly = bitcoin.ECPair.fromPublicKeyBuffer(pubKeyAsBuffer); // 从public key构造ECPair

// 验证签名:
let result = pubKeyOnly.verify(hash, signature);
console.log('Verify result: ' + result);

 

Run

Verify result: true

注意上述代码只引入了公钥,并没有引入私钥。

修改signAsStrmessagepubKeyAsStr的任意一个变量的任意一个字节,再尝试验证签名,看看是否通过。

比特币对交易数据进行签名和对消息进行签名的原理是一样的,只是格式更加复杂。对交易签名确保了只有持有私钥的人才能够花费对应地址的资金。

小结

通过私钥可以对消息进行签名,签名可以保证消息防伪造,防篡改,防抵赖。

猜你喜欢

转载自blog.csdn.net/weixin_39842528/article/details/81112208