MOAC BlockChain数据签名及验证
飞儿506
发表于 2022-12-20 23:36:45
194
0
0
本文使用智能合约完成对签名的验证,使用chain3.js完成对数据的签名以及和智能合约的交互。
环境:
MOAC版本:nuwa1.0.6.win.zip(本文在mainnet进行);
操作系统:64位Windows 10家庭版。: o, A5 m' B# N; Y' y
14 M- c. M- x3 R9 E1 k% F
签名' Q0 ]# Y2 Y% M
实施签名需要两个部分:待签名的数据 + 实施签名的账户。签名过程可以使用chain3.mc.sign()来实现,具体代码为:
var Chain3 = require(‘chain3’);/ i" L/ K0 ~/ \
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!”);9 U( R& O+ i G6 y
var signedData = chain3.mc.sign(account, sha3Msg);5 g% k# G6 I4 R
console.log("account: " + account);* ]& t) {1 v/ @& Z
console.log("sha3Msg: " + sha3Msg);6 @% w! ?/ d+ r0 L: M$ k, R
console.log("Signed data: " + signedData);
在上面的代码中,先将要签名的数据"HELLO MOAC!"生成哈希串,使用chain3.sha3(“HELLO MOAC!”)。接着我们使用当前连接节点的第一个默认帐户进行签名。此时需要chain3.personal.unlockAccount(chain3.mc.accounts[0], “xxxxxxxxxxxx”, 1000)来打开数据签名所使用帐户。需要注意的是,当你打开你的帐户时,可能有安全风险。因为其它程序也可以通过访问节点进行类似的sign,这意味着,他们可以伪造你的数据,包括以你的名义发起交易,转走你的钱。" C# y, t3 U/ f
运行的结果:9 ]0 Y0 f& @( N! U, D% {
S( r/ {& ?7 p Z4 S: F
返回值Signed data总共132字节(去掉前面的’0x’的话是130字节)。在ECDSA(EC是“椭圆曲线”的简称,DSA是“数字签名算法”的简称)签名算法中,返回值可以分为三个部分:r, s, v。其中前0~66个字节为r, 66~130之间的字节为s, 130~132的字节为v。
接下来我们可以将它打印出来,在接下来验证签名的部分会用到。该部分完整的代码如下:
var Chain3 = require(‘chain3’);" e; h3 D: I) P) H& t
var chain3 = new Chain3(new Chain3.providers.HttpProvider(‘http://localhost:8545’));! u1 }3 o: b* @# m* P2 L
chain3.personal.unlockAccount(chain3.mc.accounts[0], “xxxxxxxxxxxx”, 1000); //实施签名要求解锁账户
var account = chain3.mc.accounts[0];
var sha3Msg = chain3.sha3(“HELLO MOAC!”);0 \ I/ y7 L; O4 a+ L% G/ T2 K
var signedData = chain3.mc.sign(account, sha3Msg);& b4 Q& O$ ^8 w, _7 c$ ?6 R& [( O* [8 U
console.log("account: " + account);
console.log("sha3Msg: " + sha3Msg);
console.log("Signed data: " + signedData);# i# I7 q# Y' m* Q* X! W
let r = signedData.slice(0, 66);& O0 m7 v# |; _9 F) g+ u
let s = ‘0x’ + signedData.slice(66, 130); }& U& r) ~* w
let v = ‘0x’ + signedData.slice(130, 132);
v = chain3.toDecimal(v);
console.log();) l- q/ ^) ^0 w( M/ s
console.log(‘r:’, r);% |) ~' o9 S( P7 ? u1 b. }
console.log(‘s:’, s);
console.log(‘v:’, v);( ?6 x5 j# @' i p8 V! e4 {- v
运行的结果:
2
验证: H L/ S, z: h
签名完成了,我们如何验证某些签名后的数据是哪个账户签名的呢?& C5 z. Y5 X9 ~7 o; N. I! X/ o
本例中,验证签名通过智能合约的ecrecover函数来实现。
ecrecover接收原始数据的哈希值(就是上面输出的sha3Msg)以及r/s/v等参数作为输入,返回实施该签名的账户地址。- d6 J- V' ~4 S3 z, S
因此我们只需要通过合约拿到实施签名的地址,和真正的地址进行对比,如果地址一致,就说明验证通过了。
智能合约代码如下:( P! e* y- V6 H+ J
pragma solidity ^0.4.15;
contract Auth {+ y5 [ B9 m* R5 y
function verify( bytes32 hash, uint8 v, bytes32 r, bytes32 s) constant returns(address retAddr) {
bytes memory prefix = “\x19MoacNode Signed Message:\n32”;
bytes32 prefixedHash = sha3(prefix, hash);0 D& A* n6 R$ O# L' B# R
return ecrecover(prefixedHash, v, r, s);
}
}
合约会为要签名的消息加上"\x19MoacNode Signed Message:\n32"前缀,所以实际上真正的被签名的数据并不是message的哈希值,而是message的哈希值加上前缀后再次哈希的值。要非常注意这一点,否则后期验证签名会不成功。( f! D) r4 a: s5 _0 v, o, w
将该智能合约部署到墨客区块链mainnet,拿到合约的地址以及abiString,用于接下来和合约进行交互的代码。
const contract=chain3.mc.contract(abiString).at(contractAddr);
console.log(contract.verify(sha3Msg, v, r, s));9 F3 F; a; G4 {2 t: G
console.log(account);
运行的结果:# Y1 g G. J- g0 Y5 A' c- q+ a2 W
可以看到实施签名的地址和验证后返回的地址一致,签名通过验证。3 f2 D8 H% k6 R
将合约的abiString保存为文件./Auth-abi.json;
本部分完整代码 moacAuth.js:3 T5 R5 e0 I# p4 g% O7 Q4 h
var Chain3 = require(‘chain3’);
var chain3 = new Chain3(new Chain3.providers.HttpProvider(‘http://localhost:8545’));: ?4 }4 ~4 X" B# k6 |% h
var contractAddr = “0x273C467c9404e6867D873203805aaFFAd20aAc93”;8 ~* r; S7 Y) b9 H0 \$ ?. C
const account = chain3.mc.accounts[0];
const abiString = require(’./Auth-abi.json’);
chain3.personal.unlockAccount(chain3.mc.accounts[0], “XXXXXXXXXXX”, 1000);/ H% t7 \/ w- B! {/ k* ^# u
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);/ z( _" z' M( J2 v+ ]
let v = ‘0x’ + signedData.slice(130, 132);6 z7 i6 x; S' M4 |. x9 ^& [
v = chain3.toDecimal(v);
const contract=chain3.mc.contract(abiString).at(contractAddr);6 _ }7 v- }$ t0 e
console.log(contract.verify(sha3Msg, v, r, s));
console.log(account);! X+ g7 ~1 P4 x+ @5 m9 N8 S
可以看到,在区块链中使用智能合约完成对数据的签名和验证还是比较简单的。逻辑图如下:1 O# O) X0 c8 U. N
3
直接签名与验证7 z3 x) z4 P( x3 F3 G
步骤1和步骤2,通过部署智能合约进行验证。
也可以直接使用私钥签名,然后通过解析签名信息得到公钥或者地址,这样就不需要部署智能合约。
//run ‘npm install eth-crypto --save’
const EthCrypto = require(‘eth-crypto’);
const identity = EthCrypto.createIdentity();
//显示私钥、公钥和地址' }+ a# `& v9 P6 R: r
console.log(‘privateKey:’+identity.privateKey);5 ^1 [. {$ w; E, R
console.log('publicKey: '+identity.publicKey);- K5 c0 J- `) e7 v q9 Z
console.log('address: '+identity.address);
//用私钥给明文签名
const message = ‘Hello World’; Y! m4 `' O: G5 |! b t8 W
const messageHash = EthCrypto.hash.keccak256(message);* T& c! q/ w# |5 r3 F: ]+ p
const signature = EthCrypto.sign(
identity.privateKey, // privateKey
messageHash // hash of message; ?1 O+ k' P* P: [2 Q% P) Y# b# K
);
console.log();
console.log('signature: '+signature);
//使用签名信息+明文
//解析出签名者地址' B8 w8 o5 l% Y5 W
const signerAddress = EthCrypto.recover(
signature,5 {5 h! ?) f) O% _
EthCrypto.hash.keccak256(message) // signed message hash
);, k9 \" Z3 b0 `+ k1 c+ O
console.log();* R! F5 m; u+ Z) w
console.log('signerAddress: '+signerAddress);2 N- ]9 Q, P3 S' p; G
//使用签名信息+明文7 T: G" F! E& Q9 y$ p
//解析出签名者公钥
const signerPublic = EthCrypto.recoverPublicKey(
signature, // signature1 D' r: y4 Q" t2 o, ]; |; F
EthCrypto.hash.keccak256(message) // message hash! q& l+ k3 B C/ h/ K5 m
);
console.log();0 p: L# P" G6 p7 G% Z
console.log('signerPublic: '+signerPublic);
运行结果:
成为第一个吐槽的人