btc_transaction_utils/
lib.rs

1// Copyright 2018 The Exonum Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//   http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! BTC transaction utils is a small library that will help to create multisig addresses
16//! and sign a some types of segwit transactions.
17//!
18//! By using this library you can make the following things:
19//!
20//! - [Create][redeem-script] a redeem script and a corresponding multisig address (3 of 4).
21//! - [Sign][p2wpk] the `P2WPK` inputs.
22//! - [Sign][p2wsh] the `P2WSH` inputs.
23//!
24//! # Examples
25//!
26//! ## Create a redeem script and a corresponding multisig address (3 of 4).
27//!
28//! ```
29//! use bitcoin::network::constants::Network;
30//! use btc_transaction_utils::multisig::RedeemScriptBuilder;
31//! use btc_transaction_utils::test_data::secp_gen_keypair;
32//! use btc_transaction_utils::p2wsh;
33//!
34//! // Generate four key pairs.
35//! let keypairs = (0..4)
36//!     .map(|_| secp_gen_keypair(Network::Testnet))
37//!     .collect::<Vec<_>>();
38//! // Create a corresponding redeem script.
39//! let public_keys = keypairs.iter().map(|keypair| keypair.0);
40//! let script = RedeemScriptBuilder::with_public_keys(public_keys)
41//!     .quorum(3)
42//!     .to_script()
43//!     .unwrap();
44//! // Create a corresponding testnet address for the given redeem script.
45//! let address = p2wsh::address(&script, Network::Testnet);
46//! println!("{}", address.to_string());
47//! ```
48//!
49//! ## Sign P2WPK input
50//!
51//! ```
52//! use bitcoin::{
53//!     blockdata::opcodes::all::OP_RETURN,
54//!     blockdata::script::{Builder, Script},
55//!     blockdata::transaction::{OutPoint, Transaction, TxIn, TxOut},
56//!     network::constants::Network
57//! };
58//! use btc_transaction_utils::{
59//!     p2wpk,
60//!     test_data::{secp_gen_keypair_with_rng, btc_tx_from_hex},
61//!     TxInRef
62//! };
63//! use rand::prelude::*;
64//!
65//! // Take a transaction with the unspent P2WPK output.
66//! let prev_tx = btc_tx_from_hex(
67//!     "02000000000101beccab33bc72bfc81b63fdec8a4a9a4719e4418bdb7b20e47b0\
68//!      2074dc42f2d800000000017160014f3b1b3819c1290cd5d675c1319dc7d9d98d5\
69//!      71bcfeffffff02dceffa0200000000160014368c6b7c38f0ff0839bf78d77544d\
70//!      a96cb685bf28096980000000000160014284175e336fa10865fb4d1351c9e18e7\
71//!      30f5d6f90247304402207c893c85d75e2230dde04f5a1e2c83c4f0b7d93213372\
72//!      746eb2227b068260d840220705484b6ec70a8fc0d1f80c3a98079602595351b7a\
73//!      9bca7caddb9a6adb0a3440012103150514f05f3e3f40c7b404b16f8a09c2c71ba\
74//!      d3ba8da5dd1e411a7069cc080a004b91300",
75//! );
76//! // Take the corresponding key pair.
77//! let mut rng = thread_rng();
78//! let keypair = secp_gen_keypair_with_rng(&mut rng, Network::Testnet);
79//! // Create an unsigned transaction
80//! let mut transaction = Transaction {
81//!     version: 2,
82//!     lock_time: 0,
83//!     input: vec![
84//!         TxIn {
85//!             previous_output: OutPoint {
86//!                 txid: prev_tx.txid(),
87//!                 vout: 1,
88//!             },
89//!             script_sig: Script::default(),
90//!             sequence: 0xFFFFFFFF,
91//!             witness: Vec::default(),
92//!         },
93//!     ],
94//!     output: vec![
95//!         TxOut {
96//!             value: 0,
97//!             script_pubkey: Builder::new()
98//!                 .push_opcode(OP_RETURN)
99//!                 .push_slice(b"Hello Exonum!")
100//!                 .into_script(),
101//!         },
102//!     ],
103//! };
104//! // Create a signature for the given input.
105//! let mut signer = p2wpk::InputSigner::new(keypair.0, Network::Testnet);
106//! let signature = signer
107//!     .sign_input(TxInRef::new(&transaction, 0), &prev_tx, &keypair.1.key)
108//!     .unwrap();
109//! // Finalize the transaction.
110//! signer.spend_input(&mut transaction.input[0], signature);
111//! ```
112//!
113//! ## Sign P2WSH input
114//!
115//! ```
116//! use bitcoin::{
117//!     blockdata::opcodes::all::OP_RETURN,
118//!     blockdata::script::{Builder, Script},
119//!     blockdata::transaction::{OutPoint, Transaction, TxIn, TxOut},
120//!     network::constants::Network
121//! };
122//! use btc_transaction_utils::{
123//!     multisig::RedeemScriptBuilder,
124//!     p2wsh,
125//!     test_data::{secp_gen_keypair_with_rng, btc_tx_from_hex},
126//!     TxInRef
127//! };
128//! use rand::prelude::*;
129//!
130//! // Take a transaction with the unspent P2WSH output.
131//! let prev_tx = btc_tx_from_hex(
132//!     "02000000000101f8c16000cc59f9505046303944d42a6c264a322f80b46bb4361\
133//!      15b6e306ba9950000000000feffffff02f07dc81600000000160014f65eb9d72a\
134//!      8475dd8e26f4fa748796e211aa8869102700000000000022002001fb25c3db04c\
135//!      a5580da43a7d38dd994650d9aa6d6ee075b4578388deed338ed0247304402206b\
136//!      5f211cd7f9b89e80c734b61113c33f437ba153e7ba6bc275eed857e54fcb26022\
137//!      0038562e88b805f0cdfd4873ab3579d52268babe6af9c49086c00343187cdf28a\
138//!      012103979dff5cd9045f4b6fa454d2bc5357586a85d4789123df45f83522963d9\
139//!      4e3217fb91300",
140//! );
141//! // Take the corresponding key pairs and the redeem script.
142//! let total_count = 18;
143//! let quorum = 12;
144//! let mut rng = thread_rng();
145//! let keypairs = (0..total_count)
146//!     .into_iter()
147//!     .map(|_| secp_gen_keypair_with_rng(&mut rng, Network::Testnet))
148//!     .collect::<Vec<_>>();
149//! let public_keys = keypairs.iter().map(|keypair| keypair.0);
150//! let redeem_script = RedeemScriptBuilder::with_public_keys(public_keys)
151//!     .quorum(quorum)
152//!     .to_script()
153//!     .unwrap();
154//! // Create an unsigned transaction.
155//! let mut transaction = Transaction {
156//!     version: 2,
157//!     lock_time: 0,
158//!     input: vec![
159//!         TxIn {
160//!             previous_output: OutPoint {
161//!                 txid: prev_tx.txid(),
162//!                 vout: 1,
163//!             },
164//!             script_sig: Script::default(),
165//!             sequence: 0xFFFFFFFF,
166//!             witness: Vec::default(),
167//!         },
168//!     ],
169//!     output: vec![
170//!         TxOut {
171//!             value: 0,
172//!             script_pubkey: Builder::new()
173//!                 .push_opcode(OP_RETURN)
174//!                 .push_slice(b"Hello Exonum with multisig!")
175//!                 .into_script(),
176//!         },
177//!     ],
178//! };
179//! // Create signatures for the given input.
180//! let mut signer = p2wsh::InputSigner::new(redeem_script.clone());
181//! let signatures = keypairs[0..quorum]
182//!     .iter()
183//!     .map(|keypair| {
184//!         let txin = TxInRef::new(&transaction, 0);
185//!         signer.sign_input(txin, &prev_tx, &keypair.1.key).unwrap()
186//!     })
187//!     .collect::<Vec<_>>();
188//! // Finalize the transaction.
189//! signer.spend_input(&mut transaction.input[0], signatures);
190//! ```
191//!
192//! [redeem-script]: #create-a-redeem-script-and-a-corresponding-multisig-address-3-of-4
193//! [p2wpk]: #sign-p2wpk-input
194//! [p2wsh]: #sign-p2wsh-input
195
196#![deny(
197    missing_debug_implementations,
198    missing_docs,
199    unsafe_code,
200    bare_trait_objects
201)]
202
203#[macro_use]
204mod macros;
205mod sign;
206
207use bitcoin::blockdata::transaction::{Transaction, TxIn, TxOut};
208
209pub mod multisig;
210pub mod p2wpk;
211pub mod p2wsh;
212pub mod test_data;
213
214pub(crate) use bitcoin_hashes::{hash160::Hash as Hash160, sha256d::Hash as Sha256dHash, Hash};
215pub use sign::{InputSignature, InputSignatureRef};
216
217/// A borrowed reference to a transaction input.
218#[derive(Debug, Copy, Clone)]
219pub struct TxInRef<'a> {
220    transaction: &'a Transaction,
221    index: usize,
222}
223
224impl<'a> TxInRef<'a> {
225    /// Constructs a reference to the input with the given index of the given transaction.
226    pub fn new(transaction: &'a Transaction, index: usize) -> TxInRef<'a> {
227        assert!(transaction.input.len() > index);
228        TxInRef { transaction, index }
229    }
230
231    /// Returns a reference to the borrowed transaction.
232    pub fn transaction(&self) -> &Transaction {
233        self.transaction
234    }
235
236    /// Returns a reference to the input.
237    pub fn input(&self) -> &TxIn {
238        &self.transaction.input[self.index]
239    }
240
241    /// Returns the index of input.
242    pub fn index(&self) -> usize {
243        self.index
244    }
245}
246
247impl<'a> AsRef<TxIn> for TxInRef<'a> {
248    fn as_ref(&self) -> &TxIn {
249        self.input()
250    }
251}
252
253/// An auxiliary enumeration that helps to get the balance of the previous
254/// unspent transaction output.
255#[derive(Debug, Copy, Clone)]
256pub enum UnspentTxOutValue<'a> {
257    /// The output balance.
258    Balance(u64),
259    /// A reference to the transaction with the required unspent output.
260    PrevTx(&'a Transaction),
261    /// A reference to the transaction output to be spent.
262    PrevOut(&'a TxOut),
263}
264
265impl<'a> UnspentTxOutValue<'a> {
266    /// Returns the output balance value.
267    pub fn balance(self, txin: TxInRef) -> u64 {
268        match self {
269            UnspentTxOutValue::Balance(value) => value,
270            UnspentTxOutValue::PrevTx(prev_tx) => {
271                prev_tx.output[txin.input().previous_output.vout as usize].value
272            }
273            UnspentTxOutValue::PrevOut(out) => out.value,
274        }
275    }
276}
277
278impl<'a> From<u64> for UnspentTxOutValue<'a> {
279    fn from(balance: u64) -> UnspentTxOutValue<'a> {
280        UnspentTxOutValue::Balance(balance)
281    }
282}
283
284impl<'a> From<&'a Transaction> for UnspentTxOutValue<'a> {
285    fn from(tx_ref: &'a Transaction) -> UnspentTxOutValue {
286        UnspentTxOutValue::PrevTx(tx_ref)
287    }
288}
289
290impl<'a> From<&'a TxOut> for UnspentTxOutValue<'a> {
291    fn from(tx_out: &'a TxOut) -> UnspentTxOutValue<'a> {
292        UnspentTxOutValue::PrevOut(tx_out)
293    }
294}