From: Devrandom Date: Fri, 25 Mar 2022 19:34:02 +0000 (+0100) Subject: Add low_r signature grinding X-Git-Tag: v0.0.106~5^2 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=8d7b38fcf1a276fff78ba86aedd8a53b99846bcb;p=rust-lightning Add low_r signature grinding default on, can be turned off via a feature gate --- diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aaccb76a4..a72f4d4ce 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -115,6 +115,9 @@ jobs: cargo test --verbose --color always --no-default-features --features no-std # check if there is a conflict between no-std and the default std feature cargo test --verbose --color always --features no-std + # check that things still pass without grind_signatures + # note that outbound_commitment_test only runs in this mode, because of hardcoded signature values + cargo test --verbose --color always --no-default-features --features std # check if there is a conflict between no-std and the c_bindings cfg RUSTFLAGS="--cfg=c_bindings" cargo test --verbose --color always --no-default-features --features=no-std cd .. diff --git a/lightning/Cargo.toml b/lightning/Cargo.toml index f38bb8051..2b0c2d16b 100644 --- a/lightning/Cargo.toml +++ b/lightning/Cargo.toml @@ -32,7 +32,10 @@ _bench_unstable = [] no-std = ["hashbrown", "bitcoin/no-std", "core2/alloc"] std = ["bitcoin/std"] -default = ["std"] +# Generates low-r bitcoin signatures, which saves 1 byte in 50% of the cases +grind_signatures = [] + +default = ["std", "grind_signatures"] [dependencies] bitcoin = { version = "0.27", default-features = false, features = ["secp-recovery"] } diff --git a/lightning/src/chain/keysinterface.rs b/lightning/src/chain/keysinterface.rs index 1daeec4ef..be3103622 100644 --- a/lightning/src/chain/keysinterface.rs +++ b/lightning/src/chain/keysinterface.rs @@ -31,7 +31,7 @@ use bitcoin::secp256k1::recovery::RecoverableSignature; use bitcoin::secp256k1; use util::{byte_utils, transaction_utils}; -use util::crypto::hkdf_extract_expand_twice; +use util::crypto::{hkdf_extract_expand_twice, sign}; use util::ser::{Writeable, Writer, Readable, ReadableArgs}; use chain::transaction::OutPoint; @@ -590,7 +590,7 @@ impl InMemorySigner { let remotepubkey = self.pubkeys().payment_point; let witness_script = bitcoin::Address::p2pkh(&::bitcoin::PublicKey{compressed: true, key: remotepubkey}, Network::Testnet).script_pubkey(); let sighash = hash_to_message!(&bip143::SigHashCache::new(spend_tx).signature_hash(input_idx, &witness_script, descriptor.output.value, SigHashType::All)[..]); - let remotesig = secp_ctx.sign(&sighash, &self.payment_key); + let remotesig = sign(secp_ctx, &sighash, &self.payment_key); let payment_script = bitcoin::Address::p2wpkh(&::bitcoin::PublicKey{compressed: true, key: remotepubkey}, Network::Bitcoin).unwrap().script_pubkey(); if payment_script != descriptor.output.script_pubkey { return Err(()); } @@ -624,7 +624,7 @@ impl InMemorySigner { let delayed_payment_pubkey = PublicKey::from_secret_key(&secp_ctx, &delayed_payment_key); let witness_script = chan_utils::get_revokeable_redeemscript(&descriptor.revocation_pubkey, descriptor.to_self_delay, &delayed_payment_pubkey); let sighash = hash_to_message!(&bip143::SigHashCache::new(spend_tx).signature_hash(input_idx, &witness_script, descriptor.output.value, SigHashType::All)[..]); - let local_delayedsig = secp_ctx.sign(&sighash, &delayed_payment_key); + let local_delayedsig = sign(secp_ctx, &sighash, &delayed_payment_key); let payment_script = bitcoin::Address::p2wsh(&witness_script, Network::Bitcoin).script_pubkey(); if descriptor.output.script_pubkey != payment_script { return Err(()); } @@ -673,7 +673,7 @@ impl BaseSign for InMemorySigner { let htlc_sighashtype = if self.opt_anchors() { SigHashType::SinglePlusAnyoneCanPay } else { SigHashType::All }; let htlc_sighash = hash_to_message!(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype)[..]); let holder_htlc_key = chan_utils::derive_private_key(&secp_ctx, &keys.per_commitment_point, &self.htlc_base_key).map_err(|_| ())?; - htlc_sigs.push(secp_ctx.sign(&htlc_sighash, &holder_htlc_key)); + htlc_sigs.push(sign(secp_ctx, &htlc_sighash, &holder_htlc_key)); } Ok((commitment_sig, htlc_sigs)) @@ -714,7 +714,7 @@ impl BaseSign for InMemorySigner { }; let mut sighash_parts = bip143::SigHashCache::new(justice_tx); let sighash = hash_to_message!(&sighash_parts.signature_hash(input, &witness_script, amount, SigHashType::All)[..]); - return Ok(secp_ctx.sign(&sighash, &revocation_key)) + return Ok(sign(secp_ctx, &sighash, &revocation_key)) } fn sign_justice_revoked_htlc(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result { @@ -728,7 +728,7 @@ impl BaseSign for InMemorySigner { }; let mut sighash_parts = bip143::SigHashCache::new(justice_tx); let sighash = hash_to_message!(&sighash_parts.signature_hash(input, &witness_script, amount, SigHashType::All)[..]); - return Ok(secp_ctx.sign(&sighash, &revocation_key)) + return Ok(sign(secp_ctx, &sighash, &revocation_key)) } fn sign_counterparty_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result { @@ -742,7 +742,7 @@ impl BaseSign for InMemorySigner { } else { return Err(()) }; let mut sighash_parts = bip143::SigHashCache::new(htlc_tx); let sighash = hash_to_message!(&sighash_parts.signature_hash(input, &witness_script, amount, SigHashType::All)[..]); - return Ok(secp_ctx.sign(&sighash, &htlc_key)) + return Ok(sign(secp_ctx, &sighash, &htlc_key)) } Err(()) } @@ -756,7 +756,7 @@ impl BaseSign for InMemorySigner { fn sign_channel_announcement(&self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1) -> Result<(Signature, Signature), ()> { let msghash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]); - Ok((secp_ctx.sign(&msghash, &self.node_secret), secp_ctx.sign(&msghash, &self.funding_key))) + Ok((sign(secp_ctx, &msghash, &self.node_secret), sign(secp_ctx, &msghash, &self.funding_key))) } fn ready_channel(&mut self, channel_parameters: &ChannelTransactionParameters) { @@ -1102,7 +1102,7 @@ impl KeysManager { if payment_script != output.script_pubkey { return Err(()); }; let sighash = hash_to_message!(&bip143::SigHashCache::new(&spend_tx).signature_hash(input_idx, &witness_script, output.value, SigHashType::All)[..]); - let sig = secp_ctx.sign(&sighash, &secret.private_key.key); + let sig = sign(secp_ctx, &sighash, &secret.private_key.key); spend_tx.input[input_idx].witness.push(sig.serialize_der().to_vec()); spend_tx.input[input_idx].witness[0].push(SigHashType::All as u8); spend_tx.input[input_idx].witness.push(pubkey.key.serialize().to_vec()); diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 6dc05c2ef..370c0cc8e 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -39,6 +39,7 @@ use util::transaction_utils::sort_outputs; use ln::channel::{INITIAL_COMMITMENT_NUMBER, ANCHOR_OUTPUT_VALUE_SATOSHI}; use core::ops::Deref; use chain; +use util::crypto::sign; pub(crate) const MAX_HTLCS: u16 = 483; @@ -841,7 +842,7 @@ impl HolderCommitmentTransaction { pub fn dummy() -> Self { let secp_ctx = Secp256k1::new(); let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); - let dummy_sig = secp_ctx.sign(&secp256k1::Message::from_slice(&[42; 32]).unwrap(), &SecretKey::from_slice(&[42; 32]).unwrap()); + let dummy_sig = sign(&secp_ctx, &secp256k1::Message::from_slice(&[42; 32]).unwrap(), &SecretKey::from_slice(&[42; 32]).unwrap()); let keys = TxCreationKeys { per_commitment_point: dummy_key.clone(), @@ -936,7 +937,7 @@ impl BuiltCommitmentTransaction { /// because we are about to broadcast a holder transaction. pub fn sign(&self, funding_key: &SecretKey, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1) -> Signature { let sighash = self.get_sighash_all(funding_redeemscript, channel_value_satoshis); - secp_ctx.sign(&sighash, funding_key) + sign(secp_ctx, &sighash, funding_key) } } @@ -1060,7 +1061,7 @@ impl<'a> TrustedClosingTransaction<'a> { /// because we are about to broadcast a holder transaction. pub fn sign(&self, funding_key: &SecretKey, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1) -> Signature { let sighash = self.get_sighash_all(funding_redeemscript, channel_value_satoshis); - secp_ctx.sign(&sighash, funding_key) + sign(secp_ctx, &sighash, funding_key) } } @@ -1415,7 +1416,7 @@ impl<'a> TrustedCommitmentTransaction<'a> { let htlc_redeemscript = get_htlc_redeemscript_with_explicit_keys(&this_htlc, self.opt_anchors(), &keys.broadcaster_htlc_key, &keys.countersignatory_htlc_key, &keys.revocation_key); let sighash = hash_to_message!(&bip143::SigHashCache::new(&htlc_tx).signature_hash(0, &htlc_redeemscript, this_htlc.amount_msat / 1000, SigHashType::All)[..]); - ret.push(secp_ctx.sign(&sighash, &holder_htlc_key)); + ret.push(sign(secp_ctx, &sighash, &holder_htlc_key)); } Ok(ret) } diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 71e0ea121..0b0e09246 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -6628,6 +6628,7 @@ mod tests { } } + #[cfg(not(feature = "grind_signatures"))] #[test] fn outbound_commitment_test() { // Test vectors from BOLT 3 Appendices C and F (anchors): diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 0d1ee4fb0..185a06df9 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -69,6 +69,7 @@ use core::ops::Deref; #[cfg(any(test, feature = "std"))] use std::time::Instant; +use util::crypto::sign; mod inbound_payment { use alloc::string::ToString; @@ -3060,7 +3061,7 @@ impl ChannelMana excess_data: Vec::new(), }; let msghash = hash_to_message!(&Sha256dHash::hash(&announcement.encode()[..])[..]); - let node_announce_sig = self.secp_ctx.sign(&msghash, &self.our_network_key); + let node_announce_sig = sign(&self.secp_ctx, &msghash, &self.our_network_key); let mut channel_state_lock = self.channel_state.lock().unwrap(); let channel_state = &mut *channel_state_lock; diff --git a/lightning/src/util/crypto.rs b/lightning/src/util/crypto.rs index f8a3f847d..300ddacb0 100644 --- a/lightning/src/util/crypto.rs +++ b/lightning/src/util/crypto.rs @@ -1,6 +1,7 @@ use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::hashes::hmac::{Hmac, HmacEngine}; use bitcoin::hashes::sha256::Hash as Sha256; +use bitcoin::secp256k1::{Message, Secp256k1, SecretKey, Signature, Signing}; macro_rules! hkdf_extract_expand { ($salt: expr, $ikm: expr) => {{ @@ -36,3 +37,12 @@ pub fn hkdf_extract_expand_twice(salt: &[u8], ikm: &[u8]) -> ([u8; 32], [u8; 32] pub fn hkdf_extract_expand_thrice(salt: &[u8], ikm: &[u8]) -> ([u8; 32], [u8; 32], [u8; 32]) { hkdf_extract_expand!(salt, ikm, 3) } + +#[inline] +pub fn sign(ctx: &Secp256k1, msg: &Message, sk: &SecretKey) -> Signature { + #[cfg(feature = "grind_signatures")] + let sig = ctx.sign_low_r(msg, sk); + #[cfg(not(feature = "grind_signatures"))] + let sig = ctx.sign(msg, sk); + sig +}