MOAC BlockChain数据签名及验证
飞儿506
发表于 2022-12-20 23:36:45
149
0
0
本文使用智能合约完成对签名的验证,使用chain3.js完成对数据的签名以及和智能合约的交互。. Q" L) W0 ^& l8 M d' R
环境:+ _* k" e) ~7 N8 W
MOAC版本:nuwa1.0.6.win.zip(本文在mainnet进行);1 Z) ~. O+ |: D+ E8 |) W% T* x
操作系统:64位Windows 10家庭版。1 l. N9 w/ j/ d
1
签名
实施签名需要两个部分:待签名的数据 + 实施签名的账户。签名过程可以使用chain3.mc.sign()来实现,具体代码为:5 A9 w+ ^; b) Y- z& J3 y
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!”);( ~8 w1 d: X4 t/ S' v* @$ H; N7 A0 @
var signedData = chain3.mc.sign(account, sha3Msg);1 l' u x3 l0 [; ~. w
console.log("account: " + account);' F" B/ b/ C7 K. k
console.log("sha3Msg: " + sha3Msg);# C1 s6 V7 A u) \1 x
console.log("Signed data: " + signedData);
在上面的代码中,先将要签名的数据"HELLO MOAC!"生成哈希串,使用chain3.sha3(“HELLO MOAC!”)。接着我们使用当前连接节点的第一个默认帐户进行签名。此时需要chain3.personal.unlockAccount(chain3.mc.accounts[0], “xxxxxxxxxxxx”, 1000)来打开数据签名所使用帐户。需要注意的是,当你打开你的帐户时,可能有安全风险。因为其它程序也可以通过访问节点进行类似的sign,这意味着,他们可以伪造你的数据,包括以你的名义发起交易,转走你的钱。
运行的结果:
返回值Signed data总共132字节(去掉前面的’0x’的话是130字节)。在ECDSA(EC是“椭圆曲线”的简称,DSA是“数字签名算法”的简称)签名算法中,返回值可以分为三个部分:r, s, v。其中前0~66个字节为r, 66~130之间的字节为s, 130~132的字节为v。
接下来我们可以将它打印出来,在接下来验证签名的部分会用到。该部分完整的代码如下:
var Chain3 = require(‘chain3’);; J5 {. F7 M5 y7 |
var chain3 = new Chain3(new Chain3.providers.HttpProvider(‘http://localhost:8545’));8 S% P. I# T; T# x3 b6 p2 B6 q
chain3.personal.unlockAccount(chain3.mc.accounts[0], “xxxxxxxxxxxx”, 1000); //实施签名要求解锁账户
var account = chain3.mc.accounts[0];4 ~ ]0 V) d }: D
var sha3Msg = chain3.sha3(“HELLO MOAC!”);( g- d% ~+ d; v2 X* G$ X) i7 G
var signedData = chain3.mc.sign(account, sha3Msg);" j$ O3 n, q* K. t
console.log("account: " + account);
console.log("sha3Msg: " + sha3Msg);* _6 X r# S6 ]1 ^$ d2 p6 Q
console.log("Signed data: " + signedData);
let r = signedData.slice(0, 66);8 }% H0 y1 |9 v, ~6 W4 F) U
let s = ‘0x’ + signedData.slice(66, 130);; P9 u+ r5 o4 v0 D, d" m) t/ {, t
let v = ‘0x’ + signedData.slice(130, 132);( e& o) ~- z' N; k. f& Y) p6 n( G+ O
v = chain3.toDecimal(v);$ z# u, q* G ]& l$ Z: x2 O
console.log();0 Q) E* k, U) q B$ c# W. ~
console.log(‘r:’, r);
console.log(‘s:’, s);4 D, ?- Q2 y3 R
console.log(‘v:’, v);
运行的结果:) G. s7 h4 b* C9 T
! \5 M- y; O# P. R
2" v7 N5 l( d0 G3 Q: F
验证
签名完成了,我们如何验证某些签名后的数据是哪个账户签名的呢?
本例中,验证签名通过智能合约的ecrecover函数来实现。
ecrecover接收原始数据的哈希值(就是上面输出的sha3Msg)以及r/s/v等参数作为输入,返回实施该签名的账户地址。
因此我们只需要通过合约拿到实施签名的地址,和真正的地址进行对比,如果地址一致,就说明验证通过了。
智能合约代码如下:6 {1 n* _$ `8 z
pragma solidity ^0.4.15;2 V* T3 w0 j( ^9 L
contract Auth {# F0 M. ]( \# Y- r
function verify( bytes32 hash, uint8 v, bytes32 r, bytes32 s) constant returns(address retAddr) {* f% E8 `) L7 ]7 S
bytes memory prefix = “\x19MoacNode Signed Message:\n32”;
bytes32 prefixedHash = sha3(prefix, hash);) W8 S1 d7 \# \) d: ^4 s5 X
return ecrecover(prefixedHash, v, r, s);/ S7 i" n& r' L
}
}
合约会为要签名的消息加上"\x19MoacNode Signed Message:\n32"前缀,所以实际上真正的被签名的数据并不是message的哈希值,而是message的哈希值加上前缀后再次哈希的值。要非常注意这一点,否则后期验证签名会不成功。
将该智能合约部署到墨客区块链mainnet,拿到合约的地址以及abiString,用于接下来和合约进行交互的代码。# `$ |# n5 ~# M- m
const contract=chain3.mc.contract(abiString).at(contractAddr);
console.log(contract.verify(sha3Msg, v, r, s));
console.log(account);
运行的结果:3 X% N# X4 G( ^, P! ?
可以看到实施签名的地址和验证后返回的地址一致,签名通过验证。
将合约的abiString保存为文件./Auth-abi.json;
本部分完整代码 moacAuth.js: b* i: ?3 L" N
var Chain3 = require(‘chain3’);
var chain3 = new Chain3(new Chain3.providers.HttpProvider(‘http://localhost:8545’));
var contractAddr = “0x273C467c9404e6867D873203805aaFFAd20aAc93”;# R+ _ K. s s+ C" d( d
const account = chain3.mc.accounts[0];
const abiString = require(’./Auth-abi.json’);7 j% N+ R" N! T ] T/ c) S
chain3.personal.unlockAccount(chain3.mc.accounts[0], “XXXXXXXXXXX”, 1000);% ~0 ]8 i( P$ G& t8 M8 T
let sha3Msg = chain3.sha3(“HELLO MOAC!”);2 {( c2 f+ Q, {% Y& e- b
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);
v = chain3.toDecimal(v);
const contract=chain3.mc.contract(abiString).at(contractAddr);# _$ |9 @# f# z
console.log(contract.verify(sha3Msg, v, r, s));4 ]6 \! ]- k+ }3 _6 Q" R6 Y4 G; _/ u
console.log(account);
可以看到,在区块链中使用智能合约完成对数据的签名和验证还是比较简单的。逻辑图如下:
! x7 I4 s$ a$ _- `1 S
3! ]: w4 B: o4 v- m* O7 w4 t
直接签名与验证( B4 `- B9 C( v' z. M8 e! a# `
步骤1和步骤2,通过部署智能合约进行验证。* W- V8 w6 ]2 U. ~( n
也可以直接使用私钥签名,然后通过解析签名信息得到公钥或者地址,这样就不需要部署智能合约。3 p- ?* ]: W; V5 C6 o% P9 S$ h
//run ‘npm install eth-crypto --save’
const EthCrypto = require(‘eth-crypto’);
const identity = EthCrypto.createIdentity();" w' |0 o- l! X3 C" z
//显示私钥、公钥和地址' P+ L) P2 U" \2 K
console.log(‘privateKey:’+identity.privateKey);# } ], R* x# ?2 }% O6 ~+ K
console.log('publicKey: '+identity.publicKey);
console.log('address: '+identity.address);
//用私钥给明文签名* W( H! t/ E% j/ t$ M
const message = ‘Hello World’;7 h* z. J; ^( l, h' Q
const messageHash = EthCrypto.hash.keccak256(message);
const signature = EthCrypto.sign(* d( e+ a! ?# F& A
identity.privateKey, // privateKey( h1 J, } J5 I8 Q" m
messageHash // hash of message' `4 N1 v9 O$ V
);
console.log();5 y# E$ w* h( I/ g
console.log('signature: '+signature);4 Q: S# @5 m1 u! G, C- {# Q3 u4 K4 @
//使用签名信息+明文
//解析出签名者地址( ]0 I0 W x4 u6 r% e2 ]
const signerAddress = EthCrypto.recover(( K- j$ y* e( X" @4 R7 z" Y) O; n c
signature,
EthCrypto.hash.keccak256(message) // signed message hash
);4 O# v. w) x$ q5 D* C
console.log(); W; ^* q& R$ {' R, L! U" g) L
console.log('signerAddress: '+signerAddress);4 }' c7 m& R5 J$ `
//使用签名信息+明文
//解析出签名者公钥
const signerPublic = EthCrypto.recoverPublicKey(
signature, // signature4 x0 S; d7 u" H8 D Z* w& L2 ]' y
EthCrypto.hash.keccak256(message) // message hash0 t! V( {: x9 T% p8 `$ ?
); H& i. ]3 W- W' ^
console.log();
console.log('signerPublic: '+signerPublic);" X" Q* i6 n8 C. b
运行结果:
成为第一个吐槽的人