我需要使用JCE原语(没有bitcoinj)签署比特币交易,但我的签名被bitcoinj视为无效。
我试图模拟这个过程。我创建了一个随机哈希,并使用JCE和bitcoinj对其进行了签名。签名不相等。
这是代码
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Sha256Hash;
import org.spongycastle.crypto.digests.SHA256Digest;
import org.spongycastle.crypto.params.ECPrivateKeyParameters;
import org.spongycastle.crypto.signers.ECDSASigner;
import org.spongycastle.crypto.signers.HMacDSAKCalculator;
import sun.security.ec.ECPrivateKeyImpl;
import sun.security.ec.ECPublicKeyImpl;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
public class ECDSABitcoin {
private static final String SIGN_ALGORITHM = "SHA256withECDSA";
public static void main(String[] args) throws Exception {
KeyPairGenerator keyPairGenerator = createGenerator();
final KeyPair keyPair = keyPairGenerator.generateKeyPair();
ECPrivateKeyImpl privateKey = (ECPrivateKeyImpl) keyPair.getPrivate();
ECPublicKeyImpl publicKey = (ECPublicKeyImpl) keyPair.getPublic();
try {
Sha256Hash hashOut = Sha256Hash.wrap(toSha256("abc".getBytes()));
byte[] signatureBytes = sign(hashOut.getBytes(), keyPair);
ECKey.ECDSASignature mySignature = ECKey.ECDSASignature.decodeFromDER(signatureBytes).toCanonicalised();
ECKey.ECDSASignature bitcoinSignature = sign(privateKey.getS(), hashOut.getBytes()).toCanonicalised();
System.out.println("My signature s " + mySignature.s + " r " + mySignature.r + " canonical " + mySignature.isCanonical());
System.out.println("Verify my " + verify(keyPair, hashOut.getBytes(), signatureBytes));
System.out.println("Bitcoinj signature s " + bitcoinSignature.s + " r " + bitcoinSignature.r + " canonical " + bitcoinSignature.isCanonical());
System.out.println("Verify Bitcoinj " + verify(keyPair, hashOut.getBytes(), bitcoinSignature.encodeToDER()));
} catch (Exception e) {
e.printStackTrace();
}
}
private static boolean verify(KeyPair keyPair, byte[] message, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
final Signature verifySignature = Signature.getInstance(SIGN_ALGORITHM);
verifySignature.initVerify(keyPair.getPublic());
verifySignature.update(message);
return verifySignature.verify(signatureBytes);
}
private static byte[] sign(byte[] message, KeyPair keyPair) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException {
final Signature signature = Signature.getInstance(SIGN_ALGORITHM);
signature.initSign(keyPair.getPrivate());
signature.update(message);
return signature.sign();
}
private static KeyPairGenerator createGenerator() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
ECGenParameterSpec ecParam = new ECGenParameterSpec("secp256k1");
keyPairGenerator.initialize(ecParam);
return keyPairGenerator;
}
private static ECKey.ECDSASignature sign(BigInteger privateKeyForSigning, byte[] data) {
ECDSASigner signer = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest()));
ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(privateKeyForSigning, ECKey.CURVE);
signer.init(true, privKey);
BigInteger[] components = signer.generateSignature(data);
return new ECKey.ECDSASignature(components[0], components[1]).toCanonicalised();
}
private static byte[] toSha256(byte[] message) throws NoSuchAlgorithmException {
MessageDigest crypt = MessageDigest.getInstance("SHA-256");
crypt.reset();
crypt.update(message);
return crypt.digest();
}
}
结果是:
My signature s 45669553786690215047884329722902825758089042579493437816717142987836102849876 r 14778973653615637448416336446742229796258878351047437829727432860950944374049 canonical true
Verify my true
Bitcoinj signature s 24278043061766196831119988370534304503511938256487950554838614741011144316017 r 26413727078831382349368962255251267289169651926313668837949728205557969096319 canonical true
Verify Bitcoinj false
如您所见,即使我使用相同的私钥,签名也完全不同。我的代码有什么问题?我就是不明白。