mirror of
https://github.com/serai-dex/serai.git
synced 2024-12-22 19:49:22 +00:00
Support no-std builds of bitcoin-serai
Arguably not meaningful, as it adds the scanner yet not the RPC, and no signing code since modular-frost doesn't support no-std yet. It's a step in the right direction though.
This commit is contained in:
parent
a52c86ad81
commit
76a30fd572
10 changed files with 238 additions and 164 deletions
5
.github/workflows/no-std.yml
vendored
5
.github/workflows/no-std.yml
vendored
|
@ -30,5 +30,8 @@ jobs:
|
|||
with:
|
||||
github-token: ${{ inputs.github-token }}
|
||||
|
||||
- name: Install RISC-V Toolchain
|
||||
run: sudo apt install -y gcc-riscv64-unknown-elf gcc-multilib
|
||||
|
||||
- name: Verify no-std builds
|
||||
run: cd tests/no-std && cargo build --target riscv32imac-unknown-none-elf
|
||||
run: cd tests/no-std && CFLAGS=-I/usr/include cargo build --target riscv32imac-unknown-none-elf
|
||||
|
|
24
Cargo.lock
generated
24
Cargo.lock
generated
|
@ -462,6 +462,7 @@ dependencies = [
|
|||
"bech32 0.9.1",
|
||||
"bitcoin-private",
|
||||
"bitcoin_hashes",
|
||||
"core2 0.3.3",
|
||||
"hex_lit",
|
||||
"secp256k1",
|
||||
"serde",
|
||||
|
@ -481,7 +482,6 @@ dependencies = [
|
|||
"flexible-transcript",
|
||||
"hex",
|
||||
"k256",
|
||||
"lazy_static",
|
||||
"modular-frost",
|
||||
"rand_core 0.6.4",
|
||||
"reqwest",
|
||||
|
@ -489,6 +489,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.7",
|
||||
"std-shims",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"zeroize",
|
||||
|
@ -501,6 +502,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501"
|
||||
dependencies = [
|
||||
"bitcoin-private",
|
||||
"core2 0.3.3",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
@ -884,7 +886,7 @@ version = "0.10.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd94671561e36e4e7de75f753f577edafb0e7c05d6e4547229fdf7938fbcd2c3"
|
||||
dependencies = [
|
||||
"core2",
|
||||
"core2 0.4.0",
|
||||
"multibase",
|
||||
"multihash 0.18.1",
|
||||
"serde",
|
||||
|
@ -1140,6 +1142,15 @@ version = "0.8.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||
|
||||
[[package]]
|
||||
name = "core2"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "239fa3ae9b63c2dc74bd3fa852d4792b8b305ae64eeede946265b6af62f1fff3"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core2"
|
||||
version = "0.4.0"
|
||||
|
@ -4800,7 +4811,7 @@ dependencies = [
|
|||
"blake2b_simd",
|
||||
"blake2s_simd",
|
||||
"blake3",
|
||||
"core2",
|
||||
"core2 0.4.0",
|
||||
"digest 0.10.7",
|
||||
"multihash-derive 0.8.0",
|
||||
"sha2 0.10.7",
|
||||
|
@ -4814,7 +4825,7 @@ version = "0.19.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd59dcc2bbe70baabeac52cd22ae52c55eefe6c38ff11a9439f16a350a939f2"
|
||||
dependencies = [
|
||||
"core2",
|
||||
"core2 0.4.0",
|
||||
"unsigned-varint",
|
||||
]
|
||||
|
||||
|
@ -4827,7 +4838,7 @@ dependencies = [
|
|||
"blake2b_simd",
|
||||
"blake2s_simd",
|
||||
"blake3",
|
||||
"core2",
|
||||
"core2 0.4.0",
|
||||
"digest 0.10.7",
|
||||
"multihash-derive 0.9.0",
|
||||
"ripemd",
|
||||
|
@ -4857,7 +4868,7 @@ version = "0.9.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "890e72cb7396cb99ed98c1246a97b243cc16394470d94e0bc8b0c2c11d84290e"
|
||||
dependencies = [
|
||||
"core2",
|
||||
"core2 0.4.0",
|
||||
"multihash 0.19.0",
|
||||
"multihash-derive-impl",
|
||||
]
|
||||
|
@ -8100,6 +8111,7 @@ dependencies = [
|
|||
name = "serai-no-std-tests"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitcoin-serai",
|
||||
"ciphersuite",
|
||||
"dalek-ff-group",
|
||||
"dkg",
|
||||
|
|
|
@ -8,25 +8,27 @@ authors = ["Luke Parker <lukeparker5132@gmail.com>", "Vrx <vrx00@proton.me>"]
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
lazy_static = "1"
|
||||
thiserror = "1"
|
||||
std-shims = { version = "0.1.1", path = "../../common/std-shims", default-features = false }
|
||||
|
||||
zeroize = "^1.5"
|
||||
rand_core = "0.6"
|
||||
thiserror = { version = "1", optional = true }
|
||||
|
||||
sha2 = "0.10"
|
||||
zeroize = { version = "^1.5", default-features = false }
|
||||
rand_core = { version = "0.6", default-features = false }
|
||||
|
||||
secp256k1 = { version = "0.27", features = ["global-context"] }
|
||||
bitcoin = { version = "0.30", features = ["serde"] }
|
||||
sha2 = { version = "0.10", default-features = false }
|
||||
|
||||
k256 = { version = "^0.13.1", default-features = false, features = ["std", "arithmetic", "bits"] }
|
||||
transcript = { package = "flexible-transcript", path = "../../crypto/transcript", version = "0.3", features = ["recommended"] }
|
||||
frost = { package = "modular-frost", path = "../../crypto/frost", version = "0.8", features = ["secp256k1"] }
|
||||
secp256k1 = { version = "0.27", default-features = false }
|
||||
bitcoin = { version = "0.30", default-features = false, features = ["no-std"] }
|
||||
|
||||
hex = "0.4"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
k256 = { version = "^0.13.1", default-features = false, features = ["arithmetic", "bits"] }
|
||||
|
||||
transcript = { package = "flexible-transcript", path = "../../crypto/transcript", version = "0.3", features = ["recommended"], optional = true }
|
||||
frost = { package = "modular-frost", path = "../../crypto/frost", version = "0.8", features = ["secp256k1"], optional = true }
|
||||
|
||||
hex = { version = "0.4", optional = true }
|
||||
serde = { version = "1", features = ["derive"], optional = true }
|
||||
serde_json = { version = "1", optional = true }
|
||||
reqwest = { version = "0.11", features = ["json"], optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
frost = { package = "modular-frost", path = "../../crypto/frost", features = ["tests"] }
|
||||
|
@ -34,4 +36,29 @@ frost = { package = "modular-frost", path = "../../crypto/frost", features = ["t
|
|||
tokio = { version = "1", features = ["full"] }
|
||||
|
||||
[features]
|
||||
std = [
|
||||
"std-shims/std",
|
||||
|
||||
"thiserror",
|
||||
|
||||
"zeroize/std",
|
||||
"rand_core/std",
|
||||
|
||||
"sha2/std",
|
||||
|
||||
"secp256k1/std",
|
||||
"bitcoin/std",
|
||||
"bitcoin/serde",
|
||||
|
||||
"k256/std",
|
||||
|
||||
"transcript",
|
||||
"frost",
|
||||
|
||||
"hex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"reqwest"
|
||||
]
|
||||
hazmat = []
|
||||
default = ["std"]
|
||||
|
|
|
@ -1,26 +1,6 @@
|
|||
use core::fmt::Debug;
|
||||
use std::io;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use zeroize::Zeroizing;
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
use sha2::{Digest, Sha256};
|
||||
use transcript::Transcript;
|
||||
|
||||
use secp256k1::schnorr::Signature;
|
||||
use k256::{
|
||||
elliptic_curve::{
|
||||
ops::Reduce,
|
||||
sec1::{Tag, ToEncodedPoint},
|
||||
},
|
||||
U256, Scalar, ProjectivePoint,
|
||||
};
|
||||
use frost::{
|
||||
curve::{Ciphersuite, Secp256k1},
|
||||
Participant, ThresholdKeys, ThresholdView, FrostError,
|
||||
algorithm::{Hram as HramTrait, Algorithm, Schnorr as FrostSchnorr},
|
||||
elliptic_curve::sec1::{Tag, ToEncodedPoint},
|
||||
ProjectivePoint,
|
||||
};
|
||||
|
||||
use bitcoin::key::XOnlyPublicKey;
|
||||
|
@ -40,6 +20,7 @@ pub fn x_only(key: &ProjectivePoint) -> XOnlyPublicKey {
|
|||
/// Make a point even by adding the generator until it is even.
|
||||
///
|
||||
/// Returns the even point and the amount of additions required.
|
||||
#[cfg(any(feature = "std", feature = "hazmat"))]
|
||||
pub fn make_even(mut key: ProjectivePoint) -> (ProjectivePoint, u64) {
|
||||
let mut c = 0;
|
||||
while key.to_encoded_point(true).tag() == Tag::CompressedOddY {
|
||||
|
@ -49,116 +30,143 @@ pub fn make_even(mut key: ProjectivePoint) -> (ProjectivePoint, u64) {
|
|||
(key, c)
|
||||
}
|
||||
|
||||
/// 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 the key is odd, this will panic.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Hram;
|
||||
#[cfg(feature = "std")]
|
||||
mod frost_crypto {
|
||||
use core::fmt::Debug;
|
||||
use std_shims::{sync::OnceLock, vec::Vec, io};
|
||||
|
||||
lazy_static! {
|
||||
static ref TAG_HASH: [u8; 32] = Sha256::digest(b"BIP0340/challenge").into();
|
||||
}
|
||||
use zeroize::Zeroizing;
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
impl HramTrait<Secp256k1> for Hram {
|
||||
fn hram(R: &ProjectivePoint, A: &ProjectivePoint, m: &[u8]) -> Scalar {
|
||||
// Convert the nonce to be even
|
||||
let (R, _) = make_even(*R);
|
||||
use sha2::{Digest, Sha256};
|
||||
use transcript::Transcript;
|
||||
|
||||
let mut data = Sha256::new();
|
||||
data.update(*TAG_HASH);
|
||||
data.update(*TAG_HASH);
|
||||
data.update(x(&R));
|
||||
data.update(x(A));
|
||||
data.update(m);
|
||||
use secp256k1::schnorr::Signature;
|
||||
use k256::{elliptic_curve::ops::Reduce, U256, Scalar};
|
||||
|
||||
Scalar::reduce(U256::from_be_slice(&data.finalize()))
|
||||
}
|
||||
}
|
||||
|
||||
/// BIP-340 Schnorr signature algorithm.
|
||||
///
|
||||
/// This must be used with a ThresholdKeys whose group key is even. If it is odd, this will panic.
|
||||
#[derive(Clone)]
|
||||
pub struct Schnorr<T: Sync + Clone + Debug + Transcript>(FrostSchnorr<Secp256k1, T, Hram>);
|
||||
impl<T: Sync + Clone + Debug + Transcript> Schnorr<T> {
|
||||
/// Construct a Schnorr algorithm continuing the specified transcript.
|
||||
pub fn new(transcript: T) -> Schnorr<T> {
|
||||
Schnorr(FrostSchnorr::new(transcript))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Sync + Clone + Debug + Transcript> Algorithm<Secp256k1> for Schnorr<T> {
|
||||
type Transcript = T;
|
||||
type Addendum = ();
|
||||
type Signature = Signature;
|
||||
|
||||
fn transcript(&mut self) -> &mut Self::Transcript {
|
||||
self.0.transcript()
|
||||
}
|
||||
|
||||
fn nonces(&self) -> Vec<Vec<ProjectivePoint>> {
|
||||
self.0.nonces()
|
||||
}
|
||||
|
||||
fn preprocess_addendum<R: RngCore + CryptoRng>(
|
||||
&mut self,
|
||||
rng: &mut R,
|
||||
keys: &ThresholdKeys<Secp256k1>,
|
||||
) {
|
||||
self.0.preprocess_addendum(rng, keys)
|
||||
}
|
||||
|
||||
fn read_addendum<R: io::Read>(&self, reader: &mut R) -> io::Result<Self::Addendum> {
|
||||
self.0.read_addendum(reader)
|
||||
}
|
||||
|
||||
fn process_addendum(
|
||||
&mut self,
|
||||
view: &ThresholdView<Secp256k1>,
|
||||
i: Participant,
|
||||
addendum: (),
|
||||
) -> Result<(), FrostError> {
|
||||
self.0.process_addendum(view, i, addendum)
|
||||
}
|
||||
|
||||
fn sign_share(
|
||||
&mut self,
|
||||
params: &ThresholdView<Secp256k1>,
|
||||
nonce_sums: &[Vec<<Secp256k1 as Ciphersuite>::G>],
|
||||
nonces: Vec<Zeroizing<<Secp256k1 as Ciphersuite>::F>>,
|
||||
msg: &[u8],
|
||||
) -> <Secp256k1 as Ciphersuite>::F {
|
||||
self.0.sign_share(params, nonce_sums, nonces, msg)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn verify(
|
||||
&self,
|
||||
group_key: ProjectivePoint,
|
||||
nonces: &[Vec<ProjectivePoint>],
|
||||
sum: Scalar,
|
||||
) -> Option<Self::Signature> {
|
||||
self.0.verify(group_key, nonces, sum).map(|mut sig| {
|
||||
// Make the R of the final signature even
|
||||
let offset;
|
||||
(sig.R, offset) = make_even(sig.R);
|
||||
// s = r + cx. Since we added to the r, add to s
|
||||
sig.s += Scalar::from(offset);
|
||||
// Convert to a secp256k1 signature
|
||||
Signature::from_slice(&sig.serialize()[1 ..])
|
||||
.expect("couldn't convert SchnorrSignature to Signature")
|
||||
})
|
||||
}
|
||||
|
||||
fn verify_share(
|
||||
&self,
|
||||
verification_share: ProjectivePoint,
|
||||
nonces: &[Vec<ProjectivePoint>],
|
||||
share: Scalar,
|
||||
) -> Result<Vec<(Scalar, ProjectivePoint)>, ()> {
|
||||
self.0.verify_share(verification_share, nonces, share)
|
||||
use frost::{
|
||||
curve::{Ciphersuite, Secp256k1},
|
||||
Participant, ThresholdKeys, ThresholdView, FrostError,
|
||||
algorithm::{Hram as HramTrait, Algorithm, Schnorr as FrostSchnorr},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
/// 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 the key is odd, this will panic.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Hram;
|
||||
|
||||
static TAG_HASH_CELL: OnceLock<[u8; 32]> = OnceLock::new();
|
||||
#[allow(non_snake_case)]
|
||||
fn TAG_HASH() -> [u8; 32] {
|
||||
*TAG_HASH_CELL.get_or_init(|| Sha256::digest(b"BIP0340/challenge").into())
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
impl HramTrait<Secp256k1> for Hram {
|
||||
fn hram(R: &ProjectivePoint, A: &ProjectivePoint, m: &[u8]) -> Scalar {
|
||||
// Convert the nonce to be even
|
||||
let (R, _) = make_even(*R);
|
||||
|
||||
let mut data = Sha256::new();
|
||||
data.update(TAG_HASH());
|
||||
data.update(TAG_HASH());
|
||||
data.update(x(&R));
|
||||
data.update(x(A));
|
||||
data.update(m);
|
||||
|
||||
Scalar::reduce(U256::from_be_slice(&data.finalize()))
|
||||
}
|
||||
}
|
||||
|
||||
/// BIP-340 Schnorr signature algorithm.
|
||||
///
|
||||
/// This must be used with a ThresholdKeys whose group key is even. If it is odd, this will panic.
|
||||
#[derive(Clone)]
|
||||
pub struct Schnorr<T: Sync + Clone + Debug + Transcript>(FrostSchnorr<Secp256k1, T, Hram>);
|
||||
impl<T: Sync + Clone + Debug + Transcript> Schnorr<T> {
|
||||
/// Construct a Schnorr algorithm continuing the specified transcript.
|
||||
pub fn new(transcript: T) -> Schnorr<T> {
|
||||
Schnorr(FrostSchnorr::new(transcript))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Sync + Clone + Debug + Transcript> Algorithm<Secp256k1> for Schnorr<T> {
|
||||
type Transcript = T;
|
||||
type Addendum = ();
|
||||
type Signature = Signature;
|
||||
|
||||
fn transcript(&mut self) -> &mut Self::Transcript {
|
||||
self.0.transcript()
|
||||
}
|
||||
|
||||
fn nonces(&self) -> Vec<Vec<ProjectivePoint>> {
|
||||
self.0.nonces()
|
||||
}
|
||||
|
||||
fn preprocess_addendum<R: RngCore + CryptoRng>(
|
||||
&mut self,
|
||||
rng: &mut R,
|
||||
keys: &ThresholdKeys<Secp256k1>,
|
||||
) {
|
||||
self.0.preprocess_addendum(rng, keys)
|
||||
}
|
||||
|
||||
fn read_addendum<R: io::Read>(&self, reader: &mut R) -> io::Result<Self::Addendum> {
|
||||
self.0.read_addendum(reader)
|
||||
}
|
||||
|
||||
fn process_addendum(
|
||||
&mut self,
|
||||
view: &ThresholdView<Secp256k1>,
|
||||
i: Participant,
|
||||
addendum: (),
|
||||
) -> Result<(), FrostError> {
|
||||
self.0.process_addendum(view, i, addendum)
|
||||
}
|
||||
|
||||
fn sign_share(
|
||||
&mut self,
|
||||
params: &ThresholdView<Secp256k1>,
|
||||
nonce_sums: &[Vec<<Secp256k1 as Ciphersuite>::G>],
|
||||
nonces: Vec<Zeroizing<<Secp256k1 as Ciphersuite>::F>>,
|
||||
msg: &[u8],
|
||||
) -> <Secp256k1 as Ciphersuite>::F {
|
||||
self.0.sign_share(params, nonce_sums, nonces, msg)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn verify(
|
||||
&self,
|
||||
group_key: ProjectivePoint,
|
||||
nonces: &[Vec<ProjectivePoint>],
|
||||
sum: Scalar,
|
||||
) -> Option<Self::Signature> {
|
||||
self.0.verify(group_key, nonces, sum).map(|mut sig| {
|
||||
// Make the R of the final signature even
|
||||
let offset;
|
||||
(sig.R, offset) = make_even(sig.R);
|
||||
// s = r + cx. Since we added to the r, add to s
|
||||
sig.s += Scalar::from(offset);
|
||||
// Convert to a secp256k1 signature
|
||||
Signature::from_slice(&sig.serialize()[1 ..])
|
||||
.expect("couldn't convert SchnorrSignature to Signature")
|
||||
})
|
||||
}
|
||||
|
||||
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::*;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
extern crate alloc;
|
||||
|
||||
/// The bitcoin Rust library.
|
||||
pub use bitcoin;
|
||||
|
@ -13,6 +17,7 @@ pub(crate) mod crypto;
|
|||
/// Wallet functionality to create transactions.
|
||||
pub mod wallet;
|
||||
/// A minimal asynchronous Bitcoin RPC client.
|
||||
#[cfg(feature = "std")]
|
||||
pub mod rpc;
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -2,7 +2,7 @@ use rand_core::OsRng;
|
|||
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
use secp256k1::{SECP256K1, Message};
|
||||
use secp256k1::{Secp256k1 as BContext, Message};
|
||||
|
||||
use k256::Scalar;
|
||||
use transcript::{Transcript, RecommendedTranscript};
|
||||
|
@ -37,7 +37,7 @@ fn test_algorithm() {
|
|||
&Sha256::digest(MESSAGE),
|
||||
);
|
||||
|
||||
SECP256K1
|
||||
BContext::new()
|
||||
.verify_schnorr(
|
||||
&sig,
|
||||
&Message::from(Hash::hash(MESSAGE)),
|
||||
|
|
|
@ -1,33 +1,45 @@
|
|||
use std::{
|
||||
io::{self, Read, Write},
|
||||
use std_shims::{
|
||||
vec::Vec,
|
||||
collections::HashMap,
|
||||
io::{self, Write},
|
||||
};
|
||||
#[cfg(feature = "std")]
|
||||
use std_shims::io::Read;
|
||||
|
||||
use k256::{
|
||||
elliptic_curve::sec1::{Tag, ToEncodedPoint},
|
||||
Scalar, ProjectivePoint,
|
||||
};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use frost::{
|
||||
curve::{Ciphersuite, Secp256k1},
|
||||
ThresholdKeys,
|
||||
};
|
||||
|
||||
use bitcoin::{
|
||||
consensus::encode::{Decodable, serialize},
|
||||
consensus::encode::serialize,
|
||||
key::TweakedPublicKey,
|
||||
address::Payload,
|
||||
OutPoint, ScriptBuf, TxOut, Transaction, Block,
|
||||
};
|
||||
#[cfg(feature = "std")]
|
||||
use bitcoin::consensus::encode::Decodable;
|
||||
|
||||
use crate::crypto::{x_only, make_even};
|
||||
use crate::crypto::x_only;
|
||||
#[cfg(feature = "std")]
|
||||
use crate::crypto::make_even;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod send;
|
||||
#[cfg(feature = "std")]
|
||||
pub use send::*;
|
||||
|
||||
/// Tweak keys to ensure they're usable with Bitcoin.
|
||||
///
|
||||
/// Taproot keys, which these keys are used as, must be even. This offsets the keys until they're
|
||||
/// even.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn tweak_keys(keys: &ThresholdKeys<Secp256k1>) -> ThresholdKeys<Secp256k1> {
|
||||
let (_, offset) = make_even(keys.group_key());
|
||||
keys.offset(Scalar::from(offset))
|
||||
|
@ -72,6 +84,7 @@ impl ReceivedOutput {
|
|||
}
|
||||
|
||||
/// Read a ReceivedOutput from a generic satisfying Read.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn read<R: Read>(r: &mut R) -> io::Result<ReceivedOutput> {
|
||||
Ok(ReceivedOutput {
|
||||
offset: Secp256k1::read_F(r)?,
|
||||
|
@ -89,9 +102,9 @@ impl ReceivedOutput {
|
|||
w.write_all(&serialize(&self.outpoint))
|
||||
}
|
||||
|
||||
/// Serialize a ReceivedOutput to a Vec<u8>.
|
||||
/// Serialize a ReceivedOutput to a `Vec<u8>`.
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
let mut res = vec![];
|
||||
let mut res = Vec::new();
|
||||
self.write(&mut res).unwrap();
|
||||
res
|
||||
}
|
||||
|
@ -143,7 +156,7 @@ impl Scanner {
|
|||
|
||||
/// Scan a transaction.
|
||||
pub fn scan_transaction(&self, tx: &Transaction) -> Vec<ReceivedOutput> {
|
||||
let mut res = vec![];
|
||||
let mut res = Vec::new();
|
||||
for (vout, output) in tx.output.iter().enumerate() {
|
||||
// If the vout index exceeds 2**32, stop scanning outputs
|
||||
let Ok(vout) = u32::try_from(vout) else { break };
|
||||
|
@ -165,7 +178,7 @@ impl Scanner {
|
|||
/// must be immediately spendable, a post-processing pass is needed to remove those outputs.
|
||||
/// Alternatively, scan_transaction can be called on `block.txdata[1 ..]`.
|
||||
pub fn scan_block(&self, block: &Block) -> Vec<ReceivedOutput> {
|
||||
let mut res = vec![];
|
||||
let mut res = Vec::new();
|
||||
for tx in &block.txdata {
|
||||
res.extend(self.scan_transaction(tx));
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{
|
||||
use std_shims::{
|
||||
io::{self, Read},
|
||||
collections::HashMap,
|
||||
};
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
use std::sync::OnceLock;
|
||||
|
||||
use bitcoin_serai::rpc::Rpc;
|
||||
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref SEQUENTIAL: Mutex<()> = Mutex::new(());
|
||||
static SEQUENTIAL_CELL: OnceLock<Mutex<()>> = OnceLock::new();
|
||||
#[allow(non_snake_case)]
|
||||
pub fn SEQUENTIAL() -> &'static Mutex<()> {
|
||||
SEQUENTIAL_CELL.get_or_init(|| Mutex::new(()))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
@ -30,7 +34,7 @@ macro_rules! async_sequential {
|
|||
$(
|
||||
#[tokio::test]
|
||||
async fn $name() {
|
||||
let guard = runner::SEQUENTIAL.lock().await;
|
||||
let guard = runner::SEQUENTIAL().lock().await;
|
||||
let local = tokio::task::LocalSet::new();
|
||||
local.run_until(async move {
|
||||
if let Err(err) = tokio::task::spawn_local(async move { $body }).await {
|
||||
|
|
|
@ -30,5 +30,7 @@ dkg = { path = "../../crypto/dkg", default-features = false }
|
|||
# modular-frost = { path = "../../crypto/frost", default-features = false }
|
||||
# frost-schnorrkel = { path = "../../crypto/schnorrkel", default-features = false }
|
||||
|
||||
bitcoin-serai = { path = "../../coins/bitcoin", default-features = false, features = ["hazmat"] }
|
||||
|
||||
monero-generators = { path = "../../coins/monero/generators", default-features = false }
|
||||
monero-serai = { path = "../../coins/monero", default-features = false }
|
||||
|
|
Loading…
Reference in a new issue