一:什么是r,s,v
1):v
, r
,s
是交易签名的值。它们可以用作获取任何以太坊帐户的公钥
2):r,
s是
ECDSA 签名的输出,v
是恢复 ID
3):v是怎么来的呢?
①简单理解V
偶数r
,我们得到v = 27
,奇数r
我们得到v = 28
②其他理解
需要为签名恢复正确的公钥,因为有时(即使概率很低)签名可以检索多个有效公钥。
v
这是一个备忘单:
27
未压缩的公钥,y-parity0
,幅度x
低于曲线阶数28
未压缩的公钥,y-parity1
,幅度x
低于曲线阶数29
未压缩的公钥,y-parity0
,幅度x
大于曲线阶30
未压缩的公钥,y-parity1
,幅度x
大于曲线阶31
压缩公钥,y-parity0
,幅度x
低于曲线阶32
压缩公钥,y-parity1
,幅度x
低于曲线阶33
压缩公钥,y-parity0
,幅度x
大于曲线阶34
压缩公钥,y-parity1
,幅度x
大于曲线阶
对于v >= 35
您可能正在按照EIP-155处理以太坊签名的任何人:
v = recovery_id + CHAIN_ID * 2 + 35
链接:signature - ECDSA: (v, r, s), what is v? - Bitcoin Stack Exchange
既然对 r,s,v有了简单理解,我们接下来看代码怎么实现
二:代码部分如何获取r, s,v
1)现有的工具包直接用
然后我们看怎么直接使用这个工具包
var { fromRpcSig } = require('ethereumjs-util');
const sig = fromRpcSig(sig); //sig是签名之后的字符串,不知道怎么签名消息或数据的会单独一篇文章讲
var r = '0x' + sig.r.toString('hex'); //这里为了方便输出,我们分别把他们转成了16进制字符串
var s = '0x' + sig.s.toString('hex');
var v = sig.v;
console.log("r:", r, "s: ", s, "v: ", v);
接下来我们看 ethereumjs-util 中 fromRpcSig 方法是怎么实现的
ethereumjs-util/signature.ts at master · ethereumjs/ethereumjs-util · GitHub
/**
* Convert signature format of the `eth_sign` RPC method to signature parameters
* NOTE: all because of a bug in geth: https://github.com/ethereum/go-ethereum/issues/2053
*/
export const fromRpcSig = function (sig: string): ECDSASignature {
const buf: Buffer = toBuffer(sig)
let r: Buffer
let s: Buffer
let v: number
if (buf.length >= 65) {
r = buf.slice(0, 32)
s = buf.slice(32, 64)
v = bufferToInt(buf.slice(64))
} else if (buf.length === 64) {
// Compact Signature Representation (https://eips.ethereum.org/EIPS/eip-2098)
r = buf.slice(0, 32)
s = buf.slice(32, 64)
v = bufferToInt(buf.slice(32, 33)) >> 7
s[0] &= 0x7f
} else {
throw new Error('Invalid signature length')
}
// support both versions of `eth_sign` responses
if (v < 27) {
v += 27
}
return {
v,
r,
s,
}
}
到此我们就简单介绍了以太坊中的 r,s,v,如何获取和实现原理,下篇文章我们将讲以太坊签名