源码地址:https://gitee.com/ttx_urey/web3j-sign
其他地方大多是使用web3的形式,web3j的基本没有
首先写一个简单智能合约用于验签测试
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Sign {
function genMsg(
uint256 num,
uint256[] memory list,
address _address
) public pure returns (bytes32) {
return keccak256(abi.encodePacked(num, list, _address));
}
function check(
uint256 num,
uint256[] memory list,
address _address,
bytes memory sig
) public pure returns (address) {
return recoverSigner(genMsg(num,list,_address),sig);
}
function splitSignature(bytes memory sig)
internal
pure
returns (
uint8,
bytes32,
bytes32
)
{
require(sig.length == 65);
bytes32 r;
bytes32 s;
uint8 v;
assembly {
// first 32 bytes, after the length prefix
r := mload(add(sig, 32))
// second 32 bytes
s := mload(add(sig, 64))
// final byte (first byte of the next 32 bytes)
v := byte(0, mload(add(sig, 96)))
}
return (v, r, s);
}
function recoverSigner(bytes32 message, bytes memory sig)
internal
pure
returns (address)
{
uint8 v;
bytes32 r;
bytes32 s;
(v, r, s) = splitSignature(sig);
return ecrecover(message, v, r, s);
}
}
java签名代码
package org.urey.web3j;
import java.util.ArrayList;
import java.util.List;
import org.springframework.security.crypto.codec.Hex;
import org.web3j.abi.TypeEncoder;
import org.web3j.abi.datatypes.Address;
import org.web3j.abi.datatypes.StaticArray;
import org.web3j.abi.datatypes.generated.Uint256;
import org.web3j.crypto.ECKeyPair;
import org.web3j.crypto.Hash;
import org.web3j.crypto.Sign;
import org.web3j.crypto.Sign.SignatureData;
public class Test {
// 钱包私匙(对应的钱包地址为:0x5ebacac108d665819398e5c37e12b0162d781398)
private static final String PRIVATE_KEY = "e62248374af86aa480f9cebd44f04cd02b915130d4fbda885a201488257b0a17";
public static void main(String[] args) throws Exception {
Uint256 num = new Uint256(11);
List<Uint256> list = new ArrayList<Uint256>();
list.add(new Uint256(2));
list.add(new Uint256(8));
list.add(new Uint256(555));
StaticArray<Uint256> staticArray = new StaticArray<Uint256>(Uint256.class, list) {
};
Address address = new Address("0x6cd2Bf22B3CeaDfF6B8C226487265d81164396C5");
StringBuilder msg = new StringBuilder();
msg.append(TypeEncoder.encode(num));
msg.append(TypeEncoder.encode(staticArray));
msg.append(address.toString().substring(2, address.toString().length()));
// System.out.println(TypeEncoder.encode(address));
// 0000000000000000000000006cd2bf22b3ceadff6b8c226487265d81164396c5
// 地址前面会补0,与solidity的abi.encodePacked不一致,
System.out.println("msg:" + msg);
byte[] bytes = Hex.decode(msg.toString());
ECKeyPair keyPair = ECKeyPair.create(Hex.decode(PRIVATE_KEY));
byte[] hash = Hash.sha3(bytes);
System.out.println("hash:" + new String(Hex.encode(hash)));
SignatureData signatureData = Sign.signMessage(hash, keyPair, false);
// SignatureData signatureData = Sign.signMessage(bytes, keyPair);
// 默认内部会再调用Hash.sha3
String sign = "0x" + new String(Hex.encode(signatureData.getR())) + new String(Hex.encode(signatureData.getS())) + new String(Hex.encode(signatureData.getV()));
System.out.println("sign:" + sign);
}
}
运行签名代码,得到结果:
msg:000000000000000000000000000000000000000000000000000000000000000b00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000022b6cd2bf22b3ceadff6b8c226487265d81164396c5
hash:0899fc1cac856eae1183ed64c439d6f907693cd4547372c78a489df4c4df3c91
sign:0x78bfe6a6e88713ffb51c40b11ad638627f88425bda9166de24ff6dc81432e22272bf31badca6029cabbc0bd1409a1c1f37b9a82bd55a9f995ae29eaad45756a81b
msg相当于abi.encodePacked(num, list, _address);
hash相当于keccak256(abi.encodePacked(num, list, _address));
用num=11,list=[2,8,555],_address=0x6cd2Bf22B3CeaDfF6B8C226487265d81164396C5,sig=0x78bfe6a6e88713ffb51c40b11ad638627f88425bda9166de24ff6dc81432e22272bf31badca6029cabbc0bd1409a1c1f37b9a82bd55a9f995ae29eaad45756a81b这些参数调用智能合约的check方法,可以得到验签的结果为0x5EbacaC108D665819398E5c37E12b0162D781398(忽略地址大小写),与钱包地址一致