MOAC BlockChain数据签名及验证
飞儿506
发表于 2022-12-20 23:36:45
196
0
0
本文使用智能合约完成对签名的验证,使用chain3.js完成对数据的签名以及和智能合约的交互。$ E' Q( @* Z: ^: X: V8 w
环境:
MOAC版本:nuwa1.0.6.win.zip(本文在mainnet进行);
操作系统:64位Windows 10家庭版。
1
签名
实施签名需要两个部分:待签名的数据 + 实施签名的账户。签名过程可以使用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];
var sha3Msg = chain3.sha3(“HELLO MOAC!”);# d+ q; M1 O1 T
var signedData = chain3.mc.sign(account, sha3Msg);, W" v+ p+ Y l" `# ]1 Z
console.log("account: " + account);
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,这意味着,他们可以伪造你的数据,包括以你的名义发起交易,转走你的钱。0 }" C- B. H$ H Z( G/ g8 J
运行的结果:7 i2 F- g! S/ |9 J6 j
0 L, A* i" W4 B; g: [
返回值Signed data总共132字节(去掉前面的’0x’的话是130字节)。在ECDSA(EC是“椭圆曲线”的简称,DSA是“数字签名算法”的简称)签名算法中,返回值可以分为三个部分:r, s, v。其中前0~66个字节为r, 66~130之间的字节为s, 130~132的字节为v。
接下来我们可以将它打印出来,在接下来验证签名的部分会用到。该部分完整的代码如下:; r8 {# R! V4 a+ C& \4 ~
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];
var sha3Msg = chain3.sha3(“HELLO MOAC!”);6 D6 B: p$ N0 y/ u! j
var signedData = chain3.mc.sign(account, sha3Msg);
console.log("account: " + account);3 F! N, U) [# f; y$ D
console.log("sha3Msg: " + sha3Msg);2 N+ G) h w9 e% \
console.log("Signed data: " + signedData);
let r = signedData.slice(0, 66);# B k$ T, X' C( m
let s = ‘0x’ + signedData.slice(66, 130);
let v = ‘0x’ + signedData.slice(130, 132);
v = chain3.toDecimal(v);
console.log();, A5 J$ ^5 Z# Y- I* d5 E/ f
console.log(‘r:’, r);
console.log(‘s:’, s);
console.log(‘v:’, v);2 L- a$ F& E( B! Z, {3 N5 u
运行的结果:
25 \& Y- H* A' f
验证! V6 V' r0 r2 V1 N! R0 g% y f
签名完成了,我们如何验证某些签名后的数据是哪个账户签名的呢?" b* | q& e8 y7 k) G) B
本例中,验证签名通过智能合约的ecrecover函数来实现。
ecrecover接收原始数据的哈希值(就是上面输出的sha3Msg)以及r/s/v等参数作为输入,返回实施该签名的账户地址。* }+ F1 a& W0 y
因此我们只需要通过合约拿到实施签名的地址,和真正的地址进行对比,如果地址一致,就说明验证通过了。+ f$ v i' W3 o2 f* S( l1 Y; \3 W
智能合约代码如下:
pragma solidity ^0.4.15;" a, {" H$ _) a' b
contract Auth {; l) T0 B, V2 o& u
function verify( bytes32 hash, uint8 v, bytes32 r, bytes32 s) constant returns(address retAddr) {
bytes memory prefix = “\x19MoacNode Signed Message:\n32”;6 O! F; V0 X: O/ ?+ ^, @
bytes32 prefixedHash = sha3(prefix, hash);
return ecrecover(prefixedHash, v, r, s);" o I' p/ [% U* I& A8 o
}
}
合约会为要签名的消息加上"\x19MoacNode Signed Message:\n32"前缀,所以实际上真正的被签名的数据并不是message的哈希值,而是message的哈希值加上前缀后再次哈希的值。要非常注意这一点,否则后期验证签名会不成功。
将该智能合约部署到墨客区块链mainnet,拿到合约的地址以及abiString,用于接下来和合约进行交互的代码。% F) i" R4 i w0 v1 D3 l1 \/ v
const contract=chain3.mc.contract(abiString).at(contractAddr);
console.log(contract.verify(sha3Msg, v, r, s));
console.log(account);& ^) r8 _7 C* {1 x1 d0 m
运行的结果:% E1 w" ^2 I7 D& N
可以看到实施签名的地址和验证后返回的地址一致,签名通过验证。" E0 N* b% B+ G% _) p" I" Y' d J
将合约的abiString保存为文件./Auth-abi.json;
本部分完整代码 moacAuth.js:2 e6 j; A0 S( @$ o
var Chain3 = require(‘chain3’);6 m' X. k' c3 \# y3 R
var chain3 = new Chain3(new Chain3.providers.HttpProvider(‘http://localhost:8545’));3 g7 R/ t# A* o% L
var contractAddr = “0x273C467c9404e6867D873203805aaFFAd20aAc93”;% A# {8 A/ E0 F. F v+ H( d3 r
const account = chain3.mc.accounts[0];5 j7 `( u. ^( e; K+ Z0 x% t6 {: i1 y
const abiString = require(’./Auth-abi.json’);
chain3.personal.unlockAccount(chain3.mc.accounts[0], “XXXXXXXXXXX”, 1000);
let sha3Msg = chain3.sha3(“HELLO MOAC!”);
let signedData = chain3.mc.sign(account, sha3Msg);
let r = signedData.slice(0, 66);
let s = ‘0x’ + signedData.slice(66, 130);1 @, V) G/ a9 D6 F1 q9 ~6 s
let v = ‘0x’ + signedData.slice(130, 132);
v = chain3.toDecimal(v);
const contract=chain3.mc.contract(abiString).at(contractAddr);
console.log(contract.verify(sha3Msg, v, r, s));2 C9 J) ]5 V5 e( M
console.log(account);
可以看到,在区块链中使用智能合约完成对数据的签名和验证还是比较简单的。逻辑图如下:
3/ `3 u" }! P7 G
直接签名与验证
步骤1和步骤2,通过部署智能合约进行验证。( b+ d9 i' N2 L
也可以直接使用私钥签名,然后通过解析签名信息得到公钥或者地址,这样就不需要部署智能合约。
//run ‘npm install eth-crypto --save’
const EthCrypto = require(‘eth-crypto’);
const identity = EthCrypto.createIdentity();: F' ~& Z" X; c" n0 S5 K( F
//显示私钥、公钥和地址; d- q* V( c8 ?+ W. t& Z
console.log(‘privateKey:’+identity.privateKey);+ S" G) r) H, u- W* e
console.log('publicKey: '+identity.publicKey);$ u6 V3 J; P% G3 g E: w
console.log('address: '+identity.address);+ c4 m3 n) B# c6 U. u: A
//用私钥给明文签名; g2 m h, Q$ l ?" [2 h. k0 k( M0 r
const message = ‘Hello World’;
const messageHash = EthCrypto.hash.keccak256(message);
const signature = EthCrypto.sign(9 M2 q& x; E. @) X5 q
identity.privateKey, // privateKey& T+ _9 h* K1 k: Y1 q4 o' H
messageHash // hash of message
);5 H9 C5 {4 n2 h! }
console.log();
console.log('signature: '+signature);
//使用签名信息+明文
//解析出签名者地址
const signerAddress = EthCrypto.recover(
signature, {9 B/ @" c. r
EthCrypto.hash.keccak256(message) // signed message hash
);
console.log();- C; q1 T% o$ }7 y2 l6 X. w
console.log('signerAddress: '+signerAddress);2 u( A* G/ x5 ? b: a+ i4 r3 k
//使用签名信息+明文
//解析出签名者公钥- ]. \. Q) j% a7 p2 _
const signerPublic = EthCrypto.recoverPublicKey(
signature, // signature0 y7 z3 Q4 J: O6 v2 [6 N3 s' x- V! s
EthCrypto.hash.keccak256(message) // message hash2 R# X6 q( n/ S4 f: S; N/ r! B& H
);% v( D& c; `5 y6 x, C( C! }
console.log();
console.log('signerPublic: '+signerPublic);" Z* D# Q! A6 }
运行结果:
成为第一个吐槽的人