/** * Create a program that satisfies an OP_CHECKMULTISIG program, using pre-encoded signatures. * Optionally, appends the script program bytes if spending a P2SH output. */ public static Script createMultiSigInputScriptBytes( List<byte[]> signatures, @Nullable byte[] multisigProgramBytes) { checkArgument(signatures.size() <= 16); ScriptBuilder builder = new ScriptBuilder(); builder.smallNum( 0); // Work around a bug in CHECKMULTISIG that is now a required part of the protocol. for (byte[] signature : signatures) builder.data(signature); if (multisigProgramBytes != null) builder.data(multisigProgramBytes); return builder.build(); }
/** * Returns a copy of the given scriptSig with the signature inserted in the given position. * * <p>This function assumes that any missing sigs have OP_0 placeholders. If given scriptSig * already has all the signatures in place, IllegalArgumentException will be thrown. * * @param targetIndex where to insert the signature * @param sigsPrefixCount how many items to copy verbatim (e.g. initial OP_0 for multisig) * @param sigsSuffixCount how many items to copy verbatim at end (e.g. redeemScript for P2SH) */ public static Script updateScriptWithSignature( Script scriptSig, byte[] signature, int targetIndex, int sigsPrefixCount, int sigsSuffixCount) { ScriptBuilder builder = new ScriptBuilder(); List<ScriptChunk> inputChunks = scriptSig.getChunks(); int totalChunks = inputChunks.size(); // Check if we have a place to insert, otherwise just return given scriptSig unchanged. // We assume here that OP_0 placeholders always go after the sigs, so // to find if we have sigs missing, we can just check the chunk in latest sig position boolean hasMissingSigs = inputChunks.get(totalChunks - sigsSuffixCount - 1).equalsOpCode(OP_0); checkArgument(hasMissingSigs, "ScriptSig is already filled with signatures"); // copy the prefix for (ScriptChunk chunk : inputChunks.subList(0, sigsPrefixCount)) builder.addChunk(chunk); // copy the sigs int pos = 0; boolean inserted = false; for (ScriptChunk chunk : inputChunks.subList(sigsPrefixCount, totalChunks - sigsSuffixCount)) { if (pos == targetIndex) { inserted = true; builder.data(signature); pos++; } if (!chunk.equalsOpCode(OP_0)) { builder.addChunk(chunk); pos++; } } // add OP_0's if needed, since we skipped them in the previous loop while (pos < totalChunks - sigsPrefixCount - sigsSuffixCount) { if (pos == targetIndex) { inserted = true; builder.data(signature); } else { builder.addChunk(new ScriptChunk(OP_0, null)); } pos++; } // copy the suffix for (ScriptChunk chunk : inputChunks.subList(totalChunks - sigsSuffixCount, totalChunks)) builder.addChunk(chunk); checkState(inserted); return builder.build(); }
/** * Creates a program that requires at least N of the given keys to sign, using OP_CHECKMULTISIG. */ public static Script createMultiSigOutputScript(int threshold, List<ECKey> pubkeys) { checkArgument(threshold > 0); checkArgument(threshold <= pubkeys.size()); checkArgument(pubkeys.size() <= 16); // That's the max we can represent with a single opcode. ScriptBuilder builder = new ScriptBuilder(); builder.smallNum(threshold); for (ECKey key : pubkeys) { builder.data(key.getPubKey()); } builder.smallNum(pubkeys.size()); builder.op(OP_CHECKMULTISIG); return builder.build(); }
/** * Creates redeem script with given public keys and threshold. Given public keys will be placed in * redeem script in the lexicographical sorting order. */ public static Script createRedeemScript(int threshold, List<ECKey> pubkeys) { pubkeys = new ArrayList<ECKey>(pubkeys); Collections.sort(pubkeys, ECKey.PUBKEY_COMPARATOR); return ScriptBuilder.createMultiSigOutputScript(threshold, pubkeys); }
/** Creates a scriptPubKey for the given redeem script. */ public static Script createP2SHOutputScript(Script redeemScript) { byte[] hash = Utils.Hash160(redeemScript.getProgram()); return ScriptBuilder.createP2SHOutputScript(hash); }