Finally make modular-frost work with alloc alone

Carries the update to `frost-schnorrkel` and `bitcoin-serai`.
This commit is contained in:
Luke Parker
2025-09-15 23:16:11 -04:00
parent be68e27551
commit 19305aebc9
20 changed files with 280 additions and 204 deletions

8
Cargo.lock generated
View File

@@ -3546,11 +3546,11 @@ version = "0.2.0"
dependencies = [ dependencies = [
"ciphersuite 0.4.2", "ciphersuite 0.4.2",
"flexible-transcript", "flexible-transcript",
"group",
"modular-frost", "modular-frost",
"rand_core 0.6.4", "rand_core 0.6.4",
"schnorr-signatures", "schnorr-signatures",
"schnorrkel", "schnorrkel",
"std-shims",
"zeroize", "zeroize",
] ]
@@ -6098,6 +6098,7 @@ dependencies = [
"schnorr-signatures", "schnorr-signatures",
"serde_json", "serde_json",
"sha2 0.10.9", "sha2 0.10.9",
"std-shims",
"subtle", "subtle",
"thiserror 2.0.16", "thiserror 2.0.16",
"zeroize", "zeroize",
@@ -10235,10 +10236,15 @@ dependencies = [
"ciphersuite 0.4.2", "ciphersuite 0.4.2",
"dalek-ff-group 0.5.0", "dalek-ff-group 0.5.0",
"dkg", "dkg",
"dkg-dealer",
"dkg-evrf", "dkg-evrf",
"dkg-musig",
"dkg-recovery",
"embedwards25519", "embedwards25519",
"flexible-transcript", "flexible-transcript",
"frost-schnorrkel",
"minimal-ed448", "minimal-ed448",
"modular-frost",
"multiexp", "multiexp",
"prime-field", "prime-field",
"schnorr-signatures", "schnorr-signatures",

View File

@@ -17,33 +17,35 @@ rustdoc-args = ["--cfg", "docsrs"]
workspace = true workspace = true
[dependencies] [dependencies]
thiserror = { version = "2", default-features = false, features = ["std"] } std-shims = { version = "0.1", path = "../../common/std-shims", default-features = false, features = ["alloc"] }
rand_core = { version = "0.6", default-features = false, features = ["std"] } thiserror = { version = "2", default-features = false }
rand_chacha = { version = "0.3", default-features = false, features = ["std"] }
zeroize = { version = "^1.5", default-features = false, features = ["std", "zeroize_derive"] } rand_core = { version = "0.6", default-features = false, features = ["alloc"] }
subtle = { version = "^2.4", default-features = false, features = ["std"] } rand_chacha = { version = "0.3", default-features = false }
hex = { version = "0.4", default-features = false, features = ["std"], optional = true } zeroize = { version = "^1.5", default-features = false, features = ["alloc", "zeroize_derive"] }
subtle = { version = "^2.4", default-features = false }
transcript = { package = "flexible-transcript", path = "../transcript", version = "^0.3.2", default-features = false, features = ["std", "recommended"] } hex = { version = "0.4", default-features = false, features = ["alloc"], optional = true }
dalek-ff-group = { path = "../dalek-ff-group", version = "0.5", default-features = false, features = ["std"], optional = true } transcript = { package = "flexible-transcript", path = "../transcript", version = "^0.3.2", default-features = false, features = ["recommended"] }
minimal-ed448 = { path = "../ed448", version = "0.4", default-features = false, features = ["std"], optional = true }
ciphersuite = { path = "../ciphersuite", version = "^0.4.1", default-features = false, features = ["std"] } dalek-ff-group = { path = "../dalek-ff-group", version = "0.5", default-features = false, features = ["alloc"], optional = true }
minimal-ed448 = { path = "../ed448", version = "0.4", default-features = false, features = ["alloc"], optional = true }
ciphersuite = { path = "../ciphersuite", version = "^0.4.1", default-features = false, features = ["alloc"] }
sha2 = { version = "0.10.0", default-features = false, optional = true } sha2 = { version = "0.10.0", default-features = false, optional = true }
elliptic-curve = { version = "0.13", default-features = false, features = ["hash2curve"], optional = true } elliptic-curve = { version = "0.13", default-features = false, features = ["hash2curve"], optional = true }
ciphersuite-kp256 = { path = "../ciphersuite/kp256", version = "0.4", default-features = false, features = ["std"], optional = true } ciphersuite-kp256 = { path = "../ciphersuite/kp256", version = "0.4", default-features = false, features = ["alloc"], optional = true }
multiexp = { path = "../multiexp", version = "0.4", default-features = false, features = ["std", "batch"] } multiexp = { path = "../multiexp", version = "0.4", default-features = false, features = ["alloc", "batch"] }
schnorr = { package = "schnorr-signatures", path = "../schnorr", version = "^0.5.1", default-features = false, features = ["std"] } schnorr = { package = "schnorr-signatures", path = "../schnorr", version = "^0.5.1", default-features = false, features = ["alloc"] }
dkg = { path = "../dkg", version = "0.6.1", default-features = false, features = ["std"] } dkg = { path = "../dkg", version = "0.6.1", default-features = false }
dkg-recovery = { path = "../dkg/recovery", version = "0.6", default-features = false, features = ["std"], optional = true } dkg-recovery = { path = "../dkg/recovery", version = "0.6", default-features = false, optional = true }
dkg-dealer = { path = "../dkg/dealer", version = "0.6", default-features = false, features = ["std"], optional = true } dkg-dealer = { path = "../dkg/dealer", version = "0.6", default-features = false, optional = true }
[dev-dependencies] [dev-dependencies]
hex = "0.4" hex = "0.4"
@@ -54,6 +56,38 @@ dkg-recovery = { path = "../dkg/recovery", default-features = false, features =
dkg-dealer = { path = "../dkg/dealer", default-features = false, features = ["std"] } dkg-dealer = { path = "../dkg/dealer", default-features = false, features = ["std"] }
[features] [features]
std = [
"std-shims/std",
"thiserror/std",
"rand_core/std",
"rand_chacha/std",
"zeroize/std",
"subtle/std",
"hex?/std",
"transcript/std",
"dalek-ff-group?/std",
"minimal-ed448?/std",
"ciphersuite/std",
"sha2?/std",
"elliptic-curve?/std",
"ciphersuite-kp256?/std",
"multiexp/std",
"schnorr/std",
"dkg/std",
"dkg-recovery?/std",
"dkg-dealer?/std",
]
ed25519 = ["dalek-ff-group"] ed25519 = ["dalek-ff-group"]
ristretto = ["dalek-ff-group"] ristretto = ["dalek-ff-group"]
@@ -63,3 +97,5 @@ p256 = ["sha2", "elliptic-curve", "ciphersuite-kp256"]
ed448 = ["minimal-ed448"] ed448 = ["minimal-ed448"]
tests = ["hex", "rand_core/getrandom", "dkg-dealer", "dkg-recovery"] tests = ["hex", "rand_core/getrandom", "dkg-dealer", "dkg-recovery"]
default = ["std"]

View File

@@ -1,5 +1,7 @@
use core::{marker::PhantomData, fmt::Debug}; use core::{marker::PhantomData, fmt::Debug};
use std::io::{self, Read, Write}; #[allow(unused_imports)]
use std_shims::prelude::*;
use std_shims::io::{self, Read, Write};
use zeroize::Zeroizing; use zeroize::Zeroizing;
use rand_core::{RngCore, CryptoRng}; use rand_core::{RngCore, CryptoRng};

View File

@@ -1,5 +1,7 @@
use core::{ops::Deref, convert::AsRef}; use core::{ops::Deref, convert::AsRef};
use std::io::{self, Read}; #[allow(unused_imports)]
use std_shims::prelude::*;
use std_shims::io::{self, Read};
use rand_core::{RngCore, CryptoRng}; use rand_core::{RngCore, CryptoRng};

View File

@@ -1,8 +1,11 @@
#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
#![cfg_attr(not(feature = "std"), no_std)]
use core::fmt::Debug; use core::fmt::Debug;
use std::collections::HashMap; #[allow(unused_imports)]
use std_shims::prelude::*;
use std_shims::collections::HashMap;
use thiserror::Error; use thiserror::Error;

View File

@@ -6,7 +6,9 @@
// Each nonce remains of the form (d, e) and made into a proper nonce with d + (e * b) // Each nonce remains of the form (d, e) and made into a proper nonce with d + (e * b)
use core::ops::Deref; use core::ops::Deref;
use std::{ #[allow(unused_imports)]
use std_shims::prelude::*;
use std_shims::{
io::{self, Read, Write}, io::{self, Read, Write},
collections::HashMap, collections::HashMap,
}; };

View File

@@ -1,5 +1,7 @@
use core::{ops::Deref, fmt::Debug}; use core::{ops::Deref, fmt::Debug};
use std::{ #[allow(unused_imports)]
use std_shims::prelude::*;
use std_shims::{
io::{self, Read, Write}, io::{self, Read, Write},
collections::HashMap, collections::HashMap,
}; };

View File

@@ -1,4 +1,4 @@
use std::collections::HashMap; use std_shims::collections::HashMap;
use rand_core::{RngCore, CryptoRng}; use rand_core::{RngCore, CryptoRng};

View File

@@ -1,4 +1,4 @@
use std::io::{self, Read}; use std_shims::io::{self, Read};
use zeroize::Zeroizing; use zeroize::Zeroizing;

View File

@@ -1,8 +1,8 @@
use core::ops::Deref; use core::ops::Deref;
use std::collections::HashMap; use std_shims::collections::HashMap;
#[cfg(test)] #[cfg(test)]
use std::str::FromStr; use core::str::FromStr;
use zeroize::Zeroizing; use zeroize::Zeroizing;

View File

@@ -17,18 +17,35 @@ rustdoc-args = ["--cfg", "docsrs"]
workspace = true workspace = true
[dependencies] [dependencies]
rand_core = "0.6" std-shims = { version = "0.1", default-features = false, features = ["alloc"] }
zeroize = "^1.5"
transcript = { package = "flexible-transcript", path = "../transcript", version = "^0.3.2", features = ["merlin"] } rand_core = { version = "0.6", default-features = false }
zeroize = { version = "1.5", default-features = false, features = ["zeroize_derive", "alloc"] }
group = "0.13" transcript = { package = "flexible-transcript", path = "../transcript", version = "0.3.2", default-features = false, features = ["merlin"] }
ciphersuite = { path = "../ciphersuite", version = "^0.4.1", features = ["std"] } ciphersuite = { path = "../ciphersuite", version = "0.4.1", default-features = false, features = ["alloc"] }
schnorr = { package = "schnorr-signatures", path = "../schnorr", version = "^0.5.1" } schnorr = { package = "schnorr-signatures", path = "../schnorr", version = "0.5.1", default-features = false, features = ["alloc"] }
frost = { path = "../frost", package = "modular-frost", version = "0.11.0", features = ["ristretto"] } frost = { path = "../frost", package = "modular-frost", version = "0.11.0", default-features = false, features = ["ristretto"] }
schnorrkel = { version = "0.11" } schnorrkel = { version = "0.11", default-features = false, features = ["alloc"] }
[dev-dependencies] [dev-dependencies]
frost = { path = "../frost", package = "modular-frost", features = ["tests"] } frost = { path = "../frost", package = "modular-frost", features = ["tests"] }
[features]
std = [
"std-shims/std",
"rand_core/std",
"zeroize/std",
"transcript/std",
"ciphersuite/std",
"schnorr/std",
"frost/std",
"schnorrkel/std",
]
default = ["std"]

View File

@@ -1,7 +1,10 @@
#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
#![cfg_attr(not(feature = "std"), no_std)]
use std::io::{self, Read}; #[allow(unused_imports)]
use std_shims::prelude::*;
use std_shims::io::{self, Read};
use rand_core::{RngCore, CryptoRng}; use rand_core::{RngCore, CryptoRng};

View File

@@ -1,6 +1,6 @@
use rand_core::OsRng; use rand_core::OsRng;
use group::GroupEncoding; use ciphersuite::group::GroupEncoding;
use frost::{ use frost::{
Participant, Participant,
tests::{key_gen, algorithm_machines, sign}, tests::{key_gen, algorithm_machines, sign},

View File

@@ -27,7 +27,7 @@ rand_core = { version = "0.6", default-features = false }
bitcoin = { version = "0.32", default-features = false } bitcoin = { version = "0.32", default-features = false }
k256 = { version = "^0.13.1", default-features = false, features = ["arithmetic", "bits"] } k256 = { version = "^0.13.1", default-features = false, features = ["arithmetic", "bits"] }
frost = { package = "modular-frost", path = "../../crypto/frost", version = "0.11", default-features = false, features = ["secp256k1"], optional = true } frost = { package = "modular-frost", path = "../../crypto/frost", version = "0.11", default-features = false, features = ["secp256k1"] }
hex = { version = "0.4", default-features = false, optional = true } hex = { version = "0.4", default-features = false, optional = true }
serde = { version = "1", default-features = false, features = ["derive"], optional = true } serde = { version = "1", default-features = false, features = ["derive"], optional = true }
@@ -55,7 +55,7 @@ std = [
"bitcoin/serde", "bitcoin/serde",
"k256/std", "k256/std",
"frost", "frost/std",
"hex/std", "hex/std",
"serde/std", "serde/std",

View File

@@ -1,9 +1,27 @@
#[cfg(feature = "std")] use core::fmt::Debug;
#[allow(unused_imports)]
use std_shims::prelude::*;
use std_shims::io;
use subtle::{Choice, ConstantTimeEq, ConditionallySelectable}; use subtle::{Choice, ConstantTimeEq, ConditionallySelectable};
use zeroize::Zeroizing;
use rand_core::{RngCore, CryptoRng};
use k256::{elliptic_curve::sec1::ToEncodedPoint, ProjectivePoint}; use k256::{
elliptic_curve::{ops::Reduce, sec1::ToEncodedPoint},
U256, Scalar, ProjectivePoint,
};
use bitcoin::key::XOnlyPublicKey; use bitcoin::{
hashes::{HashEngine, Hash, sha256::Hash as Sha256},
key::XOnlyPublicKey,
};
use frost::{
curve::{WrappedGroup, Secp256k1},
Participant, ThresholdKeys, ThresholdView, FrostError,
algorithm::{Hram as HramTrait, Algorithm, IetfSchnorr as FrostSchnorr},
};
/// Get the x coordinate of a non-infinity point. /// Get the x coordinate of a non-infinity point.
/// ///
@@ -21,142 +39,118 @@ pub(crate) fn x_only(key: &ProjectivePoint) -> XOnlyPublicKey {
} }
/// Return if a point must be negated to have an even Y coordinate and be eligible for use. /// Return if a point must be negated to have an even Y coordinate and be eligible for use.
#[cfg(feature = "std")]
pub(crate) fn needs_negation(key: &ProjectivePoint) -> Choice { pub(crate) fn needs_negation(key: &ProjectivePoint) -> Choice {
use k256::elliptic_curve::sec1::Tag; use k256::elliptic_curve::sec1::Tag;
u8::from(key.to_encoded_point(true).tag()).ct_eq(&u8::from(Tag::CompressedOddY)) u8::from(key.to_encoded_point(true).tag()).ct_eq(&u8::from(Tag::CompressedOddY))
} }
#[cfg(feature = "std")] /// A BIP-340 compatible HRAm for use with the modular-frost Schnorr Algorithm.
mod frost_crypto { ///
use core::fmt::Debug; /// If passed an odd nonce, the challenge will be negated.
use std_shims::{vec::Vec, io}; ///
/// If either `R` or `A` is the point at infinity, this will panic.
#[derive(Clone, Copy, Debug)]
pub struct Hram;
#[allow(non_snake_case)]
impl HramTrait<Secp256k1> for Hram {
fn hram(R: &ProjectivePoint, A: &ProjectivePoint, m: &[u8]) -> Scalar {
const TAG_HASH: Sha256 = Sha256::const_hash(b"BIP0340/challenge");
use zeroize::Zeroizing; let mut data = Sha256::engine();
use rand_core::{RngCore, CryptoRng}; data.input(TAG_HASH.as_ref());
data.input(TAG_HASH.as_ref());
data.input(&x(R));
data.input(&x(A));
data.input(m);
use bitcoin::hashes::{HashEngine, Hash, sha256::Hash as Sha256}; let c = Scalar::reduce(U256::from_be_slice(Sha256::from_engine(data).as_ref()));
// If the nonce was odd, sign `r - cx` instead of `r + cx`, allowing us to negate `s` at the
use k256::{elliptic_curve::ops::Reduce, U256, Scalar}; // end to sign as `-r + cx`
<_>::conditional_select(&c, &-c, needs_negation(R))
use frost::{ }
curve::{WrappedGroup, Secp256k1}, }
Participant, ThresholdKeys, ThresholdView, FrostError,
algorithm::{Hram as HramTrait, Algorithm, IetfSchnorr as FrostSchnorr}, /// BIP-340 Schnorr signature algorithm.
}; ///
/// This may panic if called with nonces/a group key which are the point at infinity (which have
use super::*; /// a negligible probability for a well-reasoned caller, even with malicious participants
/// present).
/// A BIP-340 compatible HRAm for use with the modular-frost Schnorr Algorithm. ///
/// /// `verify`, `verify_share` MUST be called after `sign_share` is called. Otherwise, this library
/// If passed an odd nonce, the challenge will be negated. /// MAY panic.
/// #[derive(Clone)]
/// If either `R` or `A` is the point at infinity, this will panic. pub struct Schnorr(FrostSchnorr<Secp256k1, Hram>);
#[derive(Clone, Copy, Debug)] impl Schnorr {
pub struct Hram; /// Construct a Schnorr algorithm continuing the specified transcript.
#[allow(non_snake_case)] #[allow(clippy::new_without_default)]
impl HramTrait<Secp256k1> for Hram { pub fn new() -> Schnorr {
fn hram(R: &ProjectivePoint, A: &ProjectivePoint, m: &[u8]) -> Scalar { Schnorr(FrostSchnorr::ietf())
const TAG_HASH: Sha256 = Sha256::const_hash(b"BIP0340/challenge"); }
}
let mut data = Sha256::engine();
data.input(TAG_HASH.as_ref()); impl Algorithm<Secp256k1> for Schnorr {
data.input(TAG_HASH.as_ref()); type Transcript = <FrostSchnorr<Secp256k1, Hram> as Algorithm<Secp256k1>>::Transcript;
data.input(&x(R)); type Addendum = ();
data.input(&x(A)); type Signature = [u8; 64];
data.input(m);
fn transcript(&mut self) -> &mut Self::Transcript {
let c = Scalar::reduce(U256::from_be_slice(Sha256::from_engine(data).as_ref())); self.0.transcript()
// If the nonce was odd, sign `r - cx` instead of `r + cx`, allowing us to negate `s` at the }
// end to sign as `-r + cx`
<_>::conditional_select(&c, &-c, needs_negation(R)) fn nonces(&self) -> Vec<Vec<ProjectivePoint>> {
} self.0.nonces()
} }
/// BIP-340 Schnorr signature algorithm. fn preprocess_addendum<R: RngCore + CryptoRng>(
/// &mut self,
/// This may panic if called with nonces/a group key which are the point at infinity (which have rng: &mut R,
/// a negligible probability for a well-reasoned caller, even with malicious participants keys: &ThresholdKeys<Secp256k1>,
/// present). ) {
/// self.0.preprocess_addendum(rng, keys)
/// `verify`, `verify_share` MUST be called after `sign_share` is called. Otherwise, this library }
/// MAY panic.
#[derive(Clone)] fn read_addendum<R: io::Read>(&self, reader: &mut R) -> io::Result<Self::Addendum> {
pub struct Schnorr(FrostSchnorr<Secp256k1, Hram>); self.0.read_addendum(reader)
impl Schnorr { }
/// Construct a Schnorr algorithm continuing the specified transcript.
#[allow(clippy::new_without_default)] fn process_addendum(
pub fn new() -> Schnorr { &mut self,
Schnorr(FrostSchnorr::ietf()) view: &ThresholdView<Secp256k1>,
} i: Participant,
} addendum: (),
) -> Result<(), FrostError> {
impl Algorithm<Secp256k1> for Schnorr { self.0.process_addendum(view, i, addendum)
type Transcript = <FrostSchnorr<Secp256k1, Hram> as Algorithm<Secp256k1>>::Transcript; }
type Addendum = ();
type Signature = [u8; 64]; fn sign_share(
&mut self,
fn transcript(&mut self) -> &mut Self::Transcript { params: &ThresholdView<Secp256k1>,
self.0.transcript() nonce_sums: &[Vec<<Secp256k1 as WrappedGroup>::G>],
} nonces: Vec<Zeroizing<<Secp256k1 as WrappedGroup>::F>>,
msg: &[u8],
fn nonces(&self) -> Vec<Vec<ProjectivePoint>> { ) -> <Secp256k1 as WrappedGroup>::F {
self.0.nonces() self.0.sign_share(params, nonce_sums, nonces, msg)
} }
fn preprocess_addendum<R: RngCore + CryptoRng>( fn verify(
&mut self, &self,
rng: &mut R, group_key: ProjectivePoint,
keys: &ThresholdKeys<Secp256k1>, nonces: &[Vec<ProjectivePoint>],
) { sum: Scalar,
self.0.preprocess_addendum(rng, keys) ) -> Option<Self::Signature> {
} self.0.verify(group_key, nonces, sum).map(|mut sig| {
sig.s = <_>::conditional_select(&sum, &-sum, needs_negation(&sig.R));
fn read_addendum<R: io::Read>(&self, reader: &mut R) -> io::Result<Self::Addendum> { // Convert to a Bitcoin signature by dropping the byte for the point's sign bit
self.0.read_addendum(reader) sig.serialize()[1 ..].try_into().unwrap()
} })
}
fn process_addendum(
&mut self, fn verify_share(
view: &ThresholdView<Secp256k1>, &self,
i: Participant, verification_share: ProjectivePoint,
addendum: (), nonces: &[Vec<ProjectivePoint>],
) -> Result<(), FrostError> { share: Scalar,
self.0.process_addendum(view, i, addendum) ) -> Result<Vec<(Scalar, ProjectivePoint)>, ()> {
} self.0.verify_share(verification_share, nonces, share)
fn sign_share(
&mut self,
params: &ThresholdView<Secp256k1>,
nonce_sums: &[Vec<<Secp256k1 as WrappedGroup>::G>],
nonces: Vec<Zeroizing<<Secp256k1 as WrappedGroup>::F>>,
msg: &[u8],
) -> <Secp256k1 as WrappedGroup>::F {
self.0.sign_share(params, nonce_sums, nonces, msg)
}
fn verify(
&self,
group_key: ProjectivePoint,
nonces: &[Vec<ProjectivePoint>],
sum: Scalar,
) -> Option<Self::Signature> {
self.0.verify(group_key, nonces, sum).map(|mut sig| {
sig.s = <_>::conditional_select(&sum, &-sum, needs_negation(&sig.R));
// Convert to a Bitcoin signature by dropping the byte for the point's sign bit
sig.serialize()[1 ..].try_into().unwrap()
})
}
fn verify_share(
&self,
verification_share: ProjectivePoint,
nonces: &[Vec<ProjectivePoint>],
share: Scalar,
) -> Result<Vec<(Scalar, ProjectivePoint)>, ()> {
self.0.verify_share(verification_share, nonces, share)
}
} }
} }
#[cfg(feature = "std")]
pub use frost_crypto::*;

View File

@@ -2,9 +2,6 @@
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
#[cfg(not(feature = "std"))]
extern crate alloc;
/// The bitcoin Rust library. /// The bitcoin Rust library.
pub use bitcoin; pub use bitcoin;

View File

@@ -1,36 +1,31 @@
#[allow(unused_imports)]
use std_shims::prelude::*;
use std_shims::{ use std_shims::{
vec::Vec,
collections::HashMap, collections::HashMap,
io::{self, Write}, io::{self, Read, Write},
}; };
#[cfg(feature = "std")]
use std::io::{Read, BufReader};
use k256::{ use k256::{
elliptic_curve::sec1::{Tag, ToEncodedPoint}, elliptic_curve::sec1::{Tag, ToEncodedPoint},
Scalar, ProjectivePoint, Scalar, ProjectivePoint,
}; };
#[cfg(feature = "std")]
use frost::{ use frost::{
curve::{WrappedGroup, GroupIo, Secp256k1}, curve::{WrappedGroup, GroupIo, Secp256k1},
ThresholdKeys, ThresholdKeys,
}; };
use bitcoin::{ use bitcoin::{
consensus::encode::serialize, key::TweakedPublicKey, OutPoint, ScriptBuf, TxOut, Transaction, hashes::Hash,
Block, key::TweakedPublicKey,
TapTweakHash,
consensus::encode::{Decodable, serialize},
OutPoint, ScriptBuf, TxOut, Transaction, Block,
}; };
#[cfg(feature = "std")]
use bitcoin::{hashes::Hash, consensus::encode::Decodable, TapTweakHash};
use crate::crypto::x_only; use crate::crypto::{x_only, needs_negation};
#[cfg(feature = "std")]
use crate::crypto::needs_negation;
#[cfg(feature = "std")]
mod send; mod send;
#[cfg(feature = "std")]
pub use send::*; pub use send::*;
/// Tweak keys to ensure they're usable with Bitcoin's Taproot upgrade. /// Tweak keys to ensure they're usable with Bitcoin's Taproot upgrade.
@@ -42,7 +37,6 @@ pub use send::*;
/// After adding an unspendable script path, the key is negated if odd. /// 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. /// 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<Secp256k1>) -> ThresholdKeys<Secp256k1> { pub fn tweak_keys(keys: ThresholdKeys<Secp256k1>) -> ThresholdKeys<Secp256k1> {
// Adds the unspendable script path per // Adds the unspendable script path per
// https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-23 // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-23
@@ -118,18 +112,23 @@ impl ReceivedOutput {
} }
/// Read a ReceivedOutput from a generic satisfying Read. /// Read a ReceivedOutput from a generic satisfying Read.
#[cfg(feature = "std")]
pub fn read<R: Read>(r: &mut R) -> io::Result<ReceivedOutput> { pub fn read<R: Read>(r: &mut R) -> io::Result<ReceivedOutput> {
let offset = Secp256k1::read_F(r)?; let offset = Secp256k1::read_F(r)?;
let output;
let outpoint; struct BitcoinRead<R: Read>(R);
{ impl<R: Read> bitcoin::io::Read for BitcoinRead<R> {
let mut buf_r = BufReader::with_capacity(0, r); fn read(&mut self, buf: &mut [u8]) -> bitcoin::io::Result<usize> {
output = self
TxOut::consensus_decode(&mut buf_r).map_err(|_| io::Error::other("invalid TxOut"))?; .0
outpoint = .read(buf)
OutPoint::consensus_decode(&mut buf_r).map_err(|_| io::Error::other("invalid OutPoint"))?; .map_err(|e| bitcoin::io::Error::new(bitcoin::io::ErrorKind::Other, e.to_string()))
}
} }
let mut r = BitcoinRead(r);
let output = TxOut::consensus_decode(&mut r).map_err(|_| io::Error::other("invalid TxOut"))?;
let outpoint =
OutPoint::consensus_decode(&mut r).map_err(|_| io::Error::other("invalid OutPoint"))?;
Ok(ReceivedOutput { offset, output, outpoint }) Ok(ReceivedOutput { offset, output, outpoint })
} }

View File

@@ -1,3 +1,5 @@
#[allow(unused_imports)]
use std_shims::prelude::*;
use std_shims::{ use std_shims::{
io::{self, Read}, io::{self, Read},
collections::HashMap, collections::HashMap,

View File

@@ -36,9 +36,13 @@ secq256k1 = { path = "../../crypto/secq256k1", default-features = false }
embedwards25519 = { path = "../../crypto/embedwards25519", default-features = false } embedwards25519 = { path = "../../crypto/embedwards25519", default-features = false }
dkg = { path = "../../crypto/dkg", default-features = false, optional = true } dkg = { path = "../../crypto/dkg", default-features = false, optional = true }
dkg-dealer = { path = "../../crypto/dkg/dealer", default-features = false, optional = true }
dkg-recovery = { path = "../../crypto/dkg/recovery", default-features = false, optional = true }
dkg-musig = { path = "../../crypto/dkg/musig", default-features = false, optional = true }
dkg-evrf = { path = "../../crypto/dkg/evrf", default-features = false, features = ["secp256k1", "ed25519"], optional = true } dkg-evrf = { path = "../../crypto/dkg/evrf", default-features = false, features = ["secp256k1", "ed25519"], optional = true }
# modular-frost = { path = "../../crypto/frost", default-features = false }
# frost-schnorrkel = { path = "../../crypto/schnorrkel", default-features = false } modular-frost = { path = "../../crypto/frost", default-features = false, optional = true }
frost-schnorrkel = { path = "../../crypto/schnorrkel", default-features = false, optional = true }
bitcoin-serai = { path = "../../networks/bitcoin", default-features = false, features = ["hazmat"], optional = true } bitcoin-serai = { path = "../../networks/bitcoin", default-features = false, features = ["hazmat"], optional = true }
@@ -62,7 +66,13 @@ alloc = [
"embedwards25519/alloc", "embedwards25519/alloc",
"dkg", "dkg",
"dkg-dealer",
"dkg-recovery",
"dkg-musig",
"dkg-evrf", "dkg-evrf",
"modular-frost",
"frost-schnorrkel",
"bitcoin-serai", "bitcoin-serai",
] ]

View File

@@ -21,12 +21,13 @@ pub mod alloc {
pub use multiexp; pub use multiexp;
pub use dkg; pub use dkg;
pub use dkg_dealer;
pub use dkg_recovery;
pub use dkg_musig;
pub use dkg_evrf; pub use dkg_evrf;
pub use bitcoin_serai;
/*
pub use modular_frost; pub use modular_frost;
pub use frost_schnorrkel; pub use frost_schnorrkel;
*/
pub use bitcoin_serai;
} }