Java Code Examples for org.bitcoinj.crypto.TransactionSignature#decodeFromBitcoin()

The following examples show how to use org.bitcoinj.crypto.TransactionSignature#decodeFromBitcoin() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: PaymentChannelV1ClientState.java    From green_android with GNU General Public License v3.0 5 votes vote down vote up
/**
 * <p>When the servers signature for the refund transaction is received, call this to verify it and sign the
 * complete refund ourselves.</p>
 *
 * <p>If this does not throw an exception, we are secure against the loss of funds and can safely provide the server
 * with the multi-sig contract to lock in the agreement. In this case, both the multisig contract and the refund
 * transaction are automatically committed to wallet so that it can handle broadcasting the refund transaction at
 * the appropriate time if necessary.</p>
 */
public synchronized void provideRefundSignature(byte[] theirSignature, @Nullable KeyParameter userKey)
        throws VerificationException {
    checkNotNull(theirSignature);
    stateMachine.checkState(State.WAITING_FOR_SIGNED_REFUND);
    TransactionSignature theirSig = TransactionSignature.decodeFromBitcoin(theirSignature, true);
    if (theirSig.sigHashMode() != Transaction.SigHash.NONE || !theirSig.anyoneCanPay())
        throw new VerificationException("Refund signature was not SIGHASH_NONE|SIGHASH_ANYONECANPAY");
    // Sign the refund transaction ourselves.
    final TransactionOutput multisigContractOutput = multisigContract.getOutput(0);
    try {
        multisigScript = multisigContractOutput.getScriptPubKey();
    } catch (ScriptException e) {
        throw new RuntimeException(e);  // Cannot happen: we built this ourselves.
    }
    TransactionSignature ourSignature =
            refundTx.calculateSignature(0, myKey.maybeDecrypt(userKey),
                    multisigScript, Transaction.SigHash.ALL, false);
    // Insert the signatures.
    Script scriptSig = ScriptBuilder.createMultiSigInputScript(ourSignature, theirSig);
    log.info("Refund scriptSig: {}", scriptSig);
    log.info("Multi-sig contract scriptPubKey: {}", multisigScript);
    TransactionInput refundInput = refundTx.getInput(0);
    refundInput.setScriptSig(scriptSig);
    refundInput.verify(multisigContractOutput);
    stateMachine.transition(State.SAVE_STATE_IN_WALLET);
}
 
Example 2
Source File: LNPaymentLogicImpl.java    From thundernetwork with GNU Affero General Public License v3.0 5 votes vote down vote up
private void parseCMessage (LNPaymentCMessage message) {
    paymentSignatures.clear();
    signature1 = TransactionSignature.decodeFromBitcoin(message.newCommitSignature1, true);
    signature2 = TransactionSignature.decodeFromBitcoin(message.newCommitSignature2, true);

    Transaction channelTransaction = getServerTransaction();

    Sha256Hash hash1 = channelTransaction.hashForSignature(0, channel.getScriptAnchorOutputServer(), Transaction.SigHash.ALL, false);
    Sha256Hash hash2 = channelTransaction.hashForSignature(1, channel.getScriptAnchorOutputClient(), Transaction.SigHash.ALL, false);

    if (!channel.keyClient.verify(hash1, signature1)) {
        throw new LNPaymentException("Signature1 is not correct..");
    }

    if (!channel.keyClient.verify(hash2, signature2)) {
        throw new LNPaymentException("Signature2 is not correct..");
    }

    List<PaymentData> allPayments = new ArrayList<>(statusTemp.remainingPayments);
    allPayments.addAll(statusTemp.newPayments);
    List<Transaction> paymentTransactions = getServerPaymentTransactions();

    if (allPayments.size() != message.newPaymentSignatures.size()) {
        throw new LNPaymentException("Size of payment signature list is incorrect");
    }

    for (int i = 0; i < allPayments.size(); ++i) {
        Transaction transaction = paymentTransactions.get(i);
        PaymentData payment = allPayments.get(i);
        TransactionSignature signature = TransactionSignature.decodeFromBitcoin(message.newPaymentSignatures.get(i), true);
        Script scriptPubKey = channelTransaction.getOutput(i + 2).getScriptPubKey();

        Sha256Hash hash = transaction.hashForSignature(0, scriptPubKey, Transaction.SigHash.ALL, false);
        if (!channel.keyClient.verify(hash, signature)) {
            throw new LNPaymentException("Payment Signature " + i + "  is not correct..");
        }
        paymentSignatures.add(signature);
    }

}
 
Example 3
Source File: PaymentChannelV1ClientState.java    From GreenBits with GNU General Public License v3.0 5 votes vote down vote up
/**
 * <p>When the servers signature for the refund transaction is received, call this to verify it and sign the
 * complete refund ourselves.</p>
 *
 * <p>If this does not throw an exception, we are secure against the loss of funds and can safely provide the server
 * with the multi-sig contract to lock in the agreement. In this case, both the multisig contract and the refund
 * transaction are automatically committed to wallet so that it can handle broadcasting the refund transaction at
 * the appropriate time if necessary.</p>
 */
