Search in sources :

Example 11 with ScriptChunk

use of co.rsk.bitcoinj.script.ScriptChunk in project rskj by rsksmart.

the class BridgeUtilsTest method isInputSignedByThisFederator_isSignedByAnotherFederator.

@Test
public void isInputSignedByThisFederator_isSignedByAnotherFederator() {
    // Arrange
    BtcECKey federator1Key = new BtcECKey();
    BtcECKey federator2Key = new BtcECKey();
    Federation federation = new Federation(FederationMember.getFederationMembersFromKeys(Arrays.asList(federator1Key, federator2Key)), Instant.now(), 0, networkParameters);
    // Create a tx from the Fed to a random btc address
    BtcTransaction tx = new BtcTransaction(networkParameters);
    TransactionInput txInput = new TransactionInput(networkParameters, tx, new byte[] {}, new TransactionOutPoint(networkParameters, 0, Sha256Hash.ZERO_HASH));
    // Create script to be signed by federation members
    Script inputScript = PegTestUtils.createBaseInputScriptThatSpendsFromTheFederation(federation);
    txInput.setScriptSig(inputScript);
    tx.addInput(txInput);
    List<ScriptChunk> chunks = inputScript.getChunks();
    byte[] program = chunks.get(chunks.size() - 1).data;
    Script redeemScript = new Script(program);
    Sha256Hash sighash = tx.hashForSignature(0, redeemScript, BtcTransaction.SigHash.ALL, false);
    BtcECKey.ECDSASignature sig = federator1Key.sign(sighash);
    TransactionSignature txSig = new TransactionSignature(sig, BtcTransaction.SigHash.ALL, false);
    byte[] txSigEncoded = txSig.encodeToBitcoin();
    int sigIndex = inputScript.getSigInsertionIndex(sighash, federator1Key);
    inputScript = ScriptBuilder.updateScriptWithSignature(inputScript, txSigEncoded, sigIndex, 1, 1);
    txInput.setScriptSig(inputScript);
    // Act
    boolean isSigned = BridgeUtils.isInputSignedByThisFederator(federator2Key, sighash, txInput);
    // Assert
    Assert.assertFalse(isSigned);
}
Also used : Script(co.rsk.bitcoinj.script.Script) BtcTransaction(co.rsk.bitcoinj.core.BtcTransaction) Sha256Hash(co.rsk.bitcoinj.core.Sha256Hash) TransactionSignature(co.rsk.bitcoinj.crypto.TransactionSignature) BtcECKey(co.rsk.bitcoinj.core.BtcECKey) ScriptChunk(co.rsk.bitcoinj.script.ScriptChunk) TransactionInput(co.rsk.bitcoinj.core.TransactionInput) TransactionOutPoint(co.rsk.bitcoinj.core.TransactionOutPoint) TransactionOutPoint(co.rsk.bitcoinj.core.TransactionOutPoint) ActivationConfigsForTest(org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest) Test(org.junit.Test)

Example 12 with ScriptChunk

use of co.rsk.bitcoinj.script.ScriptChunk in project rskj by rsksmart.

the class BridgeSupportTest method addSignatureMultipleInputsPartiallyValid.

