MOAC BlockChain数据签名及验证
飞儿506
发表于 2022-12-20 23:36:45
199
0
0
本文使用智能合约完成对签名的验证,使用chain3.js完成对数据的签名以及和智能合约的交互。1 l C; w8 O p: A
环境:
MOAC版本:nuwa1.0.6.win.zip(本文在mainnet进行);' w z0 n8 c/ _$ u7 m( V
操作系统:64位Windows 10家庭版。
1; b8 r/ ~8 H& @% i5 b- ]6 l9 s
签名
实施签名需要两个部分:待签名的数据 + 实施签名的账户。签名过程可以使用chain3.mc.sign()来实现,具体代码为:
var Chain3 = require(‘chain3’);
var chain3 = new Chain3(new Chain3.providers.HttpProvider(‘http://localhost:8545’));
chain3.personal.unlockAccount(chain3.mc.accounts[0], “xxxxxxxxxxxx”, 1000); //实施签名要求解锁账户
var account = chain3.mc.accounts[0];* l, N, x! `8 J3 n
var sha3Msg = chain3.sha3(“HELLO MOAC!”);; u- }6 I! k# ?/ L' o' G7 | G
var signedData = chain3.mc.sign(account, sha3Msg);
console.log("account: " + account);! y( G; `: k- y: }. S6 `
console.log("sha3Msg: " + sha3Msg);
console.log("Signed data: " + signedData);
在上面的代码中,先将要签名的数据"HELLO MOAC!"生成哈希串,使用chain3.sha3(“HELLO MOAC!”)。接着我们使用当前连接节点的第一个默认帐户进行签名。此时需要chain3.personal.unlockAccount(chain3.mc.accounts[0], “xxxxxxxxxxxx”, 1000)来打开数据签名所使用帐户。需要注意的是,当你打开你的帐户时,可能有安全风险。因为其它程序也可以通过访问节点进行类似的sign,这意味着,他们可以伪造你的数据,包括以你的名义发起交易,转走你的钱。! M' Q+ i( l/ V: P7 h( y8 C4 w, Q7 \
运行的结果:. t; b: {$ i; E/ P% Y: s4 z6 j
返回值Signed data总共132字节(去掉前面的’0x’的话是130字节)。在ECDSA(EC是“椭圆曲线”的简称,DSA是“数字签名算法”的简称)签名算法中,返回值可以分为三个部分:r, s, v。其中前0~66个字节为r, 66~130之间的字节为s, 130~132的字节为v。" ^0 b6 ^- c8 C6 ?% Q; t
接下来我们可以将它打印出来,在接下来验证签名的部分会用到。该部分完整的代码如下:
var Chain3 = require(‘chain3’);
var chain3 = new Chain3(new Chain3.providers.HttpProvider(‘http://localhost:8545’));
chain3.personal.unlockAccount(chain3.mc.accounts[0], “xxxxxxxxxxxx”, 1000); //实施签名要求解锁账户 Z0 X+ f6 g# F& o/ ^
var account = chain3.mc.accounts[0];! U1 q% B- f. [. v+ W
var sha3Msg = chain3.sha3(“HELLO MOAC!”);
var signedData = chain3.mc.sign(account, sha3Msg);
console.log("account: " + account);
console.log("sha3Msg: " + sha3Msg);5 X! W) N# P F' L; @- D8 ^
console.log("Signed data: " + signedData);
let r = signedData.slice(0, 66);0 J7 N6 C, k8 [* u: S
let s = ‘0x’ + signedData.slice(66, 130);
let v = ‘0x’ + signedData.slice(130, 132);( Z2 F3 S7 j! d1 I" ?, m2 [: A( v3 E
v = chain3.toDecimal(v);
console.log();
console.log(‘r:’, r);
console.log(‘s:’, s);. O% }+ A7 B+ f
console.log(‘v:’, v);
运行的结果:" M3 N3 F( G9 ?3 z! T
( ^* a, e3 ]5 V% C+ `
28 L- r) `+ H( Q$ u
验证1 W9 |- c+ |& V/ N5 X; W
签名完成了,我们如何验证某些签名后的数据是哪个账户签名的呢?
本例中,验证签名通过智能合约的ecrecover函数来实现。
ecrecover接收原始数据的哈希值(就是上面输出的sha3Msg)以及r/s/v等参数作为输入,返回实施该签名的账户地址。/ E2 d7 v9 B: E- E- D4 w
因此我们只需要通过合约拿到实施签名的地址,和真正的地址进行对比,如果地址一致,就说明验证通过了。
智能合约代码如下:
pragma solidity ^0.4.15;* _' ` H1 N) c' F( T- ?) g
contract Auth {6 Z- W& i2 |- S' P8 U% J s* _
function verify( bytes32 hash, uint8 v, bytes32 r, bytes32 s) constant returns(address retAddr) {: }/ t1 X x; _! l
bytes memory prefix = “\x19MoacNode Signed Message:\n32”;! Z {# R `4 u3 l
bytes32 prefixedHash = sha3(prefix, hash);! \7 L/ K8 f( g: }5 ^" {( Q
return ecrecover(prefixedHash, v, r, s);/ ?% h3 b0 F0 j- x
}5 `- v: z6 j3 S3 d( j
}
合约会为要签名的消息加上"\x19MoacNode Signed Message:\n32"前缀,所以实际上真正的被签名的数据并不是message的哈希值,而是message的哈希值加上前缀后再次哈希的值。要非常注意这一点,否则后期验证签名会不成功。
将该智能合约部署到墨客区块链mainnet,拿到合约的地址以及abiString,用于接下来和合约进行交互的代码。
const contract=chain3.mc.contract(abiString).at(contractAddr);
console.log(contract.verify(sha3Msg, v, r, s));
console.log(account);
运行的结果:+ p; r$ E- C" {2 {0 H7 s
可以看到实施签名的地址和验证后返回的地址一致,签名通过验证。
将合约的abiString保存为文件./Auth-abi.json;
本部分完整代码 moacAuth.js:0 I4 W9 O; ~* |* O
var Chain3 = require(‘chain3’);
var chain3 = new Chain3(new Chain3.providers.HttpProvider(‘http://localhost:8545’));+ ]+ ~1 m1 c/ T* h& n
var contractAddr = “0x273C467c9404e6867D873203805aaFFAd20aAc93”;* d2 X* S0 X3 A0 \
const account = chain3.mc.accounts[0];
const abiString = require(’./Auth-abi.json’);5 z$ I' K' o& o1 `, b! \9 N6 M% Y
chain3.personal.unlockAccount(chain3.mc.accounts[0], “XXXXXXXXXXX”, 1000);
let sha3Msg = chain3.sha3(“HELLO MOAC!”);# {* B/ X. ?! u! E8 F/ b7 k
let signedData = chain3.mc.sign(account, sha3Msg);
let r = signedData.slice(0, 66);
let s = ‘0x’ + signedData.slice(66, 130);
let v = ‘0x’ + signedData.slice(130, 132);# z8 u2 d t8 R2 w# k
v = chain3.toDecimal(v);% n( D8 j9 v( h( T
const contract=chain3.mc.contract(abiString).at(contractAddr);
console.log(contract.verify(sha3Msg, v, r, s));, b) m& y" M# {
console.log(account);
可以看到,在区块链中使用智能合约完成对数据的签名和验证还是比较简单的。逻辑图如下:
) z) K8 p$ O( o+ C ^) |
3
直接签名与验证0 ? o- r$ |$ @2 P* d9 B8 a. i* l
步骤1和步骤2,通过部署智能合约进行验证。$ u9 X) n7 v4 P7 U$ o* `' Y* _
也可以直接使用私钥签名,然后通过解析签名信息得到公钥或者地址,这样就不需要部署智能合约。$ }9 t0 y3 z% _# g. T- W1 d! d
//run ‘npm install eth-crypto --save’
const EthCrypto = require(‘eth-crypto’);$ B1 t/ W. c% X/ Z( Z7 a
const identity = EthCrypto.createIdentity();
//显示私钥、公钥和地址0 A( M1 n! |6 m" T b5 @% K2 T* ~
console.log(‘privateKey:’+identity.privateKey);
console.log('publicKey: '+identity.publicKey);
console.log('address: '+identity.address);/ ]1 Z) J* ~. U0 t; v
//用私钥给明文签名
const message = ‘Hello World’;
const messageHash = EthCrypto.hash.keccak256(message);
const signature = EthCrypto.sign(4 j3 J/ O4 h0 ?0 d2 R3 g
identity.privateKey, // privateKey5 J" F1 v: G, N$ v
messageHash // hash of message
);+ @5 M6 S5 b, o
console.log();5 \( j( V7 U% [# j1 x- d. z
console.log('signature: '+signature);3 ~3 b4 j: I0 \/ G
//使用签名信息+明文0 q& b" E% ~( O% s* {; @1 S
//解析出签名者地址
const signerAddress = EthCrypto.recover(
signature,7 E" y2 G* s; p* M. }& }! \% m
EthCrypto.hash.keccak256(message) // signed message hash
);
console.log();
console.log('signerAddress: '+signerAddress);
//使用签名信息+明文4 _9 `" ]7 F; d/ s( c
//解析出签名者公钥7 q# ?; |: b. a0 q& |
const signerPublic = EthCrypto.recoverPublicKey(
signature, // signature
EthCrypto.hash.keccak256(message) // message hash
);
console.log();. E9 i0 R! G+ I
console.log('signerPublic: '+signerPublic);
运行结果:
成为第一个吐槽的人