MOAC BlockChain数据签名及验证
飞儿506
发表于 2022-12-20 23:36:45
126
0
0
本文使用智能合约完成对签名的验证,使用chain3.js完成对数据的签名以及和智能合约的交互。/ I( u1 C; ^6 J$ Z1 y
环境:. m" y4 r% F# x) z) @. t5 j% d
MOAC版本:nuwa1.0.6.win.zip(本文在mainnet进行);
操作系统:64位Windows 10家庭版。; F: n8 X* k. A7 ]* p5 S
1. n' }7 F0 d$ j$ e: G4 U
签名
实施签名需要两个部分:待签名的数据 + 实施签名的账户。签名过程可以使用chain3.mc.sign()来实现,具体代码为:
var Chain3 = require(‘chain3’);
var chain3 = new Chain3(new Chain3.providers.HttpProvider(‘http://localhost:8545’));9 Q$ F/ |+ f: D! ?+ i8 ~
chain3.personal.unlockAccount(chain3.mc.accounts[0], “xxxxxxxxxxxx”, 1000); //实施签名要求解锁账户
var account = chain3.mc.accounts[0];
var sha3Msg = chain3.sha3(“HELLO MOAC!”);
var signedData = chain3.mc.sign(account, sha3Msg);
console.log("account: " + account);( J7 r5 s- k4 ^ l
console.log("sha3Msg: " + sha3Msg);
console.log("Signed data: " + signedData);( J7 n7 b! c' k1 M
在上面的代码中,先将要签名的数据"HELLO MOAC!"生成哈希串,使用chain3.sha3(“HELLO MOAC!”)。接着我们使用当前连接节点的第一个默认帐户进行签名。此时需要chain3.personal.unlockAccount(chain3.mc.accounts[0], “xxxxxxxxxxxx”, 1000)来打开数据签名所使用帐户。需要注意的是,当你打开你的帐户时,可能有安全风险。因为其它程序也可以通过访问节点进行类似的sign,这意味着,他们可以伪造你的数据,包括以你的名义发起交易,转走你的钱。 `4 D3 a. a9 z8 \5 G# N* `
运行的结果:. I( n# a! K2 Z! R; e$ O; J' K1 W
返回值Signed data总共132字节(去掉前面的’0x’的话是130字节)。在ECDSA(EC是“椭圆曲线”的简称,DSA是“数字签名算法”的简称)签名算法中,返回值可以分为三个部分:r, s, v。其中前0~66个字节为r, 66~130之间的字节为s, 130~132的字节为v。- O. c' b2 C! m6 i% x1 t0 y
接下来我们可以将它打印出来,在接下来验证签名的部分会用到。该部分完整的代码如下:0 c& V( W; e/ Y+ M
var Chain3 = require(‘chain3’); O4 @9 Y7 x& ?* n- q; L
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!”);
var signedData = chain3.mc.sign(account, sha3Msg);( i4 _4 H7 C$ t
console.log("account: " + account);1 k2 y6 I, X# T* I1 Q/ P
console.log("sha3Msg: " + sha3Msg);
console.log("Signed data: " + signedData);6 `) a( B( m- E$ b# P4 W, H- S) ~
let r = signedData.slice(0, 66);
let s = ‘0x’ + signedData.slice(66, 130);. r. b% C+ b2 @6 @, R) V5 l, o+ h
let v = ‘0x’ + signedData.slice(130, 132);
v = chain3.toDecimal(v);1 D7 b4 }" U: J$ M6 N$ j
console.log();
console.log(‘r:’, r);
console.log(‘s:’, s);' ]+ G0 O( j3 r5 k8 A2 ?$ R
console.log(‘v:’, v);* y$ g: M8 ~: z9 P
运行的结果:
2
验证
签名完成了,我们如何验证某些签名后的数据是哪个账户签名的呢?! T8 Q4 }' c5 G F5 y) U
本例中,验证签名通过智能合约的ecrecover函数来实现。5 V/ m0 v" f! s' a3 }
ecrecover接收原始数据的哈希值(就是上面输出的sha3Msg)以及r/s/v等参数作为输入,返回实施该签名的账户地址。5 _8 I' p3 ]$ I& Q) R
因此我们只需要通过合约拿到实施签名的地址,和真正的地址进行对比,如果地址一致,就说明验证通过了。
智能合约代码如下:9 Q: v1 W$ ?" g2 t+ D5 p4 o
pragma solidity ^0.4.15;
contract Auth {- \6 ~# b2 U1 y* [4 G
function verify( bytes32 hash, uint8 v, bytes32 r, bytes32 s) constant returns(address retAddr) {6 D* z2 [0 T( X
bytes memory prefix = “\x19MoacNode Signed Message:\n32”;
bytes32 prefixedHash = sha3(prefix, hash); p S; V; D9 x6 Y1 J( p0 w
return ecrecover(prefixedHash, v, r, s);2 j7 n! ^$ d7 B/ h: t+ R0 P4 g: p
}
}! j1 j5 T. B1 P! 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));3 h3 `2 _; X6 ?# r
console.log(account);" q- ~% e4 J. d* Q# H
运行的结果:/ ?0 n, i3 C% U3 M' r
可以看到实施签名的地址和验证后返回的地址一致,签名通过验证。
将合约的abiString保存为文件./Auth-abi.json;
本部分完整代码 moacAuth.js:
var Chain3 = require(‘chain3’);9 z4 Y+ C+ X% Y! y
var chain3 = new Chain3(new Chain3.providers.HttpProvider(‘http://localhost:8545’));, ]0 E B/ Y- @* A( r+ s
var contractAddr = “0x273C467c9404e6867D873203805aaFFAd20aAc93”;
const account = chain3.mc.accounts[0];
const abiString = require(’./Auth-abi.json’);
chain3.personal.unlockAccount(chain3.mc.accounts[0], “XXXXXXXXXXX”, 1000);- {5 P2 ?9 J+ b
let sha3Msg = chain3.sha3(“HELLO MOAC!”);
let signedData = chain3.mc.sign(account, sha3Msg);
let r = signedData.slice(0, 66);, ~, R8 V' z; Q+ m" a
let s = ‘0x’ + signedData.slice(66, 130);+ y) z2 h7 G5 k: ]
let v = ‘0x’ + signedData.slice(130, 132);7 k0 u/ ~& [$ j* K* d0 J
v = chain3.toDecimal(v);/ S% j. g- u- R6 w! b5 ?+ U
const contract=chain3.mc.contract(abiString).at(contractAddr);
console.log(contract.verify(sha3Msg, v, r, s));
console.log(account);
可以看到,在区块链中使用智能合约完成对数据的签名和验证还是比较简单的。逻辑图如下:
3
直接签名与验证
步骤1和步骤2,通过部署智能合约进行验证。
也可以直接使用私钥签名,然后通过解析签名信息得到公钥或者地址,这样就不需要部署智能合约。
//run ‘npm install eth-crypto --save’8 D* C2 f, O! k- t5 z+ U, U' E
const EthCrypto = require(‘eth-crypto’);
const identity = EthCrypto.createIdentity();5 U8 ]+ ?1 Q+ \9 ^$ d Q' i) ^5 \. `
//显示私钥、公钥和地址
console.log(‘privateKey:’+identity.privateKey);: b# C2 z) c) Q
console.log('publicKey: '+identity.publicKey);
console.log('address: '+identity.address);+ g* g% l$ [; V4 a( T2 M5 k
//用私钥给明文签名4 J9 c9 e, s! E) E3 P: B
const message = ‘Hello World’;( v# m% f) `$ s- Y: F
const messageHash = EthCrypto.hash.keccak256(message);5 F5 r; G% J& S& w
const signature = EthCrypto.sign(
identity.privateKey, // privateKey- S7 _) d4 p2 u# C/ `0 q% d+ X; d
messageHash // hash of message
);/ z$ I& g3 k4 _1 n2 K
console.log();! X N2 O$ O8 f% [ V8 ?( u
console.log('signature: '+signature);
//使用签名信息+明文9 b1 e9 K3 r7 l8 q& D4 L1 f
//解析出签名者地址
const signerAddress = EthCrypto.recover(
signature,% m9 O' d( {& _5 \( o
EthCrypto.hash.keccak256(message) // signed message hash
);
console.log();" z: k( f* E" Q9 Q4 C7 ~# N2 ?
console.log('signerAddress: '+signerAddress);
//使用签名信息+明文: I- w& {5 a& K: W7 x6 z8 X
//解析出签名者公钥0 f: h& R9 H3 t: r! s0 n/ ^; b
const signerPublic = EthCrypto.recoverPublicKey(. N0 c" Q$ l8 ^/ c# J. S
signature, // signature
EthCrypto.hash.keccak256(message) // message hash/ G# M' x. J- c9 R5 O. M0 w6 v
);
console.log(); u7 P/ u9 U7 f7 h" h% `5 E
console.log('signerPublic: '+signerPublic);
运行结果:
成为第一个吐槽的人