public synchronized void provideRefundSignature(byte[] theirSignature, @Nullable KeyParameter userKey)
        throws VerificationException {
    checkNotNull(theirSignature);
    stateMachine.checkState(State.WAITING_FOR_SIGNED_REFUND);
    TransactionSignature theirSig = TransactionSignature.decodeFromBitcoin(theirSignature, true);
    if (theirSig.sigHashMode() != Transaction.SigHash.NONE || !theirSig.anyoneCanPay())
        throw new VerificationException("Refund signature was not SIGHASH_NONE|SIGHASH_ANYONECANPAY");
    // Sign the refund transaction ourselves.
    final TransactionOutput multisigContractOutput = multisigContract.getOutput(0);
    try {
        multisigScript = multisigContractOutput.getScriptPubKey();
    } catch (ScriptException e) {
        throw new RuntimeException(e);  // Cannot happen: we built this ourselves.
    }
    TransactionSignature ourSignature =
            refundTx.calculateSignature(0, myKey.maybeDecrypt(userKey),
                    multisigScript, Transaction.SigHash.ALL, false);
    // Insert the signatures.
    Script scriptSig = ScriptBuilder.createMultiSigInputScript(ourSignature, theirSig);
    log.info("Refund scriptSig: {}", scriptSig);
    log.info("Multi-sig contract scriptPubKey: {}", multisigScript);
    TransactionInput refundInput = refundTx.getInput(0);
    refundInput.setScriptSig(scriptSig);
    refundInput.verify(multisigContractOutput);
    stateMachine.transition(State.SAVE_STATE_IN_WALLET);
}
 
Example 4
Source File: Script.java    From GreenBits with GNU General Public License v3.0 5 votes vote down vote up
private int findSigInRedeem(byte[] signatureBytes, Sha256Hash hash) {
    checkArgument(chunks.get(0).isOpCode()); // P2SH scriptSig
    int numKeys = Script.decodeFromOpN(chunks.get(chunks.size() - 2).opcode);
    TransactionSignature signature = TransactionSignature.decodeFromBitcoin(signatureBytes, true);
    for (int i = 0 ; i < numKeys ; i++) {
        if (ECKey.fromPublicOnly(chunks.get(i + 1).data).verify(hash, signature)) {
            return i;
        }
    }

    throw new IllegalStateException("Could not find matching key for signature on " + hash.toString() + " sig " + HEX.encode(signatureBytes));
}
 
Example 5
Source File: Script.java    From bcm-android with GNU General Public License v3.0 5 votes vote down vote up
private int findSigInRedeem(byte[] signatureBytes, Sha256Hash hash) {
    checkArgument(chunks.get(0).isOpCode()); // P2SH scriptSig
    int numKeys = Script.decodeFromOpN(chunks.get(chunks.size() - 2).opcode);
    TransactionSignature signature = TransactionSignature.decodeFromBitcoin(signatureBytes, true);
    for (int i = 0; i < numKeys; i++) {
        if (ECKey.fromPublicOnly(chunks.get(i + 1).data).verify(hash, signature)) {
            return i;
        }
    }

    throw new IllegalStateException("Could not find matching key for signature on " + hash.toString() + " sig " + Utils.HEX.encode(signatureBytes));
}
 
Example 6
Source File: Script.java    From green_android with GNU General Public License v3.0 5 votes vote down vote up
private int findSigInRedeem(byte[] signatureBytes, Sha256Hash hash) {
    checkArgument(chunks.get(0).isOpCode()); // P2SH scriptSig
    int numKeys = Script.decodeFromOpN(chunks.get(chunks.size() - 2).opcode);
    TransactionSignature signature = TransactionSignature.decodeFromBitcoin(signatureBytes, true);
    for (int i = 0 ; i < numKeys ; i++) {
        if (ECKey.fromPublicOnly(chunks.get(i + 1).data).verify(hash, signature)) {
            return i;
        }
    }

    throw new IllegalStateException("Could not find matching key for signature on " + hash.toString() + " sig " + HEX.encode(signatureBytes));
}
 
Example 7
Source File: PaymentChannelV1ClientState.java    From bcm-android with GNU General Public License v3.0 5 votes vote down vote up
/**
 * <p>When the servers signature for the refund transaction is received, call this to verify it and sign the
 * complete refund ourselves.</p>
 * <p>
 * <p>If this does not throw an exception, we are secure against the loss of funds and can safely provide the server
 * with the multi-sig contract to lock in the agreement. In this case, both the multisig contract and the refund
 * transaction are automatically committed to wallet so that it can handle broadcasting the refund transaction at
 * the appropriate time if necessary.</p>
 */
