Skip to content

Commit 35d4ebb

Browse files
Merge pull request #1272 from lightning-signer/2022-01-sign-invoice-api
Improve KeysInterface::sign_invoice API
2 parents b19c56b + 803d6b6 commit 35d4ebb

File tree

9 files changed

+50
-38
lines changed

9 files changed

+50
-38
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ use std::collections::{HashSet, hash_map, HashMap};
6363
use std::sync::{Arc,Mutex};
6464
use std::sync::atomic;
6565
use std::io::Cursor;
66+
use bitcoin::bech32::u5;
6667

6768
const MAX_FEE: u32 = 10_000;
6869
struct FuzzEstimator {
@@ -220,7 +221,7 @@ impl KeysInterface for KeyProvider {
220221
})
221222
}
222223

223-
fn sign_invoice(&self, _invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()> {
224+
fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5]) -> Result<RecoverableSignature, ()> {
224225
unreachable!()
225226
}
226227
}

fuzz/src/full_stack.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ use std::convert::TryInto;
6060
use std::cmp;
6161
use std::sync::{Arc, Mutex};
6262
use std::sync::atomic::{AtomicU64,AtomicUsize,Ordering};
63+
use bitcoin::bech32::u5;
6364

6465
#[inline]
6566
pub fn slice_to_be16(v: &[u8]) -> u16 {
@@ -333,7 +334,7 @@ impl KeysInterface for KeyProvider {
333334
))
334335
}
335336

336-
fn sign_invoice(&self, _invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()> {
337+
fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5]) -> Result<RecoverableSignature, ()> {
337338
unreachable!()
338339
}
339340
}

lightning-invoice/src/lib.rs

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ use lightning::ln::features::InvoiceFeatures;
4343
#[cfg(any(doc, test))]
4444
use lightning::routing::network_graph::RoutingFees;
4545
use lightning::routing::router::RouteHint;
46+
use lightning::util::invoice::construct_invoice_preimage;
4647

4748
use secp256k1::key::PublicKey;
4849
use secp256k1::{Message, Secp256k1};
@@ -869,32 +870,9 @@ macro_rules! find_all_extract {
869870

870871
#[allow(missing_docs)]
871872
impl RawInvoice {
872-
/// Construct the invoice's HRP and signatureless data into a preimage to be hashed.
873-
pub(crate) fn construct_invoice_preimage(hrp_bytes: &[u8], data_without_signature: &[u5]) -> Vec<u8> {
874-
use bech32::FromBase32;
875-
876-
let mut preimage = Vec::<u8>::from(hrp_bytes);
877-
878-
let mut data_part = Vec::from(data_without_signature);
879-
let overhang = (data_part.len() * 5) % 8;
880-
if overhang > 0 {
881-
// add padding if data does not end at a byte boundary
882-
data_part.push(u5::try_from_u8(0).unwrap());
883-
884-
// if overhang is in (1..3) we need to add u5(0) padding two times
885-
if overhang < 3 {
886-
data_part.push(u5::try_from_u8(0).unwrap());
887-
}
888-
}
889-
890-
preimage.extend_from_slice(&Vec::<u8>::from_base32(&data_part)
891-
.expect("No padding error may occur due to appended zero above."));
892-
preimage
893-
}
894-
895873
/// Hash the HRP as bytes and signatureless data part.
896874
fn hash_from_parts(hrp_bytes: &[u8], data_without_signature: &[u5]) -> [u8; 32] {
897-
let preimage = RawInvoice::construct_invoice_preimage(hrp_bytes, data_without_signature);
875+
let preimage = construct_invoice_preimage(hrp_bytes, data_without_signature);
898876
let mut hash: [u8; 32] = Default::default();
899877
hash.copy_from_slice(&sha256::Hash::hash(&preimage)[..]);
900878
hash

lightning-invoice/src/utils.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Convenient utilities to create an invoice.
22
3-
use {CreationError, Currency, DEFAULT_EXPIRY_TIME, Invoice, InvoiceBuilder, SignOrCreationError, RawInvoice};
3+
use {CreationError, Currency, DEFAULT_EXPIRY_TIME, Invoice, InvoiceBuilder, SignOrCreationError};
44
use payment::{Payer, Router};
55

66
use bech32::ToBase32;
@@ -118,8 +118,7 @@ where
118118
let hrp_str = raw_invoice.hrp.to_string();
119119
let hrp_bytes = hrp_str.as_bytes();
120120
let data_without_signature = raw_invoice.data.to_base32();
121-
let invoice_preimage = RawInvoice::construct_invoice_preimage(hrp_bytes, &data_without_signature);
122-
let signed_raw_invoice = raw_invoice.sign(|_| keys_manager.sign_invoice(invoice_preimage));
121+
let signed_raw_invoice = raw_invoice.sign(|_| keys_manager.sign_invoice(hrp_bytes, &data_without_signature));
123122
match signed_raw_invoice {
124123
Ok(inv) => Ok(Invoice::from_signed(inv).unwrap()),
125124
Err(e) => Err(SignOrCreationError::SignError(e))

lightning/src/chain/keysinterface.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use bitcoin::network::constants::Network;
1818
use bitcoin::util::bip32::{ExtendedPrivKey, ExtendedPubKey, ChildNumber};
1919
use bitcoin::util::bip143;
2020

21+
use bitcoin::bech32::u5;
2122
use bitcoin::hashes::{Hash, HashEngine};
2223
use bitcoin::hashes::sha256::HashEngine as Sha256State;
2324
use bitcoin::hashes::sha256::Hash as Sha256;
@@ -42,6 +43,7 @@ use prelude::*;
4243
use core::sync::atomic::{AtomicUsize, Ordering};
4344
use io::{self, Error};
4445
use ln::msgs::{DecodeError, MAX_VALUE_MSAT};
46+
use util::invoice::construct_invoice_preimage;
4547

4648
/// Used as initial key material, to be expanded into multiple secret keys (but not to be used
4749
/// directly). This is used within LDK to encrypt/decrypt inbound payment data.
@@ -398,11 +400,12 @@ pub trait KeysInterface {
398400
/// you've read all of the provided bytes to ensure no corruption occurred.
399401
fn read_chan_signer(&self, reader: &[u8]) -> Result<Self::Signer, DecodeError>;
400402

401-
/// Sign an invoice's preimage (note that this is the preimage of the invoice, not the HTLC's
402-
/// preimage). By parameterizing by the preimage instead of the hash, we allow implementors of
403+
/// Sign an invoice.
404+
/// By parameterizing by the raw invoice bytes instead of the hash, we allow implementors of
403405
/// this trait to parse the invoice and make sure they're signing what they expect, rather than
404406
/// blindly signing the hash.
405-
fn sign_invoice(&self, invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()>;
407+
/// The hrp is ascii bytes, while the invoice data is base32.
408+
fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5]) -> Result<RecoverableSignature, ()>;
406409

407410
/// Get secret key material as bytes for use in encrypting and decrypting inbound payment data.
408411
///
@@ -1105,8 +1108,9 @@ impl KeysInterface for KeysManager {
11051108
InMemorySigner::read(&mut io::Cursor::new(reader))
11061109
}
11071110

1108-
fn sign_invoice(&self, invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()> {
1109-
Ok(self.secp_ctx.sign_recoverable(&hash_to_message!(&Sha256::hash(&invoice_preimage)), &self.get_node_secret()))
1111+
fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5]) -> Result<RecoverableSignature, ()> {
1112+
let preimage = construct_invoice_preimage(&hrp_bytes, &invoice_data);
1113+
Ok(self.secp_ctx.sign_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), &self.get_node_secret()))
11101114
}
11111115
}
11121116

lightning/src/ln/channel.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5840,6 +5840,7 @@ mod tests {
58405840
use bitcoin::hashes::Hash;
58415841
use bitcoin::hash_types::{Txid, WPubkeyHash};
58425842
use core::num::NonZeroU8;
5843+
use bitcoin::bech32::u5;
58435844
use sync::Arc;
58445845
use prelude::*;
58455846

@@ -5884,7 +5885,7 @@ mod tests {
58845885
}
58855886
fn get_secure_random_bytes(&self) -> [u8; 32] { [0; 32] }
58865887
fn read_chan_signer(&self, _data: &[u8]) -> Result<Self::Signer, DecodeError> { panic!(); }
5887-
fn sign_invoice(&self, _invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()> { panic!(); }
5888+
fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5]) -> Result<RecoverableSignature, ()> { panic!(); }
58885889
}
58895890

