我在web3js中使用以下代码片段签名了一个数据字符串
var data = "hello world";
web3.personal.sign(web3.fromUtf8(data), web3.eth.accounts[0], function(error, result) {
if (!error) {
console.log(data);
} else {
console.log(error);
}
});现在,我正在尝试验证用于从web3j签名said字符串的地址。
public static boolean verifyAddressFromSignature(String address, String signature)
{
byte[] signatureBytes = Hash.sha3(signature).getBytes();
byte v = signatureBytes[64];
if(v < 27)
{
v += 27;
}
SignatureData sd = new SignatureData(v, (byte[]) Arrays.copyOfRange(signatureBytes, 0, 32), (byte[]) Arrays.copyOfRange(signatureBytes, 32, 64));
String addressRecovered = null;
boolean match = false;
// Iterate for each possible key to recover
for (int i = 0; i < 4; i++)
{
BigInteger publicKey = Sign.recoverFromSignature((byte) i, new ECDSASignature(new BigInteger(1, sd.getR()), new BigInteger(1, sd.getS())), signature.getBytes());
if (publicKey != null)
{
addressRecovered = "0x" + Keys.getAddress(publicKey);
System.out.println(addressRecovered);
if (addressRecovered.equals(address))
{
match = true;
break;
}
}
}
return match;
}但是,生成的地址中没有一个与用于创建签名的地址相匹配。
有人能说明我做错了什么吗?
发布于 2022-03-26 14:02:08
下面是我编写的一个实现,它的工作方式与JavaScript、ethers.utils.verifyMessage(message, signature)和ethers.utils.recoverAddress(digest, signature)方法完全一样。
EthersUtils.java
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import org.web3j.crypto.ECDSASignature;
import org.web3j.crypto.Hash;
import org.web3j.crypto.Keys;
import org.web3j.crypto.Sign;
import org.web3j.crypto.Sign.SignatureData;
import org.web3j.utils.Numeric;
public class EthersUtils {
private static final String MESSAGE_PREFIX = "\u0019Ethereum Signed Message:\n";
public static String verifyMessage(String message, String signature) {
return EthersUtils.recoverAddress(EthersUtils.hashMessage(message), signature);
}
public static String hashMessage(String message) {
return Hash.sha3(
Numeric.toHexStringNoPrefix(
(EthersUtils.MESSAGE_PREFIX + message.length() + message).getBytes(StandardCharsets.UTF_8)));
}
public static String recoverAddress(String digest, String signature) {
SignatureData signatureData = EthersUtils.getSignatureData(signature);
int header = 0;
for (byte b : signatureData.getV()) {
header = (header << 8) + (b & 0xFF);
}
if (header < 27 || header > 34) {
return null;
}
int recId = header - 27;
BigInteger key = Sign.recoverFromSignature(
recId,
new ECDSASignature(
new BigInteger(1, signatureData.getR()), new BigInteger(1, signatureData.getS())),
Numeric.hexStringToByteArray(digest));
if (key == null) {
return null;
}
return ("0x" + Keys.getAddress(key)).trim();
}
private static SignatureData getSignatureData(String signature) {
byte[] signatureBytes = Numeric.hexStringToByteArray(signature);
byte v = signatureBytes[64];
if (v < 27) {
v += 27;
}
byte[] r = (byte[]) Arrays.copyOfRange(signatureBytes, 0, 32);
byte[] s = (byte[]) Arrays.copyOfRange(signatureBytes, 32, 64);
return new SignatureData(v, r, s);
}
}发布于 2021-11-09 03:43:47
package org.web3j.crypto;
import java.math.BigInteger;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
import org.web3j.crypto.Sign.SignatureData;
import org.web3j.utils.Numeric;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ECRecoverTest {
public static final String PERSONAL_MESSAGE_PREFIX = "\u0019Ethereum Signed Message:\n";
@Test
public void testRecoverAddressFromSignature() {
String signature =
"0x2c6401216c9031b9a6fb8cbfccab4fcec6c951cdf40e2320108d1856eb532250576865fbcd452bcdc4c57321b619ed7a9cfd38bd973c3e1e0243ac2777fe9d5b1b";
String address = "0x31b26e43651e9371c88af3d36c14cfd938baf4fd";
String message = "v0G9u7huK4mJb2K1";
String prefix = PERSONAL_MESSAGE_PREFIX + message.length();
byte[] msgHash = Hash.sha3((prefix + message).getBytes());
byte[] signatureBytes = Numeric.hexStringToByteArray(signature);
byte v = signatureBytes[64];
if (v < 27) {
v += 27;
}
SignatureData sd =
new SignatureData(
v,
(byte[]) Arrays.copyOfRange(signatureBytes, 0, 32),
(byte[]) Arrays.copyOfRange(signatureBytes, 32, 64));
String addressRecovered = null;
boolean match = false;
// Iterate for each possible key to recover
for (int i = 0; i < 4; i++) {
BigInteger publicKey =
Sign.recoverFromSignature(
(byte) i,
new ECDSASignature(
new BigInteger(1, sd.getR()), new BigInteger(1, sd.getS())),
msgHash);
if (publicKey != null) {
addressRecovered = "0x" + Keys.getAddress(publicKey);
if (addressRecovered.equals(address)) {
match = true;
break;
}
}
}
assertEquals(addressRecovered, (address));
assertTrue(match);
}
}https://github.com/web3j/web3j/blob/master/crypto/src/test/java/org/web3j/crypto/ECRecoverTest.java
发布于 2019-03-19 13:53:35
您正在试图验证签名,而不提供消息的哈希。这是您需要提供的另一个参数
https://ethereum.stackexchange.com/questions/55454
复制相似问题