@Test
public void addSignatureMultipleInputsPartiallyValid() throws Exception {
    // Federation is the genesis federation ATM
    Federation federation = bridgeConstants.getGenesisFederation();
    Repository repository = createRepository();
    final Keccak256 keccak256 = PegTestUtils.createHash3(1);
    BridgeStorageProvider provider = new BridgeStorageProvider(repository, PrecompiledContracts.BRIDGE_ADDR, bridgeConstants, activationsBeforeForks);
    BtcTransaction prevTx1 = new BtcTransaction(btcParams);
    TransactionOutput prevOut1 = new TransactionOutput(btcParams, prevTx1, Coin.FIFTY_COINS, federation.getAddress());
    prevTx1.addOutput(prevOut1);
    BtcTransaction prevTx2 = new BtcTransaction(btcParams);
    TransactionOutput prevOut2 = new TransactionOutput(btcParams, prevTx1, Coin.FIFTY_COINS, federation.getAddress());
    prevTx2.addOutput(prevOut2);
    BtcTransaction prevTx3 = new BtcTransaction(btcParams);
    TransactionOutput prevOut3 = new TransactionOutput(btcParams, prevTx1, Coin.FIFTY_COINS, federation.getAddress());
    prevTx3.addOutput(prevOut3);
    BtcTransaction t = new BtcTransaction(btcParams);
    TransactionOutput output = new TransactionOutput(btcParams, t, Coin.COIN, new BtcECKey().toAddress(btcParams));
    t.addOutput(output);
    t.addInput(prevOut1).setScriptSig(createBaseInputScriptThatSpendsFromTheFederation(federation));
    t.addInput(prevOut2).setScriptSig(createBaseInputScriptThatSpendsFromTheFederation(federation));
    t.addInput(prevOut3).setScriptSig(createBaseInputScriptThatSpendsFromTheFederation(federation));
    provider.getRskTxsWaitingForSignatures().put(keccak256, t);
    provider.save();
    ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class);
    List<LogInfo> logs = new ArrayList<>();
    BridgeEventLogger eventLogger = new BridgeEventLoggerImpl(bridgeConstants, activations, logs);
    BridgeSupport bridgeSupport = getBridgeSupport(bridgeConstants, new BridgeStorageProvider(repository, contractAddress, bridgeConstants, activationsAfterForks), repository, eventLogger, mock(Block.class), null);
    // Generate valid signatures for inputs
    List<byte[]> derEncodedSigsFirstFed = new ArrayList<>();
    List<byte[]> derEncodedSigsSecondFed = new ArrayList<>();
    BtcECKey privateKeyOfFirstFed = BridgeRegTestConstants.REGTEST_FEDERATION_PRIVATE_KEYS.get(0);
    BtcECKey privateKeyOfSecondFed = BridgeRegTestConstants.REGTEST_FEDERATION_PRIVATE_KEYS.get(1);
    BtcECKey.ECDSASignature lastSig = null;
    for (int i = 0; i < 3; i++) {
        Script inputScript = t.getInput(i).getScriptSig();
        List<ScriptChunk> chunks = inputScript.getChunks();
        byte[] program = chunks.get(chunks.size() - 1).data;
        Script redeemScript = new Script(program);
        Sha256Hash sighash = t.hashForSignature(i, redeemScript, BtcTransaction.SigHash.ALL, false);
        // Sign the last input with a random key
        // but keep the good signature for a subsequent call
        BtcECKey.ECDSASignature sig = privateKeyOfFirstFed.sign(sighash);
        if (i == 2) {
            lastSig = sig;
            sig = new BtcECKey().sign(sighash);
        }
        derEncodedSigsFirstFed.add(sig.encodeToDER());
        derEncodedSigsSecondFed.add(privateKeyOfSecondFed.sign(sighash).encodeToDER());
    }
    // Sign with two valid signatures and one invalid signature
    bridgeSupport.addSignature(findPublicKeySignedBy(federation.getBtcPublicKeys(), privateKeyOfFirstFed), derEncodedSigsFirstFed, keccak256.getBytes());
    bridgeSupport.save();
    // Sign with two valid signatures and one malformed signature
    byte[] malformedSignature = new byte[lastSig.encodeToDER().length];
    for (int i = 0; i < malformedSignature.length; i++) {
        malformedSignature[i] = (byte) i;
    }
    derEncodedSigsFirstFed.set(2, malformedSignature);
    bridgeSupport.addSignature(findPublicKeySignedBy(federation.getBtcPublicKeys(), privateKeyOfFirstFed), derEncodedSigsFirstFed, keccak256.getBytes());
    bridgeSupport.save();
    // Sign with fully valid signatures for same federator
    derEncodedSigsFirstFed.set(2, lastSig.encodeToDER());
    bridgeSupport.addSignature(findPublicKeySignedBy(federation.getBtcPublicKeys(), privateKeyOfFirstFed), derEncodedSigsFirstFed, keccak256.getBytes());
    bridgeSupport.save();
    // Sign with second federation
    bridgeSupport.addSignature(findPublicKeySignedBy(federation.getBtcPublicKeys(), privateKeyOfSecondFed), derEncodedSigsSecondFed, keccak256.getBytes());
    bridgeSupport.save();
    provider = new BridgeStorageProvider(repository, PrecompiledContracts.BRIDGE_ADDR, bridgeConstants, activationsBeforeForks);
    Assert.assertTrue(provider.getRskTxsWaitingForSignatures().isEmpty());
    Assert.assertThat(logs, is(not(empty())));
    Assert.assertThat(logs, hasSize(5));
    LogInfo releaseTxEvent = logs.get(4);
    Assert.assertThat(releaseTxEvent.getTopics(), hasSize(1));
    Assert.assertThat(releaseTxEvent.getTopics(), hasItem(Bridge.RELEASE_BTC_TOPIC));
    BtcTransaction releaseTx = new BtcTransaction(btcParams, ((RLPList) RLP.decode2(releaseTxEvent.getData()).get(0)).get(1).getRLPData());
    // Verify all inputs fully signed
    for (int i = 0; i < releaseTx.getInputs().size(); i++) {
        Script retrievedScriptSig = releaseTx.getInput(i).getScriptSig();
        Assert.assertEquals(4, retrievedScriptSig.getChunks().size());
        assertTrue(Objects.requireNonNull(retrievedScriptSig.getChunks().get(1).data).length > 0);
        assertTrue(Objects.requireNonNull(retrievedScriptSig.getChunks().get(2).data).length > 0);
    }
}
Also used : PegTestUtils.createBaseInputScriptThatSpendsFromTheFederation(co.rsk.peg.PegTestUtils.createBaseInputScriptThatSpendsFromTheFederation) PegTestUtils.createBaseRedeemScriptThatSpendsFromTheFederation(co.rsk.peg.PegTestUtils.createBaseRedeemScriptThatSpendsFromTheFederation) Script(co.rsk.bitcoinj.script.Script) LogInfo(org.ethereum.vm.LogInfo) Keccak256(co.rsk.crypto.Keccak256) ScriptChunk(co.rsk.bitcoinj.script.ScriptChunk) RLPList(org.ethereum.util.RLPList) ActivationConfig(org.ethereum.config.blockchain.upgrades.ActivationConfig) Repository(org.ethereum.core.Repository) MutableRepository(org.ethereum.db.MutableRepository) Block(org.ethereum.core.Block) ActivationConfigsForTest(org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest) Test(org.junit.Test)

