mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-11 21:49:26 +00:00
Begin crate smashing
This commit is contained in:
49
Cargo.lock
generated
49
Cargo.lock
generated
@@ -4751,6 +4751,27 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "monero-clsag"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"curve25519-dalek",
|
||||||
|
"dalek-ff-group",
|
||||||
|
"flexible-transcript",
|
||||||
|
"group",
|
||||||
|
"modular-frost",
|
||||||
|
"monero-generators",
|
||||||
|
"monero-io",
|
||||||
|
"monero-primitives",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
"sha3",
|
||||||
|
"std-shims",
|
||||||
|
"subtle",
|
||||||
|
"thiserror",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "monero-generators"
|
name = "monero-generators"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -4759,11 +4780,33 @@ dependencies = [
|
|||||||
"dalek-ff-group",
|
"dalek-ff-group",
|
||||||
"group",
|
"group",
|
||||||
"hex",
|
"hex",
|
||||||
|
"monero-io",
|
||||||
"sha3",
|
"sha3",
|
||||||
"std-shims",
|
"std-shims",
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "monero-io"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"curve25519-dalek",
|
||||||
|
"std-shims",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "monero-primitives"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"curve25519-dalek",
|
||||||
|
"monero-generators",
|
||||||
|
"monero-io",
|
||||||
|
"rand_core",
|
||||||
|
"sha3",
|
||||||
|
"std-shims",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "monero-serai"
|
name = "monero-serai"
|
||||||
version = "0.1.4-alpha"
|
version = "0.1.4-alpha"
|
||||||
@@ -4778,7 +4821,10 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"hex-literal",
|
"hex-literal",
|
||||||
"modular-frost",
|
"modular-frost",
|
||||||
|
"monero-clsag",
|
||||||
"monero-generators",
|
"monero-generators",
|
||||||
|
"monero-io",
|
||||||
|
"monero-primitives",
|
||||||
"multiexp",
|
"multiexp",
|
||||||
"pbkdf2 0.12.2",
|
"pbkdf2 0.12.2",
|
||||||
"rand",
|
"rand",
|
||||||
@@ -8035,7 +8081,10 @@ dependencies = [
|
|||||||
"dleq",
|
"dleq",
|
||||||
"flexible-transcript",
|
"flexible-transcript",
|
||||||
"minimal-ed448",
|
"minimal-ed448",
|
||||||
|
"monero-clsag",
|
||||||
"monero-generators",
|
"monero-generators",
|
||||||
|
"monero-io",
|
||||||
|
"monero-primitives",
|
||||||
"monero-serai",
|
"monero-serai",
|
||||||
"multiexp",
|
"multiexp",
|
||||||
"schnorr-signatures",
|
"schnorr-signatures",
|
||||||
|
|||||||
@@ -43,7 +43,10 @@ members = [
|
|||||||
"coins/ethereum",
|
"coins/ethereum",
|
||||||
"coins/ethereum/relayer",
|
"coins/ethereum/relayer",
|
||||||
|
|
||||||
|
"coins/monero/io",
|
||||||
"coins/monero/generators",
|
"coins/monero/generators",
|
||||||
|
"coins/monero/primitives",
|
||||||
|
"coins/monero/ringct/clsag",
|
||||||
"coins/monero",
|
"coins/monero",
|
||||||
|
|
||||||
"message-queue",
|
"message-queue",
|
||||||
|
|||||||
@@ -45,7 +45,10 @@ multiexp = { path = "../../crypto/multiexp", version = "0.4", default-features =
|
|||||||
transcript = { package = "flexible-transcript", path = "../../crypto/transcript", version = "0.3", default-features = false, features = ["recommended"], optional = true }
|
transcript = { package = "flexible-transcript", path = "../../crypto/transcript", version = "0.3", default-features = false, features = ["recommended"], optional = true }
|
||||||
frost = { package = "modular-frost", path = "../../crypto/frost", version = "0.8", default-features = false, features = ["ed25519"], optional = true }
|
frost = { package = "modular-frost", path = "../../crypto/frost", version = "0.8", default-features = false, features = ["ed25519"], optional = true }
|
||||||
|
|
||||||
|
monero-io = { path = "io", version = "0.1", default-features = false }
|
||||||
monero-generators = { path = "generators", version = "0.4", default-features = false }
|
monero-generators = { path = "generators", version = "0.4", default-features = false }
|
||||||
|
monero-primitives = { path = "primitives", version = "0.1", default-features = false }
|
||||||
|
monero-clsag = { path = "ringct/clsag", version = "0.1", default-features = false }
|
||||||
|
|
||||||
hex-literal = "0.4"
|
hex-literal = "0.4"
|
||||||
hex = { version = "0.4", default-features = false, features = ["alloc"] }
|
hex = { version = "0.4", default-features = false, features = ["alloc"] }
|
||||||
@@ -89,7 +92,10 @@ std = [
|
|||||||
|
|
||||||
"transcript/std",
|
"transcript/std",
|
||||||
|
|
||||||
|
"monero-io/std",
|
||||||
"monero-generators/std",
|
"monero-generators/std",
|
||||||
|
"monero-primitives/std",
|
||||||
|
"monero-clsag/std",
|
||||||
|
|
||||||
"hex/std",
|
"hex/std",
|
||||||
"serde/std",
|
"serde/std",
|
||||||
@@ -99,7 +105,7 @@ std = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
http-rpc = ["digest_auth", "simple-request", "tokio"]
|
http-rpc = ["digest_auth", "simple-request", "tokio"]
|
||||||
multisig = ["transcript", "frost", "std"]
|
multisig = ["transcript", "frost", "monero-clsag/multisig", "std"]
|
||||||
binaries = ["tokio/rt-multi-thread", "tokio/macros", "http-rpc"]
|
binaries = ["tokio/rt-multi-thread", "tokio/macros", "http-rpc"]
|
||||||
|
|
||||||
default = ["std", "http-rpc"]
|
default = ["std", "http-rpc"]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "monero-generators"
|
name = "monero-generators"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
description = "Monero's hash_to_point and generators"
|
description = "Monero's hash to point function and generators"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/serai-dex/serai/tree/develop/coins/monero/generators"
|
repository = "https://github.com/serai-dex/serai/tree/develop/coins/monero/generators"
|
||||||
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||||
@@ -20,15 +20,28 @@ std-shims = { path = "../../../common/std-shims", version = "^0.1.1", default-fe
|
|||||||
subtle = { version = "^2.4", default-features = false }
|
subtle = { version = "^2.4", default-features = false }
|
||||||
|
|
||||||
sha3 = { version = "0.10", default-features = false }
|
sha3 = { version = "0.10", default-features = false }
|
||||||
|
curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize"] }
|
||||||
curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize", "precomputed-tables"] }
|
|
||||||
|
|
||||||
group = { version = "0.13", default-features = false }
|
group = { version = "0.13", default-features = false }
|
||||||
dalek-ff-group = { path = "../../../crypto/dalek-ff-group", version = "0.4", default-features = false }
|
dalek-ff-group = { path = "../../../crypto/dalek-ff-group", version = "0.4", default-features = false }
|
||||||
|
|
||||||
|
monero-io = { path = "../io", version = "0.1", default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
std = ["std-shims/std", "subtle/std", "sha3/std", "dalek-ff-group/std"]
|
std = [
|
||||||
|
"std-shims/std",
|
||||||
|
|
||||||
|
"subtle/std",
|
||||||
|
|
||||||
|
"sha3/std",
|
||||||
|
"curve25519-dalek/precomputed-tables",
|
||||||
|
|
||||||
|
"group/alloc",
|
||||||
|
"dalek-ff-group/std",
|
||||||
|
|
||||||
|
"monero-io/std"
|
||||||
|
]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2022-2023 Luke Parker
|
Copyright (c) 2022-2024 Luke Parker
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
# Monero Generators
|
# Monero Generators
|
||||||
|
|
||||||
Generators used by Monero in both its Pedersen commitments and Bulletproofs(+).
|
Generators used by Monero in both its Pedersen commitments and Bulletproofs(+).
|
||||||
An implementation of Monero's `ge_fromfe_frombytes_vartime`, simply called
|
An implementation of Monero's `hash_to_ec` is included, as needed to generate
|
||||||
`hash_to_point` here, is included, as needed to generate generators.
|
the generators.
|
||||||
|
|
||||||
This library is usable under no-std when the `std` feature is disabled.
|
This library is usable under no-std when the `std` feature (on by default) is
|
||||||
|
disabled.
|
||||||
|
|||||||
@@ -1,27 +1,20 @@
|
|||||||
use subtle::ConditionallySelectable;
|
use subtle::ConditionallySelectable;
|
||||||
|
|
||||||
use curve25519_dalek::edwards::{EdwardsPoint, CompressedEdwardsY};
|
use curve25519_dalek::edwards::EdwardsPoint;
|
||||||
|
|
||||||
use group::ff::{Field, PrimeField};
|
use group::ff::{Field, PrimeField};
|
||||||
use dalek_ff_group::FieldElement;
|
use dalek_ff_group::FieldElement;
|
||||||
|
|
||||||
use crate::hash;
|
use monero_io::decompress_point;
|
||||||
|
|
||||||
/// Decompress canonically encoded ed25519 point
|
use crate::keccak256;
|
||||||
/// It does not check if the point is in the prime order subgroup
|
|
||||||
pub fn decompress_point(bytes: [u8; 32]) -> Option<EdwardsPoint> {
|
|
||||||
CompressedEdwardsY(bytes)
|
|
||||||
.decompress()
|
|
||||||
// Ban points which are either unreduced or -0
|
|
||||||
.filter(|point| point.compress().to_bytes() == bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Monero's hash to point function, as named `hash_to_ec`.
|
/// Monero's hash to point function, as named `hash_to_ec`.
|
||||||
pub fn hash_to_point(bytes: [u8; 32]) -> EdwardsPoint {
|
pub fn hash_to_point(bytes: [u8; 32]) -> EdwardsPoint {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
let A = FieldElement::from(486662u64);
|
let A = FieldElement::from(486662u64);
|
||||||
|
|
||||||
let v = FieldElement::from_square(hash(&bytes)).double();
|
let v = FieldElement::from_square(keccak256(&bytes)).double();
|
||||||
let w = v + FieldElement::ONE;
|
let w = v + FieldElement::ONE;
|
||||||
let x = w.square() + (-A.square() * v);
|
let x = w.square() + (-A.square() * v);
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
//! Generators used by Monero in both its Pedersen commitments and Bulletproofs(+).
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
//!
|
#![doc = include_str!("../README.md")]
|
||||||
//! An implementation of Monero's `ge_fromfe_frombytes_vartime`, simply called
|
|
||||||
//! `hash_to_point` here, is included, as needed to generate generators.
|
|
||||||
|
|
||||||
#![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::OnceLock, vec::Vec};
|
||||||
@@ -14,16 +11,15 @@ use curve25519_dalek::edwards::{EdwardsPoint as DalekPoint};
|
|||||||
use group::{Group, GroupEncoding};
|
use group::{Group, GroupEncoding};
|
||||||
use dalek_ff_group::EdwardsPoint;
|
use dalek_ff_group::EdwardsPoint;
|
||||||
|
|
||||||
mod varint;
|
use monero_io::{write_varint, decompress_point};
|
||||||
use varint::write_varint;
|
|
||||||
|
|
||||||
mod hash_to_point;
|
mod hash_to_point;
|
||||||
pub use hash_to_point::{hash_to_point, decompress_point};
|
pub use hash_to_point::hash_to_point;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
fn hash(data: &[u8]) -> [u8; 32] {
|
fn keccak256(data: &[u8]) -> [u8; 32] {
|
||||||
Keccak256::digest(data).into()
|
Keccak256::digest(data).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +28,7 @@ static H_CELL: OnceLock<DalekPoint> = OnceLock::new();
|
|||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn H() -> DalekPoint {
|
pub fn H() -> DalekPoint {
|
||||||
*H_CELL.get_or_init(|| {
|
*H_CELL.get_or_init(|| {
|
||||||
decompress_point(hash(&EdwardsPoint::generator().to_bytes())).unwrap().mul_by_cofactor()
|
decompress_point(keccak256(&EdwardsPoint::generator().to_bytes())).unwrap().mul_by_cofactor()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,10 +66,10 @@ pub fn bulletproofs_generators(dst: &'static [u8]) -> Generators {
|
|||||||
even.extend(dst);
|
even.extend(dst);
|
||||||
let mut odd = even.clone();
|
let mut odd = even.clone();
|
||||||
|
|
||||||
write_varint(&i.try_into().unwrap(), &mut even).unwrap();
|
write_varint::<Vec<u8>, u64>(&i.try_into().unwrap(), &mut even).unwrap();
|
||||||
write_varint(&(i + 1).try_into().unwrap(), &mut odd).unwrap();
|
write_varint::<Vec<u8>, u64>(&(i + 1).try_into().unwrap(), &mut odd).unwrap();
|
||||||
res.H.push(EdwardsPoint(hash_to_point(hash(&even))));
|
res.H.push(EdwardsPoint(hash_to_point(keccak256(&even))));
|
||||||
res.G.push(EdwardsPoint(hash_to_point(hash(&odd))));
|
res.G.push(EdwardsPoint(hash_to_point(keccak256(&odd))));
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
use std_shims::io::{self, Write};
|
|
||||||
|
|
||||||
const VARINT_CONTINUATION_MASK: u8 = 0b1000_0000;
|
|
||||||
pub(crate) fn write_varint<W: Write>(varint: &u64, w: &mut W) -> io::Result<()> {
|
|
||||||
let mut varint = *varint;
|
|
||||||
while {
|
|
||||||
let mut b = u8::try_from(varint & u64::from(!VARINT_CONTINUATION_MASK)).unwrap();
|
|
||||||
varint >>= 7;
|
|
||||||
if varint != 0 {
|
|
||||||
b |= VARINT_CONTINUATION_MASK;
|
|
||||||
}
|
|
||||||
w.write_all(&[b])?;
|
|
||||||
varint != 0
|
|
||||||
} {}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
24
coins/monero/io/Cargo.toml
Normal file
24
coins/monero/io/Cargo.toml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
[package]
|
||||||
|
name = "monero-io"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Serialization functions, as within the Monero protocol"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/serai-dex/serai/tree/develop/coins/monero/io"
|
||||||
|
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
std-shims = { path = "../../../common/std-shims", version = "^0.1.1", default-features = false }
|
||||||
|
|
||||||
|
curve25519-dalek = { version = "4", default-features = false, features = ["alloc"] }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
std = ["std-shims/std"]
|
||||||
|
default = ["std"]
|
||||||
21
coins/monero/io/LICENSE
Normal file
21
coins/monero/io/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022-2024 Luke Parker
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
6
coins/monero/io/README.md
Normal file
6
coins/monero/io/README.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Monero IO
|
||||||
|
|
||||||
|
Serialization functions, as within the Monero protocol.
|
||||||
|
|
||||||
|
This library is usable under no-std when the `std` feature (on by default) is
|
||||||
|
disabled.
|
||||||
@@ -1,12 +1,18 @@
|
|||||||
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
#![doc = include_str!("../README.md")]
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use std_shims::{
|
use std_shims::{
|
||||||
|
vec,
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
io::{self, Read, Write},
|
io::{self, Read, Write},
|
||||||
};
|
};
|
||||||
|
|
||||||
use curve25519_dalek::{scalar::Scalar, edwards::EdwardsPoint};
|
use curve25519_dalek::{
|
||||||
|
scalar::Scalar,
|
||||||
use monero_generators::decompress_point;
|
edwards::{EdwardsPoint, CompressedEdwardsY},
|
||||||
|
};
|
||||||
|
|
||||||
const VARINT_CONTINUATION_MASK: u8 = 0b1000_0000;
|
const VARINT_CONTINUATION_MASK: u8 = 0b1000_0000;
|
||||||
|
|
||||||
@@ -29,17 +35,17 @@ mod sealed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This will panic if the VarInt exceeds u64::MAX
|
// This will panic if the VarInt exceeds u64::MAX
|
||||||
pub(crate) fn varint_len<U: sealed::VarInt>(varint: U) -> usize {
|
pub fn varint_len<U: sealed::VarInt>(varint: U) -> usize {
|
||||||
let varint_u64: u64 = varint.try_into().map_err(|_| "varint exceeded u64").unwrap();
|
let varint_u64: u64 = varint.try_into().map_err(|_| "varint exceeded u64").unwrap();
|
||||||
((usize::try_from(u64::BITS - varint_u64.leading_zeros()).unwrap().saturating_sub(1)) / 7) + 1
|
((usize::try_from(u64::BITS - varint_u64.leading_zeros()).unwrap().saturating_sub(1)) / 7) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn write_byte<W: Write>(byte: &u8, w: &mut W) -> io::Result<()> {
|
pub fn write_byte<W: Write>(byte: &u8, w: &mut W) -> io::Result<()> {
|
||||||
w.write_all(&[*byte])
|
w.write_all(&[*byte])
|
||||||
}
|
}
|
||||||
|
|
||||||
// This will panic if the VarInt exceeds u64::MAX
|
// This will panic if the VarInt exceeds u64::MAX
|
||||||
pub(crate) fn write_varint<W: Write, U: sealed::VarInt>(varint: &U, w: &mut W) -> io::Result<()> {
|
pub fn write_varint<W: Write, U: sealed::VarInt>(varint: &U, w: &mut W) -> io::Result<()> {
|
||||||
let mut varint: u64 = (*varint).try_into().map_err(|_| "varint exceeded u64").unwrap();
|
let mut varint: u64 = (*varint).try_into().map_err(|_| "varint exceeded u64").unwrap();
|
||||||
while {
|
while {
|
||||||
let mut b = u8::try_from(varint & u64::from(!VARINT_CONTINUATION_MASK)).unwrap();
|
let mut b = u8::try_from(varint & u64::from(!VARINT_CONTINUATION_MASK)).unwrap();
|
||||||
@@ -53,15 +59,15 @@ pub(crate) fn write_varint<W: Write, U: sealed::VarInt>(varint: &U, w: &mut W) -
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn write_scalar<W: Write>(scalar: &Scalar, w: &mut W) -> io::Result<()> {
|
pub fn write_scalar<W: Write>(scalar: &Scalar, w: &mut W) -> io::Result<()> {
|
||||||
w.write_all(&scalar.to_bytes())
|
w.write_all(&scalar.to_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn write_point<W: Write>(point: &EdwardsPoint, w: &mut W) -> io::Result<()> {
|
pub fn write_point<W: Write>(point: &EdwardsPoint, w: &mut W) -> io::Result<()> {
|
||||||
w.write_all(&point.compress().to_bytes())
|
w.write_all(&point.compress().to_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn write_raw_vec<T, W: Write, F: Fn(&T, &mut W) -> io::Result<()>>(
|
pub fn write_raw_vec<T, W: Write, F: Fn(&T, &mut W) -> io::Result<()>>(
|
||||||
f: F,
|
f: F,
|
||||||
values: &[T],
|
values: &[T],
|
||||||
w: &mut W,
|
w: &mut W,
|
||||||
@@ -72,7 +78,7 @@ pub(crate) fn write_raw_vec<T, W: Write, F: Fn(&T, &mut W) -> io::Result<()>>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn write_vec<T, W: Write, F: Fn(&T, &mut W) -> io::Result<()>>(
|
pub fn write_vec<T, W: Write, F: Fn(&T, &mut W) -> io::Result<()>>(
|
||||||
f: F,
|
f: F,
|
||||||
values: &[T],
|
values: &[T],
|
||||||
w: &mut W,
|
w: &mut W,
|
||||||
@@ -81,29 +87,29 @@ pub(crate) fn write_vec<T, W: Write, F: Fn(&T, &mut W) -> io::Result<()>>(
|
|||||||
write_raw_vec(f, values, w)
|
write_raw_vec(f, values, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_bytes<R: Read, const N: usize>(r: &mut R) -> io::Result<[u8; N]> {
|
pub fn read_bytes<R: Read, const N: usize>(r: &mut R) -> io::Result<[u8; N]> {
|
||||||
let mut res = [0; N];
|
let mut res = [0; N];
|
||||||
r.read_exact(&mut res)?;
|
r.read_exact(&mut res)?;
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_byte<R: Read>(r: &mut R) -> io::Result<u8> {
|
pub fn read_byte<R: Read>(r: &mut R) -> io::Result<u8> {
|
||||||
Ok(read_bytes::<_, 1>(r)?[0])
|
Ok(read_bytes::<_, 1>(r)?[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_u16<R: Read>(r: &mut R) -> io::Result<u16> {
|
pub fn read_u16<R: Read>(r: &mut R) -> io::Result<u16> {
|
||||||
read_bytes(r).map(u16::from_le_bytes)
|
read_bytes(r).map(u16::from_le_bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_u32<R: Read>(r: &mut R) -> io::Result<u32> {
|
pub fn read_u32<R: Read>(r: &mut R) -> io::Result<u32> {
|
||||||
read_bytes(r).map(u32::from_le_bytes)
|
read_bytes(r).map(u32::from_le_bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_u64<R: Read>(r: &mut R) -> io::Result<u64> {
|
pub fn read_u64<R: Read>(r: &mut R) -> io::Result<u64> {
|
||||||
read_bytes(r).map(u64::from_le_bytes)
|
read_bytes(r).map(u64::from_le_bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_varint<R: Read, U: sealed::VarInt>(r: &mut R) -> io::Result<U> {
|
pub fn read_varint<R: Read, U: sealed::VarInt>(r: &mut R) -> io::Result<U> {
|
||||||
let mut bits = 0;
|
let mut bits = 0;
|
||||||
let mut res = 0;
|
let mut res = 0;
|
||||||
while {
|
while {
|
||||||
@@ -128,24 +134,34 @@ pub(crate) fn read_varint<R: Read, U: sealed::VarInt>(r: &mut R) -> io::Result<U
|
|||||||
// for now. There's also further edge cases as noted by
|
// for now. There's also further edge cases as noted by
|
||||||
// https://github.com/monero-project/monero/issues/8438, where some scalars had an archaic
|
// https://github.com/monero-project/monero/issues/8438, where some scalars had an archaic
|
||||||
// reduction applied
|
// reduction applied
|
||||||
pub(crate) fn read_scalar<R: Read>(r: &mut R) -> io::Result<Scalar> {
|
pub fn read_scalar<R: Read>(r: &mut R) -> io::Result<Scalar> {
|
||||||
Option::from(Scalar::from_canonical_bytes(read_bytes(r)?))
|
Option::from(Scalar::from_canonical_bytes(read_bytes(r)?))
|
||||||
.ok_or_else(|| io::Error::other("unreduced scalar"))
|
.ok_or_else(|| io::Error::other("unreduced scalar"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_point<R: Read>(r: &mut R) -> io::Result<EdwardsPoint> {
|
/// Decompress a canonically encoded ed25519 point.
|
||||||
|
///
|
||||||
|
/// This function does not check if the point is within the prime order subgroup.
|
||||||
|
pub fn decompress_point(bytes: [u8; 32]) -> Option<EdwardsPoint> {
|
||||||
|
CompressedEdwardsY(bytes)
|
||||||
|
.decompress()
|
||||||
|
// Ban points which are either unreduced or -0
|
||||||
|
.filter(|point| point.compress().to_bytes() == bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_point<R: Read>(r: &mut R) -> io::Result<EdwardsPoint> {
|
||||||
let bytes = read_bytes(r)?;
|
let bytes = read_bytes(r)?;
|
||||||
decompress_point(bytes).ok_or_else(|| io::Error::other("invalid point"))
|
decompress_point(bytes).ok_or_else(|| io::Error::other("invalid point"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_torsion_free_point<R: Read>(r: &mut R) -> io::Result<EdwardsPoint> {
|
pub fn read_torsion_free_point<R: Read>(r: &mut R) -> io::Result<EdwardsPoint> {
|
||||||
read_point(r)
|
read_point(r)
|
||||||
.ok()
|
.ok()
|
||||||
.filter(EdwardsPoint::is_torsion_free)
|
.filter(EdwardsPoint::is_torsion_free)
|
||||||
.ok_or_else(|| io::Error::other("invalid point"))
|
.ok_or_else(|| io::Error::other("invalid point"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_raw_vec<R: Read, T, F: Fn(&mut R) -> io::Result<T>>(
|
pub fn read_raw_vec<R: Read, T, F: Fn(&mut R) -> io::Result<T>>(
|
||||||
f: F,
|
f: F,
|
||||||
len: usize,
|
len: usize,
|
||||||
r: &mut R,
|
r: &mut R,
|
||||||
@@ -157,16 +173,13 @@ pub(crate) fn read_raw_vec<R: Read, T, F: Fn(&mut R) -> io::Result<T>>(
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_array<R: Read, T: Debug, F: Fn(&mut R) -> io::Result<T>, const N: usize>(
|
pub fn read_array<R: Read, T: Debug, F: Fn(&mut R) -> io::Result<T>, const N: usize>(
|
||||||
f: F,
|
f: F,
|
||||||
r: &mut R,
|
r: &mut R,
|
||||||
) -> io::Result<[T; N]> {
|
) -> io::Result<[T; N]> {
|
||||||
read_raw_vec(f, N, r).map(|vec| vec.try_into().unwrap())
|
read_raw_vec(f, N, r).map(|vec| vec.try_into().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn read_vec<R: Read, T, F: Fn(&mut R) -> io::Result<T>>(
|
pub fn read_vec<R: Read, T, F: Fn(&mut R) -> io::Result<T>>(f: F, r: &mut R) -> io::Result<Vec<T>> {
|
||||||
f: F,
|
|
||||||
r: &mut R,
|
|
||||||
) -> io::Result<Vec<T>> {
|
|
||||||
read_raw_vec(f, read_varint(r)?, r)
|
read_raw_vec(f, read_varint(r)?, r)
|
||||||
}
|
}
|
||||||
44
coins/monero/primitives/Cargo.toml
Normal file
44
coins/monero/primitives/Cargo.toml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
[package]
|
||||||
|
name = "monero-primitives"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Primitives for the Monero protocol"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/serai-dex/serai/tree/develop/coins/monero/primitives"
|
||||||
|
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.79"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
std-shims = { path = "../../../common/std-shims", version = "^0.1.1", default-features = false }
|
||||||
|
|
||||||
|
rand_core = { version = "0.6", default-features = false }
|
||||||
|
zeroize = { version = "^1.5", default-features = false, features = ["zeroize_derive"] }
|
||||||
|
|
||||||
|
# Cryptographic dependencies
|
||||||
|
sha3 = { version = "0.10", default-features = false }
|
||||||
|
curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize"] }
|
||||||
|
|
||||||
|
# Other Monero dependencies
|
||||||
|
monero-io = { path = "../io", version = "0.1", default-features = false }
|
||||||
|
monero-generators = { path = "../generators", version = "0.4", default-features = false }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
std = [
|
||||||
|
"std-shims/std",
|
||||||
|
|
||||||
|
"rand_core/std",
|
||||||
|
"zeroize/std",
|
||||||
|
|
||||||
|
"sha3/std",
|
||||||
|
"curve25519-dalek/precomputed-tables",
|
||||||
|
|
||||||
|
"monero-generators/std",
|
||||||
|
]
|
||||||
|
default = ["std"]
|
||||||
21
coins/monero/primitives/LICENSE
Normal file
21
coins/monero/primitives/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022-2024 Luke Parker
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
6
coins/monero/primitives/README.md
Normal file
6
coins/monero/primitives/README.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Monero Primitives
|
||||||
|
|
||||||
|
Primitive structures and functions for the Monero protocol.
|
||||||
|
|
||||||
|
This library is usable under no-std when the `std` feature (on by default) is
|
||||||
|
disabled.
|
||||||
122
coins/monero/primitives/src/lib.rs
Normal file
122
coins/monero/primitives/src/lib.rs
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
#![doc = include_str!("../README.md")]
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
|
use std_shims::{vec, vec::Vec};
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
use std_shims::sync::OnceLock;
|
||||||
|
|
||||||
|
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||||
|
|
||||||
|
use sha3::{Digest, Keccak256};
|
||||||
|
use curve25519_dalek::{
|
||||||
|
constants::ED25519_BASEPOINT_POINT,
|
||||||
|
traits::VartimePrecomputedMultiscalarMul,
|
||||||
|
scalar::Scalar,
|
||||||
|
edwards::{EdwardsPoint, VartimeEdwardsPrecomputation},
|
||||||
|
};
|
||||||
|
|
||||||
|
use monero_io::varint_len;
|
||||||
|
use monero_generators::H;
|
||||||
|
|
||||||
|
// TODO: Replace this with a const
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
static INV_EIGHT_CELL: OnceLock<Scalar> = OnceLock::new();
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn INV_EIGHT() -> Scalar {
|
||||||
|
*INV_EIGHT_CELL.get_or_init(|| Scalar::from(8u8).invert())
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn INV_EIGHT() -> Scalar {
|
||||||
|
Scalar::from(8u8).invert()
|
||||||
|
}
|
||||||
|
|
||||||
|
// On std, we cache this in a static
|
||||||
|
// In no-std environments, we prefer the reduced memory use and calculate it ad-hoc
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
static BASEPOINT_PRECOMP_CELL: OnceLock<VartimeEdwardsPrecomputation> = OnceLock::new();
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn BASEPOINT_PRECOMP() -> &'static VartimeEdwardsPrecomputation {
|
||||||
|
BASEPOINT_PRECOMP_CELL
|
||||||
|
.get_or_init(|| VartimeEdwardsPrecomputation::new([ED25519_BASEPOINT_POINT]))
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn BASEPOINT_PRECOMP() -> VartimeEdwardsPrecomputation {
|
||||||
|
VartimeEdwardsPrecomputation::new([ED25519_BASEPOINT_POINT])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keccak256(data: impl AsRef<[u8]>) -> [u8; 32] {
|
||||||
|
Keccak256::digest(data.as_ref()).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hash the provided data to a scalar via keccak256(data) % l.
|
||||||
|
pub fn keccak256_to_scalar(data: impl AsRef<[u8]>) -> Scalar {
|
||||||
|
let scalar = Scalar::from_bytes_mod_order(keccak256(data.as_ref()));
|
||||||
|
// Monero will explicitly error in this case
|
||||||
|
// This library acknowledges its practical impossibility of it occurring, and doesn't bother to
|
||||||
|
// code in logic to handle it. That said, if it ever occurs, something must happen in order to
|
||||||
|
// not generate/verify a proof we believe to be valid when it isn't
|
||||||
|
assert!(scalar != Scalar::ZERO, "ZERO HASH: {:?}", data.as_ref());
|
||||||
|
scalar
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transparent structure representing a Pedersen commitment's contents.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[derive(Clone, PartialEq, Eq, Zeroize, ZeroizeOnDrop)]
|
||||||
|
pub struct Commitment {
|
||||||
|
pub mask: Scalar,
|
||||||
|
pub amount: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Debug for Commitment {
|
||||||
|
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
|
||||||
|
fmt.debug_struct("Commitment").field("amount", &self.amount).finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Commitment {
|
||||||
|
/// A commitment to zero, defined with a mask of 1 (as to not be the identity).
|
||||||
|
pub fn zero() -> Commitment {
|
||||||
|
Commitment { mask: Scalar::ONE, amount: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(mask: Scalar, amount: u64) -> Commitment {
|
||||||
|
Commitment { mask, amount }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate a Pedersen commitment, as a point, from the transparent structure.
|
||||||
|
pub fn calculate(&self) -> EdwardsPoint {
|
||||||
|
EdwardsPoint::vartime_double_scalar_mul_basepoint(&Scalar::from(self.amount), &H(), &self.mask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decoy data, containing the actual member as well (at index `i`).
|
||||||
|
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
|
||||||
|
pub struct Decoys {
|
||||||
|
pub i: u8,
|
||||||
|
pub offsets: Vec<u64>,
|
||||||
|
pub ring: Vec<[EdwardsPoint; 2]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::len_without_is_empty)]
|
||||||
|
impl Decoys {
|
||||||
|
pub fn fee_weight(offsets: &[u64]) -> usize {
|
||||||
|
varint_len(offsets.len()) + offsets.iter().map(|offset| varint_len(*offset)).sum::<usize>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.offsets.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn indexes(&self) -> Vec<u64> {
|
||||||
|
let mut res = vec![self.offsets[0]; self.len()];
|
||||||
|
for m in 1 .. res.len() {
|
||||||
|
res[m] = res[m - 1] + self.offsets[m];
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
66
coins/monero/ringct/clsag/Cargo.toml
Normal file
66
coins/monero/ringct/clsag/Cargo.toml
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
[package]
|
||||||
|
name = "monero-clsag"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "The CLSAG linkable ring signature, as defined by the Monero protocol"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/serai-dex/serai/tree/develop/coins/monero/ringct/clsag"
|
||||||
|
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.79"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
std-shims = { path = "../../../../common/std-shims", version = "^0.1.1", default-features = false }
|
||||||
|
|
||||||
|
thiserror = { version = "1", default-features = false, optional = true }
|
||||||
|
|
||||||
|
rand_core = { version = "0.6", default-features = false }
|
||||||
|
zeroize = { version = "^1.5", default-features = false, features = ["zeroize_derive"] }
|
||||||
|
subtle = { version = "^2.4", default-features = false }
|
||||||
|
|
||||||
|
# Cryptographic dependencies
|
||||||
|
sha3 = { version = "0.10", default-features = false }
|
||||||
|
curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize"] }
|
||||||
|
|
||||||
|
# Multisig dependencies
|
||||||
|
rand_chacha = { version = "0.3", default-features = false, optional = true }
|
||||||
|
transcript = { package = "flexible-transcript", path = "../../../../crypto/transcript", version = "0.3", default-features = false, features = ["recommended"], optional = true }
|
||||||
|
group = { version = "0.13", default-features = false, optional = true }
|
||||||
|
dalek-ff-group = { path = "../../../../crypto/dalek-ff-group", version = "0.4", default-features = false, optional = true }
|
||||||
|
frost = { package = "modular-frost", path = "../../../../crypto/frost", default-features = false, features = ["ed25519"], optional = true }
|
||||||
|
|
||||||
|
# Other Monero dependencies
|
||||||
|
monero-io = { path = "../../io", version = "0.1", default-features = false }
|
||||||
|
monero-generators = { path = "../../generators", version = "0.4", default-features = false }
|
||||||
|
monero-primitives = { path = "../../primitives", version = "0.1", default-features = false }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
std = [
|
||||||
|
"std-shims/std",
|
||||||
|
|
||||||
|
"thiserror",
|
||||||
|
|
||||||
|
"rand_core/std",
|
||||||
|
"zeroize/std",
|
||||||
|
"subtle/std",
|
||||||
|
|
||||||
|
"sha3/std",
|
||||||
|
"curve25519-dalek/precomputed-tables",
|
||||||
|
|
||||||
|
"rand_chacha?/std",
|
||||||
|
"transcript?/std",
|
||||||
|
"group?/alloc",
|
||||||
|
"dalek-ff-group?/std",
|
||||||
|
|
||||||
|
"monero-io/std",
|
||||||
|
"monero-generators/std",
|
||||||
|
"monero-primitives/std",
|
||||||
|
]
|
||||||
|
multisig = ["rand_chacha", "transcript", "group", "dalek-ff-group", "frost", "std"]
|
||||||
|
default = ["std"]
|
||||||
21
coins/monero/ringct/clsag/LICENSE
Normal file
21
coins/monero/ringct/clsag/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022-2024 Luke Parker
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
6
coins/monero/ringct/clsag/README.md
Normal file
6
coins/monero/ringct/clsag/README.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Monero CLSAG
|
||||||
|
|
||||||
|
The CLSAG linkable ring signature, as defined by the Monero protocol.
|
||||||
|
|
||||||
|
This library is usable under no-std when the `std` feature (on by default) is
|
||||||
|
disabled.
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||||
|
#![doc = include_str!("../README.md")]
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
@@ -18,15 +21,14 @@ use curve25519_dalek::{
|
|||||||
edwards::{EdwardsPoint, VartimeEdwardsPrecomputation},
|
edwards::{EdwardsPoint, VartimeEdwardsPrecomputation},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use monero_io::*;
|
||||||
INV_EIGHT, BASEPOINT_PRECOMP, Commitment, random_scalar, hash_to_scalar, wallet::decoys::Decoys,
|
use monero_generators::hash_to_point;
|
||||||
ringct::hash_to_point, serialize::*,
|
use monero_primitives::{INV_EIGHT, BASEPOINT_PRECOMP, Commitment, Decoys, keccak256_to_scalar};
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "multisig")]
|
#[cfg(feature = "multisig")]
|
||||||
mod multisig;
|
mod multisig;
|
||||||
#[cfg(feature = "multisig")]
|
#[cfg(feature = "multisig")]
|
||||||
pub(crate) use multisig::{ClsagDetails, ClsagAddendum, ClsagMultisig};
|
pub use multisig::{ClsagDetails, ClsagAddendum, ClsagMultisig};
|
||||||
|
|
||||||
/// Errors when working with CLSAGs.
|
/// Errors when working with CLSAGs.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
@@ -59,9 +61,9 @@ pub enum ClsagError {
|
|||||||
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
|
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
|
||||||
pub struct ClsagInput {
|
pub struct ClsagInput {
|
||||||
// The actual commitment for the true spend
|
// The actual commitment for the true spend
|
||||||
pub(crate) commitment: Commitment,
|
pub commitment: Commitment,
|
||||||
// True spend index, offsets, and ring
|
// True spend index, offsets, and ring
|
||||||
pub(crate) decoys: Decoys,
|
pub decoys: Decoys,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClsagInput {
|
impl ClsagInput {
|
||||||
@@ -139,10 +141,10 @@ fn core(
|
|||||||
to_hash.extend(D_INV_EIGHT.compress().to_bytes());
|
to_hash.extend(D_INV_EIGHT.compress().to_bytes());
|
||||||
to_hash.extend(pseudo_out.compress().to_bytes());
|
to_hash.extend(pseudo_out.compress().to_bytes());
|
||||||
// mu_P with agg_0
|
// mu_P with agg_0
|
||||||
let mu_P = hash_to_scalar(&to_hash);
|
let mu_P = keccak256_to_scalar(&to_hash);
|
||||||
// mu_C with agg_1
|
// mu_C with agg_1
|
||||||
to_hash[PREFIX_AGG_0_LEN - 1] = b'1';
|
to_hash[PREFIX_AGG_0_LEN - 1] = b'1';
|
||||||
let mu_C = hash_to_scalar(&to_hash);
|
let mu_C = keccak256_to_scalar(&to_hash);
|
||||||
|
|
||||||
// Truncate it for the round transcript, altering the DST as needed
|
// Truncate it for the round transcript, altering the DST as needed
|
||||||
to_hash.truncate(((2 * n) + 1) * 32);
|
to_hash.truncate(((2 * n) + 1) * 32);
|
||||||
@@ -164,7 +166,7 @@ fn core(
|
|||||||
end = r + n;
|
end = r + n;
|
||||||
to_hash.extend(A.compress().to_bytes());
|
to_hash.extend(A.compress().to_bytes());
|
||||||
to_hash.extend(AH.compress().to_bytes());
|
to_hash.extend(AH.compress().to_bytes());
|
||||||
c = hash_to_scalar(&to_hash);
|
c = keccak256_to_scalar(&to_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mode::Verify(c1) => {
|
Mode::Verify(c1) => {
|
||||||
@@ -190,7 +192,7 @@ fn core(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let PH = hash_to_point(&P[i]);
|
let PH = hash_to_point(P[i].compress().0);
|
||||||
|
|
||||||
// (c_p * I) + (c_c * D) + (s_i * PH)
|
// (c_p * I) + (c_c * D) + (s_i * PH)
|
||||||
let R = match A_c1 {
|
let R = match A_c1 {
|
||||||
@@ -203,7 +205,7 @@ fn core(
|
|||||||
to_hash.truncate(((2 * n) + 3) * 32);
|
to_hash.truncate(((2 * n) + 3) * 32);
|
||||||
to_hash.extend(L.compress().to_bytes());
|
to_hash.extend(L.compress().to_bytes());
|
||||||
to_hash.extend(R.compress().to_bytes());
|
to_hash.extend(R.compress().to_bytes());
|
||||||
c = hash_to_scalar(&to_hash);
|
c = keccak256_to_scalar(&to_hash);
|
||||||
|
|
||||||
// This will only execute once and shouldn't need to be constant time. Making it constant time
|
// This will only execute once and shouldn't need to be constant time. Making it constant time
|
||||||
// removes the risk of branch prediction creating timing differences depending on ring index
|
// removes the risk of branch prediction creating timing differences depending on ring index
|
||||||
@@ -220,7 +222,7 @@ fn core(
|
|||||||
pub struct Clsag {
|
pub struct Clsag {
|
||||||
D: EdwardsPoint,
|
D: EdwardsPoint,
|
||||||
pub(crate) s: Vec<Scalar>,
|
pub(crate) s: Vec<Scalar>,
|
||||||
pub(crate) c1: Scalar,
|
pub c1: Scalar,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ClsagSignCore {
|
pub(crate) struct ClsagSignCore {
|
||||||
@@ -247,11 +249,11 @@ impl Clsag {
|
|||||||
let pseudo_out = Commitment::new(mask, input.commitment.amount).calculate();
|
let pseudo_out = Commitment::new(mask, input.commitment.amount).calculate();
|
||||||
let mask_delta = input.commitment.mask - mask;
|
let mask_delta = input.commitment.mask - mask;
|
||||||
|
|
||||||
let H = hash_to_point(&input.decoys.ring[r][0]);
|
let H = hash_to_point(input.decoys.ring[r][0].compress().0);
|
||||||
let D = H * mask_delta;
|
let D = H * mask_delta;
|
||||||
let mut s = Vec::with_capacity(input.decoys.ring.len());
|
let mut s = Vec::with_capacity(input.decoys.ring.len());
|
||||||
for _ in 0 .. input.decoys.ring.len() {
|
for _ in 0 .. input.decoys.ring.len() {
|
||||||
s.push(random_scalar(rng));
|
s.push(Scalar::random(rng));
|
||||||
}
|
}
|
||||||
let ((D, c_p, c_c), c1) =
|
let ((D, c_p, c_c), c1) =
|
||||||
core(&input.decoys.ring, I, &pseudo_out, msg, &D, &s, &Mode::Sign(r, A, AH));
|
core(&input.decoys.ring, I, &pseudo_out, msg, &D, &s, &Mode::Sign(r, A, AH));
|
||||||
@@ -268,7 +270,7 @@ impl Clsag {
|
|||||||
///
|
///
|
||||||
/// inputs is of the form (private key, key image, input).
|
/// inputs is of the form (private key, key image, input).
|
||||||
/// sum_outputs is for the sum of the outputs' commitment masks.
|
/// sum_outputs is for the sum of the outputs' commitment masks.
|
||||||
pub(crate) fn sign<R: RngCore + CryptoRng>(
|
pub fn sign<R: RngCore + CryptoRng>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
mut inputs: Vec<(Zeroizing<Scalar>, EdwardsPoint, ClsagInput)>,
|
mut inputs: Vec<(Zeroizing<Scalar>, EdwardsPoint, ClsagInput)>,
|
||||||
sum_outputs: Scalar,
|
sum_outputs: Scalar,
|
||||||
@@ -277,14 +279,14 @@ impl Clsag {
|
|||||||
let mut res = Vec::with_capacity(inputs.len());
|
let mut res = Vec::with_capacity(inputs.len());
|
||||||
let mut sum_pseudo_outs = Scalar::ZERO;
|
let mut sum_pseudo_outs = Scalar::ZERO;
|
||||||
for i in 0 .. inputs.len() {
|
for i in 0 .. inputs.len() {
|
||||||
let mut mask = random_scalar(rng);
|
let mut mask = Scalar::random(rng);
|
||||||
if i == (inputs.len() - 1) {
|
if i == (inputs.len() - 1) {
|
||||||
mask = sum_outputs - sum_pseudo_outs;
|
mask = sum_outputs - sum_pseudo_outs;
|
||||||
} else {
|
} else {
|
||||||
sum_pseudo_outs += mask;
|
sum_pseudo_outs += mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut nonce = Zeroizing::new(random_scalar(rng));
|
let mut nonce = Zeroizing::new(Scalar::random(rng));
|
||||||
let ClsagSignCore { mut incomplete_clsag, pseudo_out, key_challenge, challenged_mask } =
|
let ClsagSignCore { mut incomplete_clsag, pseudo_out, key_challenge, challenged_mask } =
|
||||||
Clsag::sign_core(
|
Clsag::sign_core(
|
||||||
rng,
|
rng,
|
||||||
@@ -294,7 +296,9 @@ impl Clsag {
|
|||||||
&msg,
|
&msg,
|
||||||
nonce.deref() * ED25519_BASEPOINT_TABLE,
|
nonce.deref() * ED25519_BASEPOINT_TABLE,
|
||||||
nonce.deref() *
|
nonce.deref() *
|
||||||
hash_to_point(&inputs[i].2.decoys.ring[usize::from(inputs[i].2.decoys.i)][0]),
|
hash_to_point(
|
||||||
|
inputs[i].2.decoys.ring[usize::from(inputs[i].2.decoys.i)][0].compress().0,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
// Effectively r - cx, except cx is (c_p x) + (c_c z), where z is the delta between a ring
|
// Effectively r - cx, except cx is (c_p x) + (c_c z), where z is the delta between a ring
|
||||||
// member's commitment and our input commitment (which will only have a known discrete log
|
// member's commitment and our input commitment (which will only have a known discrete log
|
||||||
@@ -349,7 +353,7 @@ impl Clsag {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn fee_weight(ring_len: usize) -> usize {
|
pub fn fee_weight(ring_len: usize) -> usize {
|
||||||
(ring_len * 32) + 32 + 32
|
(ring_len * 32) + 32 + 32
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,10 +26,9 @@ use frost::{
|
|||||||
algorithm::{WriteAddendum, Algorithm},
|
algorithm::{WriteAddendum, Algorithm},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::ringct::{
|
use monero_generators::hash_to_point;
|
||||||
hash_to_point,
|
|
||||||
clsag::{ClsagInput, Clsag},
|
use crate::{ClsagInput, Clsag};
|
||||||
};
|
|
||||||
|
|
||||||
impl ClsagInput {
|
impl ClsagInput {
|
||||||
fn transcript<T: Transcript>(&self, transcript: &mut T) {
|
fn transcript<T: Transcript>(&self, transcript: &mut T) {
|
||||||
@@ -57,13 +56,13 @@ impl ClsagInput {
|
|||||||
|
|
||||||
/// CLSAG input and the mask to use for it.
|
/// CLSAG input and the mask to use for it.
|
||||||
#[derive(Clone, Debug, Zeroize, ZeroizeOnDrop)]
|
#[derive(Clone, Debug, Zeroize, ZeroizeOnDrop)]
|
||||||
pub(crate) struct ClsagDetails {
|
pub struct ClsagDetails {
|
||||||
input: ClsagInput,
|
input: ClsagInput,
|
||||||
mask: Scalar,
|
mask: Scalar,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClsagDetails {
|
impl ClsagDetails {
|
||||||
pub(crate) fn new(input: ClsagInput, mask: Scalar) -> ClsagDetails {
|
pub fn new(input: ClsagInput, mask: Scalar) -> ClsagDetails {
|
||||||
ClsagDetails { input, mask }
|
ClsagDetails { input, mask }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,7 +70,7 @@ impl ClsagDetails {
|
|||||||
/// Addendum produced during the FROST signing process with relevant data.
|
/// Addendum produced during the FROST signing process with relevant data.
|
||||||
#[derive(Clone, PartialEq, Eq, Zeroize, Debug)]
|
#[derive(Clone, PartialEq, Eq, Zeroize, Debug)]
|
||||||
pub struct ClsagAddendum {
|
pub struct ClsagAddendum {
|
||||||
pub(crate) key_image: dfg::EdwardsPoint,
|
pub key_image: dfg::EdwardsPoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteAddendum for ClsagAddendum {
|
impl WriteAddendum for ClsagAddendum {
|
||||||
@@ -93,10 +92,10 @@ struct Interim {
|
|||||||
/// FROST algorithm for producing a CLSAG signature.
|
/// FROST algorithm for producing a CLSAG signature.
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) struct ClsagMultisig {
|
pub struct ClsagMultisig {
|
||||||
transcript: RecommendedTranscript,
|
transcript: RecommendedTranscript,
|
||||||
|
|
||||||
pub(crate) H: EdwardsPoint,
|
pub H: EdwardsPoint,
|
||||||
key_image_shares: HashMap<[u8; 32], dfg::EdwardsPoint>,
|
key_image_shares: HashMap<[u8; 32], dfg::EdwardsPoint>,
|
||||||
image: Option<dfg::EdwardsPoint>,
|
image: Option<dfg::EdwardsPoint>,
|
||||||
|
|
||||||
@@ -107,7 +106,7 @@ pub(crate) struct ClsagMultisig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ClsagMultisig {
|
impl ClsagMultisig {
|
||||||
pub(crate) fn new(
|
pub fn new(
|
||||||
transcript: RecommendedTranscript,
|
transcript: RecommendedTranscript,
|
||||||
output_key: EdwardsPoint,
|
output_key: EdwardsPoint,
|
||||||
details: Arc<RwLock<Option<ClsagDetails>>>,
|
details: Arc<RwLock<Option<ClsagDetails>>>,
|
||||||
@@ -115,7 +114,7 @@ impl ClsagMultisig {
|
|||||||
ClsagMultisig {
|
ClsagMultisig {
|
||||||
transcript,
|
transcript,
|
||||||
|
|
||||||
H: hash_to_point(&output_key),
|
H: hash_to_point(output_key.compress().0),
|
||||||
key_image_shares: HashMap::new(),
|
key_image_shares: HashMap::new(),
|
||||||
image: None,
|
image: None,
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ mod binaries {
|
|||||||
rpc::{RpcError, Rpc, HttpRpc},
|
rpc::{RpcError, Rpc, HttpRpc},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) use monero_generators::decompress_point;
|
pub(crate) use monero_io::decompress_point;
|
||||||
|
|
||||||
pub(crate) use tokio::task::JoinHandle;
|
pub(crate) use tokio::task::JoinHandle;
|
||||||
|
|
||||||
|
|||||||
@@ -6,26 +6,21 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use std_shims::{sync::OnceLock, io};
|
use std_shims::io;
|
||||||
|
|
||||||
use rand_core::{RngCore, CryptoRng};
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
|
||||||
|
|
||||||
use sha3::{Digest, Keccak256};
|
use sha3::{Digest, Keccak256};
|
||||||
|
|
||||||
use curve25519_dalek::{
|
use curve25519_dalek::scalar::Scalar;
|
||||||
constants::{ED25519_BASEPOINT_TABLE, ED25519_BASEPOINT_POINT},
|
|
||||||
scalar::Scalar,
|
|
||||||
edwards::{EdwardsPoint, VartimeEdwardsPrecomputation},
|
|
||||||
traits::VartimePrecomputedMultiscalarMul,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use monero_generators::{H, decompress_point};
|
pub use monero_io::decompress_point;
|
||||||
|
pub use monero_generators::H;
|
||||||
|
pub use monero_primitives::INV_EIGHT;
|
||||||
|
|
||||||
mod merkle;
|
mod merkle;
|
||||||
|
|
||||||
mod serialize;
|
use monero_io as serialize;
|
||||||
use serialize::{read_byte, read_u16};
|
use serialize::{read_byte, read_u16};
|
||||||
|
|
||||||
/// UnreducedScalar struct with functionality for recovering incorrectly reduced scalars.
|
/// UnreducedScalar struct with functionality for recovering incorrectly reduced scalars.
|
||||||
@@ -55,19 +50,6 @@ pub const DEFAULT_LOCK_WINDOW: usize = 10;
|
|||||||
pub const COINBASE_LOCK_WINDOW: usize = 60;
|
pub const COINBASE_LOCK_WINDOW: usize = 60;
|
||||||
pub const BLOCK_TIME: usize = 120;
|
pub const BLOCK_TIME: usize = 120;
|
||||||
|
|
||||||
static INV_EIGHT_CELL: OnceLock<Scalar> = OnceLock::new();
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
pub(crate) fn INV_EIGHT() -> Scalar {
|
|
||||||
*INV_EIGHT_CELL.get_or_init(|| Scalar::from(8u8).invert())
|
|
||||||
}
|
|
||||||
|
|
||||||
static BASEPOINT_PRECOMP_CELL: OnceLock<VartimeEdwardsPrecomputation> = OnceLock::new();
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
pub(crate) fn BASEPOINT_PRECOMP() -> &'static VartimeEdwardsPrecomputation {
|
|
||||||
BASEPOINT_PRECOMP_CELL
|
|
||||||
.get_or_init(|| VartimeEdwardsPrecomputation::new([ED25519_BASEPOINT_POINT]))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Monero protocol version.
|
/// Monero protocol version.
|
||||||
///
|
///
|
||||||
/// v15 is omitted as v15 was simply v14 and v16 being active at the same time, with regards to the
|
/// v15 is omitted as v15 was simply v14 and v16 being active at the same time, with regards to the
|
||||||
@@ -188,42 +170,7 @@ impl Protocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transparent structure representing a Pedersen commitment's contents.
|
pub use monero_primitives::Commitment;
|
||||||
#[allow(non_snake_case)]
|
|
||||||
#[derive(Clone, PartialEq, Eq, Zeroize, ZeroizeOnDrop)]
|
|
||||||
pub struct Commitment {
|
|
||||||
pub mask: Scalar,
|
|
||||||
pub amount: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::fmt::Debug for Commitment {
|
|
||||||
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
|
|
||||||
fmt.debug_struct("Commitment").field("amount", &self.amount).finish_non_exhaustive()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Commitment {
|
|
||||||
/// A commitment to zero, defined with a mask of 1 (as to not be the identity).
|
|
||||||
pub fn zero() -> Commitment {
|
|
||||||
Commitment { mask: Scalar::ONE, amount: 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(mask: Scalar, amount: u64) -> Commitment {
|
|
||||||
Commitment { mask, amount }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate a Pedersen commitment, as a point, from the transparent structure.
|
|
||||||
pub fn calculate(&self) -> EdwardsPoint {
|
|
||||||
(&self.mask * ED25519_BASEPOINT_TABLE) + (Scalar::from(self.amount) * H())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Support generating a random scalar using a modern rand, as dalek's is notoriously dated.
|
|
||||||
pub fn random_scalar<R: RngCore + CryptoRng>(rng: &mut R) -> Scalar {
|
|
||||||
let mut r = [0; 64];
|
|
||||||
rng.fill_bytes(&mut r);
|
|
||||||
Scalar::from_bytes_mod_order_wide(&r)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn hash(data: &[u8]) -> [u8; 32] {
|
pub(crate) fn hash(data: &[u8]) -> [u8; 32] {
|
||||||
Keccak256::digest(data).into()
|
Keccak256::digest(data).into()
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ pub use hash_to_point::{raw_hash_to_point, hash_to_point};
|
|||||||
/// MLSAG struct, along with verifying functionality.
|
/// MLSAG struct, along with verifying functionality.
|
||||||
pub mod mlsag;
|
pub mod mlsag;
|
||||||
/// CLSAG struct, along with signing and verifying functionality.
|
/// CLSAG struct, along with signing and verifying functionality.
|
||||||
pub mod clsag;
|
pub use monero_clsag as clsag;
|
||||||
/// BorromeanRange struct, along with verifying functionality.
|
/// BorromeanRange struct, along with verifying functionality.
|
||||||
pub mod borromean;
|
pub mod borromean;
|
||||||
/// Bulletproofs(+) structs, along with proving and verifying functionality.
|
/// Bulletproofs(+) structs, along with proving and verifying functionality.
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use async_trait::async_trait;
|
|||||||
|
|
||||||
use curve25519_dalek::edwards::EdwardsPoint;
|
use curve25519_dalek::edwards::EdwardsPoint;
|
||||||
|
|
||||||
use monero_generators::decompress_point;
|
use monero_io::decompress_point;
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize, de::DeserializeOwned};
|
use serde::{Serialize, Deserialize, de::DeserializeOwned};
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
|
|||||||
@@ -2,14 +2,11 @@ use hex_literal::hex;
|
|||||||
|
|
||||||
use rand_core::{RngCore, OsRng};
|
use rand_core::{RngCore, OsRng};
|
||||||
|
|
||||||
use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE;
|
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar};
|
||||||
|
|
||||||
use monero_generators::decompress_point;
|
use monero_io::decompress_point;
|
||||||
|
|
||||||
use crate::{
|
use crate::wallet::address::{Network, AddressType, AddressMeta, MoneroAddress};
|
||||||
random_scalar,
|
|
||||||
wallet::address::{Network, AddressType, AddressMeta, MoneroAddress},
|
|
||||||
};
|
|
||||||
|
|
||||||
const SPEND: [u8; 32] = hex!("f8631661f6ab4e6fda310c797330d86e23a682f20d5bc8cc27b18051191f16d7");
|
const SPEND: [u8; 32] = hex!("f8631661f6ab4e6fda310c797330d86e23a682f20d5bc8cc27b18051191f16d7");
|
||||||
const VIEW: [u8; 32] = hex!("4a1535063ad1fee2dabbf909d4fd9a873e29541b401f0944754e17c9a41820ce");
|
const VIEW: [u8; 32] = hex!("4a1535063ad1fee2dabbf909d4fd9a873e29541b401f0944754e17c9a41820ce");
|
||||||
@@ -75,8 +72,8 @@ fn featured() {
|
|||||||
[(Network::Mainnet, 'C'), (Network::Testnet, 'K'), (Network::Stagenet, 'F')]
|
[(Network::Mainnet, 'C'), (Network::Testnet, 'K'), (Network::Stagenet, 'F')]
|
||||||
{
|
{
|
||||||
for _ in 0 .. 100 {
|
for _ in 0 .. 100 {
|
||||||
let spend = &random_scalar(&mut OsRng) * ED25519_BASEPOINT_TABLE;
|
let spend = &Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE;
|
||||||
let view = &random_scalar(&mut OsRng) * ED25519_BASEPOINT_TABLE;
|
let view = &Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE;
|
||||||
|
|
||||||
for features in 0 .. (1 << 3) {
|
for features in 0 .. (1 << 3) {
|
||||||
const SUBADDRESS_FEATURE_BIT: u8 = 1;
|
const SUBADDRESS_FEATURE_BIT: u8 = 1;
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ use hex_literal::hex;
|
|||||||
use rand_core::OsRng;
|
use rand_core::OsRng;
|
||||||
|
|
||||||
use curve25519_dalek::scalar::Scalar;
|
use curve25519_dalek::scalar::Scalar;
|
||||||
use monero_generators::decompress_point;
|
use monero_io::decompress_point;
|
||||||
use multiexp::BatchVerifier;
|
use multiexp::BatchVerifier;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Commitment, random_scalar,
|
Commitment,
|
||||||
ringct::bulletproofs::{Bulletproof, original::OriginalStruct},
|
ringct::bulletproofs::{Bulletproof, original::OriginalStruct},
|
||||||
wallet::TransactionError,
|
wallet::TransactionError,
|
||||||
};
|
};
|
||||||
@@ -68,7 +68,7 @@ macro_rules! bulletproofs_tests {
|
|||||||
let mut verifier = BatchVerifier::new(16);
|
let mut verifier = BatchVerifier::new(16);
|
||||||
for i in 1 ..= 16 {
|
for i in 1 ..= 16 {
|
||||||
let commitments = (1 ..= i)
|
let commitments = (1 ..= i)
|
||||||
.map(|i| Commitment::new(random_scalar(&mut OsRng), u64::try_from(i).unwrap()))
|
.map(|i| Commitment::new(Scalar::random(&mut OsRng), u64::try_from(i).unwrap()))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let bp = if $plus {
|
let bp = if $plus {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use transcript::{Transcript, RecommendedTranscript};
|
|||||||
use frost::curve::Ed25519;
|
use frost::curve::Ed25519;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Commitment, random_scalar,
|
Commitment,
|
||||||
wallet::Decoys,
|
wallet::Decoys,
|
||||||
ringct::{
|
ringct::{
|
||||||
generate_key_image,
|
generate_key_image,
|
||||||
@@ -43,8 +43,8 @@ fn clsag() {
|
|||||||
let mut secrets = (Zeroizing::new(Scalar::ZERO), Scalar::ZERO);
|
let mut secrets = (Zeroizing::new(Scalar::ZERO), Scalar::ZERO);
|
||||||
let mut ring = vec![];
|
let mut ring = vec![];
|
||||||
for i in 0 .. RING_LEN {
|
for i in 0 .. RING_LEN {
|
||||||
let dest = Zeroizing::new(random_scalar(&mut OsRng));
|
let dest = Zeroizing::new(Scalar::random(&mut OsRng));
|
||||||
let mask = random_scalar(&mut OsRng);
|
let mask = Scalar::random(&mut OsRng);
|
||||||
let amount;
|
let amount;
|
||||||
if i == real {
|
if i == real {
|
||||||
secrets = (dest.clone(), mask);
|
secrets = (dest.clone(), mask);
|
||||||
@@ -72,7 +72,7 @@ fn clsag() {
|
|||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)],
|
)],
|
||||||
random_scalar(&mut OsRng),
|
Scalar::random(&mut OsRng),
|
||||||
msg,
|
msg,
|
||||||
)
|
)
|
||||||
.swap_remove(0);
|
.swap_remove(0);
|
||||||
@@ -80,7 +80,7 @@ fn clsag() {
|
|||||||
clsag.verify(&ring, &image, &pseudo_out, &msg).unwrap();
|
clsag.verify(&ring, &image, &pseudo_out, &msg).unwrap();
|
||||||
|
|
||||||
// make sure verification fails if we throw a random `c1` at it.
|
// make sure verification fails if we throw a random `c1` at it.
|
||||||
clsag.c1 = random_scalar(&mut OsRng);
|
clsag.c1 = Scalar::random(&mut OsRng);
|
||||||
assert!(clsag.verify(&ring, &image, &pseudo_out, &msg).is_err());
|
assert!(clsag.verify(&ring, &image, &pseudo_out, &msg).is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,15 +90,15 @@ fn clsag() {
|
|||||||
fn clsag_multisig() {
|
fn clsag_multisig() {
|
||||||
let keys = key_gen::<_, Ed25519>(&mut OsRng);
|
let keys = key_gen::<_, Ed25519>(&mut OsRng);
|
||||||
|
|
||||||
let randomness = random_scalar(&mut OsRng);
|
let randomness = Scalar::random(&mut OsRng);
|
||||||
let mut ring = vec![];
|
let mut ring = vec![];
|
||||||
for i in 0 .. RING_LEN {
|
for i in 0 .. RING_LEN {
|
||||||
let dest;
|
let dest;
|
||||||
let mask;
|
let mask;
|
||||||
let amount;
|
let amount;
|
||||||
if i != u64::from(RING_INDEX) {
|
if i != u64::from(RING_INDEX) {
|
||||||
dest = &random_scalar(&mut OsRng) * ED25519_BASEPOINT_TABLE;
|
dest = &Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE;
|
||||||
mask = random_scalar(&mut OsRng);
|
mask = Scalar::random(&mut OsRng);
|
||||||
amount = OsRng.next_u64();
|
amount = OsRng.next_u64();
|
||||||
} else {
|
} else {
|
||||||
dest = keys[&Participant::new(1).unwrap()].group_key().0;
|
dest = keys[&Participant::new(1).unwrap()].group_key().0;
|
||||||
@@ -108,7 +108,7 @@ fn clsag_multisig() {
|
|||||||
ring.push([dest, Commitment::new(mask, amount).calculate()]);
|
ring.push([dest, Commitment::new(mask, amount).calculate()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mask_sum = random_scalar(&mut OsRng);
|
let mask_sum = Scalar::random(&mut OsRng);
|
||||||
let algorithm = ClsagMultisig::new(
|
let algorithm = ClsagMultisig::new(
|
||||||
RecommendedTranscript::new(b"Monero Serai CLSAG Test"),
|
RecommendedTranscript::new(b"Monero Serai CLSAG Test"),
|
||||||
keys[&Participant::new(1).unwrap()].group_key().0,
|
keys[&Participant::new(1).unwrap()].group_key().0,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use zeroize::Zeroize;
|
|||||||
|
|
||||||
use curve25519_dalek::edwards::EdwardsPoint;
|
use curve25519_dalek::edwards::EdwardsPoint;
|
||||||
|
|
||||||
use monero_generators::decompress_point;
|
use monero_io::decompress_point;
|
||||||
|
|
||||||
use base58_monero::base58::{encode_check, decode_check};
|
use base58_monero::base58::{encode_check, decode_check};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std_shims::{vec::Vec, collections::HashSet};
|
use std_shims::{vec::Vec, collections::HashSet};
|
||||||
|
|
||||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
use rand_core::{RngCore, CryptoRng};
|
use rand_core::{RngCore, CryptoRng};
|
||||||
use rand_distr::{Distribution, Gamma};
|
use rand_distr::{Distribution, Gamma};
|
||||||
@@ -10,7 +10,6 @@ use rand_distr::num_traits::Float;
|
|||||||
use curve25519_dalek::edwards::EdwardsPoint;
|
use curve25519_dalek::edwards::EdwardsPoint;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
serialize::varint_len,
|
|
||||||
wallet::SpendableOutput,
|
wallet::SpendableOutput,
|
||||||
rpc::{RpcError, RpcConnection, Rpc},
|
rpc::{RpcError, RpcConnection, Rpc},
|
||||||
DEFAULT_LOCK_WINDOW, COINBASE_LOCK_WINDOW, BLOCK_TIME,
|
DEFAULT_LOCK_WINDOW, COINBASE_LOCK_WINDOW, BLOCK_TIME,
|
||||||
@@ -272,35 +271,38 @@ async fn select_decoys<R: RngCore + CryptoRng, RPC: RpcConnection>(
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decoy data, containing the actual member as well (at index `i`).
|
pub use monero_primitives::Decoys;
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
|
|
||||||
pub struct Decoys {
|
// TODO: Remove this trait
|
||||||
pub(crate) i: u8,
|
#[cfg(feature = "std")]
|
||||||
pub(crate) offsets: Vec<u64>,
|
#[async_trait::async_trait]
|
||||||
pub(crate) ring: Vec<[EdwardsPoint; 2]>,
|
pub trait DecoySelection {
|
||||||
|
async fn select<R: Send + Sync + RngCore + CryptoRng, RPC: Send + Sync + RpcConnection>(
|
||||||
|
rng: &mut R,
|
||||||
|
rpc: &Rpc<RPC>,
|
||||||
|
ring_len: usize,
|
||||||
|
height: usize,
|
||||||
|
inputs: &[SpendableOutput],
|
||||||
|
) -> Result<Vec<Decoys>, RpcError>;
|
||||||
|
|
||||||
|
async fn fingerprintable_canonical_select<
|
||||||
|
R: Send + Sync + RngCore + CryptoRng,
|
||||||
|
RPC: Send + Sync + RpcConnection,
|
||||||
|
>(
|
||||||
|
rng: &mut R,
|
||||||
|
rpc: &Rpc<RPC>,
|
||||||
|
ring_len: usize,
|
||||||
|
height: usize,
|
||||||
|
inputs: &[SpendableOutput],
|
||||||
|
) -> Result<Vec<Decoys>, RpcError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::len_without_is_empty)]
|
#[cfg(feature = "std")]
|
||||||
impl Decoys {
|
#[async_trait::async_trait]
|
||||||
pub fn fee_weight(offsets: &[u64]) -> usize {
|
impl DecoySelection for Decoys {
|
||||||
varint_len(offsets.len()) + offsets.iter().map(|offset| varint_len(*offset)).sum::<usize>()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.offsets.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn indexes(&self) -> Vec<u64> {
|
|
||||||
let mut res = vec![self.offsets[0]; self.len()];
|
|
||||||
for m in 1 .. res.len() {
|
|
||||||
res[m] = res[m - 1] + self.offsets[m];
|
|
||||||
}
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Select decoys using the same distribution as Monero. Relies on the monerod RPC
|
/// Select decoys using the same distribution as Monero. Relies on the monerod RPC
|
||||||
/// response for an output's unlocked status, minimizing trips to the daemon.
|
/// response for an output's unlocked status, minimizing trips to the daemon.
|
||||||
pub async fn select<R: RngCore + CryptoRng, RPC: RpcConnection>(
|
async fn select<R: Send + Sync + RngCore + CryptoRng, RPC: Send + Sync + RpcConnection>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
rpc: &Rpc<RPC>,
|
rpc: &Rpc<RPC>,
|
||||||
ring_len: usize,
|
ring_len: usize,
|
||||||
@@ -318,7 +320,10 @@ impl Decoys {
|
|||||||
///
|
///
|
||||||
/// TODO: upstream change to monerod get_outs RPC to accept a height param for checking
|
/// TODO: upstream change to monerod get_outs RPC to accept a height param for checking
|
||||||
/// output's unlocked status and remove all usage of fingerprintable_canonical
|
/// output's unlocked status and remove all usage of fingerprintable_canonical
|
||||||
pub async fn fingerprintable_canonical_select<R: RngCore + CryptoRng, RPC: RpcConnection>(
|
async fn fingerprintable_canonical_select<
|
||||||
|
R: Send + Sync + RngCore + CryptoRng,
|
||||||
|
RPC: Send + Sync + RpcConnection,
|
||||||
|
>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
rpc: &Rpc<RPC>,
|
rpc: &Rpc<RPC>,
|
||||||
ring_len: usize,
|
ring_len: usize,
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ use curve25519_dalek::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
hash, hash_to_scalar, serialize::write_varint, Commitment, ringct::EncryptedAmount, transaction::Input,
|
hash, hash_to_scalar, serialize::write_varint, Commitment, ringct::EncryptedAmount,
|
||||||
|
transaction::Input,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod extra;
|
pub mod extra;
|
||||||
@@ -26,8 +27,14 @@ use address::{Network, AddressType, SubaddressIndex, AddressSpec, AddressMeta, M
|
|||||||
mod scan;
|
mod scan;
|
||||||
pub use scan::{ReceivedOutput, SpendableOutput, Timelocked};
|
pub use scan::{ReceivedOutput, SpendableOutput, Timelocked};
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
pub mod decoys;
|
pub mod decoys;
|
||||||
pub use decoys::Decoys;
|
#[cfg(not(feature = "std"))]
|
||||||
|
pub mod decoys {
|
||||||
|
pub use monero_primitives::Decoys;
|
||||||
|
pub trait DecoySelection {}
|
||||||
|
}
|
||||||
|
pub use decoys::{DecoySelection, Decoys};
|
||||||
|
|
||||||
mod send;
|
mod send;
|
||||||
pub use send::{FeePriority, Fee, TransactionError, Change, SignableTransaction, Eventuality};
|
pub use send::{FeePriority, Fee, TransactionError, Change, SignableTransaction, Eventuality};
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use zeroize::{Zeroize, ZeroizeOnDrop};
|
|||||||
|
|
||||||
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwards::EdwardsPoint};
|
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwards::EdwardsPoint};
|
||||||
|
|
||||||
use monero_generators::decompress_point;
|
use monero_io::decompress_point;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Commitment,
|
Commitment,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use rand_core::{RngCore, CryptoRng};
|
|||||||
|
|
||||||
use curve25519_dalek::scalar::Scalar;
|
use curve25519_dalek::scalar::Scalar;
|
||||||
|
|
||||||
use crate::{random_scalar, wallet::seed::SeedError};
|
use crate::wallet::seed::SeedError;
|
||||||
|
|
||||||
pub(crate) const CLASSIC_SEED_LENGTH: usize = 24;
|
pub(crate) const CLASSIC_SEED_LENGTH: usize = 24;
|
||||||
pub(crate) const CLASSIC_SEED_LENGTH_WITH_CHECKSUM: usize = 25;
|
pub(crate) const CLASSIC_SEED_LENGTH_WITH_CHECKSUM: usize = 25;
|
||||||
@@ -276,7 +276,7 @@ pub(crate) fn seed_to_bytes(lang: Language, words: &str) -> Result<Zeroizing<[u8
|
|||||||
pub struct ClassicSeed(Language, Zeroizing<String>);
|
pub struct ClassicSeed(Language, Zeroizing<String>);
|
||||||
impl ClassicSeed {
|
impl ClassicSeed {
|
||||||
pub(crate) fn new<R: RngCore + CryptoRng>(rng: &mut R, lang: Language) -> ClassicSeed {
|
pub(crate) fn new<R: RngCore + CryptoRng>(rng: &mut R, lang: Language) -> ClassicSeed {
|
||||||
key_to_seed(lang, Zeroizing::new(random_scalar(rng)))
|
key_to_seed(lang, Zeroizing::new(Scalar::random(rng)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_pass_by_value)]
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use dalek_ff_group as dfg;
|
|||||||
use frost::FrostError;
|
use frost::FrostError;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Protocol, Commitment, hash, random_scalar,
|
Protocol, Commitment, hash,
|
||||||
serialize::{
|
serialize::{
|
||||||
read_byte, read_bytes, read_u64, read_scalar, read_point, read_vec, write_byte, write_scalar,
|
read_byte, read_bytes, read_u64, read_scalar, read_point, read_vec, write_byte, write_scalar,
|
||||||
write_point, write_raw_vec, write_vec,
|
write_point, write_raw_vec, write_vec,
|
||||||
@@ -616,7 +616,7 @@ impl SignableTransaction {
|
|||||||
payments.shuffle(&mut rng);
|
payments.shuffle(&mut rng);
|
||||||
|
|
||||||
// Used for all non-subaddress outputs, or if there's only one subaddress output and a change
|
// Used for all non-subaddress outputs, or if there's only one subaddress output and a change
|
||||||
let tx_key = Zeroizing::new(random_scalar(&mut rng));
|
let tx_key = Zeroizing::new(Scalar::random(&mut rng));
|
||||||
let mut tx_public_key = tx_key.deref() * ED25519_BASEPOINT_TABLE;
|
let mut tx_public_key = tx_key.deref() * ED25519_BASEPOINT_TABLE;
|
||||||
|
|
||||||
// If any of these outputs are to a subaddress, we need keys distinct to them
|
// If any of these outputs are to a subaddress, we need keys distinct to them
|
||||||
@@ -660,7 +660,7 @@ impl SignableTransaction {
|
|||||||
let (output, payment_id) = match payment {
|
let (output, payment_id) = match payment {
|
||||||
InternalPayment::Payment(payment, need_dummy_payment_id) => {
|
InternalPayment::Payment(payment, need_dummy_payment_id) => {
|
||||||
// If this is a subaddress, generate a dedicated r. Else, reuse the TX key
|
// If this is a subaddress, generate a dedicated r. Else, reuse the TX key
|
||||||
let dedicated = Zeroizing::new(random_scalar(&mut rng));
|
let dedicated = Zeroizing::new(Scalar::random(&mut rng));
|
||||||
let use_dedicated = additional && payment.0.is_subaddress();
|
let use_dedicated = additional && payment.0.is_subaddress();
|
||||||
let r = if use_dedicated { &dedicated } else { &tx_key };
|
let r = if use_dedicated { &dedicated } else { &tx_key };
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ use frost::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
random_scalar,
|
|
||||||
ringct::{
|
ringct::{
|
||||||
clsag::{ClsagInput, ClsagDetails, ClsagAddendum, ClsagMultisig},
|
clsag::{ClsagInput, ClsagDetails, ClsagAddendum, ClsagMultisig},
|
||||||
RctPrunable,
|
RctPrunable,
|
||||||
@@ -348,7 +347,7 @@ impl SignMachine<Transaction> for TransactionSignMachine {
|
|||||||
while !sorted.is_empty() {
|
while !sorted.is_empty() {
|
||||||
let value = sorted.remove(0);
|
let value = sorted.remove(0);
|
||||||
|
|
||||||
let mut mask = random_scalar(&mut rng);
|
let mut mask = Scalar::random(&mut rng);
|
||||||
if sorted.is_empty() {
|
if sorted.is_empty() {
|
||||||
mask = output_masks - sum_pseudo_outs;
|
mask = output_masks - sum_pseudo_outs;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar};
|
|||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use monero_serai::{
|
use monero_serai::{
|
||||||
random_scalar,
|
|
||||||
rpc::{HttpRpc, Rpc},
|
rpc::{HttpRpc, Rpc},
|
||||||
wallet::{
|
wallet::{
|
||||||
ViewPair, Scanner,
|
ViewPair, Scanner,
|
||||||
@@ -21,9 +20,9 @@ use monero_serai::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn random_address() -> (Scalar, ViewPair, MoneroAddress) {
|
pub fn random_address() -> (Scalar, ViewPair, MoneroAddress) {
|
||||||
let spend = random_scalar(&mut OsRng);
|
let spend = Scalar::random(&mut OsRng);
|
||||||
let spend_pub = &spend * ED25519_BASEPOINT_TABLE;
|
let spend_pub = &spend * ED25519_BASEPOINT_TABLE;
|
||||||
let view = Zeroizing::new(random_scalar(&mut OsRng));
|
let view = Zeroizing::new(Scalar::random(&mut OsRng));
|
||||||
(
|
(
|
||||||
spend,
|
spend,
|
||||||
ViewPair::new(spend_pub, view.clone()),
|
ViewPair::new(spend_pub, view.clone()),
|
||||||
@@ -103,8 +102,8 @@ pub async fn rpc() -> Rpc<HttpRpc> {
|
|||||||
|
|
||||||
let addr = MoneroAddress {
|
let addr = MoneroAddress {
|
||||||
meta: AddressMeta::new(Network::Mainnet, AddressType::Standard),
|
meta: AddressMeta::new(Network::Mainnet, AddressType::Standard),
|
||||||
spend: &random_scalar(&mut OsRng) * ED25519_BASEPOINT_TABLE,
|
spend: &Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE,
|
||||||
view: &random_scalar(&mut OsRng) * ED25519_BASEPOINT_TABLE,
|
view: &Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE,
|
||||||
}
|
}
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
@@ -161,7 +160,7 @@ macro_rules! test {
|
|||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
use rand_core::OsRng;
|
use rand_core::OsRng;
|
||||||
|
|
||||||
use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE;
|
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar};
|
||||||
|
|
||||||
#[cfg(feature = "multisig")]
|
#[cfg(feature = "multisig")]
|
||||||
use transcript::{Transcript, RecommendedTranscript};
|
use transcript::{Transcript, RecommendedTranscript};
|
||||||
@@ -173,9 +172,9 @@ macro_rules! test {
|
|||||||
};
|
};
|
||||||
|
|
||||||
use monero_serai::{
|
use monero_serai::{
|
||||||
random_scalar,
|
|
||||||
wallet::{
|
wallet::{
|
||||||
address::{Network, AddressSpec}, ViewPair, Scanner, Change, Decoys, FeePriority,
|
address::{Network, AddressSpec},
|
||||||
|
ViewPair, Scanner, Change, DecoySelection, Decoys, FeePriority,
|
||||||
SignableTransaction, SignableTransactionBuilder,
|
SignableTransaction, SignableTransactionBuilder,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -196,7 +195,7 @@ macro_rules! test {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let spend = Zeroizing::new(random_scalar(&mut OsRng));
|
let spend = Zeroizing::new(Scalar::random(&mut OsRng));
|
||||||
#[cfg(feature = "multisig")]
|
#[cfg(feature = "multisig")]
|
||||||
let keys = key_gen::<_, Ed25519>(&mut OsRng);
|
let keys = key_gen::<_, Ed25519>(&mut OsRng);
|
||||||
|
|
||||||
@@ -211,7 +210,7 @@ macro_rules! test {
|
|||||||
|
|
||||||
let rpc = rpc().await;
|
let rpc = rpc().await;
|
||||||
|
|
||||||
let view = ViewPair::new(spend_pub, Zeroizing::new(random_scalar(&mut OsRng)));
|
let view = ViewPair::new(spend_pub, Zeroizing::new(Scalar::random(&mut OsRng)));
|
||||||
let addr = view.address(Network::Mainnet, AddressSpec::Standard);
|
let addr = view.address(Network::Mainnet, AddressSpec::Standard);
|
||||||
|
|
||||||
let miner_tx = get_miner_tx_output(&rpc, &view).await;
|
let miner_tx = get_miner_tx_output(&rpc, &view).await;
|
||||||
@@ -223,8 +222,8 @@ macro_rules! test {
|
|||||||
rpc.get_fee(protocol, FeePriority::Unimportant).await.unwrap(),
|
rpc.get_fee(protocol, FeePriority::Unimportant).await.unwrap(),
|
||||||
Change::new(
|
Change::new(
|
||||||
&ViewPair::new(
|
&ViewPair::new(
|
||||||
&random_scalar(&mut OsRng) * ED25519_BASEPOINT_TABLE,
|
&Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE,
|
||||||
Zeroizing::new(random_scalar(&mut OsRng))
|
Zeroizing::new(Scalar::random(&mut OsRng))
|
||||||
),
|
),
|
||||||
false
|
false
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ use rand_core::OsRng;
|
|||||||
use monero_serai::{
|
use monero_serai::{
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
wallet::{
|
wallet::{
|
||||||
extra::Extra, address::SubaddressIndex, ReceivedOutput, SpendableOutput, Decoys,
|
extra::Extra, address::SubaddressIndex, ReceivedOutput, SpendableOutput, DecoySelection,
|
||||||
SignableTransactionBuilder,
|
Decoys, SignableTransactionBuilder,
|
||||||
},
|
},
|
||||||
rpc::{Rpc, HttpRpc},
|
rpc::{Rpc, HttpRpc},
|
||||||
Protocol,
|
Protocol,
|
||||||
@@ -104,8 +104,8 @@ test!(
|
|||||||
use monero_serai::wallet::FeePriority;
|
use monero_serai::wallet::FeePriority;
|
||||||
|
|
||||||
let change_view = ViewPair::new(
|
let change_view = ViewPair::new(
|
||||||
&random_scalar(&mut OsRng) * ED25519_BASEPOINT_TABLE,
|
&Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE,
|
||||||
Zeroizing::new(random_scalar(&mut OsRng)),
|
Zeroizing::new(Scalar::random(&mut OsRng)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut builder = SignableTransactionBuilder::new(
|
let mut builder = SignableTransactionBuilder::new(
|
||||||
@@ -117,8 +117,8 @@ test!(
|
|||||||
|
|
||||||
// Send to a subaddress
|
// Send to a subaddress
|
||||||
let sub_view = ViewPair::new(
|
let sub_view = ViewPair::new(
|
||||||
&random_scalar(&mut OsRng) * ED25519_BASEPOINT_TABLE,
|
&Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE,
|
||||||
Zeroizing::new(random_scalar(&mut OsRng)),
|
Zeroizing::new(Scalar::random(&mut OsRng)),
|
||||||
);
|
);
|
||||||
builder.add_payment(
|
builder.add_payment(
|
||||||
sub_view
|
sub_view
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ use monero_serai::{
|
|||||||
wallet::{
|
wallet::{
|
||||||
ViewPair, Scanner,
|
ViewPair, Scanner,
|
||||||
address::{Network as MoneroNetwork, SubaddressIndex, AddressSpec},
|
address::{Network as MoneroNetwork, SubaddressIndex, AddressSpec},
|
||||||
Fee, SpendableOutput, Change, Decoys, TransactionError,
|
Fee, SpendableOutput, Change, DecoySelection, Decoys, TransactionError,
|
||||||
SignableTransaction as MSignableTransaction, Eventuality, TransactionMachine,
|
SignableTransaction as MSignableTransaction, Eventuality, TransactionMachine,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -349,7 +349,7 @@ async fn mint_and_burn_test() {
|
|||||||
Protocol,
|
Protocol,
|
||||||
transaction::Timelock,
|
transaction::Timelock,
|
||||||
wallet::{
|
wallet::{
|
||||||
ViewPair, Scanner, Decoys, Change, FeePriority, SignableTransaction,
|
ViewPair, Scanner, DecoySelection, Decoys, Change, FeePriority, SignableTransaction,
|
||||||
address::{Network, AddressType, AddressMeta, MoneroAddress},
|
address::{Network, AddressType, AddressMeta, MoneroAddress},
|
||||||
},
|
},
|
||||||
decompress_point,
|
decompress_point,
|
||||||
|
|||||||
@@ -35,5 +35,8 @@ dkg = { path = "../../crypto/dkg", default-features = false }
|
|||||||
|
|
||||||
bitcoin-serai = { path = "../../coins/bitcoin", default-features = false, features = ["hazmat"] }
|
bitcoin-serai = { path = "../../coins/bitcoin", default-features = false, features = ["hazmat"] }
|
||||||
|
|
||||||
|
monero-io = { path = "../../coins/monero/io", default-features = false }
|
||||||
monero-generators = { path = "../../coins/monero/generators", default-features = false }
|
monero-generators = { path = "../../coins/monero/generators", default-features = false }
|
||||||
|
monero-primitives = { path = "../../coins/monero/primitives", default-features = false }
|
||||||
|
monero-clsag = { path = "../../coins/monero/ringct/clsag", default-features = false }
|
||||||
monero-serai = { path = "../../coins/monero", default-features = false }
|
monero-serai = { path = "../../coins/monero", default-features = false }
|
||||||
|
|||||||
@@ -440,7 +440,8 @@ impl Wallet {
|
|||||||
Protocol,
|
Protocol,
|
||||||
wallet::{
|
wallet::{
|
||||||
address::{Network, AddressType, AddressMeta, Address},
|
address::{Network, AddressType, AddressMeta, Address},
|
||||||
SpendableOutput, Decoys, Change, FeePriority, Scanner, SignableTransaction,
|
SpendableOutput, DecoySelection, Decoys, Change, FeePriority, Scanner,
|
||||||
|
SignableTransaction,
|
||||||
},
|
},
|
||||||
rpc::HttpRpc,
|
rpc::HttpRpc,
|
||||||
decompress_point,
|
decompress_point,
|
||||||
|
|||||||
Reference in New Issue
Block a user