Skip to content

Commit 9d5adfc

Browse files
authored
Merge pull request #2205 from wpaulino/sign-ecdsa-with-noncedata
Generate local signatures with additional randomness
2 parents a7600dc + 86531e5 commit 9d5adfc

12 files changed

+122
-40
lines changed

ci/ci-tests.sh

+4-3
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,14 @@ for DIR in lightning lightning-invoice lightning-rapid-gossip-sync; do
3535
cargo test --verbose --color always --no-default-features --features no-std
3636
# check if there is a conflict between no-std and the default std feature
3737
cargo test --verbose --color always --features no-std
38-
# check that things still pass without grind_signatures
39-
# note that outbound_commitment_test only runs in this mode, because of hardcoded signature values
40-
cargo test --verbose --color always --no-default-features --features std
4138
# check if there is a conflict between no-std and the c_bindings cfg
4239
RUSTFLAGS="--cfg=c_bindings" cargo test --verbose --color always --no-default-features --features=no-std
4340
popd
4441
done
42+
# Note that outbound_commitment_test only runs in this mode because of hardcoded signature values
43+
pushd lightning
44+
cargo test --verbose --color always --no-default-features --features=std,_test_vectors
45+
popd
4546
# This one only works for lightning-invoice
4647
pushd lightning-invoice
4748
# check that compile with no-std and serde works in lightning-invoice

fuzz/src/chanmon_consistency.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ impl SignerProvider for KeyProvider {
240240
[id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, self.node_secret[31]],
241241
channel_value_satoshis,
242242
channel_keys_id,
243+
channel_keys_id,
243244
);
244245
let revoked_commitment = self.make_enforcement_state_cell(keys.commitment_seed);
245246
EnforcingSigner::new_with_revoked(keys, revoked_commitment, false)
@@ -248,7 +249,7 @@ impl SignerProvider for KeyProvider {
248249
fn read_chan_signer(&self, buffer: &[u8]) -> Result<Self::Signer, DecodeError> {
249250
let mut reader = std::io::Cursor::new(buffer);
250251

251-
let inner: InMemorySigner = Readable::read(&mut reader)?;
252+
let inner: InMemorySigner = ReadableArgs::read(&mut reader, self)?;
252253
let state = self.make_enforcement_state_cell(inner.commitment_seed);
253254

254255
Ok(EnforcingSigner {

fuzz/src/full_stack.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ use lightning::util::config::UserConfig;
4848
use lightning::util::errors::APIError;
4949
use lightning::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
5050
use lightning::util::logger::Logger;
51-
use lightning::util::ser::{Readable, Writeable};
51+
use lightning::util::ser::{Readable, ReadableArgs, Writeable};
5252

5353
use crate::utils::test_logger;
5454
use crate::utils::test_persister::TestPersister;
@@ -347,6 +347,7 @@ impl SignerProvider for KeyProvider {
347347
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, ctr],
348348
channel_value_satoshis,
349349
channel_keys_id,
350+
channel_keys_id,
350351
)
351352
} else {
352353
InMemorySigner::new(
@@ -359,12 +360,13 @@ impl SignerProvider for KeyProvider {
359360
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, ctr],
360361
channel_value_satoshis,
361362
channel_keys_id,
363+
channel_keys_id,
362364
)
363365
}, state, false)
364366
}
365367

