mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-09 04:39:24 +00:00
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "monero-serai"
|
||||
version = "0.1.1-alpha"
|
||||
version = "0.1.2-alpha"
|
||||
description = "A modern Monero transaction library"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/serai-dex/serai/tree/develop/coins/monero"
|
||||
@@ -34,8 +34,8 @@ dalek-ff-group = { path = "../../crypto/dalek-ff-group", version = "0.1" }
|
||||
multiexp = { path = "../../crypto/multiexp", version = "0.2", features = ["batch"] }
|
||||
|
||||
transcript = { package = "flexible-transcript", path = "../../crypto/transcript", version = "0.2", features = ["recommended"], optional = true }
|
||||
frost = { package = "modular-frost", path = "../../crypto/frost", version = "0.4", features = ["ed25519"], optional = true }
|
||||
dleq = { path = "../../crypto/dleq", version = "0.1", features = ["serialize"], optional = true }
|
||||
frost = { package = "modular-frost", path = "../../crypto/frost", version = "0.5", features = ["ed25519"], optional = true }
|
||||
dleq = { path = "../../crypto/dleq", version = "0.2", features = ["serialize"], optional = true }
|
||||
|
||||
monero-generators = { path = "generators", version = "0.1" }
|
||||
|
||||
@@ -55,7 +55,7 @@ monero-generators = { path = "generators", version = "0.1" }
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
||||
frost = { package = "modular-frost", path = "../../crypto/frost", version = "0.4", features = ["ed25519", "tests"] }
|
||||
frost = { package = "modular-frost", path = "../../crypto/frost", version = "0.5", features = ["ed25519", "tests"] }
|
||||
|
||||
[features]
|
||||
multisig = ["rand_chacha", "blake2", "transcript", "frost", "dleq"]
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use core::ops::Deref;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use thiserror::Error;
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
|
||||
use subtle::{ConstantTimeEq, Choice, CtOption};
|
||||
|
||||
use curve25519_dalek::{
|
||||
@@ -233,7 +235,7 @@ impl Clsag {
|
||||
/// sum_outputs is for the sum of the outputs' commitment masks.
|
||||
pub fn sign<R: RngCore + CryptoRng>(
|
||||
rng: &mut R,
|
||||
mut inputs: Vec<(Scalar, EdwardsPoint, ClsagInput)>,
|
||||
mut inputs: Vec<(Zeroizing<Scalar>, EdwardsPoint, ClsagInput)>,
|
||||
sum_outputs: Scalar,
|
||||
msg: [u8; 32],
|
||||
) -> Vec<(Clsag, EdwardsPoint)> {
|
||||
@@ -247,17 +249,19 @@ impl Clsag {
|
||||
sum_pseudo_outs += mask;
|
||||
}
|
||||
|
||||
let mut nonce = random_scalar(rng);
|
||||
let mut nonce = Zeroizing::new(random_scalar(rng));
|
||||
let (mut clsag, pseudo_out, p, c) = Clsag::sign_core(
|
||||
rng,
|
||||
&inputs[i].1,
|
||||
&inputs[i].2,
|
||||
mask,
|
||||
&msg,
|
||||
&nonce * &ED25519_BASEPOINT_TABLE,
|
||||
nonce * hash_to_point(inputs[i].2.decoys.ring[usize::from(inputs[i].2.decoys.i)][0]),
|
||||
nonce.deref() * &ED25519_BASEPOINT_TABLE,
|
||||
nonce.deref() *
|
||||
hash_to_point(inputs[i].2.decoys.ring[usize::from(inputs[i].2.decoys.i)][0]),
|
||||
);
|
||||
clsag.s[usize::from(inputs[i].2.decoys.i)] = nonce - ((p * inputs[i].0) + c);
|
||||
clsag.s[usize::from(inputs[i].2.decoys.i)] =
|
||||
(-((p * inputs[i].0.deref()) + c)) + nonce.deref();
|
||||
inputs[i].0.zeroize();
|
||||
nonce.zeroize();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use core::fmt::Debug;
|
||||
use core::{ops::Deref, fmt::Debug};
|
||||
use std::{
|
||||
io::{self, Read, Write},
|
||||
sync::{Arc, RwLock},
|
||||
@@ -7,7 +7,7 @@ use std::{
|
||||
use rand_core::{RngCore, CryptoRng, SeedableRng};
|
||||
use rand_chacha::ChaCha20Rng;
|
||||
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
|
||||
|
||||
use curve25519_dalek::{
|
||||
constants::ED25519_BASEPOINT_TABLE,
|
||||
@@ -157,7 +157,7 @@ impl Algorithm<Ed25519> for ClsagMultisig {
|
||||
view: &ThresholdView<Ed25519>,
|
||||
) -> ClsagAddendum {
|
||||
ClsagAddendum {
|
||||
key_image: dfg::EdwardsPoint(self.H * view.secret_share().0),
|
||||
key_image: dfg::EdwardsPoint(self.H) * view.secret_share().deref(),
|
||||
dleq: DLEqProof::prove(
|
||||
rng,
|
||||
// Doesn't take in a larger transcript object due to the usage of this
|
||||
@@ -167,7 +167,7 @@ impl Algorithm<Ed25519> for ClsagMultisig {
|
||||
// try to merge later in some form, when it should instead just merge xH (as it does)
|
||||
&mut dleq_transcript(),
|
||||
&[dfg::EdwardsPoint::generator(), dfg::EdwardsPoint(self.H)],
|
||||
dfg::Scalar(view.secret_share().0),
|
||||
view.secret_share(),
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -223,7 +223,7 @@ impl Algorithm<Ed25519> for ClsagMultisig {
|
||||
&mut self,
|
||||
view: &ThresholdView<Ed25519>,
|
||||
nonce_sums: &[Vec<dfg::EdwardsPoint>],
|
||||
nonces: &[dfg::Scalar],
|
||||
nonces: Vec<Zeroizing<dfg::Scalar>>,
|
||||
msg: &[u8],
|
||||
) -> dfg::Scalar {
|
||||
// Use the transcript to get a seeded random number generator
|
||||
@@ -247,7 +247,7 @@ impl Algorithm<Ed25519> for ClsagMultisig {
|
||||
);
|
||||
self.interim = Some(Interim { p, c, clsag, pseudo_out });
|
||||
|
||||
nonces[0] - (dfg::Scalar(p) * view.secret_share())
|
||||
(-(dfg::Scalar(p) * view.secret_share().deref())) + nonces[0].deref()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use zeroize::Zeroize;
|
||||
use core::ops::Deref;
|
||||
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwards::EdwardsPoint};
|
||||
|
||||
@@ -17,10 +19,8 @@ use crate::{
|
||||
};
|
||||
|
||||
/// Generate a key image for a given key. Defined as `x * hash_to_point(xG)`.
|
||||
pub fn generate_key_image(mut secret: Scalar) -> EdwardsPoint {
|
||||
let res = secret * hash_to_point(&secret * &ED25519_BASEPOINT_TABLE);
|
||||
secret.zeroize();
|
||||
res
|
||||
pub fn generate_key_image(secret: &Zeroizing<Scalar>) -> EdwardsPoint {
|
||||
hash_to_point(&ED25519_BASEPOINT_TABLE * secret.deref()) * secret.deref()
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use core::ops::Deref;
|
||||
#[cfg(feature = "multisig")]
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use zeroize::Zeroizing;
|
||||
use rand_core::{RngCore, OsRng};
|
||||
|
||||
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar};
|
||||
@@ -35,29 +37,30 @@ fn clsag() {
|
||||
for real in 0 .. RING_LEN {
|
||||
let msg = [1; 32];
|
||||
|
||||
let mut secrets = [Scalar::zero(), Scalar::zero()];
|
||||
let mut secrets = (Zeroizing::new(Scalar::zero()), Scalar::zero());
|
||||
let mut ring = vec![];
|
||||
for i in 0 .. RING_LEN {
|
||||
let dest = random_scalar(&mut OsRng);
|
||||
let dest = Zeroizing::new(random_scalar(&mut OsRng));
|
||||
let mask = random_scalar(&mut OsRng);
|
||||
let amount;
|
||||
if i == u64::from(real) {
|
||||
secrets = [dest, mask];
|
||||
secrets = (dest.clone(), mask);
|
||||
amount = AMOUNT;
|
||||
} else {
|
||||
amount = OsRng.next_u64();
|
||||
}
|
||||
ring.push([&dest * &ED25519_BASEPOINT_TABLE, Commitment::new(mask, amount).calculate()]);
|
||||
ring
|
||||
.push([dest.deref() * &ED25519_BASEPOINT_TABLE, Commitment::new(mask, amount).calculate()]);
|
||||
}
|
||||
|
||||
let image = generate_key_image(secrets[0]);
|
||||
let image = generate_key_image(&secrets.0);
|
||||
let (clsag, pseudo_out) = Clsag::sign(
|
||||
&mut OsRng,
|
||||
vec![(
|
||||
secrets[0],
|
||||
secrets.0,
|
||||
image,
|
||||
ClsagInput::new(
|
||||
Commitment::new(secrets[1], AMOUNT),
|
||||
Commitment::new(secrets.1, AMOUNT),
|
||||
Decoys {
|
||||
i: u8::try_from(real).unwrap(),
|
||||
offsets: (1 ..= RING_LEN).into_iter().collect(),
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use core::ops::Deref;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
use rand::seq::SliceRandom;
|
||||
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
|
||||
|
||||
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwards::EdwardsPoint};
|
||||
|
||||
@@ -108,9 +110,9 @@ async fn prepare_inputs<R: RngCore + CryptoRng>(
|
||||
rpc: &Rpc,
|
||||
ring_len: usize,
|
||||
inputs: &[SpendableOutput],
|
||||
spend: &Scalar,
|
||||
spend: &Zeroizing<Scalar>,
|
||||
tx: &mut Transaction,
|
||||
) -> Result<Vec<(Scalar, EdwardsPoint, ClsagInput)>, TransactionError> {
|
||||
) -> Result<Vec<(Zeroizing<Scalar>, EdwardsPoint, ClsagInput)>, TransactionError> {
|
||||
let mut signable = Vec::with_capacity(inputs.len());
|
||||
|
||||
// Select decoys
|
||||
@@ -125,9 +127,11 @@ async fn prepare_inputs<R: RngCore + CryptoRng>(
|
||||
.map_err(TransactionError::RpcError)?;
|
||||
|
||||
for (i, input) in inputs.iter().enumerate() {
|
||||
let input_spend = Zeroizing::new(input.key_offset() + spend.deref());
|
||||
let image = generate_key_image(&input_spend);
|
||||
signable.push((
|
||||
spend + input.key_offset(),
|
||||
generate_key_image(spend + input.key_offset()),
|
||||
input_spend,
|
||||
image,
|
||||
ClsagInput::new(input.commitment().clone(), decoys[i].clone())
|
||||
.map_err(TransactionError::ClsagError)?,
|
||||
));
|
||||
@@ -358,16 +362,16 @@ impl SignableTransaction {
|
||||
&mut self,
|
||||
rng: &mut R,
|
||||
rpc: &Rpc,
|
||||
spend: &Scalar,
|
||||
spend: &Zeroizing<Scalar>,
|
||||
) -> Result<Transaction, TransactionError> {
|
||||
let mut images = Vec::with_capacity(self.inputs.len());
|
||||
for input in &self.inputs {
|
||||
let mut offset = spend + input.key_offset();
|
||||
if (&offset * &ED25519_BASEPOINT_TABLE) != input.key() {
|
||||
let mut offset = Zeroizing::new(spend.deref() + input.key_offset());
|
||||
if (offset.deref() * &ED25519_BASEPOINT_TABLE) != input.key() {
|
||||
Err(TransactionError::WrongPrivateKey)?;
|
||||
}
|
||||
|
||||
images.push(generate_key_image(offset));
|
||||
images.push(generate_key_image(&offset));
|
||||
offset.zeroize();
|
||||
}
|
||||
images.sort_by(key_image_sort);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use core::ops::Deref;
|
||||
use std::{sync::Mutex, collections::HashSet};
|
||||
#[cfg(feature = "multisig")]
|
||||
use std::collections::HashMap;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use zeroize::Zeroizing;
|
||||
use rand_core::OsRng;
|
||||
|
||||
#[cfg(feature = "multisig")]
|
||||
@@ -55,11 +56,11 @@ async fn send_core(test: usize, multisig: bool) {
|
||||
let rpc = rpc().await;
|
||||
|
||||
// Generate an address
|
||||
let spend = random_scalar(&mut OsRng);
|
||||
let spend = Zeroizing::new(random_scalar(&mut OsRng));
|
||||
#[allow(unused_mut)]
|
||||
let mut view = random_scalar(&mut OsRng);
|
||||
#[allow(unused_mut)]
|
||||
let mut spend_pub = &spend * &ED25519_BASEPOINT_TABLE;
|
||||
let mut spend_pub = spend.deref() * &ED25519_BASEPOINT_TABLE;
|
||||
|
||||
#[cfg(feature = "multisig")]
|
||||
let keys = key_gen::<_, Ed25519>(&mut OsRng);
|
||||
|
||||
Reference in New Issue
Block a user