public synchronized void provideRefundSignature(byte[] theirSignature, @Nullable KeyParameter userKey)
        throws VerificationException {
    checkNotNull(theirSignature);
    stateMachine.checkState(State.WAITING_FOR_SIGNED_REFUND);
    TransactionSignature theirSig = TransactionSignature.decodeFromBitcoin(theirSignature, true);
    if (theirSig.sigHashMode() != Transaction.SigHash.NONE || !theirSig.anyoneCanPay())
        throw new VerificationException("Refund signature was not SIGHASH_NONE|SIGHASH_ANYONECANPAY");
    // Sign the refund transaction ourselves.
    final TransactionOutput multisigContractOutput = multisigContract.getOutput(0);
    try {
        multisigScript = multisigContractOutput.getScriptPubKey();
    } catch (ScriptException e) {
        throw new RuntimeException(e);  // Cannot happen: we built this ourselves.
    }
    TransactionSignature ourSignature =
            refundTx.calculateSignature(0, myKey.maybeDecrypt(userKey),
                    multisigScript, Transaction.SigHash.ALL, false);
    // Insert the signatures.
    Script scriptSig = ScriptBuilder.createMultiSigInputScript(ourSignature, theirSig);
    log.info("Refund scriptSig: {}", scriptSig);
    log.info("Multi-sig contract scriptPubKey: {}", multisigScript);
    TransactionInput refundInput = refundTx.getInput(0);
    refundInput.setScriptSig(scriptSig);
    refundInput.verify(multisigContractOutput);
    stateMachine.transition(State.SAVE_STATE_IN_WALLET);
}
 
Example 8
Source File: Script.java    From green_android with GNU General Public License v3.0 4 votes vote down vote up
private static void executeCheckSig(Transaction txContainingThis, int index, Script script,
                                    LinkedList<byte[]> stack, int lastCodeSepLocation, int opcode,
                                    Coin value, boolean segwit,
                                    Set<VerifyFlag> verifyFlags) throws ScriptException {
    final boolean requireCanonical = verifyFlags.contains(VerifyFlag.STRICTENC)
        || verifyFlags.contains(VerifyFlag.DERSIG)
        || verifyFlags.contains(VerifyFlag.LOW_S);
    if (stack.size() < 2)
        throw new ScriptException("Attempted OP_CHECKSIG(VERIFY) on a stack with size < 2");
    byte[] pubKey = stack.pollLast();
    byte[] sigBytes = stack.pollLast();

    byte[] prog = script.getProgram();
    byte[] connectedScript = Arrays.copyOfRange(prog, lastCodeSepLocation, prog.length);

    UnsafeByteArrayOutputStream outStream = new UnsafeByteArrayOutputStream(sigBytes.length + 1);
    try {
        writeBytes(outStream, sigBytes);
    } catch (IOException e) {
        throw new RuntimeException(e); // Cannot happen
    }
    if (!segwit) connectedScript = removeAllInstancesOf(connectedScript, outStream.toByteArray());

    // TODO: Use int for indexes everywhere, we can't have that many inputs/outputs
    boolean sigValid = false;
    try {
        TransactionSignature sig  = TransactionSignature.decodeFromBitcoin(sigBytes, requireCanonical,
            verifyFlags.contains(VerifyFlag.LOW_S));

        // TODO: Should check hash type is known
        Sha256Hash hash = segwit
            ? txContainingThis.hashForSignatureWitness(
                index, connectedScript, value, sig.sigHashMode(), sig.anyoneCanPay())
            : txContainingThis.hashForSignature(
                index, connectedScript, (byte) sig.sighashFlags);
        sigValid = ECKey.verify(hash.getBytes(), sig, pubKey);
    } catch (Exception e1) {
        // There is (at least) one exception that could be hit here (EOFException, if the sig is too short)
        // Because I can't verify there aren't more, we use a very generic Exception catch

        // This RuntimeException occurs when signing as we run partial/invalid scripts to see if they need more
        // signing work to be done inside LocalTransactionSigner.signInputs.
        if (!e1.getMessage().contains("Reached past end of ASN.1 stream"))
            log.warn("Signature checking failed!", e1);
    }

    if (opcode == OP_CHECKSIG)
        stack.add(sigValid ? new byte[] {1} : new byte[] {});
    else if (opcode == OP_CHECKSIGVERIFY)
        if (!sigValid)
            throw new ScriptException("Script failed OP_CHECKSIGVERIFY");
}
 
Example 9
Source File: PaymentChannelServerState.java    From green_android with GNU General Public License v3.0 4 votes vote down vote up
/**
 * Called when the client provides us with a new signature and wishes to increment total payment by size.		+
 * Verifies the provided signature and only updates values if everything checks out.
 * If the new refundSize is not the lowest we have seen, it is simply ignored.
 *
 * @param refundSize How many satoshis of the original contract are refunded to the client (the rest are ours)
 * @param signatureBytes The new signature spending the multi-sig contract to a new payment transaction
 * @throws VerificationException If the signature does not verify or size is out of range (incl being rejected by the network as dust).
 * @return true if there is more value left on the channel, false if it is now fully used up.
 */