366368
fn read_chan_signer(&self, mut data: &[u8]) -> Result<EnforcingSigner, DecodeError> {
367-
let inner: InMemorySigner = Readable::read(&mut data)?;
369+
let inner: InMemorySigner = ReadableArgs::read(&mut data, self)?;
368370
let state = Arc::new(Mutex::new(EnforcementState::new()));
369371

370372
Ok(EnforcingSigner::new_with_revoked(

lightning/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ max_level_trace = []
2929
# This is unsafe to use in production because it may result in the counterparty publishing taking our funds.
3030
unsafe_revoked_tx_signing = []
3131
_bench_unstable = []
32+
# Override signing to not include randomness when generating signatures for test vectors.
33+
_test_vectors = []
3234

3335
no-std = ["hashbrown", "bitcoin/no-std", "core2/alloc"]
3436
std = ["bitcoin/std"]

lightning/src/chain/channelmonitor.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4235,6 +4235,7 @@ mod tests {
42354235
[41; 32],
42364236
0,
42374237
[0; 32],
4238+
[0; 32],
42384239
);
42394240

42404241
let counterparty_pubkeys = ChannelPublicKeys {

lightning/src/chain/keysinterface.rs

+61-21
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ use bitcoin::secp256k1::ecdsa::RecoverableSignature;
3232
use bitcoin::{PackedLockTime, secp256k1, Sequence, Witness};
3333

3434
use crate::util::transaction_utils;
35-
use crate::util::crypto::{hkdf_extract_expand_twice, sign};
36-
use crate::util::ser::{Writeable, Writer, Readable};
35+
use crate::util::crypto::{hkdf_extract_expand_twice, sign, sign_with_aux_rand};
36+
use crate::util::ser::{Writeable, Writer, Readable, ReadableArgs};
3737
use crate::chain::transaction::OutPoint;
3838
#[cfg(anchors)]
3939
use crate::events::bump_transaction::HTLCDescriptor;
@@ -45,6 +45,7 @@ use crate::ln::script::ShutdownScript;
4545

4646
use crate::prelude::*;
4747
use core::convert::TryInto;
48+
use core::ops::Deref;
4849
use core::sync::atomic::{AtomicUsize, Ordering};
4950
use crate::io::{self, Error};
5051
use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
@@ -553,7 +554,6 @@ pub trait SignerProvider {
553554
fn get_shutdown_scriptpubkey(&self) -> ShutdownScript;
554555
}
555556

556-
#[derive(Clone)]
557557
/// A simple implementation of [`WriteableEcdsaChannelSigner`] that just keeps the private keys in memory.
558558
///
559559
/// This implementation performs no policy checks and is insufficient by itself as
@@ -580,6 +580,30 @@ pub struct InMemorySigner {
580580
channel_value_satoshis: u64,
581581
/// Key derivation parameters.
582582
channel_keys_id: [u8; 32],
583+
/// Seed from which all randomness produced is derived from.
584+
rand_bytes_unique_start: [u8; 32],
585+
/// Tracks the number of times we've produced randomness to ensure we don't return the same
586+
/// bytes twice.
587+
rand_bytes_index: AtomicCounter,
588+
}
589+
590+
impl Clone for InMemorySigner {
591+
fn clone(&self) -> Self {
592+
Self {
593+
funding_key: self.funding_key.clone(),
594+
revocation_base_key: self.revocation_base_key.clone(),
595+
payment_key: self.payment_key.clone(),
596+
delayed_payment_base_key: self.delayed_payment_base_key.clone(),
597+
htlc_base_key: self.htlc_base_key.clone(),
598+
commitment_seed: self.commitment_seed.clone(),
599+
holder_channel_pubkeys: self.holder_channel_pubkeys.clone(),
600+
channel_parameters: self.channel_parameters.clone(),
601+
channel_value_satoshis: self.channel_value_satoshis,
602+
channel_keys_id: self.channel_keys_id,
603+
rand_bytes_unique_start: self.get_secure_random_bytes(),
604+
rand_bytes_index: AtomicCounter::new(),
605+
}
606+
}
583607
}
584608

585609
impl InMemorySigner {
@@ -594,6 +618,7 @@ impl InMemorySigner {
594618
commitment_seed: [u8; 32],
595619
channel_value_satoshis: u64,
596620
channel_keys_id: [u8; 32],
621+
rand_bytes_unique_start: [u8; 32],
597622
) -> InMemorySigner {
598623
let holder_channel_pubkeys =
599624
InMemorySigner::make_holder_keys(secp_ctx, &funding_key, &revocation_base_key,
@@ -610,6 +635,8 @@ impl InMemorySigner {
610635
holder_channel_pubkeys,
611636
channel_parameters: None,
612637
channel_keys_id,
638+
rand_bytes_unique_start,
639+
rand_bytes_index: AtomicCounter::new(),
613640
}
614641
}
615642

@@ -686,7 +713,7 @@ impl InMemorySigner {
686713
let remotepubkey = self.pubkeys().payment_point;
687714
let witness_script = bitcoin::Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: remotepubkey}, Network::Testnet).script_pubkey();
688715
let sighash = hash_to_message!(&sighash::SighashCache::new(spend_tx).segwit_signature_hash(input_idx, &witness_script, descriptor.output.value, EcdsaSighashType::All).unwrap()[..]);
689-
let remotesig = sign(secp_ctx, &sighash, &self.payment_key);
716+
let remotesig = sign_with_aux_rand(secp_ctx, &sighash, &self.payment_key, &self);
690717
let payment_script = bitcoin::Address::p2wpkh(&::bitcoin::PublicKey{compressed: true, inner: remotepubkey}, Network::Bitcoin).unwrap().script_pubkey();
691718

692719
if payment_script != descriptor.output.script_pubkey { return Err(()); }
@@ -722,7 +749,7 @@ impl InMemorySigner {
722749
let delayed_payment_pubkey = PublicKey::from_secret_key(&secp_ctx, &delayed_payment_key);
723750
let witness_script = chan_utils::get_revokeable_redeemscript(&descriptor.revocation_pubkey, descriptor.to_self_delay, &delayed_payment_pubkey);
724751
let sighash = hash_to_message!(&sighash::SighashCache::new(spend_tx).segwit_signature_hash(input_idx, &witness_script, descriptor.output.value, EcdsaSighashType::All).unwrap()[..]);
725-
let local_delayedsig = sign(secp_ctx, &sighash, &delayed_payment_key);
752+
let local_delayedsig = sign_with_aux_rand(secp_ctx, &sighash, &delayed_payment_key, &self);
726753
let payment_script = bitcoin::Address::p2wsh(&witness_script, Network::Bitcoin).script_pubkey();
727754

728755
if descriptor.output.script_pubkey != payment_script { return Err(()); }
@@ -736,6 +763,15 @@ impl InMemorySigner {
736763
}
737764
}
738765

766+
impl EntropySource for InMemorySigner {
767+
fn get_secure_random_bytes(&self) -> [u8; 32] {
768+
let index = self.rand_bytes_index.get_increment();
769+
let mut nonce = [0u8; 16];
770+
nonce[..8].copy_from_slice(&index.to_be_bytes());
771+
ChaCha20::get_single_block(&self.rand_bytes_unique_start, &nonce)
772+
}
773+
}
774+
739775
impl ChannelSigner for InMemorySigner {
740776
fn get_per_commitment_point(&self, idx: u64, secp_ctx: &Secp256k1<secp256k1::All>) -> PublicKey {
741777
let commitment_secret = SecretKey::from_slice(&chan_utils::build_commitment_secret(&self.commitment_seed, idx)).unwrap();
@@ -774,7 +810,7 @@ impl EcdsaChannelSigner for InMemorySigner {
774810
let channel_funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);
775811

776812
let built_tx = trusted_tx.built_transaction();
777-
let commitment_sig = built_tx.sign(&self.funding_key, &channel_funding_redeemscript, self.channel_value_satoshis, secp_ctx);
813+
let commitment_sig = built_tx.sign_counterparty_commitment(&self.funding_key, &channel_funding_redeemscript, self.channel_value_satoshis, secp_ctx);
778814
let commitment_txid = built_tx.txid;
779815

780816
let mut htlc_sigs = Vec::with_capacity(commitment_tx.htlcs().len());
@@ -799,9 +835,9 @@ impl EcdsaChannelSigner for InMemorySigner {
799835
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
800836
let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);
801837
let trusted_tx = commitment_tx.trust();
802-
let sig = trusted_tx.built_transaction().sign(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, secp_ctx);
838+
let sig = trusted_tx.built_transaction().sign_holder_commitment(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, &self, secp_ctx);
803839
let channel_parameters = self.get_channel_parameters();
804-
let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), secp_ctx)?;
840+
let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), &self, secp_ctx)?;
805841
Ok((sig, htlc_sigs))
806842
}
807843

@@ -810,9 +846,9 @@ impl EcdsaChannelSigner for InMemorySigner {
810846
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
811847
let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);
812848
let trusted_tx = commitment_tx.trust();
813-
let sig = trusted_tx.built_transaction().sign(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, secp_ctx);
849+
let sig = trusted_tx.built_transaction().sign_holder_commitment(&self.funding_key, &funding_redeemscript, self.channel_value_satoshis, &self, secp_ctx);
814850
let channel_parameters = self.get_channel_parameters();
815-
let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), secp_ctx)?;
851+
let htlc_sigs = trusted_tx.get_htlc_sigs(&self.htlc_base_key, &channel_parameters.as_holder_broadcastable(), &self, secp_ctx)?;
816852
Ok((sig, htlc_sigs))
817853
}
818854