58905891
fn public_from_secret_hex(secp_ctx: &Secp256k1<All>, hex: &str) -> PublicKey {

lightning/src/util/invoice.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//! Low level invoice utilities.
2+
3+
use bitcoin::bech32::{u5, FromBase32};
4+
use prelude::*;
5+
6+
/// Construct the invoice's HRP and signatureless data into a preimage to be hashed.
7+
pub fn construct_invoice_preimage(hrp_bytes: &[u8], data_without_signature: &[u5]) -> Vec<u8> {
8+
let mut preimage = Vec::<u8>::from(hrp_bytes);
9+
10+
let mut data_part = Vec::from(data_without_signature);
11+
let overhang = (data_part.len() * 5) % 8;
12+
if overhang > 0 {
13+
// add padding if data does not end at a byte boundary
14+
data_part.push(u5::try_from_u8(0).unwrap());
15+
16+
// if overhang is in (1..3) we need to add u5(0) padding two times
17+
if overhang < 3 {
18+
data_part.push(u5::try_from_u8(0).unwrap());
19+
}
20+
}
21+
22+
preimage.extend_from_slice(&Vec::<u8>::from_base32(&data_part)
23+
.expect("No padding error may occur due to appended zero above."));
24+
preimage
25+
}
26+

lightning/src/util/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub mod events;
1919
pub mod errors;
2020
pub mod ser;
2121
pub mod message_signing;
22+
pub mod invoice;
2223

2324
pub(crate) mod atomic_counter;
2425
pub(crate) mod byte_utils;

lightning/src/util/test_utils.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ use core::time::Duration;
4747
use sync::{Mutex, Arc};
4848
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
4949
use core::{cmp, mem};
50+
use bitcoin::bech32::u5;
5051
use chain::keysinterface::{InMemorySigner, KeyMaterial};
5152

5253
pub struct TestVecWriter(pub Vec<u8>);
@@ -87,7 +88,7 @@ impl keysinterface::KeysInterface for OnlyReadsKeysInterface {
8788
false
8889
))
8990
}
90-
fn sign_invoice(&self, _invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()> { unreachable!(); }
91+
fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5]) -> Result<RecoverableSignature, ()> { unreachable!(); }
9192
}
9293

9394
pub struct TestChainMonitor<'a> {
@@ -528,8 +529,8 @@ impl keysinterface::KeysInterface for TestKeysInterface {
528529
))
529530
}
530531

531-
fn sign_invoice(&self, invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()> {
532-
self.backing.sign_invoice(invoice_preimage)
532+
fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5]) -> Result<RecoverableSignature, ()> {
533+
self.backing.sign_invoice(hrp_bytes, invoice_data)
533534
}
534535
}
535536

0 commit comments

Comments
 (0)