public synchronized boolean incrementPayment(Coin refundSize, byte[] signatureBytes) throws VerificationException, ValueOutOfRangeException, InsufficientMoneyException {
    stateMachine.checkState(State.READY);
    checkNotNull(refundSize);
    checkNotNull(signatureBytes);
    TransactionSignature signature = TransactionSignature.decodeFromBitcoin(signatureBytes, true);
    // We allow snapping to zero for the payment amount because it's treated specially later, but not less than
    // the dust level because that would prevent the transaction from being relayed/mined.
    final boolean fullyUsedUp = refundSize.equals(Coin.ZERO);
    Coin newValueToMe = getTotalValue().subtract(refundSize);
    if (newValueToMe.signum() < 0)
        throw new ValueOutOfRangeException("Attempt to refund more than the contract allows.");
    if (newValueToMe.compareTo(bestValueToMe) < 0)
        throw new ValueOutOfRangeException("Attempt to roll back payment on the channel.");

    SendRequest req = makeUnsignedChannelContract(newValueToMe);

    if (!fullyUsedUp && refundSize.isLessThan(req.tx.getOutput(0).getMinNonDustValue()))
        throw new ValueOutOfRangeException("Attempt to refund negative value or value too small to be accepted by the network");

    // Get the wallet's copy of the contract (ie with confidence information), if this is null, the wallet
    // was not connected to the peergroup when the contract was broadcast (which may cause issues down the road, and
    // disables our double-spend check next)
    Transaction walletContract = wallet.getTransaction(contract.getHash());
    checkNotNull(walletContract, "Wallet did not contain multisig contract {} after state was marked READY", contract.getHash());

    // Note that we check for DEAD state here, but this test is essentially useless in production because we will
    // miss most double-spends due to bloom filtering right now anyway. This will eventually fixed by network-wide
    // double-spend notifications, so we just wait instead of attempting to add all dependant outpoints to our bloom
    // filters (and probably missing lots of edge-cases).
    if (walletContract.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.DEAD) {
        close();
        throw new VerificationException("Multisig contract was double-spent");
    }

    Transaction.SigHash mode;
    // If the client doesn't want anything back, they shouldn't sign any outputs at all.
    if (fullyUsedUp)
        mode = Transaction.SigHash.NONE;
    else
        mode = Transaction.SigHash.SINGLE;

    if (signature.sigHashMode() != mode || !signature.anyoneCanPay())
        throw new VerificationException("New payment signature was not signed with the right SIGHASH flags.");

    // Now check the signature is correct.
    // Note that the client must sign with SIGHASH_{SINGLE/NONE} | SIGHASH_ANYONECANPAY to allow us to add additional
    // inputs (in case we need to add significant fee, or something...) and any outputs we want to pay to.
    Sha256Hash sighash = req.tx.hashForSignature(0, getSignedScript(), mode, true);

    if (!getClientKey().verify(sighash, signature))
        throw new VerificationException("Signature does not verify on tx\n" + req.tx);
    bestValueToMe = newValueToMe;
    bestValueSignature = signatureBytes;
    updateChannelInWallet();
    return !fullyUsedUp;
}
 
Example 10
Source File: GenerateLowSTests.java    From green_android with GNU General Public License v3.0 4 votes vote down vote up
public static void main(final String[] argv) throws NoSuchAlgorithmException, IOException {
    final NetworkParameters params = new MainNetParams();
    final LocalTransactionSigner signer = new LocalTransactionSigner();
    final SecureRandom secureRandom = SecureRandom.getInstanceStrong();
    final ECKey key = new ECKey(secureRandom);
    final KeyBag bag = new KeyBag() {
        @Override
        public ECKey findKeyFromPubHash(byte[] pubkeyHash) {
            return key;
        }

        @Override
        public ECKey findKeyFromPubKey(byte[] pubkey) {
            return key;
        }

        @Override
        public RedeemData findRedeemDataFromScriptHash(byte[] scriptHash) {
            return null;
        }

    };

    // Generate a fictional output transaction we take values from, and
    // an input transaction for the test case

    final Transaction outputTransaction = new Transaction(params);
    final Transaction inputTransaction = new Transaction(params);
    final TransactionOutput output = new TransactionOutput(params, inputTransaction, Coin.ZERO, key.toAddress(params));

    inputTransaction.addOutput(output);
    outputTransaction.addInput(output);
    outputTransaction.addOutput(Coin.ZERO, new ECKey(secureRandom).toAddress(params));

    addOutputs(outputTransaction, bag);

    // Sign the transaction
    final ProposedTransaction proposedTransaction = new ProposedTransaction(outputTransaction);
    signer.signInputs(proposedTransaction, bag);
    final TransactionInput input = proposedTransaction.partialTx.getInput(0);

    input.verify(output);
    input.getScriptSig().correctlySpends(outputTransaction, 0, output.getScriptPubKey(),
        EnumSet.of(Script.VerifyFlag.DERSIG, Script.VerifyFlag.P2SH));

    final Script scriptSig = input.getScriptSig();
    final TransactionSignature signature = TransactionSignature.decodeFromBitcoin(scriptSig.getChunks().get(0).data, true, false);

    // First output a conventional low-S transaction with the LOW_S flag, for the tx_valid.json set
    System.out.println("[\"A transaction with a low-S signature.\"],");
    System.out.println("[[[\""
        + inputTransaction.getHashAsString() + "\", "
        + output.getIndex() + ", \""
        + scriptToString(output.getScriptPubKey()) + "\"]],\n"
        + "\"" + Utils.HEX.encode(proposedTransaction.partialTx.unsafeBitcoinSerialize()) + "\", \""
        + Script.VerifyFlag.P2SH.name() + "," + Script.VerifyFlag.LOW_S.name() + "\"],");

    final BigInteger highS = HIGH_S_DIFFERENCE.subtract(signature.s);
    final TransactionSignature highSig = new TransactionSignature(signature.r, highS);
    input.setScriptSig(new ScriptBuilder().data(highSig.encodeToBitcoin()).data(scriptSig.getChunks().get(1).data).build());
    input.getScriptSig().correctlySpends(outputTransaction, 0, output.getScriptPubKey(),
        EnumSet.of(Script.VerifyFlag.P2SH));

    // A high-S transaction without the LOW_S flag, for the tx_valid.json set
    System.out.println("[\"A transaction with a high-S signature.\"],");
    System.out.println("[[[\""
        + inputTransaction.getHashAsString() + "\", "
        + output.getIndex() + ", \""
        + scriptToString(output.getScriptPubKey()) + "\"]],\n"
        + "\"" + Utils.HEX.encode(proposedTransaction.partialTx.unsafeBitcoinSerialize()) + "\", \""
        + Script.VerifyFlag.P2SH.name() + "\"],");

    // Lastly a conventional high-S transaction with the LOW_S flag, for the tx_invalid.json set
    System.out.println("[\"A transaction with a high-S signature.\"],");
    System.out.println("[[[\""
        + inputTransaction.getHashAsString() + "\", "
        + output.getIndex() + ", \""
        + scriptToString(output.getScriptPubKey()) + "\"]],\n"
        + "\"" + Utils.HEX.encode(proposedTransaction.partialTx.unsafeBitcoinSerialize()) + "\", \""
        + Script.VerifyFlag.P2SH.name() + "," + Script.VerifyFlag.LOW_S.name() + "\"],");
}
 
