Typify payment_hash and payment_preimage
[rust-lightning] / src / ln / chan_utils.rs
1 use bitcoin::blockdata::script::{Script,Builder};
2 use bitcoin::blockdata::opcodes;
3 use bitcoin::blockdata::transaction::{TxIn,TxOut,OutPoint,Transaction};
4 use bitcoin::util::hash::{Hash160,Sha256dHash};
5
6 use ln::channelmanager::PaymentHash;
7
8 use secp256k1::key::{PublicKey,SecretKey};
9 use secp256k1::Secp256k1;
10 use secp256k1;
11
12 use crypto::digest::Digest;
13 use crypto::ripemd160::Ripemd160;
14
15 use util::sha2::Sha256;
16
17 pub const HTLC_SUCCESS_TX_WEIGHT: u64 = 703;
18 pub const HTLC_TIMEOUT_TX_WEIGHT: u64 = 663;
19
20 // Various functions for key derivation and transaction creation for use within channels. Primarily
21 // used in Channel and ChannelMonitor.
22
23 pub fn build_commitment_secret(commitment_seed: [u8; 32], idx: u64) -> [u8; 32] {
24         let mut res: [u8; 32] = commitment_seed;
25         for i in 0..48 {
26                 let bitpos = 47 - i;
27                 if idx & (1 << bitpos) == (1 << bitpos) {
28                         res[bitpos / 8] ^= 1 << (bitpos & 7);
29                         let mut sha = Sha256::new();
30                         sha.input(&res);
31                         sha.result(&mut res);
32                 }
33         }
34         res
35 }
36
37 pub fn derive_private_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, base_secret: &SecretKey) -> Result<SecretKey, secp256k1::Error> {
38         let mut sha = Sha256::new();
39         sha.input(&per_commitment_point.serialize());
40         sha.input(&PublicKey::from_secret_key(&secp_ctx, &base_secret).serialize());
41         let mut res = [0; 32];
42         sha.result(&mut res);
43
44         let mut key = base_secret.clone();
45         key.add_assign(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &res)?)?;
46         Ok(key)
47 }
48
49 pub fn derive_public_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, base_point: &PublicKey) -> Result<PublicKey, secp256k1::Error> {
50         let mut sha = Sha256::new();
51         sha.input(&per_commitment_point.serialize());
52         sha.input(&base_point.serialize());
53         let mut res = [0; 32];
54         sha.result(&mut res);
55
56         let hashkey = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &res)?);
57         base_point.combine(&secp_ctx, &hashkey)
58 }
59
60 /// Derives a revocation key from its constituent parts
61 pub fn derive_private_revocation_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_secret: &SecretKey, revocation_base_secret: &SecretKey) -> Result<SecretKey, secp256k1::Error> {
62         let revocation_base_point = PublicKey::from_secret_key(&secp_ctx, &revocation_base_secret);
63         let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret);
64
65         let rev_append_commit_hash_key = {
66                 let mut sha = Sha256::new();
67                 sha.input(&revocation_base_point.serialize());
68                 sha.input(&per_commitment_point.serialize());
69                 let mut res = [0; 32];
70                 sha.result(&mut res);
71
72                 SecretKey::from_slice(&secp_ctx, &res)?
73         };
74         let commit_append_rev_hash_key = {
75                 let mut sha = Sha256::new();
76                 sha.input(&per_commitment_point.serialize());
77                 sha.input(&revocation_base_point.serialize());
78                 let mut res = [0; 32];
79                 sha.result(&mut res);
80
81                 SecretKey::from_slice(&secp_ctx, &res)?
82         };
83
84         let mut part_a = revocation_base_secret.clone();
85         part_a.mul_assign(&secp_ctx, &rev_append_commit_hash_key)?;
86         let mut part_b = per_commitment_secret.clone();
87         part_b.mul_assign(&secp_ctx, &commit_append_rev_hash_key)?;
88         part_a.add_assign(&secp_ctx, &part_b)?;
89         Ok(part_a)
90 }
91
92 pub fn derive_public_revocation_key<T: secp256k1::Verification>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, revocation_base_point: &PublicKey) -> Result<PublicKey, secp256k1::Error> {
93         let rev_append_commit_hash_key = {
94                 let mut sha = Sha256::new();
95                 sha.input(&revocation_base_point.serialize());
96                 sha.input(&per_commitment_point.serialize());
97                 let mut res = [0; 32];
98                 sha.result(&mut res);
99
100                 SecretKey::from_slice(&secp_ctx, &res)?
101         };
102         let commit_append_rev_hash_key = {
103                 let mut sha = Sha256::new();
104                 sha.input(&per_commitment_point.serialize());
105                 sha.input(&revocation_base_point.serialize());
106                 let mut res = [0; 32];
107                 sha.result(&mut res);
108
109                 SecretKey::from_slice(&secp_ctx, &res)?
110         };
111
112         let mut part_a = revocation_base_point.clone();
113         part_a.mul_assign(&secp_ctx, &rev_append_commit_hash_key)?;
114         let mut part_b = per_commitment_point.clone();
115         part_b.mul_assign(&secp_ctx, &commit_append_rev_hash_key)?;
116         part_a.combine(&secp_ctx, &part_b)
117 }
118
119 pub struct TxCreationKeys {
120         pub per_commitment_point: PublicKey,
121         pub revocation_key: PublicKey,
122         pub a_htlc_key: PublicKey,
123         pub b_htlc_key: PublicKey,
124         pub a_delayed_payment_key: PublicKey,
125         pub b_payment_key: PublicKey,
126 }
127
128 impl TxCreationKeys {
129         pub fn new<T: secp256k1::Signing + secp256k1::Verification>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, a_delayed_payment_base: &PublicKey, a_htlc_base: &PublicKey, b_revocation_base: &PublicKey, b_payment_base: &PublicKey, b_htlc_base: &PublicKey) -> Result<TxCreationKeys, secp256k1::Error> {
130                 Ok(TxCreationKeys {
131                         per_commitment_point: per_commitment_point.clone(),
132                         revocation_key: derive_public_revocation_key(&secp_ctx, &per_commitment_point, &b_revocation_base)?,
133                         a_htlc_key: derive_public_key(&secp_ctx, &per_commitment_point, &a_htlc_base)?,
134                         b_htlc_key: derive_public_key(&secp_ctx, &per_commitment_point, &b_htlc_base)?,
135                         a_delayed_payment_key: derive_public_key(&secp_ctx, &per_commitment_point, &a_delayed_payment_base)?,
136                         b_payment_key: derive_public_key(&secp_ctx, &per_commitment_point, &b_payment_base)?,
137                 })
138         }
139 }
140
141 /// Gets the "to_local" output redeemscript, ie the script which is time-locked or spendable by
142 /// the revocation key
143 pub fn get_revokeable_redeemscript(revocation_key: &PublicKey, to_self_delay: u16, delayed_payment_key: &PublicKey) -> Script {
144         Builder::new().push_opcode(opcodes::All::OP_IF)
145                       .push_slice(&revocation_key.serialize())
146                       .push_opcode(opcodes::All::OP_ELSE)
147                       .push_int(to_self_delay as i64)
148                       .push_opcode(opcodes::OP_CSV)
149                       .push_opcode(opcodes::All::OP_DROP)
150                       .push_slice(&delayed_payment_key.serialize())
151                       .push_opcode(opcodes::All::OP_ENDIF)
152                       .push_opcode(opcodes::All::OP_CHECKSIG)
153                       .into_script()
154 }
155
156 #[derive(Clone, PartialEq)]
157 pub struct HTLCOutputInCommitment {
158         pub offered: bool,
159         pub amount_msat: u64,
160         pub cltv_expiry: u32,
161         pub payment_hash: PaymentHash,
162         pub transaction_output_index: u32,
163 }
164
165 #[inline]
166 pub fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, a_htlc_key: &PublicKey, b_htlc_key: &PublicKey, revocation_key: &PublicKey) -> Script {
167         let payment_hash160 = {
168                 let mut ripemd = Ripemd160::new();
169                 ripemd.input(&htlc.payment_hash.0[..]);
170                 let mut res = [0; 20];
171                 ripemd.result(&mut res);
172                 res
173         };
174         if htlc.offered {
175                 Builder::new().push_opcode(opcodes::All::OP_DUP)
176                               .push_opcode(opcodes::All::OP_HASH160)
177                               .push_slice(&Hash160::from_data(&revocation_key.serialize())[..])
178                               .push_opcode(opcodes::All::OP_EQUAL)
179                               .push_opcode(opcodes::All::OP_IF)
180                               .push_opcode(opcodes::All::OP_CHECKSIG)
181                               .push_opcode(opcodes::All::OP_ELSE)
182                               .push_slice(&b_htlc_key.serialize()[..])
183                               .push_opcode(opcodes::All::OP_SWAP)
184                               .push_opcode(opcodes::All::OP_SIZE)
185                               .push_int(32)
186                               .push_opcode(opcodes::All::OP_EQUAL)
187                               .push_opcode(opcodes::All::OP_NOTIF)
188                               .push_opcode(opcodes::All::OP_DROP)
189                               .push_int(2)
190                               .push_opcode(opcodes::All::OP_SWAP)
191                               .push_slice(&a_htlc_key.serialize()[..])
192                               .push_int(2)
193                               .push_opcode(opcodes::All::OP_CHECKMULTISIG)
194                               .push_opcode(opcodes::All::OP_ELSE)
195                               .push_opcode(opcodes::All::OP_HASH160)
196                               .push_slice(&payment_hash160)
197                               .push_opcode(opcodes::All::OP_EQUALVERIFY)
198                               .push_opcode(opcodes::All::OP_CHECKSIG)
199                               .push_opcode(opcodes::All::OP_ENDIF)
200                               .push_opcode(opcodes::All::OP_ENDIF)
201                               .into_script()
202         } else {
203                 Builder::new().push_opcode(opcodes::All::OP_DUP)
204                               .push_opcode(opcodes::All::OP_HASH160)
205                               .push_slice(&Hash160::from_data(&revocation_key.serialize())[..])
206                               .push_opcode(opcodes::All::OP_EQUAL)
207                               .push_opcode(opcodes::All::OP_IF)
208                               .push_opcode(opcodes::All::OP_CHECKSIG)
209                               .push_opcode(opcodes::All::OP_ELSE)
210                               .push_slice(&b_htlc_key.serialize()[..])
211                               .push_opcode(opcodes::All::OP_SWAP)
212                               .push_opcode(opcodes::All::OP_SIZE)
213                               .push_int(32)
214                               .push_opcode(opcodes::All::OP_EQUAL)
215                               .push_opcode(opcodes::All::OP_IF)
216                               .push_opcode(opcodes::All::OP_HASH160)
217                               .push_slice(&payment_hash160)
218                               .push_opcode(opcodes::All::OP_EQUALVERIFY)
219                               .push_int(2)
220                               .push_opcode(opcodes::All::OP_SWAP)
221                               .push_slice(&a_htlc_key.serialize()[..])
222                               .push_int(2)
223                               .push_opcode(opcodes::All::OP_CHECKMULTISIG)
224                               .push_opcode(opcodes::All::OP_ELSE)
225                               .push_opcode(opcodes::All::OP_DROP)
226                               .push_int(htlc.cltv_expiry as i64)
227                               .push_opcode(opcodes::OP_CLTV)
228                               .push_opcode(opcodes::All::OP_DROP)
229                               .push_opcode(opcodes::All::OP_CHECKSIG)
230                               .push_opcode(opcodes::All::OP_ENDIF)
231                               .push_opcode(opcodes::All::OP_ENDIF)
232                               .into_script()
233         }
234 }
235
236 /// note here that 'a_revocation_key' is generated using b_revocation_basepoint and a's
237 /// commitment secret. 'htlc' does *not* need to have its previous_output_index filled.
238 #[inline]
239 pub fn get_htlc_redeemscript(htlc: &HTLCOutputInCommitment, keys: &TxCreationKeys) -> Script {
240         get_htlc_redeemscript_with_explicit_keys(htlc, &keys.a_htlc_key, &keys.b_htlc_key, &keys.revocation_key)
241 }
242
243 pub fn build_htlc_transaction(prev_hash: &Sha256dHash, feerate_per_kw: u64, to_self_delay: u16, htlc: &HTLCOutputInCommitment, a_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction {
244         let mut txins: Vec<TxIn> = Vec::new();
245         txins.push(TxIn {
246                 previous_output: OutPoint {
247                         txid: prev_hash.clone(),
248                         vout: htlc.transaction_output_index,
249                 },
250                 script_sig: Script::new(),
251                 sequence: 0,
252                 witness: Vec::new(),
253         });
254
255         let total_fee = if htlc.offered {
256                         feerate_per_kw * HTLC_TIMEOUT_TX_WEIGHT / 1000
257                 } else {
258                         feerate_per_kw * HTLC_SUCCESS_TX_WEIGHT / 1000
259                 };
260
261         let mut txouts: Vec<TxOut> = Vec::new();
262         txouts.push(TxOut {
263                 script_pubkey: get_revokeable_redeemscript(revocation_key, to_self_delay, a_delayed_payment_key).to_v0_p2wsh(),
264                 value: htlc.amount_msat / 1000 - total_fee //TODO: BOLT 3 does not specify if we should add amount_msat before dividing or if we should divide by 1000 before subtracting (as we do here)
265         });
266
267         Transaction {
268                 version: 2,
269                 lock_time: if htlc.offered { htlc.cltv_expiry } else { 0 },
270                 input: txins,
271                 output: txouts,
272         }
273 }