diff --git a/lightning-background-processor/Cargo.toml b/lightning-background-processor/Cargo.toml index 59f77ac5fa4..3f9bae76405 100644 --- a/lightning-background-processor/Cargo.toml +++ b/lightning-background-processor/Cargo.toml @@ -22,11 +22,11 @@ default = ["std"] [dependencies] bitcoin = { version = "0.29.0", default-features = false } -lightning = { version = "0.0.118", path = "../lightning", default-features = false } -lightning-rapid-gossip-sync = { version = "0.0.118", path = "../lightning-rapid-gossip-sync", default-features = false } +lightning = { path = "../lightning", default-features = false } +lightning-rapid-gossip-sync = { path = "../lightning-rapid-gossip-sync", default-features = false } [dev-dependencies] tokio = { version = "1.14", features = [ "macros", "rt", "rt-multi-thread", "sync", "time" ] } -lightning = { version = "0.0.118", path = "../lightning", features = ["_test_utils"] } +lightning = { path = "../lightning", features = ["_test_utils"] } lightning-invoice = { version = "0.26.0", path = "../lightning-invoice" } -lightning-persister = { version = "0.0.118", path = "../lightning-persister" } +lightning-persister = { path = "../lightning-persister" } diff --git a/lightning-block-sync/Cargo.toml b/lightning-block-sync/Cargo.toml index d9bb4ee7b1e..03dcec6c805 100644 --- a/lightning-block-sync/Cargo.toml +++ b/lightning-block-sync/Cargo.toml @@ -19,11 +19,11 @@ rpc-client = [ "serde_json", "chunked_transfer" ] [dependencies] bitcoin = "0.29.0" -lightning = { version = "0.0.118", path = "../lightning" } +lightning = { path = "../lightning" } tokio = { version = "1.0", features = [ "io-util", "net", "time" ], optional = true } serde_json = { version = "1.0", optional = true } chunked_transfer = { version = "1.4", optional = true } [dev-dependencies] -lightning = { version = "0.0.118", path = "../lightning", features = ["_test_utils"] } +lightning = { path = "../lightning", features = ["_test_utils"] } tokio = { version = "1.14", features = [ "macros", "rt" ] } diff --git a/lightning-invoice/Cargo.toml b/lightning-invoice/Cargo.toml index a34bd63b7f2..4c5cb9d9921 100644 --- a/lightning-invoice/Cargo.toml +++ b/lightning-invoice/Cargo.toml @@ -21,7 +21,7 @@ std = ["bitcoin_hashes/std", "num-traits/std", "lightning/std", "bech32/std"] [dependencies] bech32 = { version = "0.9.0", default-features = false } -lightning = { version = "0.0.118", path = "../lightning", default-features = false } +lightning = { path = "../lightning", default-features = false } secp256k1 = { version = "0.24.0", default-features = false, features = ["recovery", "alloc"] } num-traits = { version = "0.2.8", default-features = false } bitcoin_hashes = { version = "0.11", default-features = false } @@ -30,6 +30,6 @@ serde = { version = "1.0.118", optional = true } bitcoin = { version = "0.29.0", default-features = false } [dev-dependencies] -lightning = { version = "0.0.118", path = "../lightning", default-features = false, features = ["_test_utils"] } +lightning = { path = "../lightning", default-features = false, features = ["_test_utils"] } hex = "0.4" serde_json = { version = "1"} diff --git a/lightning-net-tokio/Cargo.toml b/lightning-net-tokio/Cargo.toml index 6cd3a1fa382..3c350091803 100644 --- a/lightning-net-tokio/Cargo.toml +++ b/lightning-net-tokio/Cargo.toml @@ -16,9 +16,9 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] bitcoin = "0.29.0" -lightning = { version = "0.0.118", path = "../lightning" } +lightning = { path = "../lightning" } tokio = { version = "1.0", features = [ "rt", "sync", "net", "time" ] } [dev-dependencies] tokio = { version = "1.14", features = [ "macros", "rt", "rt-multi-thread", "sync", "net", "time" ] } -lightning = { version = "0.0.118", path = "../lightning", features = ["_test_utils"] } +lightning = { path = "../lightning", features = ["_test_utils"] } diff --git a/lightning-persister/Cargo.toml b/lightning-persister/Cargo.toml index 525b9507329..aaeaa748c9c 100644 --- a/lightning-persister/Cargo.toml +++ b/lightning-persister/Cargo.toml @@ -15,7 +15,7 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] bitcoin = "0.29.0" -lightning = { version = "0.0.118", path = "../lightning" } +lightning = { path = "../lightning" } [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.48.0", default-features = false, features = ["Win32_Storage_FileSystem", "Win32_Foundation"] } @@ -24,5 +24,5 @@ windows-sys = { version = "0.48.0", default-features = false, features = ["Win32 criterion = { version = "0.4", optional = true, default-features = false } [dev-dependencies] -lightning = { version = "0.0.118", path = "../lightning", features = ["_test_utils"] } +lightning = { path = "../lightning", features = ["_test_utils"] } bitcoin = { version = "0.29.0", default-features = false } diff --git a/lightning/src/blinded_path/mod.rs b/lightning/src/blinded_path/mod.rs index d75b4f25b36..b1fc9e1c0a4 100644 --- a/lightning/src/blinded_path/mod.rs +++ b/lightning/src/blinded_path/mod.rs @@ -105,7 +105,7 @@ impl BlindedPath { /// /// [`ForwardTlvs`]: crate::blinded_path::payment::ForwardTlvs // TODO: make all payloads the same size with padding + add dummy hops - pub(crate) fn new_for_payment( + pub fn new_for_payment( intermediate_nodes: &[payment::ForwardNode], payee_node_id: PublicKey, payee_tlvs: payment::ReceiveTlvs, htlc_maximum_msat: u64, entropy_source: &ES, secp_ctx: &Secp256k1 diff --git a/lightning/src/offers/invoice.rs b/lightning/src/offers/invoice.rs index c6fd5d05649..5bd5a95d8e6 100644 --- a/lightning/src/offers/invoice.rs +++ b/lightning/src/offers/invoice.rs @@ -439,6 +439,7 @@ impl UnsignedBolt12Invoice { bytes: self.bytes, contents: self.contents, signature, + tagged_hash: self.tagged_hash, }) } } @@ -463,6 +464,7 @@ pub struct Bolt12Invoice { bytes: Vec, contents: InvoiceContents, signature: Signature, + tagged_hash: TaggedHash, } /// The contents of an [`Bolt12Invoice`] for responding to either an [`Offer`] or a [`Refund`]. @@ -707,7 +709,7 @@ impl Bolt12Invoice { /// Hash that was used for signing the invoice. pub fn signable_hash(&self) -> [u8; 32] { - merkle::message_digest(SIGNATURE_TAG, &self.bytes).as_ref().clone() + self.tagged_hash.as_digest().as_ref().clone() } /// Verifies that the invoice was for a request or refund created using the given key. Returns @@ -1212,11 +1214,11 @@ impl TryFrom> for Bolt12Invoice { None => return Err(Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSignature)), Some(signature) => signature, }; - let message = TaggedHash::new(SIGNATURE_TAG, &bytes); + let tagged_hash = TaggedHash::new(SIGNATURE_TAG, &bytes); let pubkey = contents.fields().signing_pubkey; - merkle::verify_signature(&signature, message, pubkey)?; + merkle::verify_signature(&signature, &tagged_hash, pubkey)?; - Ok(Bolt12Invoice { bytes, contents, signature }) + Ok(Bolt12Invoice { bytes, contents, signature, tagged_hash }) } } @@ -1431,7 +1433,7 @@ mod tests { assert_eq!(invoice.signing_pubkey(), recipient_pubkey()); let message = TaggedHash::new(SIGNATURE_TAG, &invoice.bytes); - assert!(merkle::verify_signature(&invoice.signature, message, recipient_pubkey()).is_ok()); + assert!(merkle::verify_signature(&invoice.signature, &message, recipient_pubkey()).is_ok()); let digest = Message::from_slice(&invoice.signable_hash()).unwrap(); let pubkey = recipient_pubkey().into(); @@ -1528,7 +1530,7 @@ mod tests { assert_eq!(invoice.signing_pubkey(), recipient_pubkey()); let message = TaggedHash::new(SIGNATURE_TAG, &invoice.bytes); - assert!(merkle::verify_signature(&invoice.signature, message, recipient_pubkey()).is_ok()); + assert!(merkle::verify_signature(&invoice.signature, &message, recipient_pubkey()).is_ok()); assert_eq!( invoice.as_tlv_stream(), diff --git a/lightning/src/offers/invoice_request.rs b/lightning/src/offers/invoice_request.rs index bd6d58371a9..9ddd741a1d5 100644 --- a/lightning/src/offers/invoice_request.rs +++ b/lightning/src/offers/invoice_request.rs @@ -876,7 +876,7 @@ impl TryFrom> for InvoiceRequest { Some(signature) => signature, }; let message = TaggedHash::new(SIGNATURE_TAG, &bytes); - merkle::verify_signature(&signature, message, contents.payer_id)?; + merkle::verify_signature(&signature, &message, contents.payer_id)?; Ok(InvoiceRequest { bytes, contents, signature }) } @@ -1013,7 +1013,7 @@ mod tests { assert_eq!(invoice_request.payer_note(), None); let message = TaggedHash::new(SIGNATURE_TAG, &invoice_request.bytes); - assert!(merkle::verify_signature(&invoice_request.signature, message, payer_pubkey()).is_ok()); + assert!(merkle::verify_signature(&invoice_request.signature, &message, payer_pubkey()).is_ok()); assert_eq!( invoice_request.as_tlv_stream(), diff --git a/lightning/src/offers/merkle.rs b/lightning/src/offers/merkle.rs index 7390b58fef8..a86f0b4e6fb 100644 --- a/lightning/src/offers/merkle.rs +++ b/lightning/src/offers/merkle.rs @@ -30,20 +30,41 @@ tlv_stream!(SignatureTlvStream, SignatureTlvStreamRef, SIGNATURE_TYPES, { /// /// [BIP 340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki /// [BOLT 12]: https://github.com/rustyrussell/lightning-rfc/blob/guilt/offers/12-offer-encoding.md#signature-calculation -#[derive(Debug, PartialEq)] -pub struct TaggedHash(Message); +#[derive(Clone, Debug, PartialEq)] +pub struct TaggedHash { + tag: String, + merkle_root: sha256::Hash, + digest: Message, +} impl TaggedHash { /// Creates a tagged hash with the given parameters. /// /// Panics if `tlv_stream` is not a well-formed TLV stream containing at least one TLV record. pub(super) fn new(tag: &str, tlv_stream: &[u8]) -> Self { - Self(message_digest(tag, tlv_stream)) + let tag_hash = sha256::Hash::hash(tag.as_bytes()); + let merkle_root = root_hash(tlv_stream); + let digest = Message::from_slice(&tagged_hash(tag_hash, merkle_root)).unwrap(); + Self { + tag: tag.to_owned(), + merkle_root, + digest, + } } /// Returns the digest to sign. pub fn as_digest(&self) -> &Message { - &self.0 + &self.digest + } + + /// Returns the tag used in the tagged hash. + pub fn tag(&self) -> &str { + &self.tag + } + + /// Returns the merkle root used in the tagged hash. + pub fn merkle_root(&self) -> sha256::Hash { + self.merkle_root } } @@ -91,7 +112,7 @@ where /// Verifies the signature with a pubkey over the given message using a tagged hash as the message /// digest. pub(super) fn verify_signature( - signature: &Signature, message: TaggedHash, pubkey: PublicKey, + signature: &Signature, message: &TaggedHash, pubkey: PublicKey, ) -> Result<(), secp256k1::Error> { let digest = message.as_digest(); let pubkey = pubkey.into(); @@ -99,12 +120,6 @@ pub(super) fn verify_signature( secp_ctx.verify_schnorr(signature, digest, &pubkey) } -pub(super) fn message_digest(tag: &str, bytes: &[u8]) -> Message { - let tag = sha256::Hash::hash(tag.as_bytes()); - let merkle_root = root_hash(bytes); - Message::from_slice(&tagged_hash(tag, merkle_root)).unwrap() -} - /// Computes a merkle root hash for the given data, which must be a well-formed TLV stream /// containing at least one TLV record. fn root_hash(data: &[u8]) -> sha256::Hash { @@ -258,12 +273,13 @@ mod tests { use super::{SIGNATURE_TYPES, TlvStream, WithoutSignatures}; use bitcoin::hashes::{Hash, sha256}; - use bitcoin::secp256k1::{KeyPair, Secp256k1, SecretKey}; + use bitcoin::secp256k1::{KeyPair, Message, Secp256k1, SecretKey}; use bitcoin::secp256k1::schnorr::Signature; use core::convert::Infallible; use crate::offers::offer::{Amount, OfferBuilder}; use crate::offers::invoice_request::InvoiceRequest; use crate::offers::parse::Bech32Encode; + use crate::offers::test_utils::{payer_pubkey, recipient_pubkey}; use crate::util::ser::Writeable; #[test] @@ -322,6 +338,25 @@ mod tests { ); } + #[test] + fn compute_tagged_hash() { + let unsigned_invoice_request = OfferBuilder::new("foo".into(), recipient_pubkey()) + .amount_msats(1000) + .build().unwrap() + .request_invoice(vec![1; 32], payer_pubkey()).unwrap() + .payer_note("bar".into()) + .build().unwrap(); + + // Simply test that we can grab the tag and merkle root exposed by the accessor + // functions, then use them to succesfully compute a tagged hash. + let tagged_hash = unsigned_invoice_request.as_ref(); + let expected_digest = unsigned_invoice_request.as_ref().as_digest(); + let tag = sha256::Hash::hash(tagged_hash.tag().as_bytes()); + let actual_digest = Message::from_slice(&super::tagged_hash(tag, tagged_hash.merkle_root())) + .unwrap(); + assert_eq!(*expected_digest, actual_digest); + } + #[test] fn skips_encoding_signature_tlv_records() { let secp_ctx = Secp256k1::new();