Example 11
Source File: Signature.java    From balzac with Apache License 2.0 4 votes vote down vote up
public static void isValidAndCanonical(byte[] signature) throws VerificationException, SignatureDecodeException {
    TransactionSignature.decodeFromBitcoin(signature, true, true);
}
 
Example 12
Source File: LNEstablishBMessage.java    From thunder with GNU Affero General Public License v3.0 4 votes vote down vote up
public TransactionSignature getChannelSignature () {
    return TransactionSignature.decodeFromBitcoin(channelSignature, true);
}
 
Example 13
Source File: GenerateLowSTests.java    From GreenBits with GNU General Public License v3.0 4 votes vote down vote up
public static void main(final String[] argv) throws NoSuchAlgorithmException, IOException {
    final NetworkParameters params = new MainNetParams();
    final LocalTransactionSigner signer = new LocalTransactionSigner();
    final SecureRandom secureRandom = SecureRandom.getInstanceStrong();
    final ECKey key = new ECKey(secureRandom);
    final KeyBag bag = new KeyBag() {
        @Override
        public ECKey findKeyFromPubHash(byte[] pubkeyHash) {
            return key;
        }

        @Override
        public ECKey findKeyFromPubKey(byte[] pubkey) {
            return key;
        }

        @Override
        public RedeemData findRedeemDataFromScriptHash(byte[] scriptHash) {
            return null;
        }

    };

    // Generate a fictional output transaction we take values from, and
    // an input transaction for the test case

    final Transaction outputTransaction = new Transaction(params);
    final Transaction inputTransaction = new Transaction(params);
    final TransactionOutput output = new TransactionOutput(params, inputTransaction, Coin.ZERO, key.toAddress(params));

    inputTransaction.addOutput(output);
    outputTransaction.addInput(output);
    outputTransaction.addOutput(Coin.ZERO, new ECKey(secureRandom).toAddress(params));

    addOutputs(outputTransaction, bag);

    // Sign the transaction
    final ProposedTransaction proposedTransaction = new ProposedTransaction(outputTransaction);
    signer.signInputs(proposedTransaction, bag);
    final TransactionInput input = proposedTransaction.partialTx.getInput(0);

    input.verify(output);
    input.getScriptSig().correctlySpends(outputTransaction, 0, output.getScriptPubKey(),
        EnumSet.of(Script.VerifyFlag.DERSIG, Script.VerifyFlag.P2SH));

    final Script scriptSig = input.getScriptSig();
    final TransactionSignature signature = TransactionSignature.decodeFromBitcoin(scriptSig.getChunks().get(0).data, true, false);

    // First output a conventional low-S transaction with the LOW_S flag, for the tx_valid.json set
    System.out.println("[\"A transaction with a low-S signature.\"],");
    System.out.println("[[[\""
        + inputTransaction.getHashAsString() + "\", "
        + output.getIndex() + ", \""
        + scriptToString(output.getScriptPubKey()) + "\"]],\n"
        + "\"" + Utils.HEX.encode(proposedTransaction.partialTx.unsafeBitcoinSerialize()) + "\", \""
        + Script.VerifyFlag.P2SH.name() + "," + Script.VerifyFlag.LOW_S.name() + "\"],");

    final BigInteger highS = HIGH_S_DIFFERENCE.subtract(signature.s);
    final TransactionSignature highSig = new TransactionSignature(signature.r, highS);
    input.setScriptSig(new ScriptBuilder().data(highSig.encodeToBitcoin()).data(scriptSig.getChunks().get(1).data).build());
    input.getScriptSig().correctlySpends(outputTransaction, 0, output.getScriptPubKey(),
        EnumSet.of(Script.VerifyFlag.P2SH));

    // A high-S transaction without the LOW_S flag, for the tx_valid.json set
    System.out.println("[\"A transaction with a high-S signature.\"],");
    System.out.println("[[[\""
        + inputTransaction.getHashAsString() + "\", "
        + output.getIndex() + ", \""
        + scriptToString(output.getScriptPubKey()) + "\"]],\n"
        + "\"" + Utils.HEX.encode(proposedTransaction.partialTx.unsafeBitcoinSerialize()) + "\", \""
        + Script.VerifyFlag.P2SH.name() + "\"],");

    // Lastly a conventional high-S transaction with the LOW_S flag, for the tx_invalid.json set
    System.out.println("[\"A transaction with a high-S signature.\"],");
    System.out.println("[[[\""
        + inputTransaction.getHashAsString() + "\", "
        + output.getIndex() + ", \""
        + scriptToString(output.getScriptPubKey()) + "\"]],\n"
        + "\"" + Utils.HEX.encode(proposedTransaction.partialTx.unsafeBitcoinSerialize()) + "\", \""
        + Script.VerifyFlag.P2SH.name() + "," + Script.VerifyFlag.LOW_S.name() + "\"],");
}
 
