Как подписать биткойн-транзакции с использованием JCE? - PullRequest
0 голосов
/ 27 июня 2019

Мне нужно подписать биткойн-транзакции с использованием примитивов 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

Как видите, подписи совершенно разные, хотя я использую один и тот же закрытый ключ. Что не так с моим кодом? Я просто не понимаю.

...