From 399eb16a31d5f8fbda98cea8b3ee23ceb8b5f79b Mon Sep 17 00:00:00 2001 From: Steven Roose Date: Fri, 21 Mar 2025 17:32:55 +0000 Subject: [PATCH] Add musig support This reverts commit c85ead1dd855f3aa4f587a4e4a22bdc0f2377cb0. --- Cargo.lock | 50 +++++++++++++++++++++++++++++++++++++--- Cargo.toml | 1 + src/bin/hal/cmd/mod.rs | 2 ++ src/bin/hal/cmd/musig.rs | 43 ++++++++++++++++++++++++++++++++++ src/bin/hal/main.rs | 1 + 5 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 src/bin/hal/cmd/musig.rs diff --git a/Cargo.lock b/Cargo.lock index f1b9aed..7fbd75e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -90,7 +90,7 @@ dependencies = [ "bitcoin_hashes 0.14.0", "hex-conservative 0.2.1", "hex_lit", - "secp256k1", + "secp256k1 0.29.1", "serde", ] @@ -115,6 +115,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" +[[package]] +name = "bitcoin-private" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" + [[package]] name = "bitcoin-units" version = "0.1.2" @@ -249,7 +255,8 @@ dependencies = [ "lightning-invoice", "log", "miniscript", - "secp256k1", + "secp256k1 0.29.1", + "secp256k1-zkp", "serde", "serde_json", "serde_yaml", @@ -484,6 +491,15 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "secp256k1-sys 0.8.1", +] + [[package]] name = "secp256k1" version = "0.29.1" @@ -492,10 +508,19 @@ checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ "bitcoin_hashes 0.14.0", "rand 0.8.5", - "secp256k1-sys", + "secp256k1-sys 0.10.1", "serde", ] +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + [[package]] name = "secp256k1-sys" version = "0.10.1" @@ -505,6 +530,25 @@ dependencies = [ "cc", ] +[[package]] +name = "secp256k1-zkp" +version = "0.9.2" +source = "git+https://github.com/sanket1729/rust-secp256k1-zkp.git?rev=0de61c2cc536a58f08822851528a5dfa5968d155#0de61c2cc536a58f08822851528a5dfa5968d155" +dependencies = [ + "bitcoin-private", + "secp256k1 0.27.0", + "secp256k1-zkp-sys", +] + +[[package]] +name = "secp256k1-zkp-sys" +version = "0.8.1" +source = "git+https://github.com/sanket1729/rust-secp256k1-zkp.git?rev=0de61c2cc536a58f08822851528a5dfa5968d155#0de61c2cc536a58f08822851528a5dfa5968d155" +dependencies = [ + "cc", + "secp256k1-sys 0.8.1", +] + [[package]] name = "serde" version = "1.0.125" diff --git a/Cargo.toml b/Cargo.toml index 1750d53..141e380 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ cli = ["base64-compat", "clap", "fern", "log", "jobserver", "shell-escape"] [dependencies] bitcoin = { version = "0.32.5", features = [ "std", "serde", "rand", "rand-std" ] } secp256k1 = { version = "0.29", features = [ "recovery" ] } +secp256k1_zkp_musig = { package = "secp256k1-zkp", git = "https://github.com/sanket1729/rust-secp256k1-zkp.git", rev = "0de61c2cc536a58f08822851528a5dfa5968d155" } bip39 = { version = "2.1.0", features = [ "all-languages" ] } lightning-invoice = { version = "0.32.0", features = [ "std" ] } miniscript = { version = "12.3.0", features = ["compiler"] } diff --git a/src/bin/hal/cmd/mod.rs b/src/bin/hal/cmd/mod.rs index 7318483..d434434 100644 --- a/src/bin/hal/cmd/mod.rs +++ b/src/bin/hal/cmd/mod.rs @@ -9,6 +9,7 @@ pub mod ln; pub mod merkle; pub mod message; pub mod miniscript; +pub mod musig; pub mod psbt; pub mod random; pub mod script; @@ -28,6 +29,7 @@ pub fn subcommands() -> Vec> { merkle::subcommand(), message::subcommand(), miniscript::subcommand(), + musig::subcommand(), psbt::subcommand(), random::subcommand(), script::subcommand(), diff --git a/src/bin/hal/cmd/musig.rs b/src/bin/hal/cmd/musig.rs new file mode 100644 index 0000000..d074586 --- /dev/null +++ b/src/bin/hal/cmd/musig.rs @@ -0,0 +1,43 @@ + +use std::str::FromStr; +use crate::prelude::*; +use secp256k1_zkp_musig as zkpmusig; + +pub fn subcommand<'a>() -> clap::App<'a, 'a> { + cmd::subcommand_group("musig", "use the MuSig2 multisignature protocol") + .subcommand(cmd_aggregate()) +} + +pub fn execute<'a>(args: &clap::ArgMatches<'a>) { + match args.subcommand() { + ("aggregate", Some(ref m)) => exec_aggregate(&m), + (_, _) => unreachable!("clap prints help"), + }; +} + +fn cmd_aggregate<'a>() -> clap::App<'a, 'a> { + cmd::subcommand("aggregate", "aggregate public keys in a MuSig2 compatible way") + .arg(args::flag( + "ordered", "aggregate in the specified order instead of ordering lexicographically", + )) + .arg(args::arg("pubkeys", "list of public keys in hex").required(true).multiple(true)) +} + +fn exec_aggregate<'a>(args: &clap::ArgMatches<'a>) { + let mut pks = Vec::with_capacity(2); + for arg in args.values_of("pubkeys").need("no pubkeys provided") { + let pk = bitcoin::PublicKey::from_str(&arg).unwrap_or_else(|_| { + exit!("invalid public key provided: {}", arg); + }); + pks.push(zkpmusig::PublicKey::from_slice(&pk.inner.serialize()).unwrap()); + } + + if !args.is_present("ordered") { + //TODO(stevenroose) is this lexicographically + pks.sort_by_key(|k| k.serialize()); + } + + let secp = zkpmusig::Secp256k1::new(); + let agg = zkpmusig::MusigKeyAggCache::new(&secp, &pks[..]); + print!("{}", agg.agg_pk()); +} diff --git a/src/bin/hal/main.rs b/src/bin/hal/main.rs index 57bd1dc..b0efdd8 100644 --- a/src/bin/hal/main.rs +++ b/src/bin/hal/main.rs @@ -141,6 +141,7 @@ fn main() { ("merkle", Some(ref m)) => cmd::merkle::execute(&m), ("message", Some(ref m)) => cmd::message::execute(&m), ("miniscript", Some(ref m)) => cmd::miniscript::execute(&m), + ("musig", Some(ref m)) => cmd::musig::execute(&m), ("psbt", Some(ref m)) => cmd::psbt::execute(&m), ("random", Some(ref m)) => cmd::random::execute(&m), ("script", Some(ref m)) => cmd::script::execute(&m),