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);
}
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);
}
}
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;
}
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;
}
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;
}
Aggregations