@@ -826,7 +862,7 @@ impl EcdsaChannelSigner for InMemorySigner {
826862
};
827863
let mut sighash_parts = sighash::SighashCache::new(justice_tx);
828864
let sighash = hash_to_message!(&sighash_parts.segwit_signature_hash(input, &witness_script, amount, EcdsaSighashType::All).unwrap()[..]);
829-
return Ok(sign(secp_ctx, &sighash, &revocation_key))
865+
return Ok(sign_with_aux_rand(secp_ctx, &sighash, &revocation_key, &self))
830866
}
831867

832868
fn sign_justice_revoked_htlc(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
@@ -840,7 +876,7 @@ impl EcdsaChannelSigner for InMemorySigner {
840876
};
841877
let mut sighash_parts = sighash::SighashCache::new(justice_tx);
842878
let sighash = hash_to_message!(&sighash_parts.segwit_signature_hash(input, &witness_script, amount, EcdsaSighashType::All).unwrap()[..]);
843-
return Ok(sign(secp_ctx, &sighash, &revocation_key))
879+
return Ok(sign_with_aux_rand(secp_ctx, &sighash, &revocation_key, &self))
844880
}
845881

846882
#[cfg(anchors)]
@@ -858,7 +894,7 @@ impl EcdsaChannelSigner for InMemorySigner {
858894
let our_htlc_private_key = chan_utils::derive_private_key(
859895
&secp_ctx, &per_commitment_point, &self.htlc_base_key
860896
);
861-
Ok(sign(&secp_ctx, &hash_to_message!(sighash), &our_htlc_private_key))
897+
Ok(sign_with_aux_rand(&secp_ctx, &hash_to_message!(sighash), &our_htlc_private_key, &self))
862898
}
863899

