Rust 1.80

Preserves the fn accessors within the Monero crates so that we can use statics
in some cfgs yet not all (in order to provide support for more low-memory
devices) with the exception of `H` (which truly should be cached).
This commit is contained in:
Luke Parker
2024-07-26 19:20:04 -04:00
parent 6f34c2ff77
commit 880565cb81
38 changed files with 147 additions and 195 deletions

View File

@@ -17,7 +17,7 @@ rustdoc-args = ["--cfg", "docsrs"]
workspace = true workspace = true
[dependencies] [dependencies]
spin = { version = "0.9", default-features = false, features = ["use_ticket_mutex", "once"] } spin = { version = "0.9", default-features = false, features = ["use_ticket_mutex", "lazy"] }
hashbrown = { version = "0.14", default-features = false, features = ["ahash", "inline-more"] } hashbrown = { version = "0.14", default-features = false, features = ["ahash", "inline-more"] }
[features] [features]

View File

@@ -26,27 +26,6 @@ mod mutex_shim {
pub use mutex_shim::{ShimMutex as Mutex, MutexGuard}; pub use mutex_shim::{ShimMutex as Mutex, MutexGuard};
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std::sync::OnceLock; pub use std::sync::LazyLock;
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
mod oncelock_shim { pub use spin::Lazy as LazyLock;
use spin::Once;
pub struct OnceLock<T>(Once<T>);
impl<T> OnceLock<T> {
pub const fn new() -> OnceLock<T> {
OnceLock(Once::new())
}
pub fn get(&self) -> Option<&T> {
self.0.poll()
}
pub fn get_mut(&mut self) -> Option<&mut T> {
self.0.get_mut()
}
pub fn get_or_init<F: FnOnce() -> T>(&self, f: F) -> &T {
self.0.call_once(f)
}
}
}
#[cfg(not(feature = "std"))]
pub use oncelock_shim::*;

View File

@@ -6,7 +6,7 @@ license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/bitcoin" repository = "https://github.com/serai-dex/serai/tree/develop/networks/bitcoin"
authors = ["Luke Parker <lukeparker5132@gmail.com>", "Vrx <vrx00@proton.me>"] authors = ["Luke Parker <lukeparker5132@gmail.com>", "Vrx <vrx00@proton.me>"]
edition = "2021" edition = "2021"
rust-version = "1.79" rust-version = "1.80"
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@@ -1,14 +1,11 @@
use std::sync::OnceLock; use std::sync::LazyLock;
use bitcoin_serai::rpc::Rpc; use bitcoin_serai::rpc::Rpc;
use tokio::sync::Mutex; use tokio::sync::Mutex;
static SEQUENTIAL_CELL: OnceLock<Mutex<()>> = OnceLock::new(); #[allow(dead_code)]
#[allow(non_snake_case)] pub(crate) static SEQUENTIAL: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
pub fn SEQUENTIAL() -> &'static Mutex<()> {
SEQUENTIAL_CELL.get_or_init(|| Mutex::new(()))
}
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) async fn rpc() -> Rpc { pub(crate) async fn rpc() -> Rpc {
@@ -34,7 +31,7 @@ macro_rules! async_sequential {
$( $(
#[tokio::test] #[tokio::test]
async fn $name() { async fn $name() {
let guard = runner::SEQUENTIAL().lock().await; let guard = runner::SEQUENTIAL.lock().await;
let local = tokio::task::LocalSet::new(); let local = tokio::task::LocalSet::new();
local.run_until(async move { local.run_until(async move {
if let Err(err) = tokio::task::spawn_local(async move { $body }).await { if let Err(err) = tokio::task::spawn_local(async move { $body }).await {

View File

@@ -6,7 +6,7 @@ license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero" repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero"
authors = ["Luke Parker <lukeparker5132@gmail.com>"] authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021" edition = "2021"
rust-version = "1.79" rust-version = "1.80"
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@@ -3,7 +3,7 @@
#![deny(missing_docs)] #![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
use std_shims::{sync::OnceLock, vec::Vec}; use std_shims::{sync::LazyLock, vec::Vec};
use sha3::{Digest, Keccak256}; use sha3::{Digest, Keccak256};
@@ -21,33 +21,30 @@ fn keccak256(data: &[u8]) -> [u8; 32] {
Keccak256::digest(data).into() Keccak256::digest(data).into()
} }
static H_CELL: OnceLock<EdwardsPoint> = OnceLock::new();
/// Monero's `H` generator. /// Monero's `H` generator.
/// ///
/// Contrary to convention (`G` for values, `H` for randomness), `H` is used by Monero for amounts /// Contrary to convention (`G` for values, `H` for randomness), `H` is used by Monero for amounts
/// within Pedersen commitments. /// within Pedersen commitments.
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn H() -> EdwardsPoint { pub static H: LazyLock<EdwardsPoint> = LazyLock::new(|| {
*H_CELL.get_or_init(|| { decompress_point(keccak256(&ED25519_BASEPOINT_POINT.compress().to_bytes()))
decompress_point(keccak256(&ED25519_BASEPOINT_POINT.compress().to_bytes())) .unwrap()
.unwrap() .mul_by_cofactor()
.mul_by_cofactor() });
})
}
static H_POW_2_CELL: OnceLock<[EdwardsPoint; 64]> = OnceLock::new(); static H_POW_2_CELL: LazyLock<[EdwardsPoint; 64]> = LazyLock::new(|| {
let mut res = [*H; 64];
for i in 1 .. 64 {
res[i] = res[i - 1] + res[i - 1];
}
res
});
/// Monero's `H` generator, multiplied by 2**i for i in 1 ..= 64. /// Monero's `H` generator, multiplied by 2**i for i in 1 ..= 64.
/// ///
/// This table is useful when working with amounts, which are u64s. /// This table is useful when working with amounts, which are u64s.
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn H_pow_2() -> &'static [EdwardsPoint; 64] { pub fn H_pow_2() -> &'static [EdwardsPoint; 64] {
H_POW_2_CELL.get_or_init(|| { &H_POW_2_CELL
let mut res = [H(); 64];
for i in 1 .. 64 {
res[i] = res[i - 1] + res[i - 1];
}
res
})
} }
/// The maximum amount of commitments provable for within a single range proof. /// The maximum amount of commitments provable for within a single range proof.
@@ -74,7 +71,7 @@ pub fn bulletproofs_generators(dst: &'static [u8]) -> Generators {
// The maximum amount of bits used within a single range proof. // The maximum amount of bits used within a single range proof.
const MAX_MN: usize = MAX_COMMITMENTS * COMMITMENT_BITS; const MAX_MN: usize = MAX_COMMITMENTS * COMMITMENT_BITS;
let mut preimage = H().compress().to_bytes().to_vec(); let mut preimage = H.compress().to_bytes().to_vec();
preimage.extend(dst); preimage.extend(dst);
let mut res = Generators { G: Vec::with_capacity(MAX_MN), H: Vec::with_capacity(MAX_MN) }; let mut res = Generators { G: Vec::with_capacity(MAX_MN), H: Vec::with_capacity(MAX_MN) };

View File

@@ -6,6 +6,7 @@ license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/io" repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/io"
authors = ["Luke Parker <lukeparker5132@gmail.com>"] authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021" edition = "2021"
rust-version = "1.80"
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@@ -6,7 +6,7 @@ license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/primitives" repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/primitives"
authors = ["Luke Parker <lukeparker5132@gmail.com>"] authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021" edition = "2021"
rust-version = "1.79" rust-version = "1.80"
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@@ -5,7 +5,7 @@
use std_shims::{io, vec::Vec}; use std_shims::{io, vec::Vec};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std_shims::sync::OnceLock; use std_shims::sync::LazyLock;
use zeroize::{Zeroize, ZeroizeOnDrop}; use zeroize::{Zeroize, ZeroizeOnDrop};
@@ -28,15 +28,15 @@ mod tests;
// On std, we cache some variables in statics. // On std, we cache some variables in statics.
#[cfg(feature = "std")] #[cfg(feature = "std")]
static INV_EIGHT_CELL: OnceLock<Scalar> = OnceLock::new(); static INV_EIGHT_CELL: LazyLock<Scalar> = LazyLock::new(|| Scalar::from(8u8).invert());
/// The inverse of 8 over l. /// The inverse of 8 over l, the prime factor of the order of Ed25519.
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn INV_EIGHT() -> Scalar { pub fn INV_EIGHT() -> Scalar {
*INV_EIGHT_CELL.get_or_init(|| Scalar::from(8u8).invert()) *INV_EIGHT_CELL
} }
// In no-std environments, we prefer the reduced memory use and calculate it ad-hoc. // In no-std environments, we prefer the reduced memory use and calculate it ad-hoc.
/// The inverse of 8 over l. /// The inverse of 8 over l, the prime factor of the order of Ed25519.
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn INV_EIGHT() -> Scalar { pub fn INV_EIGHT() -> Scalar {
@@ -44,12 +44,13 @@ pub fn INV_EIGHT() -> Scalar {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
static G_PRECOMP_CELL: OnceLock<VartimeEdwardsPrecomputation> = OnceLock::new(); static G_PRECOMP_CELL: LazyLock<VartimeEdwardsPrecomputation> =
LazyLock::new(|| VartimeEdwardsPrecomputation::new([ED25519_BASEPOINT_POINT]));
/// A cached (if std) pre-computation of the Ed25519 generator, G. /// A cached (if std) pre-computation of the Ed25519 generator, G.
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn G_PRECOMP() -> &'static VartimeEdwardsPrecomputation { pub fn G_PRECOMP() -> &'static VartimeEdwardsPrecomputation {
G_PRECOMP_CELL.get_or_init(|| VartimeEdwardsPrecomputation::new([ED25519_BASEPOINT_POINT])) &G_PRECOMP_CELL
} }
/// A cached (if std) pre-computation of the Ed25519 generator, G. /// A cached (if std) pre-computation of the Ed25519 generator, G.
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
@@ -105,7 +106,7 @@ impl Commitment {
/// Calculate the Pedersen commitment, as a point, from this transparent structure. /// Calculate the Pedersen commitment, as a point, from this transparent structure.
pub fn calculate(&self) -> EdwardsPoint { pub fn calculate(&self) -> EdwardsPoint {
EdwardsPoint::vartime_double_scalar_mul_basepoint(&Scalar::from(self.amount), &H(), &self.mask) EdwardsPoint::vartime_double_scalar_mul_basepoint(&Scalar::from(self.amount), &H, &self.mask)
} }
/// Write the Commitment. /// Write the Commitment.

View File

@@ -1,6 +1,6 @@
use core::cmp::Ordering; use core::cmp::Ordering;
use std_shims::{ use std_shims::{
sync::OnceLock, sync::LazyLock,
io::{self, *}, io::{self, *},
}; };
@@ -10,18 +10,14 @@ use curve25519_dalek::scalar::Scalar;
use monero_io::*; use monero_io::*;
static PRECOMPUTED_SCALARS_CELL: OnceLock<[Scalar; 8]> = OnceLock::new();
// Precomputed scalars used to recover an incorrectly reduced scalar. // Precomputed scalars used to recover an incorrectly reduced scalar.
#[allow(non_snake_case)] static PRECOMPUTED_SCALARS: LazyLock<[Scalar; 8]> = LazyLock::new(|| {
fn PRECOMPUTED_SCALARS() -> [Scalar; 8] { let mut precomputed_scalars = [Scalar::ONE; 8];
*PRECOMPUTED_SCALARS_CELL.get_or_init(|| { for (i, scalar) in precomputed_scalars.iter_mut().enumerate().skip(1) {
let mut precomputed_scalars = [Scalar::ONE; 8]; *scalar = Scalar::from(u8::try_from((i * 2) + 1).unwrap());
for (i, scalar) in precomputed_scalars.iter_mut().enumerate().skip(1) { }
*scalar = Scalar::from(u8::try_from((i * 2) + 1).unwrap()); precomputed_scalars
} });
precomputed_scalars
})
}
/// An unreduced scalar. /// An unreduced scalar.
/// ///
@@ -127,14 +123,12 @@ impl UnreducedScalar {
return Scalar::from_bytes_mod_order(self.0); return Scalar::from_bytes_mod_order(self.0);
} }
let precomputed_scalars = PRECOMPUTED_SCALARS();
let mut recovered = Scalar::ZERO; let mut recovered = Scalar::ZERO;
for &numb in self.non_adjacent_form().iter().rev() { for &numb in self.non_adjacent_form().iter().rev() {
recovered += recovered; recovered += recovered;
match numb.cmp(&0) { match numb.cmp(&0) {
Ordering::Greater => recovered += precomputed_scalars[usize::try_from(numb).unwrap() / 2], Ordering::Greater => recovered += PRECOMPUTED_SCALARS[usize::try_from(numb).unwrap() / 2],
Ordering::Less => recovered -= precomputed_scalars[usize::try_from(-numb).unwrap() / 2], Ordering::Less => recovered -= PRECOMPUTED_SCALARS[usize::try_from(-numb).unwrap() / 2],
Ordering::Equal => (), Ordering::Equal => (),
} }
} }

View File

@@ -6,7 +6,7 @@ license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/ringct/borromean" repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/ringct/borromean"
authors = ["Luke Parker <lukeparker5132@gmail.com>"] authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021" edition = "2021"
rust-version = "1.79" rust-version = "1.80"
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@@ -6,7 +6,7 @@ license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/ringct/bulletproofs" repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/ringct/bulletproofs"
authors = ["Luke Parker <lukeparker5132@gmail.com>"] authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021" edition = "2021"
rust-version = "1.79" rust-version = "1.80"
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@@ -40,17 +40,14 @@ fn generators(prefix: &'static str, path: &str) {
.write_all( .write_all(
format!( format!(
" "
static GENERATORS_CELL: OnceLock<Generators> = OnceLock::new(); pub(crate) static GENERATORS: LazyLock<Generators> = LazyLock::new(|| Generators {{
pub(crate) fn GENERATORS() -> &'static Generators {{ G: std_shims::vec![
GENERATORS_CELL.get_or_init(|| Generators {{ {G_str}
G: std_shims::vec![ ],
{G_str} H: std_shims::vec![
], {H_str}
H: std_shims::vec![ ],
{H_str} }});
],
}})
}}
", ",
) )
.as_bytes(), .as_bytes(),
@@ -67,12 +64,9 @@ fn generators(prefix: &'static str, path: &str) {
.write_all( .write_all(
format!( format!(
r#" r#"
static GENERATORS_CELL: OnceLock<Generators> = OnceLock::new(); pub(crate) static GENERATORS: LazyLock<Generators> = LazyLock::new(|| {{
pub(crate) fn GENERATORS() -> &'static Generators {{ monero_generators::bulletproofs_generators(b"{prefix}")
GENERATORS_CELL.get_or_init(|| {{ }});
monero_generators::bulletproofs_generators(b"{prefix}")
}})
}}
"#, "#,
) )
.as_bytes(), .as_bytes(),

View File

@@ -7,7 +7,7 @@ use curve25519_dalek::{
edwards::EdwardsPoint, edwards::EdwardsPoint,
}; };
use monero_generators::{H, Generators}; use monero_generators::{H as MONERO_H, Generators};
use crate::{original, plus}; use crate::{original, plus};
@@ -57,7 +57,7 @@ pub(crate) struct BulletproofsBatchVerifier(pub(crate) InternalBatchVerifier);
impl BulletproofsBatchVerifier { impl BulletproofsBatchVerifier {
#[must_use] #[must_use]
pub(crate) fn verify(self) -> bool { pub(crate) fn verify(self) -> bool {
self.0.verify(ED25519_BASEPOINT_POINT, H(), original::GENERATORS()) self.0.verify(ED25519_BASEPOINT_POINT, *MONERO_H, &original::GENERATORS)
} }
} }
@@ -68,7 +68,7 @@ impl BulletproofsPlusBatchVerifier {
pub(crate) fn verify(self) -> bool { pub(crate) fn verify(self) -> bool {
// Bulletproofs+ is written as per the paper, with G for the value and H for the mask // Bulletproofs+ is written as per the paper, with G for the value and H for the mask
// Monero uses H for the value and G for the mask // Monero uses H for the value and G for the mask
self.0.verify(H(), ED25519_BASEPOINT_POINT, plus::GENERATORS()) self.0.verify(*MONERO_H, ED25519_BASEPOINT_POINT, &plus::GENERATORS)
} }
} }

View File

@@ -96,13 +96,13 @@ impl IpStatement {
mut transcript: Scalar, mut transcript: Scalar,
witness: IpWitness, witness: IpWitness,
) -> Result<IpProof, IpError> { ) -> Result<IpProof, IpError> {
let generators = crate::original::GENERATORS(); let generators = &crate::original::GENERATORS;
let g_bold_slice = &generators.G[.. witness.a.len()]; let g_bold_slice = &generators.G[.. witness.a.len()];
let h_bold_slice = &generators.H[.. witness.a.len()]; let h_bold_slice = &generators.H[.. witness.a.len()];
let (mut g_bold, mut h_bold, u, mut a, mut b) = { let (mut g_bold, mut h_bold, u, mut a, mut b) = {
let IpStatement { h_bold_weights, u } = self; let IpStatement { h_bold_weights, u } = self;
let u = H() * u; let u = *H * u;
// Ensure we have the exact amount of weights // Ensure we have the exact amount of weights
if h_bold_weights.len() != g_bold_slice.len() { if h_bold_weights.len() != g_bold_slice.len() {
@@ -218,7 +218,7 @@ impl IpStatement {
verifier_weight: Scalar, verifier_weight: Scalar,
proof: IpProof, proof: IpProof,
) -> Result<(), IpError> { ) -> Result<(), IpError> {
let generators = crate::original::GENERATORS(); let generators = &crate::original::GENERATORS;
let g_bold_slice = &generators.G[.. ip_rows]; let g_bold_slice = &generators.G[.. ip_rows];
let h_bold_slice = &generators.H[.. ip_rows]; let h_bold_slice = &generators.H[.. ip_rows];

View File

@@ -1,4 +1,4 @@
use std_shims::{sync::OnceLock, vec::Vec}; use std_shims::{sync::LazyLock, vec::Vec};
use rand_core::{RngCore, CryptoRng}; use rand_core::{RngCore, CryptoRng};
@@ -6,7 +6,7 @@ use zeroize::Zeroize;
use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, Scalar, EdwardsPoint}; use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, Scalar, EdwardsPoint};
use monero_generators::{H, Generators, MAX_COMMITMENTS, COMMITMENT_BITS}; use monero_generators::{H as MONERO_H, Generators, MAX_COMMITMENTS, COMMITMENT_BITS};
use monero_primitives::{Commitment, INV_EIGHT, keccak256_to_scalar}; use monero_primitives::{Commitment, INV_EIGHT, keccak256_to_scalar};
use crate::{core::multiexp, scalar_vector::ScalarVector, BulletproofsBatchVerifier}; use crate::{core::multiexp, scalar_vector::ScalarVector, BulletproofsBatchVerifier};
@@ -107,7 +107,7 @@ impl<'a> AggregateRangeStatement<'a> {
None? None?
}; };
let generators = GENERATORS(); let generators = &GENERATORS;
let (mut transcript, _) = self.initial_transcript(); let (mut transcript, _) = self.initial_transcript();
@@ -186,7 +186,7 @@ impl<'a> AggregateRangeStatement<'a> {
let tau_1 = Scalar::random(&mut *rng); let tau_1 = Scalar::random(&mut *rng);
let T1 = { let T1 = {
let mut T1_terms = [(t1, H()), (tau_1, ED25519_BASEPOINT_POINT)]; let mut T1_terms = [(t1, *MONERO_H), (tau_1, ED25519_BASEPOINT_POINT)];
for term in &mut T1_terms { for term in &mut T1_terms {
term.0 *= INV_EIGHT(); term.0 *= INV_EIGHT();
} }
@@ -196,7 +196,7 @@ impl<'a> AggregateRangeStatement<'a> {
}; };
let tau_2 = Scalar::random(&mut *rng); let tau_2 = Scalar::random(&mut *rng);
let T2 = { let T2 = {
let mut T2_terms = [(t2, H()), (tau_2, ED25519_BASEPOINT_POINT)]; let mut T2_terms = [(t2, *MONERO_H), (tau_2, ED25519_BASEPOINT_POINT)];
for term in &mut T2_terms { for term in &mut T2_terms {
term.0 *= INV_EIGHT(); term.0 *= INV_EIGHT();
} }

View File

@@ -1,6 +1,6 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use std_shims::sync::OnceLock; use std_shims::sync::LazyLock;
use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar, edwards::EdwardsPoint}; use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar, edwards::EdwardsPoint};
@@ -39,7 +39,7 @@ include!(concat!(env!("OUT_DIR"), "/generators_plus.rs"));
impl BpPlusGenerators { impl BpPlusGenerators {
#[allow(clippy::new_without_default)] #[allow(clippy::new_without_default)]
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self {
let gens = GENERATORS(); let gens = &GENERATORS;
BpPlusGenerators { g_bold: &gens.G, h_bold: &gens.H } BpPlusGenerators { g_bold: &gens.G, h_bold: &gens.H }
} }
@@ -48,7 +48,7 @@ impl BpPlusGenerators {
} }
pub(crate) fn g() -> EdwardsPoint { pub(crate) fn g() -> EdwardsPoint {
H() *H
} }
pub(crate) fn h() -> EdwardsPoint { pub(crate) fn h() -> EdwardsPoint {

View File

@@ -1,4 +1,4 @@
use std_shims::{sync::OnceLock, vec::Vec}; use std_shims::{sync::LazyLock, vec::Vec};
use curve25519_dalek::{scalar::Scalar, edwards::EdwardsPoint}; use curve25519_dalek::{scalar::Scalar, edwards::EdwardsPoint};
@@ -6,15 +6,12 @@ use monero_generators::hash_to_point;
use monero_primitives::{keccak256, keccak256_to_scalar}; use monero_primitives::{keccak256, keccak256_to_scalar};
// Monero starts BP+ transcripts with the following constant. // Monero starts BP+ transcripts with the following constant.
static TRANSCRIPT_CELL: OnceLock<[u8; 32]> = OnceLock::new(); // Why this uses a hash_to_point is completely unknown.
pub(crate) fn TRANSCRIPT() -> [u8; 32] { pub(crate) static TRANSCRIPT: LazyLock<[u8; 32]> =
// Why this uses a hash_to_point is completely unknown. LazyLock::new(|| hash_to_point(keccak256(b"bulletproof_plus_transcript")).compress().to_bytes());
*TRANSCRIPT_CELL
.get_or_init(|| hash_to_point(keccak256(b"bulletproof_plus_transcript")).compress().to_bytes())
}
pub(crate) fn initial_transcript(commitments: core::slice::Iter<'_, EdwardsPoint>) -> Scalar { pub(crate) fn initial_transcript(commitments: core::slice::Iter<'_, EdwardsPoint>) -> Scalar {
let commitments_hash = let commitments_hash =
keccak256_to_scalar(commitments.flat_map(|V| V.compress().to_bytes()).collect::<Vec<_>>()); keccak256_to_scalar(commitments.flat_map(|V| V.compress().to_bytes()).collect::<Vec<_>>());
keccak256_to_scalar([TRANSCRIPT().as_ref(), &commitments_hash.to_bytes()].concat()) keccak256_to_scalar([TRANSCRIPT.as_ref(), &commitments_hash.to_bytes()].concat())
} }

View File

@@ -35,12 +35,12 @@ fn test_zero_inner_product() {
#[test] #[test]
fn test_inner_product() { fn test_inner_product() {
// P = sum(g_bold * a, h_bold * b, g * u * <a, b>) // P = sum(g_bold * a, h_bold * b, g * u * <a, b>)
let generators = GENERATORS(); let generators = &GENERATORS;
let mut verifier = BulletproofsBatchVerifier::default(); let mut verifier = BulletproofsBatchVerifier::default();
verifier.0.g_bold = vec![Scalar::ZERO; 32]; verifier.0.g_bold = vec![Scalar::ZERO; 32];
verifier.0.h_bold = vec![Scalar::ZERO; 32]; verifier.0.h_bold = vec![Scalar::ZERO; 32];
for i in [1, 2, 4, 8, 16, 32] { for i in [1, 2, 4, 8, 16, 32] {
let g = H(); let g = *H;
let mut g_bold = vec![]; let mut g_bold = vec![];
let mut h_bold = vec![]; let mut h_bold = vec![];
for i in 0 .. i { for i in 0 .. i {

View File

@@ -6,7 +6,7 @@ license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/ringct/clsag" repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/ringct/clsag"
authors = ["Luke Parker <lukeparker5132@gmail.com>"] authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021" edition = "2021"
rust-version = "1.79" rust-version = "1.80"
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@@ -6,7 +6,7 @@ license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/ringct/mlsag" repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/ringct/mlsag"
authors = ["Luke Parker <lukeparker5132@gmail.com>"] authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021" edition = "2021"
rust-version = "1.79" rust-version = "1.80"
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@@ -203,7 +203,7 @@ impl AggregateRingMatrixBuilder {
AggregateRingMatrixBuilder { AggregateRingMatrixBuilder {
key_ring: vec![], key_ring: vec![],
amounts_ring: vec![], amounts_ring: vec![],
sum_out: commitments.iter().sum::<EdwardsPoint>() + (H() * Scalar::from(fee)), sum_out: commitments.iter().sum::<EdwardsPoint>() + (*H * Scalar::from(fee)),
} }
} }

View File

@@ -6,7 +6,7 @@ license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/rpc" repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/rpc"
authors = ["Luke Parker <lukeparker5132@gmail.com>"] authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021" edition = "2021"
rust-version = "1.79" rust-version = "1.80"
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@@ -6,7 +6,7 @@ license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/rpc/simple-request" repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/rpc/simple-request"
authors = ["Luke Parker <lukeparker5132@gmail.com>"] authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021" edition = "2021"
rust-version = "1.79" rust-version = "1.80"
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@@ -1,4 +1,4 @@
use std::sync::OnceLock; use std::sync::LazyLock;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use monero_address::{Network, MoneroAddress}; use monero_address::{Network, MoneroAddress};
@@ -8,7 +8,7 @@ use monero_address::{Network, MoneroAddress};
// Accordingly, we test monero-rpc here (implicitly testing the simple-request transport) // Accordingly, we test monero-rpc here (implicitly testing the simple-request transport)
use monero_simple_request_rpc::*; use monero_simple_request_rpc::*;
static SEQUENTIAL: OnceLock<Mutex<()>> = OnceLock::new(); static SEQUENTIAL: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
const ADDRESS: &str = const ADDRESS: &str =
"4B33mFPMq6mKi7Eiyd5XuyKRVMGVZz1Rqb9ZTyGApXW5d1aT7UBDZ89ewmnWFkzJ5wPd2SFbn313vCT8a4E2Qf4KQH4pNey"; "4B33mFPMq6mKi7Eiyd5XuyKRVMGVZz1Rqb9ZTyGApXW5d1aT7UBDZ89ewmnWFkzJ5wPd2SFbn313vCT8a4E2Qf4KQH4pNey";
@@ -17,7 +17,7 @@ const ADDRESS: &str =
async fn test_rpc() { async fn test_rpc() {
use monero_rpc::Rpc; use monero_rpc::Rpc;
let guard = SEQUENTIAL.get_or_init(|| Mutex::new(())).lock().await; let guard = SEQUENTIAL.lock().await;
let rpc = let rpc =
SimpleRequestRpc::new("http://serai:seraidex@127.0.0.1:18081".to_string()).await.unwrap(); SimpleRequestRpc::new("http://serai:seraidex@127.0.0.1:18081".to_string()).await.unwrap();
@@ -68,7 +68,7 @@ async fn test_rpc() {
async fn test_decoy_rpc() { async fn test_decoy_rpc() {
use monero_rpc::{Rpc, DecoyRpc}; use monero_rpc::{Rpc, DecoyRpc};
let guard = SEQUENTIAL.get_or_init(|| Mutex::new(())).lock().await; let guard = SEQUENTIAL.lock().await;
let rpc = let rpc =
SimpleRequestRpc::new("http://serai:seraidex@127.0.0.1:18081".to_string()).await.unwrap(); SimpleRequestRpc::new("http://serai:seraidex@127.0.0.1:18081".to_string()).await.unwrap();
@@ -122,7 +122,7 @@ async fn test_decoy_rpc() {
async fn test_zero_out_tx_o_indexes() { async fn test_zero_out_tx_o_indexes() {
use monero_rpc::Rpc; use monero_rpc::Rpc;
let guard = SEQUENTIAL.get_or_init(|| Mutex::new(())).lock().await; let guard = SEQUENTIAL.lock().await;
let rpc = SimpleRequestRpc::new("https://node.sethforprivacy.com".to_string()).await.unwrap(); let rpc = SimpleRequestRpc::new("https://node.sethforprivacy.com".to_string()).await.unwrap();

View File

@@ -6,7 +6,7 @@ license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/verify-chain" repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/verify-chain"
authors = ["Luke Parker <lukeparker5132@gmail.com>"] authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021" edition = "2021"
rust-version = "1.79" rust-version = "1.80"
publish = false publish = false
[package.metadata.docs.rs] [package.metadata.docs.rs]

View File

@@ -6,7 +6,7 @@ license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/wallet" repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/wallet"
authors = ["Luke Parker <lukeparker5132@gmail.com>"] authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021" edition = "2021"
rust-version = "1.79" rust-version = "1.80"
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@@ -6,7 +6,7 @@ license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/wallet/address" repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/wallet/address"
authors = ["Luke Parker <lukeparker5132@gmail.com>"] authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021" edition = "2021"
rust-version = "1.79" rust-version = "1.80"
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@@ -6,7 +6,7 @@ license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/wallet/polyseed" repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/wallet/polyseed"
authors = ["Luke Parker <lukeparker5132@gmail.com>"] authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021" edition = "2021"
rust-version = "1.79" rust-version = "1.80"
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@@ -4,7 +4,7 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
use core::fmt; use core::fmt;
use std_shims::{sync::OnceLock, string::String, collections::HashMap}; use std_shims::{sync::LazyLock, string::String, collections::HashMap};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
@@ -163,30 +163,26 @@ impl WordList {
} }
} }
static LANGUAGES_CELL: OnceLock<HashMap<Language, WordList>> = OnceLock::new(); static LANGUAGES: LazyLock<HashMap<Language, WordList>> = LazyLock::new(|| {
#[allow(non_snake_case)] HashMap::from([
fn LANGUAGES() -> &'static HashMap<Language, WordList> { (Language::Czech, WordList::new(include!("./words/cs.rs"), true, false)),
LANGUAGES_CELL.get_or_init(|| { (Language::French, WordList::new(include!("./words/fr.rs"), true, true)),
HashMap::from([ (Language::Korean, WordList::new(include!("./words/ko.rs"), false, false)),
(Language::Czech, WordList::new(include!("./words/cs.rs"), true, false)), (Language::English, WordList::new(include!("./words/en.rs"), true, false)),
(Language::French, WordList::new(include!("./words/fr.rs"), true, true)), (Language::Italian, WordList::new(include!("./words/it.rs"), true, false)),
(Language::Korean, WordList::new(include!("./words/ko.rs"), false, false)), (Language::Spanish, WordList::new(include!("./words/es.rs"), true, true)),
(Language::English, WordList::new(include!("./words/en.rs"), true, false)), (Language::Japanese, WordList::new(include!("./words/ja.rs"), false, false)),
(Language::Italian, WordList::new(include!("./words/it.rs"), true, false)), (Language::Portuguese, WordList::new(include!("./words/pt.rs"), true, false)),
(Language::Spanish, WordList::new(include!("./words/es.rs"), true, true)), (
(Language::Japanese, WordList::new(include!("./words/ja.rs"), false, false)), Language::ChineseSimplified,
(Language::Portuguese, WordList::new(include!("./words/pt.rs"), true, false)), WordList::new(include!("./words/zh_simplified.rs"), false, false),
( ),
Language::ChineseSimplified, (
WordList::new(include!("./words/zh_simplified.rs"), false, false), Language::ChineseTraditional,
), WordList::new(include!("./words/zh_traditional.rs"), false, false),
( ),
Language::ChineseTraditional, ])
WordList::new(include!("./words/zh_traditional.rs"), false, false), });
),
])
})
}
/// A Polyseed. /// A Polyseed.
#[derive(Clone, PartialEq, Eq, Zeroize, ZeroizeOnDrop)] #[derive(Clone, PartialEq, Eq, Zeroize, ZeroizeOnDrop)]
@@ -317,7 +313,7 @@ impl Polyseed {
let mut poly = [0; POLYSEED_LENGTH]; let mut poly = [0; POLYSEED_LENGTH];
// Validate words are in the lang word list // Validate words are in the lang word list
let lang_word_list: &WordList = &LANGUAGES()[&lang]; let lang_word_list: &WordList = &LANGUAGES[&lang];
for (i, word) in seed.split_whitespace().enumerate() { for (i, word) in seed.split_whitespace().enumerate() {
// Find the word's index // Find the word's index
fn check_if_matches<S: AsRef<str>, I: Iterator<Item = S>>( fn check_if_matches<S: AsRef<str>, I: Iterator<Item = S>>(
@@ -464,7 +460,7 @@ impl Polyseed {
// Output words // Output words
let mut seed = Zeroizing::new(String::new()); let mut seed = Zeroizing::new(String::new());
let words = &LANGUAGES()[&self.language].words; let words = &LANGUAGES[&self.language].words;
for i in 0 .. poly.len() { for i in 0 .. poly.len() {
seed.push_str(words[usize::from(poly[i])]); seed.push_str(words[usize::from(poly[i])]);
if i < poly.len() - 1 { if i < poly.len() - 1 {

View File

@@ -6,7 +6,7 @@ license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/wallet/seed" repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/wallet/seed"
authors = ["Luke Parker <lukeparker5132@gmail.com>"] authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021" edition = "2021"
rust-version = "1.79" rust-version = "1.80"
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@@ -5,7 +5,7 @@
use core::{ops::Deref, fmt}; use core::{ops::Deref, fmt};
use std_shims::{ use std_shims::{
sync::OnceLock, sync::LazyLock,
vec, vec,
vec::Vec, vec::Vec,
string::{String, ToString}, string::{String, ToString},
@@ -102,27 +102,23 @@ impl WordList {
} }
} }
static LANGUAGES_CELL: OnceLock<HashMap<Language, WordList>> = OnceLock::new(); static LANGUAGES: LazyLock<HashMap<Language, WordList>> = LazyLock::new(|| {
#[allow(non_snake_case)] HashMap::from([
fn LANGUAGES() -> &'static HashMap<Language, WordList> { (Language::Chinese, WordList::new(include!("./words/zh.rs"), 1)),
LANGUAGES_CELL.get_or_init(|| { (Language::English, WordList::new(include!("./words/en.rs"), 3)),
HashMap::from([ (Language::Dutch, WordList::new(include!("./words/nl.rs"), 4)),
(Language::Chinese, WordList::new(include!("./words/zh.rs"), 1)), (Language::French, WordList::new(include!("./words/fr.rs"), 4)),
(Language::English, WordList::new(include!("./words/en.rs"), 3)), (Language::Spanish, WordList::new(include!("./words/es.rs"), 4)),
(Language::Dutch, WordList::new(include!("./words/nl.rs"), 4)), (Language::German, WordList::new(include!("./words/de.rs"), 4)),
(Language::French, WordList::new(include!("./words/fr.rs"), 4)), (Language::Italian, WordList::new(include!("./words/it.rs"), 4)),
(Language::Spanish, WordList::new(include!("./words/es.rs"), 4)), (Language::Portuguese, WordList::new(include!("./words/pt.rs"), 4)),
(Language::German, WordList::new(include!("./words/de.rs"), 4)), (Language::Japanese, WordList::new(include!("./words/ja.rs"), 3)),
(Language::Italian, WordList::new(include!("./words/it.rs"), 4)), (Language::Russian, WordList::new(include!("./words/ru.rs"), 4)),
(Language::Portuguese, WordList::new(include!("./words/pt.rs"), 4)), (Language::Esperanto, WordList::new(include!("./words/eo.rs"), 4)),
(Language::Japanese, WordList::new(include!("./words/ja.rs"), 3)), (Language::Lojban, WordList::new(include!("./words/jbo.rs"), 4)),
(Language::Russian, WordList::new(include!("./words/ru.rs"), 4)), (Language::DeprecatedEnglish, WordList::new(include!("./words/ang.rs"), 4)),
(Language::Esperanto, WordList::new(include!("./words/eo.rs"), 4)), ])
(Language::Lojban, WordList::new(include!("./words/jbo.rs"), 4)), });
(Language::DeprecatedEnglish, WordList::new(include!("./words/ang.rs"), 4)),
])
})
}
fn checksum_index(words: &[Zeroizing<String>], lang: &WordList) -> usize { fn checksum_index(words: &[Zeroizing<String>], lang: &WordList) -> usize {
let mut trimmed_words = Zeroizing::new(String::new()); let mut trimmed_words = Zeroizing::new(String::new());
@@ -170,7 +166,7 @@ fn key_to_seed(lang: Language, key: Zeroizing<Scalar>) -> Seed {
let bytes = Zeroizing::new(key.to_bytes()); let bytes = Zeroizing::new(key.to_bytes());
// get the language words // get the language words
let words = &LANGUAGES()[&lang].word_list; let words = &LANGUAGES[&lang].word_list;
let list_len = u64::try_from(words.len()).unwrap(); let list_len = u64::try_from(words.len()).unwrap();
// To store the found words & add the checksum word later. // To store the found words & add the checksum word later.
@@ -204,7 +200,7 @@ fn key_to_seed(lang: Language, key: Zeroizing<Scalar>) -> Seed {
// create a checksum word for all languages except old english // create a checksum word for all languages except old english
if lang != Language::DeprecatedEnglish { if lang != Language::DeprecatedEnglish {
let checksum = seed[checksum_index(&seed, &LANGUAGES()[&lang])].clone(); let checksum = seed[checksum_index(&seed, &LANGUAGES[&lang])].clone();
seed.push(checksum); seed.push(checksum);
} }
@@ -232,7 +228,7 @@ fn seed_to_bytes(lang: Language, words: &str) -> Result<Zeroizing<[u8; 32]>, See
} }
// Validate words are in the language word list // Validate words are in the language word list
let lang_word_list: &WordList = &LANGUAGES()[&lang]; let lang_word_list: &WordList = &LANGUAGES[&lang];
let matched_indices = (|| { let matched_indices = (|| {
let has_checksum = words.len() == SEED_LENGTH_WITH_CHECKSUM; let has_checksum = words.len() == SEED_LENGTH_WITH_CHECKSUM;
let mut matched_indices = Zeroizing::new(vec![]); let mut matched_indices = Zeroizing::new(vec![]);

View File

@@ -183,7 +183,7 @@ fn test_original_seed() {
for vector in vectors { for vector in vectors {
fn trim_by_lang(word: &str, lang: Language) -> String { fn trim_by_lang(word: &str, lang: Language) -> String {
if lang != Language::DeprecatedEnglish { if lang != Language::DeprecatedEnglish {
word.chars().take(LANGUAGES()[&lang].unique_prefix_length).collect() word.chars().take(LANGUAGES[&lang].unique_prefix_length).collect()
} else { } else {
word.to_string() word.to_string()
} }

View File

@@ -1,5 +1,5 @@
use core::ops::Deref; use core::ops::Deref;
use std_shims::sync::OnceLock; use std_shims::sync::LazyLock;
use zeroize::Zeroizing; use zeroize::Zeroizing;
use rand_core::OsRng; use rand_core::OsRng;
@@ -145,7 +145,7 @@ pub async fn rpc() -> SimpleRequestRpc {
rpc rpc
} }
pub static SEQUENTIAL: OnceLock<Mutex<()>> = OnceLock::new(); pub(crate) static SEQUENTIAL: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
#[macro_export] #[macro_export]
macro_rules! async_sequential { macro_rules! async_sequential {
@@ -153,7 +153,7 @@ macro_rules! async_sequential {
$( $(
#[tokio::test] #[tokio::test]
async fn $name() { async fn $name() {
let guard = runner::SEQUENTIAL.get_or_init(|| tokio::sync::Mutex::new(())).lock().await; let guard = runner::SEQUENTIAL.lock().await;
let local = tokio::task::LocalSet::new(); let local = tokio::task::LocalSet::new();
local.run_until(async move { local.run_until(async move {
if let Err(err) = tokio::task::spawn_local(async move { $body }).await { if let Err(err) = tokio::task::spawn_local(async move { $body }).await {

View File

@@ -6,7 +6,7 @@ license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/wallet/util" repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/wallet/util"
authors = ["Luke Parker <lukeparker5132@gmail.com>"] authors = ["Luke Parker <lukeparker5132@gmail.com>"]
edition = "2021" edition = "2021"
rust-version = "1.79" rust-version = "1.80"
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true

View File

@@ -1,5 +1,5 @@
# rust:1.79.0-slim-bookworm as of June 14th, 2024 (GMT) # rust:1.80.0-slim-bookworm as of July 27th, 2024 (GMT)
FROM --platform=linux/amd64 rust@sha256:fa189cd885739dd17fc6bb4e132687fce43f2bf42983c0ac39b60e4943201e9c as deterministic FROM --platform=linux/amd64 rust@sha256:37e6f90f98b3afd15c2526d7abb257a1f4cb7d49808fe3729d9d62020b07b544 as deterministic
# Move to a Debian package snapshot # Move to a Debian package snapshot
RUN rm -rf /etc/apt/sources.list.d/debian.sources && \ RUN rm -rf /etc/apt/sources.list.d/debian.sources && \

View File

@@ -146,7 +146,7 @@ fn build_serai_service(prelude: &str, release: bool, features: &str, package: &s
format!( format!(
r#" r#"
FROM rust:1.79-slim-bookworm as builder FROM rust:1.80-slim-bookworm as builder
COPY --from=mimalloc-debian libmimalloc.so /usr/lib COPY --from=mimalloc-debian libmimalloc.so /usr/lib
RUN echo "/usr/lib/libmimalloc.so" >> /etc/ld.so.preload RUN echo "/usr/lib/libmimalloc.so" >> /etc/ld.so.preload

View File

@@ -1,5 +1,5 @@
[toolchain] [toolchain]
channel = "1.79" channel = "1.80"
targets = ["wasm32-unknown-unknown"] targets = ["wasm32-unknown-unknown"]
profile = "minimal" profile = "minimal"
components = ["rust-src", "rustfmt", "clippy"] components = ["rust-src", "rustfmt", "clippy"]