<p>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 <a href="https://docs.oracle.com/javacard/3.0.5/api/javacard/security/Signature.html" rel="nofollow noreferrer">Signature Hash Algorithm</a> you're using:</p>

<blockquote>
  <p>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</p>
</blockquote>

<p>You are taking in the Z value already but then hashing it again with only 1 round of SHA-256. You <em>could</em> 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):</p>



<pre><code>/**
 * @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;
}
</code></pre>

<p>The methodology was essentially copied directly from <a href="https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Signature_verification_algorithm" rel="nofollow noreferrer">the ECDSA Wikipedia Page</a> and translated into Java.</p>

CC BY-SA 4.0
2019-12-31T21:00:01.510Z
2019-12-31T21:07:37.960Z
2019-12-31T21:07:37.960Z
Septem151
<pre><code>static void test_sig ( )
{
  const MyByteArray pubkey ( QByteArray::fromHex ( "042daa93315eebbe2cb9b5c3505df4c6fb6caca8b756786098567550d4820c09db988fe9997d049d687292f815ccd6e7fb5c1b1a91137999818d17c73d0f80aef9" ) );
  const MyByteArray signat ( QByteArray::fromHex ( "30450220587ce0cf0252e2db3a7c3c91b355aa8f3385e128227cd8727c5f7777877ad772022100edc508b7c14891ed15ab38c687019d7ebaf5c12908cf21a83e8ae57e8c47e95c" ) );
  const MyKey32     digest ( QByteArray::fromHex ( "30f10a6468b7d98257af63fb40dfcf2cefe991346fd37c67cf7b51ff8d4404d3" ) );
  qDebug ( ) &lt;&lt; ( digest.verify ( pubkey, signat ) ? "passed" : "failed" );
}
</code></pre>

<p>my result is:: <strong>passed</strong></p>

<p>the <code>signature</code> is correct for <code>digest</code> and <code>public key</code></p>

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

CC BY-SA 4.0
2019-12-01T07:29:42.627Z
2019-12-01T07:29:42.627Z
amaclin
<p>Following the great post [<a href="https://bitcoin.stackexchange.com/questions/32628/redeeming-a-raw-transaction-step-by-step-example-required]">Redeeming a raw transaction step by step example required</a>, I came up with  code below but the verification failed.</p>

<pre><code>// 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);
</code></pre>

<p>Assertion failed at the end. </p>

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

<transaction-verification><java>
Verify Bitcoin Transaction
YongJiang Zhang
# Verify Bitcoin Transaction

(Asked by: username_0 on 2019-11-28)

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.

**Tags:** transaction-verification, java


---

## 2 answers

### Answer by username_1 on 2019-12-31. Score: 1

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.


---

### Answer by username_2 on 2019-12-01. Score: 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?


---

