From 95c30720d26421b837f2522f1c10bc341c33f8c0 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Mon, 18 Aug 2025 13:02:35 -0400 Subject: [PATCH] Update how x coordinates are handled in bitcoin-serai --- networks/bitcoin/src/crypto.rs | 24 +++++++++++++++--------- networks/bitcoin/src/wallet/mod.rs | 6 +++--- networks/bitcoin/src/wallet/send.rs | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/networks/bitcoin/src/crypto.rs b/networks/bitcoin/src/crypto.rs index 12aa2c1e..36f85f29 100644 --- a/networks/bitcoin/src/crypto.rs +++ b/networks/bitcoin/src/crypto.rs @@ -7,15 +7,18 @@ use k256::{ use bitcoin::key::XOnlyPublicKey; -/// Get the x coordinate of a non-infinity, even point. Panics on invalid input. -pub fn x(key: &ProjectivePoint) -> [u8; 32] { +/// Get the x coordinate of a non-infinity point. +/// +/// Panics on invalid input. +fn x(key: &ProjectivePoint) -> [u8; 32] { let encoded = key.to_encoded_point(true); - assert_eq!(encoded.tag(), Tag::CompressedEvenY, "x coordinate of odd key"); (*encoded.x().expect("point at infinity")).into() } -/// Convert a non-infinity even point to a XOnlyPublicKey. Panics on invalid input. -pub fn x_only(key: &ProjectivePoint) -> XOnlyPublicKey { +/// Convert a non-infinity point to a XOnlyPublicKey (dropping its sign). +/// +/// Panics on invalid input. +pub(crate) fn x_only(key: &ProjectivePoint) -> XOnlyPublicKey { XOnlyPublicKey::from_slice(&x(key)).expect("x_only was passed a point which was infinity or odd") } @@ -46,9 +49,9 @@ mod frost_crypto { /// A BIP-340 compatible HRAm for use with the modular-frost Schnorr Algorithm. /// - /// If passed an odd nonce, it will have the generator added until it is even. + /// If passed an odd nonce, the challenge will be negated. /// - /// If the key is odd, this will panic. + /// If either `R` or `A` is the point at infinity, this will panic. #[derive(Clone, Copy, Debug)] pub struct Hram; #[allow(non_snake_case)] @@ -72,9 +75,12 @@ mod frost_crypto { /// BIP-340 Schnorr signature algorithm. /// - /// This must be used with a ThresholdKeys whose group key is even. If it is odd, this may panic. + /// This may panic if called with nonces/a group key which are the point at infinity (which have + /// a negligible probability for a well-reasoned caller, even with malicious participants + /// present). /// - /// `verify`, `verify_share` must be called after `sign_share` is called. + /// `verify`, `verify_share` MUST be called after `sign_share` is called. Otherwise, this library + /// MAY panic. #[derive(Clone)] pub struct Schnorr(FrostSchnorr); impl Schnorr { diff --git a/networks/bitcoin/src/wallet/mod.rs b/networks/bitcoin/src/wallet/mod.rs index 7e985db0..1dc385df 100644 --- a/networks/bitcoin/src/wallet/mod.rs +++ b/networks/bitcoin/src/wallet/mod.rs @@ -39,9 +39,9 @@ pub use send::*; /// from being spent via a script. To have keys which have spendable script paths, further offsets /// from this position must be used. /// -/// After adding an unspendable script path, the key is incremented until its even. This means the -/// existence of the unspendable script path may not provable, without an understanding of the -/// algorithm used here. +/// After adding an unspendable script path, the key is negated if odd. +/// +/// This has a neligible probability of returning keys whose group key is the point at infinity. #[cfg(feature = "std")] pub fn tweak_keys(keys: ThresholdKeys) -> ThresholdKeys { // Adds the unspendable script path per diff --git a/networks/bitcoin/src/wallet/send.rs b/networks/bitcoin/src/wallet/send.rs index 276f536e..52824280 100644 --- a/networks/bitcoin/src/wallet/send.rs +++ b/networks/bitcoin/src/wallet/send.rs @@ -288,7 +288,7 @@ impl SignableTransaction { /// A FROST signing machine to produce a Bitcoin transaction. /// /// This does not support caching its preprocess. When sign is called, the message must be empty. -/// This will panic if either `cache` is called or the message isn't empty. +/// This will panic if either `cache`, `from_cache` is called or the message isn't empty. pub struct TransactionMachine { tx: SignableTransaction, sigs: Vec>,