Example 13 with ScriptChunk

use of co.rsk.bitcoinj.script.ScriptChunk in project rskj by rsksmart.

the class BridgeUtils method isInputSignedByThisFederator.

/**
 * Check if the p2sh multisig scriptsig of the given input was already signed by federatorPublicKey.
 * @param federatorPublicKey The key that may have been used to sign
 * @param sighash the sighash that corresponds to the input
 * @param input The input
 * @return true if the input was already signed by the specified key, false otherwise.
 */
public static boolean isInputSignedByThisFederator(BtcECKey federatorPublicKey, Sha256Hash sighash, TransactionInput input) {
    List<ScriptChunk> chunks = input.getScriptSig().getChunks();
    for (int j = 1; j < chunks.size() - 1; j++) {
        ScriptChunk chunk = chunks.get(j);
        if (chunk.data.length == 0) {
            continue;
        }
        TransactionSignature sig2 = TransactionSignature.decodeFromBitcoin(chunk.data, false, false);
        if (federatorPublicKey.verify(sighash, sig2)) {
            return true;
        }
    }
    return false;
}
Also used : TransactionSignature(co.rsk.bitcoinj.crypto.TransactionSignature) ScriptChunk(co.rsk.bitcoinj.script.ScriptChunk)

Example 14 with ScriptChunk

use of co.rsk.bitcoinj.script.ScriptChunk in project rskj by rsksmart.

the class BridgeUtils method hasEnoughSignatures.

/**
 * Checks whether a btc tx has been signed by the required number of federators.
 * @param btcContext Btc context
 * @param btcTx The btc tx to check
 * @return True if was signed by the required number of federators, false otherwise
 */
