byte[] res = sig.encodeToDER();
/** * Verifies the given ASN.1 encoded ECDSA signature against a hash using the public key. * * @param data Hash of the data to verify. * @param signature ASN.1 encoded signature. * @param pub The public key bytes to use. */ public static boolean verify(byte[] data, byte[] signature, byte[] pub) { if (Secp256k1Context.isEnabled()) { try { return NativeSecp256k1.verify(data, signature, pub); } catch (NativeSecp256k1Util.AssertFailException e) { log.error("Caught AssertFailException inside secp256k1", e); return false; } } return verify(data, ECDSASignature.decodeFromDER(signature), pub); }
BigInteger r = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 1, 33)); BigInteger s = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 33, 65)); ECDSASignature sig = new ECDSASignature(r, s); byte[] messageBytes = Utils.formatMessageForSigning(message);
bos.write(coinbaseOutKey.sign(hash).encodeToDER()); bos.write(SigHash.SINGLE.value); byte[] signature = bos.toByteArray(); ByteArrayOutputStream bos = new UnsafeByteArrayOutputStream( 73); bos.write(coinbaseOutKey.sign(hash).encodeToDER()); bos.write(SigHash.SINGLE.value); byte[] signature = bos.toByteArray();
Sha256Hash hash = transactionToSign.hashForSignature(index, outputToSpend, SigHash.ALL, false); ECDSASignature signature = key.sign(hash).toCanonicalised(); return new TransactionSignature(signature, SigHash.ALL, false);
BigInteger r = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 1, 33)); BigInteger s = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 33, 65)); ECDSASignature sig = new ECDSASignature(r, s); byte[] messageBytes = Utils.formatMessageForSigning(message);
BigInteger r = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 1, 33)); BigInteger s = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 33, 65)); ECDSASignature sig = new ECDSASignature(r, s); byte[] messageBytes = Utils.formatMessageForSigning(message);
BigInteger r = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 1, 33)); BigInteger s = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 33, 65)); ECDSASignature sig = new ECDSASignature(r, s); byte[] messageBytes = Utils.formatMessageForSigning(message);
return NativeSecp256k1.verify(data, signature.encodeToDER(), pub); } catch (NativeSecp256k1Util.AssertFailException e) { log.error("Caught AssertFailException inside secp256k1", e);
return NativeSecp256k1.verify(data, signature.encodeToDER(), pub); } catch (NativeSecp256k1Util.AssertFailException e) { log.error("Caught AssertFailException inside secp256k1", e);
return NativeSecp256k1.verify(data, signature.encodeToDER(), pub); } catch (NativeSecp256k1Util.AssertFailException e) { log.error("Caught AssertFailException inside secp256k1", e);
public static ECKey signedMessageToKey(byte [] message, byte [] signatureEncoded) throws SignatureException { // Parse the signature bytes into r/s and the selector value. if (signatureEncoded.length < 65) throw new SignatureException("Signature truncated, expected 65 bytes and got " + signatureEncoded.length); int header = signatureEncoded[0] & 0xFF; // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, // 0x1D = second key with even y, 0x1E = second key with odd y if (header < 27 || header > 34) throw new SignatureException("Header byte out of range: " + header); BigInteger r = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 1, 33)); BigInteger s = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 33, 65)); ECDSASignature sig = new ECDSASignature(r, s); byte[] messageBytes = Utils.formatMessageForSigning(message); // Note that the C++ code doesn't actually seem to specify any character encoding. Presumably it's whatever // JSON-SPIRIT hands back. Assume UTF-8 for now. Sha256Hash messageHash = Sha256Hash.twiceOf(messageBytes); boolean compressed = false; if (header >= 31) { compressed = true; header -= 4; } int recId = header - 27; ECKey key = ECKey.recoverFromSignature(recId, sig, messageHash, compressed); if (key == null) throw new SignatureException("Could not recover public key from signature"); return key; }
@Test public void testKeyPairRoundtrip() throws Exception { byte[] privkeyASN1 = HEX.decode( "3082011302010104205c0b98e524ad188ddef35dc6abba13c34a351a05409e5d285403718b93336a4aa081a53081a2020101302c06072a8648ce3d0101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f300604010004010704410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020101a144034200042af7a2aafe8dafd7dc7f9cfb58ce09bda7dce28653ab229b98d1d3d759660c672dd0db18c8c2d76aa470448e876fc2089ab1354c01a6e72cefc50915f4a963ee"); ECKey decodedKey = ECKey.fromASN1(privkeyASN1); // Now re-encode and decode the ASN.1 to see if it is equivalent (it does not produce the exact same byte // sequence, some integers are padded now). ECKey roundtripKey = ECKey.fromPrivateAndPrecalculatedPublic(decodedKey.getPrivKey(), decodedKey.getPubKeyPoint()); for (ECKey key : new ECKey[] {decodedKey, roundtripKey}) { byte[] message = reverseBytes(HEX.decode( "11da3761e86431e4a54c176789e41f1651b324d240d599a7067bee23d328ec2a")); byte[] output = key.sign(Sha256Hash.wrap(message)).encodeToDER(); assertTrue(key.verify(message, output)); output = HEX.decode( "304502206faa2ebc614bf4a0b31f0ce4ed9012eb193302ec2bcaccc7ae8bb40577f47549022100c73a1a1acc209f3f860bf9b9f5e13e9433db6f8b7bd527a088a0e0cd0a4c83e9"); assertTrue(key.verify(message, output)); } // Try to sign with one key and verify with the other. byte[] message = reverseBytes(HEX.decode( "11da3761e86431e4a54c176789e41f1651b324d240d599a7067bee23d328ec2a")); assertTrue(roundtripKey.verify(message, decodedKey.sign(Sha256Hash.wrap(message)).encodeToDER())); assertTrue(decodedKey.verify(message, roundtripKey.sign(Sha256Hash.wrap(message)).encodeToDER())); // Verify bytewise equivalence of public keys (i.e. compression state is preserved) ECKey key = new ECKey(); ECKey key2 = ECKey.fromASN1(key.toASN1()); assertArrayEquals(key.getPubKey(), key2.getPubKey()); }
@Test public void sValue() throws Exception { // Check that we never generate an S value that is larger than half the curve order. This avoids a malleability // issue that can allow someone to change a transaction [hash] without invalidating the signature. final int ITERATIONS = 10; ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(ITERATIONS)); List<ListenableFuture<ECKey.ECDSASignature>> sigFutures = Lists.newArrayList(); final ECKey key = new ECKey(); for (byte i = 0; i < ITERATIONS; i++) { final Sha256Hash hash = Sha256Hash.of(new byte[]{i}); sigFutures.add(executor.submit(new Callable<ECKey.ECDSASignature>() { @Override public ECKey.ECDSASignature call() throws Exception { return key.sign(hash); } })); } List<ECKey.ECDSASignature> sigs = Futures.allAsList(sigFutures).get(); for (ECKey.ECDSASignature signature : sigs) { assertTrue(signature.isCanonical()); } final ECDSASignature first = sigs.get(0); final ECKey.ECDSASignature duplicate = new ECKey.ECDSASignature(first.r, first.s); assertEquals(first, duplicate); assertEquals(first.hashCode(), duplicate.hashCode()); final ECKey.ECDSASignature highS = new ECKey.ECDSASignature(first.r, ECKey.CURVE.getN().subtract(first.s)); assertFalse(highS.isCanonical()); }
return NativeSecp256k1.verify(data, signature.encodeToDER(), pub); } catch (NativeSecp256k1Util.AssertFailException e) { log.error("Caught AssertFailException inside secp256k1", e);
/** * Returns a decoded signature. * * @param requireCanonicalEncoding if the encoding of the signature must * be canonical. * @param requireCanonicalSValue if the S-value must be canonical (below half * the order of the curve). * @throws RuntimeException if the signature is invalid or unparseable in some way. */ public static TransactionSignature decodeFromBitcoin(byte[] bytes, boolean requireCanonicalEncoding, boolean requireCanonicalSValue) throws VerificationException { // Bitcoin encoding is DER signature + sighash byte. if (requireCanonicalEncoding && !isEncodingCanonical(bytes)) throw new VerificationException("Signature encoding is not canonical."); ECKey.ECDSASignature sig; try { sig = ECKey.ECDSASignature.decodeFromDER(bytes); } catch (IllegalArgumentException e) { throw new VerificationException("Could not decode DER", e); } if (requireCanonicalSValue && !sig.isCanonical()) throw new VerificationException("S-value is not canonical."); // In Bitcoin, any value of the final byte is valid, but not necessarily canonical. See javadocs for // isEncodingCanonical to learn more about this. So we must store the exact byte found. return new TransactionSignature(sig.r, sig.s, bytes[bytes.length - 1]); } }
public static ECDSASignature decodeFromDER(byte[] bytes) throws IllegalArgumentException { ASN1InputStream decoder = null; try { decoder = new ASN1InputStream(bytes); final ASN1Primitive seqObj = decoder.readObject(); if (seqObj == null) throw new IllegalArgumentException("Reached past end of ASN.1 stream."); if (!(seqObj instanceof DLSequence)) throw new IllegalArgumentException("Read unexpected class: " + seqObj.getClass().getName()); final DLSequence seq = (DLSequence) seqObj; ASN1Integer r, s; try { r = (ASN1Integer) seq.getObjectAt(0); s = (ASN1Integer) seq.getObjectAt(1); } catch (ClassCastException e) { throw new IllegalArgumentException(e); } // OpenSSL deviates from the DER spec by interpreting these values as unsigned, though they should not be // Thus, we always use the positive versions. See: http://r6.ca/blog/20111119T211504Z.html return new ECDSASignature(r.getPositiveValue(), s.getPositiveValue()); } catch (IOException e) { throw new IllegalArgumentException(e); } finally { if (decoder != null) try { decoder.close(); } catch (IOException x) {} } }
public static ECDSASignature decodeFromDER(byte[] bytes) { ASN1InputStream decoder = null; try { decoder = new ASN1InputStream(bytes); DLSequence seq = (DLSequence) decoder.readObject(); if (seq == null) throw new RuntimeException("Reached past end of ASN.1 stream."); ASN1Integer r, s; try { r = (ASN1Integer) seq.getObjectAt(0); s = (ASN1Integer) seq.getObjectAt(1); } catch (ClassCastException e) { throw new IllegalArgumentException(e); } // OpenSSL deviates from the DER spec by interpreting these values as unsigned, though they should not be // Thus, we always use the positive versions. See: http://r6.ca/blog/20111119T211504Z.html return new ECDSASignature(r.getPositiveValue(), s.getPositiveValue()); } catch (IOException e) { throw new RuntimeException(e); } finally { if (decoder != null) try { decoder.close(); } catch (IOException x) {} } }
/** * Returns a decoded signature. * * @param requireCanonicalEncoding if the encoding of the signature must * be canonical. * @param requireCanonicalSValue if the S-value must be canonical (below half * the order of the curve). * @throws RuntimeException if the signature is invalid or unparseable in some way. */ public static TransactionSignature decodeFromBitcoin(byte[] bytes, boolean requireCanonicalEncoding, boolean requireCanonicalSValue) throws VerificationException { // Bitcoin encoding is DER signature + sighash byte. if (requireCanonicalEncoding && !isEncodingCanonical(bytes)) throw new VerificationException("Signature encoding is not canonical."); ECKey.ECDSASignature sig; try { sig = ECKey.ECDSASignature.decodeFromDER(bytes); } catch (IllegalArgumentException e) { throw new VerificationException("Could not decode DER", e); } if (requireCanonicalSValue && !sig.isCanonical()) throw new VerificationException("S-value is not canonical."); // In Bitcoin, any value of the final byte is valid, but not necessarily canonical. See javadocs for // isEncodingCanonical to learn more about this. So we must store the exact byte found. return new TransactionSignature(sig.r, sig.s, bytes[bytes.length - 1]); } }
public static ECDSASignature decodeFromDER(byte[] bytes) { ASN1InputStream decoder = null; try { decoder = new ASN1InputStream(bytes); DLSequence seq = (DLSequence) decoder.readObject(); if (seq == null) throw new RuntimeException("Reached past end of ASN.1 stream."); ASN1Integer r, s; try { r = (ASN1Integer) seq.getObjectAt(0); s = (ASN1Integer) seq.getObjectAt(1); } catch (ClassCastException e) { throw new IllegalArgumentException(e); } // OpenSSL deviates from the DER spec by interpreting these values as unsigned, though they should not be // Thus, we always use the positive versions. See: http://r6.ca/blog/20111119T211504Z.html return new ECDSASignature(r.getPositiveValue(), s.getPositiveValue()); } catch (IOException e) { throw new RuntimeException(e); } finally { if (decoder != null) try { decoder.close(); } catch (IOException x) {} } }