JAVA 版本 personal_sign 签名验证2 (personal_sign portal与fluent的不同点)

此文主要对新钱包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;
}
1 Like

博主,可以分享个 solidity版本的 person_sign 签名验证的代码吗?想参考一下。

1 Like