|
4 | 4 |
|
5 | 5 | use bitcoin::blockdata::script::{Script,Builder};
|
6 | 6 | use bitcoin::blockdata::opcodes;
|
7 |
| -use bitcoin::blockdata::transaction::{TxIn,TxOut,OutPoint,Transaction}; |
| 7 | +use bitcoin::blockdata::transaction::{TxIn,TxOut,OutPoint,Transaction, SigHashType}; |
| 8 | +use bitcoin::consensus::encode::{self, Decodable, Encodable}; |
| 9 | +use bitcoin::util::bip143; |
8 | 10 |
|
9 | 11 | use bitcoin_hashes::{Hash, HashEngine};
|
10 | 12 | use bitcoin_hashes::sha256::Hash as Sha256;
|
11 | 13 | use bitcoin_hashes::ripemd160::Hash as Ripemd160;
|
12 | 14 | use bitcoin_hashes::hash160::Hash as Hash160;
|
13 | 15 | use bitcoin_hashes::sha256d::Hash as Sha256dHash;
|
14 | 16 |
|
15 |
| -use ln::channelmanager::PaymentHash; |
| 17 | +use ln::channelmanager::{PaymentHash, PaymentPreimage}; |
| 18 | +use ln::msgs::DecodeError; |
| 19 | +use util::ser::{Readable, Writeable, Writer, WriterWriteAdaptor}; |
16 | 20 |
|
17 |
| -use secp256k1::key::{PublicKey,SecretKey}; |
18 |
| -use secp256k1::Secp256k1; |
| 21 | +use secp256k1::key::{SecretKey,PublicKey}; |
| 22 | +use secp256k1::{Secp256k1, Signature}; |
19 | 23 | use secp256k1;
|
20 | 24 |
|
21 | 25 | pub(super) const HTLC_SUCCESS_TX_WEIGHT: u64 = 703;
|
@@ -59,7 +63,9 @@ pub(super) fn derive_public_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>,
|
59 | 63 | base_point.combine(&hashkey)
|
60 | 64 | }
|
61 | 65 |
|
62 |
| -/// Derives a revocation key from its constituent parts |
| 66 | +/// Derives a revocation key from its constituent parts. |
| 67 | +/// Note that this is infallible iff we trust that at least one of the two input keys are randomly |
| 68 | +/// generated (ie our own). |
63 | 69 | pub(super) fn derive_private_revocation_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_secret: &SecretKey, revocation_base_secret: &SecretKey) -> Result<SecretKey, secp256k1::Error> {
|
64 | 70 | let revocation_base_point = PublicKey::from_secret_key(&secp_ctx, &revocation_base_secret);
|
65 | 71 | let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret);
|
@@ -281,3 +287,153 @@ pub fn build_htlc_transaction(prev_hash: &Sha256dHash, feerate_per_kw: u64, to_s
|
281 | 287 | output: txouts,
|
282 | 288 | }
|
283 | 289 | }
|
| 290 | + |
| 291 | +/// Signs a transaction created by build_htlc_transaction. If the transaction is an |
| 292 | +/// HTLC-Success transaction (ie htlc.offered is false), preimage must be set! |
| 293 | +pub(crate) fn sign_htlc_transaction<T: secp256k1::Signing>(tx: &mut Transaction, their_sig: &Signature, preimage: &Option<PaymentPreimage>, htlc: &HTLCOutputInCommitment, a_htlc_key: &PublicKey, b_htlc_key: &PublicKey, revocation_key: &PublicKey, per_commitment_point: &PublicKey, htlc_base_key: &SecretKey, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Script), ()> { |
| 294 | + if tx.input.len() != 1 { return Err(()); } |
| 295 | + if tx.input[0].witness.len() != 0 { return Err(()); } |
| 296 | + |
| 297 | + let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&htlc, a_htlc_key, b_htlc_key, revocation_key); |
| 298 | + |
| 299 | + let our_htlc_key = derive_private_key(secp_ctx, per_commitment_point, htlc_base_key).map_err(|_| ())?; |
| 300 | + let sighash = hash_to_message!(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]); |
| 301 | + let local_tx = PublicKey::from_secret_key(&secp_ctx, &our_htlc_key) == *a_htlc_key; |
| 302 | + let our_sig = secp_ctx.sign(&sighash, &our_htlc_key); |
| 303 | + |
| 304 | + tx.input[0].witness.push(Vec::new()); // First is the multisig dummy |
| 305 | + |
| 306 | + if local_tx { // b, then a |
| 307 | + tx.input[0].witness.push(their_sig.serialize_der().to_vec()); |
| 308 | + tx.input[0].witness.push(our_sig.serialize_der().to_vec()); |
| 309 | + } else { |
| 310 | + tx.input[0].witness.push(our_sig.serialize_der().to_vec()); |
| 311 | + tx.input[0].witness.push(their_sig.serialize_der().to_vec()); |
| 312 | + } |
| 313 | + tx.input[0].witness[1].push(SigHashType::All as u8); |
| 314 | + tx.input[0].witness[2].push(SigHashType::All as u8); |
| 315 | + |
| 316 | + if htlc.offered { |
| 317 | + tx.input[0].witness.push(Vec::new()); |
| 318 | + assert!(preimage.is_none()); |
| 319 | + } else { |
| 320 | + tx.input[0].witness.push(preimage.unwrap().0.to_vec()); |
| 321 | + } |
| 322 | + |
| 323 | + tx.input[0].witness.push(htlc_redeemscript.as_bytes().to_vec()); |
| 324 | + |
| 325 | + Ok((our_sig, htlc_redeemscript)) |
| 326 | +} |
| 327 | + |
| 328 | +#[derive(Clone)] |
| 329 | +/// We use this to track local commitment transactions and put off signing them until we are ready |
| 330 | +/// to broadcast. Eventually this will require a signer which is possibly external, but for now we |
| 331 | +/// just pass in the SecretKeys required. |
| 332 | +pub(crate) struct LocalCommitmentTransaction { |
| 333 | + tx: Transaction |
| 334 | +} |
| 335 | +impl LocalCommitmentTransaction { |
| 336 | + #[cfg(test)] |
| 337 | + pub fn dummy() -> Self { |
| 338 | + Self { tx: Transaction { |
| 339 | + version: 2, |
| 340 | + input: Vec::new(), |
| 341 | + output: Vec::new(), |
| 342 | + lock_time: 0, |
| 343 | + } } |
| 344 | + } |
| 345 | + |
| 346 | + pub fn new_missing_local_sig(mut tx: Transaction, their_sig: &Signature, our_funding_key: &PublicKey, their_funding_key: &PublicKey) -> LocalCommitmentTransaction { |
| 347 | + if tx.input.len() != 1 { panic!("Tried to store a commitment transaction that had input count != 1!"); } |
| 348 | + if tx.input[0].witness.len() != 0 { panic!("Tried to store a signed commitment transaction?"); } |
| 349 | + |
| 350 | + tx.input[0].witness.push(Vec::new()); // First is the multisig dummy |
| 351 | + |
| 352 | + if our_funding_key.serialize()[..] < their_funding_key.serialize()[..] { |
| 353 | + tx.input[0].witness.push(Vec::new()); |
| 354 | + tx.input[0].witness.push(their_sig.serialize_der().to_vec()); |
| 355 | + tx.input[0].witness[2].push(SigHashType::All as u8); |
| 356 | + } else { |
| 357 | + tx.input[0].witness.push(their_sig.serialize_der().to_vec()); |
| 358 | + tx.input[0].witness[1].push(SigHashType::All as u8); |
| 359 | + tx.input[0].witness.push(Vec::new()); |
| 360 | + } |
| 361 | + |
| 362 | + Self { tx } |
| 363 | + } |
| 364 | + |
| 365 | + pub fn txid(&self) -> Sha256dHash { |
| 366 | + self.tx.txid() |
| 367 | + } |
| 368 | + |
| 369 | + pub fn has_local_sig(&self) -> bool { |
| 370 | + if self.tx.input.len() != 1 { panic!("Commitment transactions must have input count == 1!"); } |
| 371 | + if self.tx.input[0].witness.len() == 4 { |
| 372 | + assert!(!self.tx.input[0].witness[1].is_empty()); |
| 373 | + assert!(!self.tx.input[0].witness[2].is_empty()); |
| 374 | + true |
| 375 | + } else { |
| 376 | + assert_eq!(self.tx.input[0].witness.len(), 3); |
| 377 | + assert!(self.tx.input[0].witness[0].is_empty()); |
| 378 | + assert!(self.tx.input[0].witness[1].is_empty() || self.tx.input[0].witness[2].is_empty()); |
| 379 | + false |
| 380 | + } |
| 381 | + } |
| 382 | + |
| 383 | + pub fn add_local_sig<T: secp256k1::Signing>(&mut self, funding_key: &SecretKey, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1<T>) { |
| 384 | + if self.has_local_sig() { return; } |
| 385 | + let sighash = hash_to_message!(&bip143::SighashComponents::new(&self.tx) |
| 386 | + .sighash_all(&self.tx.input[0], funding_redeemscript, channel_value_satoshis)[..]); |
| 387 | + let our_sig = secp_ctx.sign(&sighash, funding_key); |
| 388 | + |
| 389 | + if self.tx.input[0].witness[1].is_empty() { |
| 390 | + self.tx.input[0].witness[1] = our_sig.serialize_der().to_vec(); |
| 391 | + self.tx.input[0].witness[1].push(SigHashType::All as u8); |
| 392 | + } else { |
| 393 | + self.tx.input[0].witness[2] = our_sig.serialize_der().to_vec(); |
| 394 | + self.tx.input[0].witness[2].push(SigHashType::All as u8); |
| 395 | + } |
| 396 | + |
| 397 | + self.tx.input[0].witness.push(funding_redeemscript.as_bytes().to_vec()); |
| 398 | + } |
| 399 | + |
| 400 | + pub fn without_valid_witness(&self) -> &Transaction { &self.tx } |
| 401 | + pub fn with_valid_witness(&self) -> &Transaction { |
| 402 | + assert!(self.has_local_sig()); |
| 403 | + &self.tx |
| 404 | + } |
| 405 | +} |
| 406 | +impl PartialEq for LocalCommitmentTransaction { |
| 407 | + // We dont care whether we are signed in equality comparison |
| 408 | + fn eq(&self, o: &Self) -> bool { |
| 409 | + self.txid() == o.txid() |
| 410 | + } |
| 411 | +} |
| 412 | +impl Writeable for LocalCommitmentTransaction { |
| 413 | + fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> { |
| 414 | + if let Err(e) = self.tx.consensus_encode(&mut WriterWriteAdaptor(writer)) { |
| 415 | + match e { |
| 416 | + encode::Error::Io(e) => return Err(e), |
| 417 | + _ => panic!("local tx must have been well-formed!"), |
| 418 | + } |
| 419 | + } |
| 420 | + Ok(()) |
| 421 | + } |
| 422 | +} |
| 423 | +impl<R: ::std::io::Read> Readable<R> for LocalCommitmentTransaction { |
| 424 | + fn read(reader: &mut R) -> Result<Self, DecodeError> { |
| 425 | + let tx = match Transaction::consensus_decode(reader.by_ref()) { |
| 426 | + Ok(tx) => tx, |
| 427 | + Err(e) => match e { |
| 428 | + encode::Error::Io(ioe) => return Err(DecodeError::Io(ioe)), |
| 429 | + _ => return Err(DecodeError::InvalidValue), |
| 430 | + }, |
| 431 | + }; |
| 432 | + |
| 433 | + if tx.input.len() != 1 { |
| 434 | + // Ensure tx didn't hit the 0-input ambiguity case. |
| 435 | + return Err(DecodeError::InvalidValue); |
| 436 | + } |
| 437 | + Ok(Self { tx }) |
| 438 | + } |
| 439 | +} |
0 commit comments