1use bitcoin::{
18 blockdata::{
19 script::{Builder, Script},
20 transaction::TxIn,
21 },
22 network::constants::Network,
23 util::{address::Address, key::PublicKey, psbt::serialize::Serialize},
24};
25use secp256k1::{self, All, Secp256k1, SecretKey};
26
27use crate::{
28 sign, Hash, Hash160, InputSignature, InputSignatureRef, Sha256dHash, TxInRef, UnspentTxOutValue,
29};
30
31pub fn address(pk: &PublicKey, network: Network) -> Address {
33 Address::p2wpkh(pk, network)
34}
35
36pub fn script_pubkey(pk: &PublicKey) -> Script {
38 let witness_version = 0;
39 let pk_hash = Hash160::hash(&pk.key.serialize()).into_inner().to_vec();
40 Builder::new()
41 .push_int(witness_version)
42 .push_slice(&pk_hash)
43 .into_script()
44}
45
46#[derive(Debug)]
48pub struct InputSigner {
49 context: Secp256k1<All>,
50 public_key: PublicKey,
51 network: Network,
52}
53
54impl InputSigner {
55 pub fn new(public_key: PublicKey, network: Network) -> InputSigner {
57 InputSigner {
58 context: Secp256k1::new(),
59 public_key,
60 network,
61 }
62 }
63
64 pub fn secp256k1_context(&self) -> &Secp256k1<All> {
66 &self.context
67 }
68
69 pub fn secp256k1_context_mut(&mut self) -> &mut Secp256k1<All> {
71 &mut self.context
72 }
73
74 pub fn signature_hash<'a, 'b, V: Into<UnspentTxOutValue<'b>>>(
80 &mut self,
81 txin: TxInRef<'a>,
82 value: V,
83 ) -> Sha256dHash {
84 sign::signature_hash(txin, &self.witness_script(), value)
85 }
86
87 pub fn sign_input<'a, 'b, V: Into<UnspentTxOutValue<'b>>>(
94 &mut self,
95 txin: TxInRef<'a>,
96 value: V,
97 secret_key: &SecretKey,
98 ) -> Result<InputSignature, secp256k1::Error> {
99 let script = self.witness_script();
100 sign::sign_input(&mut self.context, txin, &script, value, secret_key)
101 }
102
103 pub fn verify_input<'a, 'b, 'c, V, S>(
105 &self,
106 txin: TxInRef<'a>,
107 value: V,
108 public_key: &PublicKey,
109 signature: S,
110 ) -> Result<(), secp256k1::Error>
111 where
112 V: Into<UnspentTxOutValue<'b>>,
113 S: Into<InputSignatureRef<'c>>,
114 {
115 sign::verify_input_signature(
116 &self.context,
117 txin,
118 &self.witness_script(),
119 value,
120 public_key,
121 signature.into().content(),
122 )
123 }
124
125 pub fn spend_input(&self, input: &mut TxIn, signature: InputSignature) {
127 input.witness = self.witness_data(signature.into());
128 }
129
130 fn witness_data(&self, signature: Vec<u8>) -> Vec<Vec<u8>> {
131 vec![signature, self.public_key.serialize().to_vec()]
132 }
133
134 fn witness_script(&self) -> Script {
135 Address::p2pkh(&self.public_key, self.network).script_pubkey()
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use bitcoin::{
142 blockdata::opcodes::all::OP_RETURN,
143 blockdata::script::{Builder, Script},
144 blockdata::transaction::{OutPoint, Transaction, TxIn, TxOut},
145 network::constants::Network,
146 };
147
148 use crate::{
149 p2wpk,
150 test_data::{btc_tx_from_hex, keypair_from_wif},
151 TxInRef,
152 };
153
154 #[test]
155 fn test_native_segwit() {
156 let (pk, sk) = keypair_from_wif("cPHmynxvqfr7sXsJcohiGzoPGBShggxL6VWUdW14skohFZ1LQoeV");
157
158 let prev_tx = btc_tx_from_hex(
159 "02000000000101beccab33bc72bfc81b63fdec8a4a9a4719e4418bdb7b20e47b02074dc42f2d800000000\
160 017160014f3b1b3819c1290cd5d675c1319dc7d9d98d571bcfeffffff02dceffa0200000000160014368c\
161 6b7c38f0ff0839bf78d77544da96cb685bf28096980000000000160014284175e336fa10865fb4d1351c9\
162 e18e730f5d6f90247304402207c893c85d75e2230dde04f5a1e2c83c4f0b7d93213372746eb2227b06826\
163 0d840220705484b6ec70a8fc0d1f80c3a98079602595351b7a9bca7caddb9a6adb0a3440012103150514f\
164 05f3e3f40c7b404b16f8a09c2c71bad3ba8da5dd1e411a7069cc080a004b91300",
165 );
166 assert_eq!(prev_tx.output[1].script_pubkey, p2wpk::script_pubkey(&pk));
167
168 let mut transaction = Transaction {
170 version: 2,
171 lock_time: 0,
172 input: vec![TxIn {
173 previous_output: OutPoint {
174 txid: prev_tx.txid(),
175 vout: 1,
176 },
177 script_sig: Script::default(),
178 sequence: 0xFFFF_FFFF,
179 witness: Vec::default(),
180 }],
181 output: vec![TxOut {
182 value: 0,
183 script_pubkey: Builder::new()
184 .push_opcode(OP_RETURN)
185 .push_slice(b"Hello Exonum!")
186 .into_script(),
187 }],
188 };
189 let mut signer = p2wpk::InputSigner::new(pk, Network::Testnet);
191 let signature = signer
192 .sign_input(TxInRef::new(&transaction, 0), &prev_tx, &sk.key)
193 .unwrap();
194 signer
196 .verify_input(TxInRef::new(&transaction, 0), &prev_tx, &pk, &signature)
197 .expect("Signature should be correct");
198 signer.spend_input(&mut transaction.input[0], signature);
200 let expected_tx = btc_tx_from_hex(
202 "0200000000010145f4a039a4bd6cc753ec02a22498b98427c6c288244340fff9d2abb5c63e48390100000\
203 000ffffffff0100000000000000000f6a0d48656c6c6f2045786f6e756d2102483045022100bdc1be9286\
204 2281061a14f7153dd57b7b3befa2b98fe85ae5d427d3921fe165ca02202f259a63f965f6d7f0503584b46\
205 3ce4b67c09b5a2e99c27f236f7a986743a94a0121031cf96b4fef362af7d86ee6c7159fa89485730dac8e\
206 3090163dd0c282dbc84f2200000000",
207 );
208 assert_eq!(transaction, expected_tx);
209 }
210}