0

Following the great post [Redeeming a raw transaction step by step example required, I came up with code below but the verification failed.

// pubkeyBytes, len: 65
// 042daa93315eebbe2cb9b5c3505df4c6fb6caca8b756786098567550d4820c09db988fe9997d049d687292f815ccd6e7fb5c1b1a91137999818d17c73d0f80aef9

// data, len: 32
// 30f10a6468b7d98257af63fb40dfcf2cefe991346fd37c67cf7b51ff8d4404d3

// signatureBytes, len: 71
// 30450220587ce0cf0252e2db3a7c3c91b355aa8f3385e128227cd8727c5f7777877ad772022100edc508b7c14891ed15ab38c687019d7ebaf5c12908cf21a83e8ae57e8c47e95c

    ECPublicKey publicKey = (ECPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC, KeyBuilder.LENGTH_EC_FP_256, false);;
    Secp256k1.setCommonCurveParameters(publicKey);
    publicKey.setW(pubkeyBytes, (short) 0, (short) pubkeyBytes.length);

    Signature eccSign = Signature.getInstance(Signature.ALG_ECDSA_SHA_256, false);
    eccSign.init(publicKey, Signature.MODE_VERIFY);
    boolean verified = eccSign.verify(data, (short)0, (short) data.length,
                signatureBytes, (short)0, (short)signatureBytes.length
            );
    Assert.assertTrue(verified);

Assertion failed at the end.

Have been stucked for hours. Cannot figure it out. Any help is highly appreciated. Thanks.

0
static void test_sig ( )
{
  const MyByteArray pubkey ( QByteArray::fromHex ( "042daa93315eebbe2cb9b5c3505df4c6fb6caca8b756786098567550d4820c09db988fe9997d049d687292f815ccd6e7fb5c1b1a91137999818d17c73d0f80aef9" ) );
  const MyByteArray signat ( QByteArray::fromHex ( "30450220587ce0cf0252e2db3a7c3c91b355aa8f3385e128227cd8727c5f7777877ad772022100edc508b7c14891ed15ab38c687019d7ebaf5c12908cf21a83e8ae57e8c47e95c" ) );
  const MyKey32     digest ( QByteArray::fromHex ( "30f10a6468b7d98257af63fb40dfcf2cefe991346fd37c67cf7b51ff8d4404d3" ) );
  qDebug ( ) << ( digest.verify ( pubkey, signat ) ? "passed" : "failed" );
}

my result is:: passed

the signature is correct for digest and public key

may be something is wrong in your verification code with decoding hex values and/or byte order in digest?

| improve this answer | |
0

Usually the issue is the Signature Verification algorithm used. Bitcoin uses double SHA-256 as the hashing algorithm for ECDSA, thus the Z value is the Double SHA-256 hash of the unsigned transaction. Looking at the Signature Hash Algorithm you're using:

Signature algorithm ALG_ECDSA_SHA_256 generates a 32-byte SHA-256 digest and signs/verifies the digest using ECDSA with the curve defined in the ECKey parameters

You are taking in the Z value already but then hashing it again with only 1 round of SHA-256. You could try to pass in a preimage of only 1 SHA-256 hash then let the Signature object handle the second round, but I do not have much luck with this method using standard Java Security libraries. In order to accomplish Bitcoin Transaction signing/verification in Java, you will need to either (1) implement your own ECDSA signing/verification, or (2) use a library such as BitcoinJ. The following is the code I use in my own project(s) within my ECPubKey class (note that I am using a ton of other custom code that you will see method calls from, yet are not included here, but you will get the gist):

/**
 * @param preimage the Preimage to verify
 * @param signature An ECDSA Signature (R/S Value pair)
 * @return whether this Public Key was used to generate the signature for the given preimage
 */
public boolean verify(String preimage, ECSignature signature) {
    String sigHash = HashUtil.doubleSha256(preimage);
    BigInteger z = new BigInteger(1, ByteUtil.hex2bytes(sigHash));
    BigInteger r = signature.getR();
    BigInteger s = signature.getS();
    BigInteger sInv = s.modInverse(CurveParams.n);
    BigInteger u1 = z.multiply(sInv).mod(CurveParams.n);
    BigInteger u2 = r.multiply(sInv).mod(CurveParams.n);
    ECPoint u1Point = ScalarMultiply.scalmult(CurveParams.G, u1);
    ECPoint u2Point = ScalarMultiply.scalmult(this.getPoint(), u2);
    ECPoint sigPoint = ScalarMultiply.addPoint(u1Point, u2Point);
    return r.compareTo(sigPoint.getAffineX().mod(CurveParams.n)) == 0;
}

The methodology was essentially copied directly from the ECDSA Wikipedia Page and translated into Java.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.