Example 14
Source File: Script.java    From GreenBits with GNU General Public License v3.0 4 votes vote down vote up
private static void executeCheckSig(Transaction txContainingThis, int index, Script script,
                                    LinkedList<byte[]> stack, int lastCodeSepLocation, int opcode,
                                    Coin value, boolean segwit,
                                    Set<VerifyFlag> verifyFlags) throws ScriptException {
    final boolean requireCanonical = verifyFlags.contains(VerifyFlag.STRICTENC)
        || verifyFlags.contains(VerifyFlag.DERSIG)
        || verifyFlags.contains(VerifyFlag.LOW_S);
    if (stack.size() < 2)
        throw new ScriptException("Attempted OP_CHECKSIG(VERIFY) on a stack with size < 2");
    byte[] pubKey = stack.pollLast();
    byte[] sigBytes = stack.pollLast();

    byte[] prog = script.getProgram();
    byte[] connectedScript = Arrays.copyOfRange(prog, lastCodeSepLocation, prog.length);

    UnsafeByteArrayOutputStream outStream = new UnsafeByteArrayOutputStream(sigBytes.length + 1);
    try {
        writeBytes(outStream, sigBytes);
    } catch (IOException e) {
        throw new RuntimeException(e); // Cannot happen
    }
    if (!segwit) connectedScript = removeAllInstancesOf(connectedScript, outStream.toByteArray());

    // TODO: Use int for indexes everywhere, we can't have that many inputs/outputs
    boolean sigValid = false;
    try {
        TransactionSignature sig  = TransactionSignature.decodeFromBitcoin(sigBytes, requireCanonical,
            verifyFlags.contains(VerifyFlag.LOW_S));

        // TODO: Should check hash type is known
        Sha256Hash hash = segwit
            ? txContainingThis.hashForSignatureWitness(
                index, connectedScript, value, sig.sigHashMode(), sig.anyoneCanPay())
            : txContainingThis.hashForSignature(
                index, connectedScript, (byte) sig.sighashFlags);
        sigValid = ECKey.verify(hash.getBytes(), sig, pubKey);
    } catch (Exception e1) {
        // There is (at least) one exception that could be hit here (EOFException, if the sig is too short)
        // Because I can't verify there aren't more, we use a very generic Exception catch

        // This RuntimeException occurs when signing as we run partial/invalid scripts to see if they need more
        // signing work to be done inside LocalTransactionSigner.signInputs.
        if (!e1.getMessage().contains("Reached past end of ASN.1 stream"))
            log.warn("Signature checking failed!", e1);
    }

    if (opcode == OP_CHECKSIG)
        stack.add(sigValid ? new byte[] {1} : new byte[] {});
    else if (opcode == OP_CHECKSIGVERIFY)
        if (!sigValid)
            throw new ScriptException("Script failed OP_CHECKSIGVERIFY");
}
 
Example 15
Source File: PaymentChannelServerState.java    From GreenBits with GNU General Public License v3.0 4 votes vote down vote up
/**
 * Called when the client provides us with a new signature and wishes to increment total payment by size.		+
 * Verifies the provided signature and only updates values if everything checks out.
 * If the new refundSize is not the lowest we have seen, it is simply ignored.
 *
 * @param refundSize How many satoshis of the original contract are refunded to the client (the rest are ours)
 * @param signatureBytes The new signature spending the multi-sig contract to a new payment transaction
 * @throws VerificationException If the signature does not verify or size is out of range (incl being rejected by the network as dust).
 * @return true if there is more value left on the channel, false if it is now fully used up.
 */