864900
fn sign_counterparty_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
@@ -869,7 +905,7 @@ impl EcdsaChannelSigner for InMemorySigner {
869905
let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, self.opt_anchors(), &counterparty_htlcpubkey, &htlcpubkey, &revocation_pubkey);
870906
let mut sighash_parts = sighash::SighashCache::new(htlc_tx);
871907
let sighash = hash_to_message!(&sighash_parts.segwit_signature_hash(input, &witness_script, amount, EcdsaSighashType::All).unwrap()[..]);
872-
Ok(sign(secp_ctx, &sighash, &htlc_key))
908+
Ok(sign_with_aux_rand(secp_ctx, &sighash, &htlc_key, &self))
873909
}
874910

875911
fn sign_closing_transaction(&self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
@@ -885,14 +921,14 @@ impl EcdsaChannelSigner for InMemorySigner {
885921
let sighash = sighash::SighashCache::new(&*anchor_tx).segwit_signature_hash(
886922
input, &witness_script, ANCHOR_OUTPUT_VALUE_SATOSHI, EcdsaSighashType::All,
887923
).unwrap();
888-
Ok(sign(secp_ctx, &hash_to_message!(&sighash[..]), &self.funding_key))
924+
Ok(sign_with_aux_rand(secp_ctx, &hash_to_message!(&sighash[..]), &self.funding_key, &self))
889925
}
890926

891927
fn sign_channel_announcement_with_funding_key(
892928
&self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<secp256k1::All>
893929
) -> Result<Signature, ()> {
894930
let msghash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]);
895-
Ok(sign(secp_ctx, &msghash, &self.funding_key))
931+
Ok(secp_ctx.sign_ecdsa(&msghash, &self.funding_key))
896932
}
897933
}
898934

