此文主要对新钱包fluent的一些改动内容,portal不维护了,所以相关的上一篇文章可以舍弃了
先简单的说下之前的签名组合规则(不牵扯密码学部分)
主要从下面简单介绍下,或者直接看代码实现:代签名数据、签名验证、代码实现
v: QUANTITY - ECDSA recovery id
r: DATA, 32 Bytes - ECDSA signature r
s: DATA, 32 Bytes - ECDSA signature s
(详细的可以自行查阅资料,上面的为 https://eth.wiki/json-rpc/API 搜索eth_getTransactionByHash)
Portal personal_sign 代签名数据:
若签名 hello world,规则为:
“\u0019Conflux Signed Message:\n” + byte(hex(byte(hello world))) + len(byte(hex(byte(hello world))))
也就是之前写的那份代码
public static byte[] getMessageHash(String message) {
byte[] message = Numeric.toHexString(src.getBytes()).getBytes();
byte[] prefix = ("\u0019Conflux Signed Message:\n".concat(String.valueOf(message.length))).getBytes();
byte[] result = new byte[prefix.length + message.length];
System.arraycopy(prefix, 0, result, 0, prefix.length);
System.arraycopy(message, 0, result, prefix.length, message.length);
return result;
}
Fluent personal_sign 代签名数据:
与Portal类似,但是入参部分较为简单,直接是
“\u0019Conflux Signed Message:\n” + (byte(hello world))) + len((byte(hello world))
代码:
public static byte[] getMessageHash(byte[] message) {
byte[] prefix = ("\u0019Conflux Signed Message:\n".concat(String.valueOf(message.length))).getBytes();
byte[] result = new byte[prefix.length + message.length];
System.arraycopy(prefix, 0, result, 0, prefix.length);
System.arraycopy(message, 0, result, prefix.length, message.length);
return result;
}
更简单的写法:
String PERSONAL_MESSAGE_PREFIX = "\u0019Conflux Signed Message:\n";
String prefix = PERSONAL_MESSAGE_PREFIX + message.length();
byte[] msgHash = (prefix + message).getBytes();
fluent 签名
public static String signPrefixedCfxFluentMessage(String message, String privateKey) {
Credentials credentials = Credentials.create(privateKey);
Sign.SignatureData signatureData = Sign.signMessage(
getMessageHash(message.getBytes()), credentials.getEcKeyPair());
String r = Numeric.toHexStringNoPrefix(signatureData.getR());
String v = Numeric.toHexStringNoPrefix(signatureData.getV());
String s = Numeric.toHexStringNoPrefix(signatureData.getS());
log.info("hex.getR(): {}", r);
log.info("hex.getV(): {}", v);
log.info("hex.getS(): {}", s);
return "0x" + r + s + v;
}
Portal 签名验证
之前文章已提到 JAVA版本 personal_sign 签名验证
fluent签名验证
与eth几乎差不多,修改了prefix
public static String recoverFluentAddressFromSignature(String signature, String message) throws SignatureException {
String PERSONAL_MESSAGE_PREFIX = "\u0019Conflux Signed Message:\n";
String prefix = PERSONAL_MESSAGE_PREFIX + message.length();
byte[] msgHash = (prefix + message).getBytes();
byte[] signatureBytes = Numeric.hexStringToByteArray(signature);
byte v = signatureBytes[64];
if (v < 27) {
v += 27;
}
Sign.SignatureData sd = new Sign.SignatureData(
v,
(byte[]) Arrays.copyOfRange(signatureBytes, 0, 32),
(byte[]) Arrays.copyOfRange(signatureBytes, 32, 64));
boolean match = false;
BigInteger pubkey = Sign.signedMessageToKey(msgHash, sd);
String addressRecovered = "0x" + Keys.getAddress(pubkey);
log.info("-22-->" + addressRecovered);
String hexAddress = AddressType.User.normalize(addressRecovered);
log.info("--> " + hexAddress);
return hexAddress;
}