Skip to content

Commit 3f82564

Browse files
Merge pull request #4064 from erickcestari/improve-check-signature-bolt11
refactor(invoice): align signature checks with BOLT11 semantics
2 parents 5ae19b4 + c678a9a commit 3f82564

File tree

3 files changed

+31
-42
lines changed

3 files changed

+31
-42
lines changed

lightning-invoice/src/de.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -772,9 +772,6 @@ impl Display for Bolt11ParseError {
772772
Bolt11ParseError::InvalidScriptHashLength => {
773773
f.write_str("fallback script hash has a length unequal 32 bytes")
774774
},
775-
Bolt11ParseError::InvalidRecoveryId => {
776-
f.write_str("recovery id is out of range (should be in [0,3])")
777-
},
778775
Bolt11ParseError::Skip => f.write_str(
779776
"the tagged field has to be skipped because of an unexpected, but allowed property",
780777
),

lightning-invoice/src/lib.rs

Lines changed: 11 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ pub enum Bolt11ParseError {
106106
InvalidSegWitProgramLength,
107107
InvalidPubKeyHashLength,
108108
InvalidScriptHashLength,
109-
InvalidRecoveryId,
110109
// Invalid length, with actual length, expected length, and name of the element
111110
InvalidSliceLength(usize, usize, &'static str),
112111

@@ -1011,31 +1010,19 @@ impl SignedRawBolt11Invoice {
10111010
}
10121011

10131012
/// Checks if the signature is valid for the included payee public key or if none exists if it's
1014-
/// valid for the recovered signature (which should always be true?).
1013+
/// possible to recover the public key from the signature.
10151014
pub fn check_signature(&self) -> bool {
1016-
let included_pub_key = self.raw_invoice.payee_pub_key();
1015+
match self.raw_invoice.payee_pub_key() {
1016+
Some(pk) => {
1017+
let hash = Message::from_digest(self.hash);
10171018

1018-
let mut recovered_pub_key = Option::None;
1019-
if recovered_pub_key.is_none() {
1020-
let recovered = match self.recover_payee_pub_key() {
1021-
Ok(pk) => pk,
1022-
Err(_) => return false,
1023-
};
1024-
recovered_pub_key = Some(recovered);
1025-
}
1019+
let secp_context = Secp256k1::new();
1020+
let verification_result =
1021+
secp_context.verify_ecdsa(&hash, &self.signature.to_standard(), pk);
10261022

1027-
let pub_key =
1028-
included_pub_key.or(recovered_pub_key.as_ref()).expect("One is always present");
1029-
1030-
let hash = Message::from_digest(self.hash);
1031-
1032-
let secp_context = Secp256k1::new();
1033-
let verification_result =
1034-
secp_context.verify_ecdsa(&hash, &self.signature.to_standard(), pub_key);
1035-
1036-
match verification_result {
1037-
Ok(()) => true,
1038-
Err(_) => false,
1023+
verification_result.is_ok()
1024+
},
1025+
None => self.recover_payee_pub_key().is_ok(),
10391026
}
10401027
}
10411028
}
@@ -1410,19 +1397,8 @@ impl Bolt11Invoice {
14101397
}
14111398
}
14121399

1413-
/// Check that the invoice is signed correctly and that key recovery works
1400+
/// Check that the invoice is signed correctly
14141401
pub fn check_signature(&self) -> Result<(), Bolt11SemanticError> {
1415-
match self.signed_invoice.recover_payee_pub_key() {
1416-
Err(bitcoin::secp256k1::Error::InvalidRecoveryId) => {
1417-
return Err(Bolt11SemanticError::InvalidRecoveryId)
1418-
},
1419-
Err(bitcoin::secp256k1::Error::InvalidSignature) => {
1420-
return Err(Bolt11SemanticError::InvalidSignature)
1421-
},
1422-
Err(e) => panic!("no other error may occur, got {:?}", e),
1423-
Ok(_) => {},
1424-
}
1425-
14261402
if !self.signed_invoice.check_signature() {
14271403
return Err(Bolt11SemanticError::InvalidSignature);
14281404
}
@@ -1873,9 +1849,6 @@ pub enum Bolt11SemanticError {
18731849
/// The invoice's features are invalid
18741850
InvalidFeatures,
18751851

1876-
/// The recovery id doesn't fit the signature/pub key
1877-
InvalidRecoveryId,
1878-
18791852
/// The invoice's signature is invalid
18801853
InvalidSignature,
18811854

@@ -1893,7 +1866,6 @@ impl Display for Bolt11SemanticError {
18931866
Bolt11SemanticError::NoPaymentSecret => f.write_str("The invoice is missing the mandatory payment secret"),
18941867
Bolt11SemanticError::MultiplePaymentSecrets => f.write_str("The invoice contains multiple payment secrets"),
18951868
Bolt11SemanticError::InvalidFeatures => f.write_str("The invoice's features are invalid"),
1896-
Bolt11SemanticError::InvalidRecoveryId => f.write_str("The recovery id doesn't fit the signature/pub key"),
18971869
Bolt11SemanticError::InvalidSignature => f.write_str("The invoice's signature is invalid"),
18981870
Bolt11SemanticError::ImpreciseAmount => f.write_str("The invoice's amount was not a whole number of millisatoshis"),
18991871
}

lightning-invoice/tests/ser_de.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,26 @@ fn get_test_tuples() -> Vec<(String, SignedRawBolt11Invoice, bool, bool)> {
373373
false, // Different features than set in InvoiceBuilder
374374
true, // Some unknown fields
375375
),
376+
(
377+
"lnbc1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq9qrsgq357wnc5r2ueh7ck6q93dj32dlqnls087fxdwk8qakdyafkq3yap2r09nt4ndd0unm3z9u5t48y6ucv4r5sg7lk98c77ctvjczkspk5qprc90gx".to_owned(),
378+
InvoiceBuilder::new(Currency::Bitcoin)
379+
.duration_since_epoch(Duration::from_secs(1496314658))
380+
.payment_secret(PaymentSecret([0x11; 32]))
381+
.payment_hash(sha256::Hash::from_str(
382+
"0001020304050607080900010203040506070809000102030405060708090102"
383+
).unwrap())
384+
.description("Please consider supporting this project".to_owned())
385+
.build_raw()
386+
.unwrap()
387+
.sign(|_| {
388+
RecoverableSignature::from_compact(
389+
&<Vec<u8>>::from_hex("8d3ce9e28357337f62da0162d9454df827f83cfe499aeb1c1db349d4d8112742a1bcb35d66d6bf93dc445e51753935cc32a3a411efd8a7c7bd85b25815a01b50").unwrap(),
390+
RecoveryId::from_i32(1).unwrap()
391+
)
392+
}).unwrap(),
393+
false, // Different features than set in InvoiceBuilder
394+
false, // Some unknown fields
395+
),
376396

377397
]
378398
}

0 commit comments

Comments
 (0)