public static boolean hasEnoughSignatures(Context btcContext, BtcTransaction btcTx) {
    // When the tx is constructed OP_0 are placed where signature should go.
    // Check all OP_0 have been replaced with actual signatures in all inputs
    Context.propagate(btcContext);
    Script scriptSig;
    List<ScriptChunk> chunks;
    Script redeemScript;
    RedeemScriptParser parser;
    MultiSigType multiSigType;
    int lastChunk;
    for (TransactionInput input : btcTx.getInputs()) {
        scriptSig = input.getScriptSig();
        chunks = scriptSig.getChunks();
        redeemScript = new Script(chunks.get(chunks.size() - 1).data);
        parser = RedeemScriptParserFactory.get(redeemScript.getChunks());
        multiSigType = parser.getMultiSigType();
        if (multiSigType == MultiSigType.STANDARD_MULTISIG || multiSigType == MultiSigType.FAST_BRIDGE_MULTISIG) {
            lastChunk = chunks.size() - 1;
        } else {
            lastChunk = chunks.size() - 2;
        }
        for (int i = 1; i < lastChunk; i++) {
            ScriptChunk chunk = chunks.get(i);
            if (!chunk.isOpCode() && chunk.data.length == 0) {
                return false;
            }
        }
    }
    return true;
}
Also used : Script(co.rsk.bitcoinj.script.Script) MultiSigType(co.rsk.bitcoinj.script.RedeemScriptParser.MultiSigType) ScriptChunk(co.rsk.bitcoinj.script.ScriptChunk) RedeemScriptParser(co.rsk.bitcoinj.script.RedeemScriptParser)

Example 15 with ScriptChunk

use of co.rsk.bitcoinj.script.ScriptChunk in project rskj by rsksmart.

the class BridgeSupport method hasEnoughSignatures.

/**
 * Checks whether a btc tx has been signed by the required number of federators.
 * @param btcTx The btc tx to check
 * @return True if was signed by the required number of federators, false otherwise
 */
private boolean hasEnoughSignatures(BtcTransaction btcTx) {
    // When the tx is constructed OP_0 are placed where signature should go.
    // Check all OP_0 have been replaced with actual signatures in all inputs
    Context.propagate(btcContext);
    for (TransactionInput input : btcTx.getInputs()) {
        Script scriptSig = input.getScriptSig();
        List<ScriptChunk> chunks = scriptSig.getChunks();
        for (int i = 1; i < chunks.size(); i++) {
            ScriptChunk chunk = chunks.get(i);
            if (!chunk.isOpCode() && chunk.data.length == 0) {
                return false;
            }
        }
    }
    return true;
}
Also used : Script(co.rsk.bitcoinj.script.Script) ScriptChunk(co.rsk.bitcoinj.script.ScriptChunk)

Aggregations

ScriptChunk (co.rsk.bitcoinj.script.ScriptChunk)17 Script (co.rsk.bitcoinj.script.Script)14 TransactionSignature (co.rsk.bitcoinj.crypto.TransactionSignature)7 Keccak256 (co.rsk.crypto.Keccak256)5 ActivationConfigsForTest (org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest)5 Test (org.junit.Test)5 BtcECKey (co.rsk.bitcoinj.core.BtcECKey)4 Sha256Hash (co.rsk.bitcoinj.core.Sha256Hash)4 TransactionInput (co.rsk.bitcoinj.core.TransactionInput)4 BtcTransaction (co.rsk.bitcoinj.core.BtcTransaction)3 TransactionOutPoint (co.rsk.bitcoinj.core.TransactionOutPoint)3 PegTestUtils.createBaseInputScriptThatSpendsFromTheFederation (co.rsk.peg.PegTestUtils.createBaseInputScriptThatSpendsFromTheFederation)3 PegTestUtils.createBaseRedeemScriptThatSpendsFromTheFederation (co.rsk.peg.PegTestUtils.createBaseRedeemScriptThatSpendsFromTheFederation)3 Block (org.ethereum.core.Block)3 Repository (org.ethereum.core.Repository)3 MutableRepository (org.ethereum.db.MutableRepository)3 RLPList (org.ethereum.util.RLPList)3 RedeemScriptParser (co.rsk.bitcoinj.script.RedeemScriptParser)2 MultiSigType (co.rsk.bitcoinj.script.RedeemScriptParser.MultiSigType)2 ActivationConfig (org.ethereum.config.blockchain.upgrades.ActivationConfig)2