Skip to content

Add low_r signature grinding #1388

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 ..
Expand Down
5 changes: 4 additions & 1 deletion lightning/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand Down
18 changes: 9 additions & 9 deletions lightning/src/chain/keysinterface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(()); }
Expand Down Expand Up @@ -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(()); }
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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<secp256k1::All>) -> Result<Signature, ()> {
Expand All @@ -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<secp256k1::All>) -> Result<Signature, ()> {
Expand All @@ -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(())
}
Expand All @@ -756,7 +756,7 @@ impl BaseSign for InMemorySigner {
fn sign_channel_announcement(&self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<secp256k1::All>)
-> 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) {
Expand Down Expand Up @@ -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());
Expand Down
9 changes: 5 additions & 4 deletions lightning/src/ln/chan_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -936,7 +937,7 @@ impl BuiltCommitmentTransaction {
/// because we are about to broadcast a holder transaction.
pub fn sign<T: secp256k1::Signing>(&self, funding_key: &SecretKey, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1<T>) -> Signature {
let sighash = self.get_sighash_all(funding_redeemscript, channel_value_satoshis);
secp_ctx.sign(&sighash, funding_key)
sign(secp_ctx, &sighash, funding_key)
}
}

Expand Down Expand Up @@ -1060,7 +1061,7 @@ impl<'a> TrustedClosingTransaction<'a> {
/// because we are about to broadcast a holder transaction.
pub fn sign<T: secp256k1::Signing>(&self, funding_key: &SecretKey, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1<T>) -> Signature {
let sighash = self.get_sighash_all(funding_redeemscript, channel_value_satoshis);
secp_ctx.sign(&sighash, funding_key)
sign(secp_ctx, &sighash, funding_key)
}
}

Expand Down Expand Up @@ -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)
}
Expand Down
1 change: 1 addition & 0 deletions lightning/src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
3 changes: 2 additions & 1 deletion lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -3060,7 +3061,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> 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;
Expand Down
10 changes: 10 additions & 0 deletions lightning/src/util/crypto.rs
Original file line number Diff line number Diff line change
@@ -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) => {{
Expand Down Expand Up @@ -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<C: Signing>(ctx: &Secp256k1<C>, 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
}