MOAC BlockChain数据签名及验证
飞儿506
发表于 2022-12-20 23:36:45
125
0
0
本文使用智能合约完成对签名的验证,使用chain3.js完成对数据的签名以及和智能合约的交互。0 U+ p# c3 V! q$ W/ W
环境:
MOAC版本:nuwa1.0.6.win.zip(本文在mainnet进行);
操作系统:64位Windows 10家庭版。# y- k7 @+ ~8 q7 Z1 e
1) S; Q1 f" M) _/ [: N. D2 K
签名3 T- p( K9 d' ~; N" l2 m3 o, k
实施签名需要两个部分:待签名的数据 + 实施签名的账户。签名过程可以使用chain3.mc.sign()来实现,具体代码为:
var Chain3 = require(‘chain3’);
var chain3 = new Chain3(new Chain3.providers.HttpProvider(‘http://localhost:8545’));$ B8 t7 o( L4 {4 a4 ^. H
chain3.personal.unlockAccount(chain3.mc.accounts[0], “xxxxxxxxxxxx”, 1000); //实施签名要求解锁账户' o: M, U M$ D1 D: R8 y7 B
var account = chain3.mc.accounts[0];
var sha3Msg = chain3.sha3(“HELLO MOAC!”);
var signedData = chain3.mc.sign(account, sha3Msg);
console.log("account: " + account);
console.log("sha3Msg: " + sha3Msg);
console.log("Signed data: " + signedData);/ Q9 D1 J$ v) r/ c1 A
在上面的代码中,先将要签名的数据"HELLO MOAC!"生成哈希串,使用chain3.sha3(“HELLO MOAC!”)。接着我们使用当前连接节点的第一个默认帐户进行签名。此时需要chain3.personal.unlockAccount(chain3.mc.accounts[0], “xxxxxxxxxxxx”, 1000)来打开数据签名所使用帐户。需要注意的是,当你打开你的帐户时,可能有安全风险。因为其它程序也可以通过访问节点进行类似的sign,这意味着,他们可以伪造你的数据,包括以你的名义发起交易,转走你的钱。6 U/ U3 Y& Y8 w# r3 O! ~0 I0 b
运行的结果:
返回值Signed data总共132字节(去掉前面的’0x’的话是130字节)。在ECDSA(EC是“椭圆曲线”的简称,DSA是“数字签名算法”的简称)签名算法中,返回值可以分为三个部分:r, s, v。其中前0~66个字节为r, 66~130之间的字节为s, 130~132的字节为v。
接下来我们可以将它打印出来,在接下来验证签名的部分会用到。该部分完整的代码如下:7 h }' e B+ X$ l; L1 o/ [5 V
var Chain3 = require(‘chain3’);6 A/ O) p1 Y5 N$ [, |' v
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];; Z# Q b/ a$ A9 v* ]
var sha3Msg = chain3.sha3(“HELLO MOAC!”);( E/ ]# v: p9 M
var signedData = chain3.mc.sign(account, sha3Msg);
console.log("account: " + account);/ [# Y# v. L- ]1 d1 l- o6 A
console.log("sha3Msg: " + sha3Msg);$ H% S0 ^5 h# A! B
console.log("Signed data: " + signedData);
let r = signedData.slice(0, 66);
let s = ‘0x’ + signedData.slice(66, 130);7 p6 d# \* e! D+ o
let v = ‘0x’ + signedData.slice(130, 132);
v = chain3.toDecimal(v);
console.log();
console.log(‘r:’, r); Y: V- K' H! \4 ^/ _6 L; Q
console.log(‘s:’, s);1 D Q4 U1 a Y5 @; P* h
console.log(‘v:’, v);; U% p) K6 F* ^8 T) e
运行的结果:
27 `7 b v& H* ~! v
验证6 I- N5 G/ K' A9 g
签名完成了,我们如何验证某些签名后的数据是哪个账户签名的呢?6 g. F0 o s' s' V0 e2 y. ?, T
本例中,验证签名通过智能合约的ecrecover函数来实现。& N6 b& e. C& j* t, N/ s
ecrecover接收原始数据的哈希值(就是上面输出的sha3Msg)以及r/s/v等参数作为输入,返回实施该签名的账户地址。
因此我们只需要通过合约拿到实施签名的地址,和真正的地址进行对比,如果地址一致,就说明验证通过了。1 a; j# W9 s' X
智能合约代码如下:" D: | x7 ~+ B( b2 Q3 Z% Q) l
pragma solidity ^0.4.15;
contract Auth {
function verify( bytes32 hash, uint8 v, bytes32 r, bytes32 s) constant returns(address retAddr) {
bytes memory prefix = “\x19MoacNode Signed Message:\n32”;# T% v- Z7 r6 v8 l
bytes32 prefixedHash = sha3(prefix, hash);- W. R" X# @! V+ {. v3 T! [
return ecrecover(prefixedHash, v, r, s);) |* d8 j$ D" z
}% r4 N' e9 z' Z7 c
}
合约会为要签名的消息加上"\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);
运行的结果:
可以看到实施签名的地址和验证后返回的地址一致,签名通过验证。
将合约的abiString保存为文件./Auth-abi.json;) Q) _, d) a- d* W0 L* Z7 G
本部分完整代码 moacAuth.js:
var Chain3 = require(‘chain3’);
var chain3 = new Chain3(new Chain3.providers.HttpProvider(‘http://localhost:8545’));
var contractAddr = “0x273C467c9404e6867D873203805aaFFAd20aAc93”;
const account = chain3.mc.accounts[0];
const abiString = require(’./Auth-abi.json’);
chain3.personal.unlockAccount(chain3.mc.accounts[0], “XXXXXXXXXXX”, 1000);
let sha3Msg = chain3.sha3(“HELLO MOAC!”);. @2 B) N: P1 b' C8 E, ]7 {
let signedData = chain3.mc.sign(account, sha3Msg);$ z8 N: ~6 N' V$ o0 @9 x* V5 x) ?
let r = signedData.slice(0, 66);% d3 U% B* L/ Y) S8 K
let s = ‘0x’ + signedData.slice(66, 130);
let v = ‘0x’ + signedData.slice(130, 132);
v = chain3.toDecimal(v);+ [) b+ E% L: S) W+ [" q$ { D
const contract=chain3.mc.contract(abiString).at(contractAddr);2 K; d) \" t, A/ d z
console.log(contract.verify(sha3Msg, v, r, s));
console.log(account);& r8 b5 u$ u3 e
可以看到,在区块链中使用智能合约完成对数据的签名和验证还是比较简单的。逻辑图如下:( J- ]. S$ U# B& _. w b! c# u
3
直接签名与验证
步骤1和步骤2,通过部署智能合约进行验证。: W0 |, ]- N, r; {. t. \ P: Z
也可以直接使用私钥签名,然后通过解析签名信息得到公钥或者地址,这样就不需要部署智能合约。, ~: V$ v% V1 O+ t- W& D2 T
//run ‘npm install eth-crypto --save’
const EthCrypto = require(‘eth-crypto’);% A2 n0 K: V& f* Z' t- f4 V
const identity = EthCrypto.createIdentity();
//显示私钥、公钥和地址
console.log(‘privateKey:’+identity.privateKey);4 _7 | F6 f: \ T6 f- t$ \
console.log('publicKey: '+identity.publicKey);7 C/ R B, q( n. }8 r5 E% g
console.log('address: '+identity.address);
//用私钥给明文签名
const message = ‘Hello World’;$ m1 z9 ^3 E* ^7 N( k
const messageHash = EthCrypto.hash.keccak256(message);, s! N( b7 ?. F( r/ F) J9 ~& K5 O8 p
const signature = EthCrypto.sign(3 e3 ?) D( L. t, J5 g
identity.privateKey, // privateKey
messageHash // hash of message
);
console.log();( h1 u6 a0 I+ j8 o5 h7 i
console.log('signature: '+signature);
//使用签名信息+明文
//解析出签名者地址9 C' {. @" |. r$ m, r
const signerAddress = EthCrypto.recover(4 R5 a3 _' a+ v# g
signature,3 k) c" M6 s. Y( a
EthCrypto.hash.keccak256(message) // signed message hash) _7 f9 G) x' A
);
console.log();- s G& i/ D1 b! M/ q5 z0 \- T
console.log('signerAddress: '+signerAddress);
//使用签名信息+明文
//解析出签名者公钥
const signerPublic = EthCrypto.recoverPublicKey(
signature, // signature
EthCrypto.hash.keccak256(message) // message hash8 |; u0 }2 C2 y4 w/ p* v
);. p, h6 |4 O, Q, D( j
console.log();
console.log('signerPublic: '+signerPublic);0 z2 K$ E, l0 s7 R
运行结果:
成为第一个吐槽的人