public synchronized boolean incrementPayment(Coin refundSize, byte[] signatureBytes) throws VerificationException, ValueOutOfRangeException, InsufficientMoneyException {
    stateMachine.checkState(State.READY);
    checkNotNull(refundSize);
    checkNotNull(signatureBytes);
    TransactionSignature signature = TransactionSignature.decodeFromBitcoin(signatureBytes, true);
    // We allow snapping to zero for the payment amount because it's treated specially later, but not less than
    // the dust level because that would prevent the transaction from being relayed/mined.
    final boolean fullyUsedUp = refundSize.equals(Coin.ZERO);
    Coin newValueToMe = getTotalValue().subtract(refundSize);
    if (newValueToMe.signum() < 0)
        throw new ValueOutOfRangeException("Attempt to refund more than the contract allows.");
    if (newValueToMe.compareTo(bestValueToMe) < 0)
        throw new ValueOutOfRangeException("Attempt to roll back payment on the channel.");

    SendRequest req = makeUnsignedChannelContract(newValueToMe);

    if (!fullyUsedUp && refundSize.isLessThan(req.tx.getOutput(0).getMinNonDustValue()))
        throw new ValueOutOfRangeException("Attempt to refund negative value or value too small to be accepted by the network");

    // Get the wallet's copy of the contract (ie with confidence information), if this is null, the wallet
    // was not connected to the peergroup when the contract was broadcast (which may cause issues down the road, and
    // disables our double-spend check next)
    Transaction walletContract = wallet.getTransaction(contract.getHash());
    checkNotNull(walletContract, "Wallet did not contain multisig contract {} after state was marked READY", contract.getHash());

    // Note that we check for DEAD state here, but this test is essentially useless in production because we will
    // miss most double-spends due to bloom filtering right now anyway. This will eventually fixed by network-wide
    // double-spend notifications, so we just wait instead of attempting to add all dependant outpoints to our bloom
    // filters (and probably missing lots of edge-cases).
    if (walletContract.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.DEAD) {
        close();
        throw new VerificationException("Multisig contract was double-spent");
    }

    Transaction.SigHash mode;
    // If the client doesn't want anything back, they shouldn't sign any outputs at all.
    if (fullyUsedUp)
        mode = Transaction.SigHash.NONE;
    else
        mode = Transaction.SigHash.SINGLE;

    if (signature.sigHashMode() != mode || !signature.anyoneCanPay())
        throw new VerificationException("New payment signature was not signed with the right SIGHASH flags.");

    // Now check the signature is correct.
    // Note that the client must sign with SIGHASH_{SINGLE/NONE} | SIGHASH_ANYONECANPAY to allow us to add additional
    // inputs (in case we need to add significant fee, or something...) and any outputs we want to pay to.
    Sha256Hash sighash = req.tx.hashForSignature(0, getSignedScript(), mode, true);

    if (!getClientKey().verify(sighash, signature))
        throw new VerificationException("Signature does not verify on tx\n" + req.tx);
    bestValueToMe = newValueToMe;
    bestValueSignature = signatureBytes;
    updateChannelInWallet();
    return !fullyUsedUp;
}
 
Example 16
Source File: PaymentChannelServerState.java    From bcm-android with GNU General Public License v3.0 4 votes vote down vote up
/**
 * Called when the client provides us with a new signature and wishes to increment total payment by size.		+
 * Verifies the provided signature and only updates values if everything checks out.
 * If the new refundSize is not the lowest we have seen, it is simply ignored.
 *
 * @param refundSize     How many satoshis of the original contract are refunded to the client (the rest are ours)
 * @param signatureBytes The new signature spending the multi-sig contract to a new payment transaction
 * @return true if there is more value left on the channel, false if it is now fully used up.
 * @throws VerificationException If the signature does not verify or size is out of range (incl being rejected by the network as dust).
 */
