From 2f270e907f8ef0dcaf26c14def0c3dc853ff0181 Mon Sep 17 00:00:00 2001 From: LLFourn Date: Mon, 19 Feb 2024 10:16:51 +1100 Subject: [PATCH] [libsecp_compat_0_28] Update compatibility to rust-libsecp256k1 v0.28 --- CHANGELOG.md | 1 + ecdsa_fun/Cargo.toml | 3 +- ecdsa_fun/benches/bench_ecdsa.rs | 9 ++- ecdsa_fun/src/libsecp_compat.rs | 17 +++++ ecdsa_fun/tests/against_c_lib.rs | 8 +- schnorr_fun/Cargo.toml | 3 +- schnorr_fun/benches/bench_schnorr.rs | 12 +-- schnorr_fun/src/libsecp_compat.rs | 17 +++++ schnorr_fun/tests/against_c_lib.rs | 8 +- secp256kfun/Cargo.toml | 27 +++++-- secp256kfun/src/lib.rs | 18 +++-- secp256kfun/src/libsecp_compat.rs | 105 ++++++++++++++++++++++++++- 12 files changed, 197 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 669a8cb4..60009414 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ## Unreleased - Change `Scalar::from_bytes` to work for `Scalar<_, NonZero>` as well. +- Updated compatibility to `rust-secp256k1` v0.28.0 - Bumped MSRV to 1.63.0 to reduce friction - Added `share_backup` module in `schnorr_fun` - Added `arithmetic_macros` to make `g!` and `s!` macros into procedural macros diff --git a/ecdsa_fun/Cargo.toml b/ecdsa_fun/Cargo.toml index 1a6cdb07..97e109ec 100644 --- a/ecdsa_fun/Cargo.toml +++ b/ecdsa_fun/Cargo.toml @@ -34,8 +34,9 @@ required-features = ["libsecp_compat"] [features] default = ["std"] -libsecp_compat = ["secp256kfun/libsecp_compat", "libsecp_compat_0_27"] +libsecp_compat = ["secp256kfun/libsecp_compat", "libsecp_compat_0_28"] libsecp_compat_0_27 = ["secp256kfun/libsecp_compat_0_27"] +libsecp_compat_0_28 = ["secp256kfun/libsecp_compat_0_28"] std = ["alloc"] alloc = ["secp256kfun/alloc", "sigma_fun?/alloc" ] serde = ["secp256kfun/serde","sigma_fun?/serde"] diff --git a/ecdsa_fun/benches/bench_ecdsa.rs b/ecdsa_fun/benches/bench_ecdsa.rs index d937f3b3..371042a1 100644 --- a/ecdsa_fun/benches/bench_ecdsa.rs +++ b/ecdsa_fun/benches/bench_ecdsa.rs @@ -20,7 +20,12 @@ fn sign_ecdsa(c: &mut Criterion) { let secret_key = SecretKey::from_slice(&SK.to_bytes()[..]).unwrap(); { group.bench_function("secp256k1::ecdsa_sign", |b| { - b.iter(|| secp.sign_ecdsa(&Message::from_slice(&MESSAGE[..]).unwrap(), &secret_key)) + b.iter(|| { + secp.sign_ecdsa( + &Message::from_digest_slice(&MESSAGE[..]).unwrap(), + &secret_key, + ) + }) }); } } @@ -53,7 +58,7 @@ fn verify_ecdsa(c: &mut Criterion) { group.bench_function("secp256k1::ecdsa_verify", |b| { b.iter(|| { secp.verify_ecdsa( - &Message::from_slice(&MESSAGE[..]).unwrap(), + &Message::from_digest_slice(&MESSAGE[..]).unwrap(), &sig, &public_key, ) diff --git a/ecdsa_fun/src/libsecp_compat.rs b/ecdsa_fun/src/libsecp_compat.rs index deef6e0e..5d2213dc 100644 --- a/ecdsa_fun/src/libsecp_compat.rs +++ b/ecdsa_fun/src/libsecp_compat.rs @@ -14,3 +14,20 @@ mod v0_27 { } } } + +#[cfg(feature = "libsecp_compat_0_28")] +mod v0_28 { + use crate::{fun::secp256k1_0_28::ecdsa, Signature}; + + impl From for ecdsa::Signature { + fn from(sig: Signature) -> Self { + ecdsa::Signature::from_compact(sig.to_bytes().as_ref()).unwrap() + } + } + + impl From for Signature { + fn from(sig: ecdsa::Signature) -> Self { + Signature::from_bytes(sig.serialize_compact()).unwrap() + } + } +} diff --git a/ecdsa_fun/tests/against_c_lib.rs b/ecdsa_fun/tests/against_c_lib.rs index 7ba4ab50..97119df3 100644 --- a/ecdsa_fun/tests/against_c_lib.rs +++ b/ecdsa_fun/tests/against_c_lib.rs @@ -28,7 +28,7 @@ fn ecdsa_sign() { let c_public_key = PublicKey::from(public_key); let message = rand_32_bytes(); let signature = ecdsa.sign(&secret_key, &message); - let c_message = Message::from_slice(&message[..]).unwrap(); + let c_message = Message::from_digest_slice(&message[..]).unwrap(); let c_siganture = ecdsa::Signature::from_compact(&signature.to_bytes()).unwrap(); assert!(secp .verify_ecdsa(&c_message, &c_siganture, &c_public_key) @@ -48,7 +48,7 @@ fn ecdsa_verify() { let c_public_key = PublicKey::from_secret_key(&secp, &c_secret_key); let public_key = Point::from(c_public_key); let message = rand_32_bytes(); - let c_message = Message::from_slice(&message[..]).unwrap(); + let c_message = Message::from_digest_slice(&message[..]).unwrap(); let c_signature = secp.sign_ecdsa(&c_message, &c_secret_key); let signature = ecdsa_fun::Signature::from(c_signature); assert!(ecdsa.verify(&public_key, &message, &signature)); @@ -66,7 +66,7 @@ fn ecdsa_verify_high_message() { let message = hex::decode_array("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF") .unwrap(); - let c_message = Message::from_slice(&message[..]).unwrap(); + let c_message = Message::from_digest_slice(&message[..]).unwrap(); let c_signature = secp.sign_ecdsa(&c_message, &c_secret_key); let signature = ecdsa_fun::Signature::from_bytes(c_signature.serialize_compact()).unwrap(); @@ -86,7 +86,7 @@ fn ecdsa_sign_high_message() { hex::decode_array("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF") .unwrap(); let signature = ecdsa.sign(&secret_key, &message); - let c_message = Message::from_slice(&message[..]).unwrap(); + let c_message = Message::from_digest_slice(&message[..]).unwrap(); let c_siganture = ecdsa::Signature::from_compact(&signature.to_bytes()).unwrap(); assert!(secp .verify_ecdsa(&c_message, &c_siganture, &c_public_key) diff --git a/schnorr_fun/Cargo.toml b/schnorr_fun/Cargo.toml index 2a1cb62c..198ab9b6 100644 --- a/schnorr_fun/Cargo.toml +++ b/schnorr_fun/Cargo.toml @@ -42,8 +42,9 @@ alloc = ["secp256kfun/alloc" ] std = ["alloc", "secp256kfun/std"] bincode = ["secp256kfun/bincode"] serde = ["secp256kfun/serde"] -libsecp_compat = ["secp256kfun/libsecp_compat", "libsecp_compat_0_27"] +libsecp_compat = ["secp256kfun/libsecp_compat", "libsecp_compat_0_28"] libsecp_compat_0_27 = ["secp256kfun/libsecp_compat_0_27"] +libsecp_compat_0_28 = ["secp256kfun/libsecp_compat_0_28"] proptest = ["secp256kfun/proptest"] share_backup = ["dep:bech32"] diff --git a/schnorr_fun/benches/bench_schnorr.rs b/schnorr_fun/benches/bench_schnorr.rs index ddc9e4d1..38d4989a 100755 --- a/schnorr_fun/benches/bench_schnorr.rs +++ b/schnorr_fun/benches/bench_schnorr.rs @@ -25,10 +25,10 @@ fn sign_schnorr(c: &mut Criterion) { } { - use secp256k1::{KeyPair, Message, Secp256k1}; + use secp256k1::{Keypair, Message, Secp256k1}; let secp = Secp256k1::new(); - let kp = KeyPair::from_secret_key(&secp, &(*SK).into()); - let msg = Message::from_slice(&MESSAGE[..]).unwrap(); + let kp = Keypair::from_secret_key(&secp, &(*SK).into()); + let msg = Message::from_digest_slice(&MESSAGE[..]).unwrap(); group.bench_function("secp::schnorrsig_sign_no_aux_rand", |b| { b.iter(|| { secp.sign_schnorr_no_aux_rand(&msg, &kp); @@ -57,11 +57,11 @@ fn verify_schnorr(c: &mut Criterion) { } { - use secp256k1::{KeyPair, Message, Secp256k1, XOnlyPublicKey}; + use secp256k1::{Keypair, Message, Secp256k1, XOnlyPublicKey}; let secp = Secp256k1::new(); - let kp = KeyPair::from_secret_key(&secp, &(*SK).into()); + let kp = Keypair::from_secret_key(&secp, &(*SK).into()); let pk = XOnlyPublicKey::from_keypair(&kp).0; - let msg = Message::from_slice(&MESSAGE[..]).unwrap(); + let msg = Message::from_digest_slice(&MESSAGE[..]).unwrap(); let sig = secp.sign_schnorr_no_aux_rand(&msg, &kp); group.bench_function("secp::schnorrsig_verify", |b| { b.iter(|| secp.verify_schnorr(&sig, &msg, &pk)); diff --git a/schnorr_fun/src/libsecp_compat.rs b/schnorr_fun/src/libsecp_compat.rs index e8fe7417..4dc7c724 100644 --- a/schnorr_fun/src/libsecp_compat.rs +++ b/schnorr_fun/src/libsecp_compat.rs @@ -14,3 +14,20 @@ mod v0_27 { } } } + +#[cfg(feature = "libsecp_compat_0_28")] +mod v0_28 { + use secp256kfun::secp256k1_0_28::schnorr; + + impl From for schnorr::Signature { + fn from(sig: crate::Signature) -> Self { + schnorr::Signature::from_slice(sig.to_bytes().as_ref()).unwrap() + } + } + + impl From for crate::Signature { + fn from(sig: schnorr::Signature) -> Self { + crate::Signature::from_bytes(*sig.as_ref()).unwrap() + } + } +} diff --git a/schnorr_fun/tests/against_c_lib.rs b/schnorr_fun/tests/against_c_lib.rs index d40a93f7..71de8fb6 100644 --- a/schnorr_fun/tests/against_c_lib.rs +++ b/schnorr_fun/tests/against_c_lib.rs @@ -63,8 +63,8 @@ proptest! { msg in any::<[u8;32]>(), ) { let secp = &*SECP; - let keypair = secp256k1::KeyPair::from_secret_key(secp, &key.into()); - let secp_msg = secp256k1::Message::from_slice(&msg).unwrap(); + let keypair = secp256k1::Keypair::from_secret_key(secp, &key.into()); + let secp_msg = secp256k1::Message::from_digest_slice(&msg).unwrap(); let sig = secp.sign_schnorr_no_aux_rand(&secp_msg, &keypair); let schnorr = Schnorr::::default(); let fun_keypair = schnorr.new_keypair(key); @@ -77,9 +77,9 @@ proptest! { #[test] fn verify_secp_sigs(key in any::(), msg in any::<[u8;32]>(), aux_rand in any::<[u8;32]>()) { let secp = &*SECP; - let keypair = secp256k1::KeyPair::from_secret_key(secp, &key.into()); + let keypair = secp256k1::Keypair::from_secret_key(secp, &key.into()); let fun_pk = secp256k1::XOnlyPublicKey::from_keypair(&keypair).0.into(); - let secp_msg = secp256k1::Message::from_slice(&msg).unwrap(); + let secp_msg = secp256k1::Message::from_digest_slice(&msg).unwrap(); let sig = secp.sign_schnorr_with_aux_rand(&secp_msg, &keypair, &aux_rand); let schnorr = Schnorr::::verify_only(); let fun_msg = Message::::raw(&msg); diff --git a/secp256kfun/Cargo.toml b/secp256kfun/Cargo.toml index 395c8f4f..6da40e9e 100644 --- a/secp256kfun/Cargo.toml +++ b/secp256kfun/Cargo.toml @@ -22,10 +22,13 @@ secp256kfun_arithmetic_macros = { version = "0.9.0", path = "../arithmetic_macro # optional serde = { version = "1.0", optional = true, default-features = false, features = ["derive"] } -secp256k1_0_27 = { package = "secp256k1", version = "0.27", optional = true, default-features = false } proptest = { version = "1", optional = true } bincode = { version = "2.0.0-rc.3", optional = true, default-features = false, features = ["derive"] } +secp256k1_0_27 = { package = "secp256k1", version = "0.27", optional = true, default-features = false } +secp256k1_0_28 = { package = "secp256k1", version = "0.28", optional = true, default-features = false } + + [dev-dependencies] serde_json = "1" rand = { version = "0.8" } @@ -39,11 +42,25 @@ wasm-bindgen-test = "0.3" [features] default = ["std"] +libsecp_compat = ["libsecp_compat_0_28"] +alloc = [ +"serde?/alloc", +"digest/alloc", +"bincode?/alloc", +"secp256k1_0_27?/alloc", +"secp256k1_0_28?/alloc", +] +std = ["alloc", "subtle/std", "digest/std", "bincode?/std", "secp256k1_0_27?/std", "secp256k1_0_28?/std"] +serde = [ +"dep:serde", +"bincode?/serde", +"secp256k1_0_27?/serde", +"secp256k1_0_28?/serde", +] + libsecp_compat_0_27 = [ "dep:secp256k1_0_27" ] -libsecp_compat = ["libsecp_compat_0_27"] -alloc = ["serde?/alloc", "digest/alloc", "secp256k1_0_27?/alloc", "bincode?/alloc"] -std = ["alloc", "subtle/std", "digest/std", "bincode?/std", "secp256k1_0_27?/std"] -serde = [ "dep:serde", "secp256k1_0_27?/serde", "bincode?/serde" ] +libsecp_compat_0_28 = [ "dep:secp256k1_0_28" ] + [[bench]] name = "bench_ecmult" diff --git a/secp256kfun/src/lib.rs b/secp256kfun/src/lib.rs index e89bde64..dfb5b3c2 100755 --- a/secp256kfun/src/lib.rs +++ b/secp256kfun/src/lib.rs @@ -43,13 +43,6 @@ pub use point::Point; pub use scalar::Scalar; pub use slice::Slice; -#[cfg(feature = "libsecp_compat_0_27")] -/// Re-export `secp256k1` -pub extern crate secp256k1_0_27; - -#[cfg(feature = "libsecp_compat")] -pub use secp256k1_0_27 as secp256k1; - /// Re-export `serde` #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] #[cfg(feature = "serde")] @@ -89,3 +82,14 @@ pub static G: &Point = // it is applied to nonce generators too so export at root pub use hash::Tag; + +#[cfg(feature = "libsecp_compat_0_27")] +/// Re-export `secp256k1` +pub extern crate secp256k1_0_27; + +#[cfg(feature = "libsecp_compat_0_28")] +/// Re-export `secp256k1` +pub extern crate secp256k1_0_28; + +#[cfg(feature = "libsecp_compat")] +pub use secp256k1_0_28 as secp256k1; diff --git a/secp256kfun/src/libsecp_compat.rs b/secp256kfun/src/libsecp_compat.rs index 02a45c4d..4a6107b1 100644 --- a/secp256kfun/src/libsecp_compat.rs +++ b/secp256kfun/src/libsecp_compat.rs @@ -1,5 +1,108 @@ +#[cfg(feature = "libsecp_compat_0_28")] +mod v0_28 { + use crate::{marker::*, Point, Scalar}; + use secp256k1::{PublicKey, SecretKey, XOnlyPublicKey}; + use secp256k1_0_28 as secp256k1; + + impl From for SecretKey { + fn from(scalar: Scalar) -> Self { + SecretKey::from_slice(scalar.to_bytes().as_ref()).unwrap() + } + } + + impl From for Scalar { + fn from(sk: SecretKey) -> Self { + Scalar::from_slice(&sk[..]) + .unwrap() + .non_zero() + .expect("SecretKey is never zero") + } + } + + impl From> for secp256k1::Scalar { + fn from(value: Scalar) -> Self { + secp256k1::Scalar::from_be_bytes(value.to_bytes()).unwrap() + } + } + + impl From for Scalar { + fn from(value: secp256k1::Scalar) -> Self { + Scalar::from_bytes(value.to_be_bytes()).unwrap() + } + } + + impl From for Point { + fn from(pk: PublicKey) -> Self { + Point::::from_bytes(pk.serialize()).unwrap() + } + } + + impl From for PublicKey { + fn from(pk: Point) -> Self { + PublicKey::from_slice(pk.to_bytes().as_ref()).unwrap() + } + } + + impl From> for XOnlyPublicKey { + fn from(point: Point) -> Self { + XOnlyPublicKey::from_slice(point.to_xonly_bytes().as_ref()).unwrap() + } + } + + impl From for Point { + fn from(pk: XOnlyPublicKey) -> Self { + Point::from_xonly_bytes(pk.serialize()).unwrap() + } + } + + #[cfg(test)] + mod test { + use super::*; + use core::str::FromStr; + #[cfg(feature = "proptest")] + use proptest::prelude::*; + + #[test] + fn public_key() { + let pk = PublicKey::from_str("0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8").unwrap(); + let point = Point::from(pk); + assert_eq!(pk.serialize().as_ref(), point.to_bytes().as_ref()); + } + + #[cfg(feature = "proptest")] + proptest! { + + #[test] + fn prop_public_key(first_byte in 0u8..10, x_bytes in any::<[u8;32]>()) { + let mut bytes = [0u8;33]; + bytes[0] = first_byte; + bytes[1..33].copy_from_slice(&x_bytes[..]); + let pk = PublicKey::from_slice(&bytes[..]).ok(); + let point = Point::<_,Public, >::from_bytes(bytes); + assert_eq!(pk.map(|pk| pk.serialize()), point.map(|point| point.to_bytes())); + } + + #[test] + fn prop_secret_key(bytes in any::<[u8;32]>()) { + let sk = SecretKey::from_slice(&bytes[..]).unwrap(); + let scalar = Scalar::from(sk); + assert_eq!(&sk[..], scalar.to_bytes().as_ref()); + } + + + + #[test] + fn scalar_roundtrip(scalar in any::>()) { + let secp_scalar = secp256k1::Scalar::from(scalar); + let rt_scalar = Scalar::from(secp_scalar); + assert_eq!(rt_scalar, scalar); + } + } + } +} + #[cfg(feature = "libsecp_compat_0_27")] -mod v27_0 { +mod v0_27 { use crate::{marker::*, Point, Scalar}; use secp256k1::{PublicKey, SecretKey, XOnlyPublicKey}; use secp256k1_0_27 as secp256k1;