@@ -922,8 +958,8 @@ impl Writeable for InMemorySigner {
922958
}
923959
}
924960

925-
impl Readable for InMemorySigner {
926-
fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
961+
impl<ES: Deref> ReadableArgs<ES> for InMemorySigner where ES::Target: EntropySource {
962+
fn read<R: io::Read>(reader: &mut R, entropy_source: ES) -> Result<Self, DecodeError> {
927963
let _ver = read_ver_prefix!(reader, SERIALIZATION_VERSION);
928964

929965
let funding_key = Readable::read(reader)?;
@@ -953,6 +989,8 @@ impl Readable for InMemorySigner {
953989
holder_channel_pubkeys,
954990
channel_parameters: counterparty_channel_data,
955991
channel_keys_id: keys_id,
992+
rand_bytes_unique_start: entropy_source.get_secure_random_bytes(),
993+
rand_bytes_index: AtomicCounter::new(),
956994
})
957995
}
958996
}
@@ -1107,6 +1145,7 @@ impl KeysManager {
11071145
let payment_key = key_step!(b"payment key", revocation_base_key);
11081146
let delayed_payment_base_key = key_step!(b"delayed payment base key", payment_key);
11091147
let htlc_base_key = key_step!(b"HTLC base key", delayed_payment_base_key);
1148+
let prng_seed = self.get_secure_random_bytes();
11101149

11111150
InMemorySigner::new(
11121151
&self.secp_ctx,
@@ -1118,6 +1157,7 @@ impl KeysManager {
11181157
commitment_seed,
11191158
channel_value_satoshis,
11201159
params.clone(),
1160+
prng_seed,
11211161
)
11221162
}
11231163

@@ -1233,7 +1273,7 @@ impl KeysManager {
12331273
if payment_script != output.script_pubkey { return Err(()); };
12341274

12351275
let sighash = hash_to_message!(&sighash::SighashCache::new(&spend_tx).segwit_signature_hash(input_idx, &witness_script, output.value, EcdsaSighashType::All).unwrap()[..]);
1236-
let sig = sign(secp_ctx, &sighash, &secret.private_key);
1276+
let sig = sign_with_aux_rand(secp_ctx, &sighash, &secret.private_key, &self);
12371277
let mut sig_ser = sig.serialize_der().to_vec();
12381278
sig_ser.push(EcdsaSighashType::All as u8);
12391279
spend_tx.input[input_idx].witness.push(sig_ser);
@@ -1295,7 +1335,7 @@ impl NodeSigner for KeysManager {
12951335

12961336
fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result<Signature, ()> {
12971337
let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]);
1298-
Ok(sign(&self.secp_ctx, &msg_hash, &self.node_secret))
1338+
Ok(self.secp_ctx.sign_ecdsa(&msg_hash, &self.node_secret))
12991339
}
13001340
}
13011341

@@ -1323,7 +1363,7 @@ impl SignerProvider for KeysManager {
13231363
}
13241364

13251365
fn read_chan_signer(&self, reader: &[u8]) -> Result<Self::Signer, DecodeError> {
1326-
InMemorySigner::read(&mut io::Cursor::new(reader))
1366+
InMemorySigner::read(&mut io::Cursor::new(reader), self)
13271367
}
13281368

13291369
fn get_destination_script(&self) -> Script {

0 commit comments

Comments
 (0)