public synchronized boolean incrementPayment(Coin refundSize, byte[] signatureBytes) throws VerificationException, ValueOutOfRangeException, InsufficientMoneyException {
    stateMachine.checkState(State.READY);
    checkNotNull(refundSize);
    checkNotNull(signatureBytes);
    TransactionSignature signature = TransactionSignature.decodeFromBitcoin(signatureBytes, true);
    // We allow snapping to zero for the payment amount because it's treated specially later, but not less than
    // the dust level because that would prevent the transaction from being relayed/mined.
    final boolean fullyUsedUp = refundSize.equals(Coin.ZERO);
    Coin newValueToMe = getTotalValue().subtract(refundSize);
    if (newValueToMe.signum() < 0)
        throw new ValueOutOfRangeException("Attempt to refund more than the contract allows.");
    if (newValueToMe.compareTo(bestValueToMe) < 0)
        throw new ValueOutOfRangeException("Attempt to roll back payment on the channel.");

    SendRequest req = makeUnsignedChannelContract(newValueToMe);

    if (!fullyUsedUp && refundSize.isLessThan(req.tx.getOutput(0).getMinNonDustValue()))
        throw new ValueOutOfRangeException("Attempt to refund negative value or value too small to be accepted by the network");

    // Get the wallet's copy of the contract (ie with confidence information), if this is null, the wallet
    // was not connected to the peergroup when the contract was broadcast (which may cause issues down the road, and
    // disables our double-spend check next)
    Transaction walletContract = wallet.getTransaction(contract.getHash());
    checkNotNull(walletContract, "Wallet did not contain multisig contract {} after state was marked READY", contract.getHash());

    // Note that we check for DEAD state here, but this test is essentially useless in production because we will
    // miss most double-spends due to bloom filtering right now anyway. This will eventually fixed by network-wide
    // double-spend notifications, so we just wait instead of attempting to add all dependant outpoints to our bloom
    // filters (and probably missing lots of edge-cases).
    if (walletContract.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.DEAD) {
        close();
        throw new VerificationException("Multisig contract was double-spent");
    }

    Transaction.SigHash mode;
    // If the client doesn't want anything back, they shouldn't sign any outputs at all.
    if (fullyUsedUp)
        mode = Transaction.SigHash.NONE;
    else
        mode = Transaction.SigHash.SINGLE;

    if (signature.sigHashMode() != mode || !signature.anyoneCanPay())
        throw new VerificationException("New payment signature was not signed with the right SIGHASH flags.");

    // Now check the signature is correct.
    // Note that the client must sign with SIGHASH_{SINGLE/NONE} | SIGHASH_ANYONECANPAY to allow us to add additional
    // inputs (in case we need to add significant fee, or something...) and any outputs we want to pay to.
    Sha256Hash sighash = req.tx.hashForSignature(0, getSignedScript(), mode, true);

    if (!getClientKey().verify(sighash, signature))
        throw new VerificationException("Signature does not verify on tx\n" + req.tx);
    bestValueToMe = newValueToMe;
    bestValueSignature = signatureBytes;
    updateChannelInWallet();
    return !fullyUsedUp;
}
 
Example 17
Source File: Script.java    From bcm-android with GNU General Public License v3.0 4 votes vote down vote up
private static void executeCheckSig(Transaction txContainingThis, int index, Script script, LinkedList<byte[]> stack,
                                    int lastCodeSepLocation, int opcode,
                                    Set<VerifyFlag> verifyFlags) throws ScriptException {
    final boolean requireCanonical = verifyFlags.contains(VerifyFlag.STRICTENC)
            || verifyFlags.contains(VerifyFlag.DERSIG)
            || verifyFlags.contains(VerifyFlag.LOW_S);
    if (stack.size() < 2)
        throw new ScriptException(ScriptError.SCRIPT_ERR_INVALID_STACK_OPERATION, "Attempted OP_CHECKSIG(VERIFY) on a stack with size < 2");
    byte[] pubKey = stack.pollLast();
    byte[] sigBytes = stack.pollLast();

    byte[] prog = script.getProgram();
    byte[] connectedScript = Arrays.copyOfRange(prog, lastCodeSepLocation, prog.length);

    UnsafeByteArrayOutputStream outStream = new UnsafeByteArrayOutputStream(sigBytes.length + 1);
    try {
        writeBytes(outStream, sigBytes);
    } catch (IOException e) {
        throw new RuntimeException(e); // Cannot happen
    }
    connectedScript = removeAllInstancesOf(connectedScript, outStream.toByteArray());

    // TODO: Use int for indexes everywhere, we can't have that many inputs/outputs
    boolean sigValid = false;
    try {
        TransactionSignature sig = TransactionSignature.decodeFromBitcoin(sigBytes, requireCanonical,
                verifyFlags.contains(VerifyFlag.LOW_S));

        // TODO: Should check hash type is known
        Sha256Hash hash = txContainingThis.hashForSignature(index, connectedScript, (byte) sig.sighashFlags);
        sigValid = ECKey.verify(hash.getBytes(), sig, pubKey);
    } catch (Exception e1) {
        // There is (at least) one exception that could be hit here (EOFException, if the sig is too short)
        // Because I can't verify there aren't more, we use a very generic Exception catch

        // This RuntimeException occurs when signing as we run partial/invalid scripts to see if they need more
        // signing work to be done inside LocalTransactionSigner.signInputs.
        // FIXME don't rely on exception message
        if (e1.getMessage() != null && !e1.getMessage().contains("Reached past end of ASN.1 stream"))
            // Don't put critical code here; the above check is not reliable on HotSpot due to optimization:
            // http://jawspeak.com/2010/05/26/hotspot-caused-exceptions-to-lose-their-stack-traces-in-production-and-the-fix/
            log.warn("Signature checking failed!", e1);
    }

    if (opcode == OP_CHECKSIG)
        stack.add(sigValid ? new byte[]{1} : new byte[]{});
    else if (opcode == OP_CHECKSIGVERIFY)
        if (!sigValid)
            throw new ScriptException(ScriptError.SCRIPT_ERR_CHECKSIGVERIFY, "Script failed OP_CHECKSIGVERIFY");
}