diff --git a/coins/monero/src/ringct/borromean.rs b/coins/monero/src/ringct/borromean.rs index f618df04..3546986f 100644 --- a/coins/monero/src/ringct/borromean.rs +++ b/coins/monero/src/ringct/borromean.rs @@ -1,5 +1,3 @@ -#![allow(non_snake_case)] - use core::fmt::Debug; use std_shims::io::{self, Read, Write}; @@ -52,11 +50,13 @@ impl BorromeanSignatures { for i in 0 .. 64 { // TODO: These aren't the correct reduction // TODO: Can either of these be tightened? + #[allow(non_snake_case)] let LL = EdwardsPoint::vartime_double_scalar_mul_basepoint( &Scalar::from_bytes_mod_order(self.ee), &keys_a[i], &Scalar::from_bytes_mod_order(self.s0[i]), ); + #[allow(non_snake_case)] let LV = EdwardsPoint::vartime_double_scalar_mul_basepoint( &hash_to_scalar(LL.compress().as_bytes()), &keys_b[i], @@ -74,19 +74,19 @@ impl BorromeanSignatures { /// A range proof premised on Borromean ring signatures. #[derive(Clone, PartialEq, Eq, Debug)] pub struct BorromeanRange { - pub sig: BorromeanSignatures, + pub sigs: BorromeanSignatures, pub bit_commitments: [EdwardsPoint; 64], } impl BorromeanRange { pub fn read(r: &mut R) -> io::Result { Ok(BorromeanRange { - sig: BorromeanSignatures::read(r)?, + sigs: BorromeanSignatures::read(r)?, bit_commitments: read_array(read_point, r)?, }) } pub fn write(&self, w: &mut W) -> io::Result<()> { - self.sig.write(w)?; + self.sigs.write(w)?; write_raw_vec(write_point, &self.bit_commitments, w) } @@ -96,12 +96,13 @@ impl BorromeanRange { return false; } + #[allow(non_snake_case)] let H_pow_2 = H_pow_2(); let mut commitments_sub_one = [EdwardsPoint::identity(); 64]; for i in 0 .. 64 { commitments_sub_one[i] = self.bit_commitments[i] - H_pow_2[i]; } - self.sig.verify(&self.bit_commitments, &commitments_sub_one) + self.sigs.verify(&self.bit_commitments, &commitments_sub_one) } } diff --git a/coins/monero/src/ringct/mlsag/mod.rs b/coins/monero/src/ringct/mlsag/mod.rs index 172770aa..d41fcfc0 100644 --- a/coins/monero/src/ringct/mlsag/mod.rs +++ b/coins/monero/src/ringct/mlsag/mod.rs @@ -1,23 +1,23 @@ -#![allow(non_snake_case)] - -use std::io; -use std::io::{Read, Write}; +use std_shims::{ + vec::Vec, + io::{self, Read, Write}, +}; use curve25519_dalek::scalar::Scalar; +#[cfg(feature = "experimental")] use curve25519_dalek::edwards::EdwardsPoint; -use curve25519_dalek::traits::Identity; -use crate::{hash_to_scalar, serialize::*}; -use crate::ringct::hash_to_point; +use crate::serialize::*; +#[cfg(feature = "experimental")] +use crate::{hash_to_scalar, ringct::hash_to_point}; -/// MgSig part of MLSAG, as used in Monero. #[derive(Clone, PartialEq, Eq, Debug)] -pub struct MgSig { +pub struct Mlsag { pub ss: Vec<[Scalar; 2]>, pub cc: Scalar, } -impl MgSig { +impl Mlsag { pub fn write(&self, w: &mut W) -> io::Result<()> { for ss in self.ss.iter() { write_raw_vec(write_scalar, ss, w)?; @@ -25,8 +25,8 @@ impl MgSig { write_scalar(&self.cc, w) } - pub fn read(mixins: usize, r: &mut R) -> io::Result { - Ok(MgSig { + pub fn read(mixins: usize, r: &mut R) -> io::Result { + Ok(Mlsag { ss: (0 .. mixins).map(|_| read_array(read_scalar, r)).collect::>()?, cc: read_scalar(r)?, }) @@ -38,27 +38,16 @@ impl MgSig { pubs: &[[EdwardsPoint; 2]], out_pks: &[EdwardsPoint], fee: &EdwardsPoint, - I: &EdwardsPoint, + key_image: &EdwardsPoint, ) -> bool { - if pubs.is_empty() { - return false; - } - - let sum_out_pk = { - let mut sum = EdwardsPoint::identity(); - for out_pk in out_pks { - sum += out_pk; - } - sum - }; + let sum_out_pk = out_pks.iter().sum::(); let mut ring_matrix = Vec::with_capacity(pubs.len()); - for member in pubs.iter() { ring_matrix.push([member[0], member[1] - sum_out_pk - fee]) } - self.verify_mlsag(msg, &ring_matrix, I) + self.verify(msg, &ring_matrix, key_image) } pub fn verify_rct_simple( @@ -66,44 +55,45 @@ impl MgSig { msg: &[u8; 32], pubs: &[[EdwardsPoint; 2]], pseudo_out: &EdwardsPoint, - I: &EdwardsPoint, + key_image: &EdwardsPoint, ) -> bool { - if pubs.is_empty() { - return false; - } - let mut ring_matrix = Vec::with_capacity(pubs.len()); - for member in pubs.iter() { ring_matrix.push([member[0], member[1] - pseudo_out]) } - self.verify_mlsag(msg, &ring_matrix, I) + self.verify(msg, &ring_matrix, key_image) } - fn verify_mlsag(&self, msg: &[u8; 32], ring: &[[EdwardsPoint; 2]], I: &EdwardsPoint) -> bool { - let mut buf = Vec::with_capacity(32 * 6); + #[cfg(feature = "experimental")] + pub fn verify( + &self, + msg: &[u8; 32], + ring: &[[EdwardsPoint; 2]], + key_image: &EdwardsPoint, + ) -> bool { + if ring.is_empty() { + return false; + } + let mut buf = Vec::with_capacity(6 * 32); let mut ci = self.cc; - for (i, ring_member) in ring.iter().enumerate() { buf.extend_from_slice(msg); + + #[allow(non_snake_case)] + let L = + |r| EdwardsPoint::vartime_double_scalar_mul_basepoint(&ci, &ring_member[r], &self.ss[i][r]); + buf.extend_from_slice(ring_member[0].compress().as_bytes()); + buf.extend_from_slice(L(0).compress().as_bytes()); - let L1 = - EdwardsPoint::vartime_double_scalar_mul_basepoint(&ci, &ring_member[0], &self.ss[i][0]); - buf.extend_from_slice(L1.compress().as_bytes()); - - let temp = hash_to_point(ring_member[0]); - - let R = self.ss[i][0] * temp + ci * I; + #[allow(non_snake_case)] + let R = (self.ss[i][0] * hash_to_point(ring_member[0])) + (ci * key_image); buf.extend_from_slice(R.compress().as_bytes()); buf.extend_from_slice(ring_member[1].compress().as_bytes()); - - let L2 = - EdwardsPoint::vartime_double_scalar_mul_basepoint(&ci, &ring_member[1], &self.ss[i][1]); - buf.extend_from_slice(L2.compress().as_bytes()); + buf.extend_from_slice(L(1).compress().as_bytes()); ci = hash_to_scalar(&buf); buf.clear(); diff --git a/coins/monero/src/ringct/mod.rs b/coins/monero/src/ringct/mod.rs index 8053020e..445a6473 100644 --- a/coins/monero/src/ringct/mod.rs +++ b/coins/monero/src/ringct/mod.rs @@ -23,7 +23,7 @@ pub mod bulletproofs; use crate::{ Protocol, serialize::*, - ringct::{clsag::Clsag, mlsag::MgSig, bulletproofs::Bulletproofs, borromean::BorromeanRange}, + ringct::{clsag::Clsag, mlsag::Mlsag, bulletproofs::Bulletproofs, borromean::BorromeanRange}, }; /// Generate a key image for a given key. Defined as `x * hash_to_point(xG)`. @@ -111,12 +111,12 @@ pub enum RctPrunable { Null, Borromean { range_sigs: Vec, - mlsags: Vec, + mlsags: Vec, simple: bool, }, BulletProof { bulletproofs: Vec, - mlsags: Vec, + mlsags: Vec, pseudo_outs: Vec, v2: bool, }, @@ -166,7 +166,7 @@ impl RctPrunable { RctPrunable::Null => Ok(()), RctPrunable::Borromean { range_sigs, mlsags, simple: _ } => { write_raw_vec(BorromeanRange::write, range_sigs, w)?; - write_raw_vec(MgSig::write, mlsags, w) + write_raw_vec(Mlsag::write, mlsags, w) } RctPrunable::BulletProof { bulletproofs, mlsags, pseudo_outs, v2 } => { if !v2 { @@ -175,7 +175,7 @@ impl RctPrunable { write_varint(&bulletproofs.len().try_into().unwrap(), w)?; } write_raw_vec(Bulletproofs::write, bulletproofs, w)?; - write_raw_vec(MgSig::write, mlsags, w)?; + write_raw_vec(Mlsag::write, mlsags, w)?; write_raw_vec(write_point, pseudo_outs, w) } RctPrunable::Clsag { bulletproofs, clsags, pseudo_outs } => { @@ -202,7 +202,7 @@ impl RctPrunable { 0 => RctPrunable::Null, 1 | 2 => RctPrunable::Borromean { range_sigs: read_raw_vec(BorromeanRange::read, outputs, r)?, - mlsags: decoys.iter().map(|d| MgSig::read(*d, r)).collect::>()?, + mlsags: decoys.iter().map(|d| Mlsag::read(*d, r)).collect::>()?, simple: rct_type == 2, }, 3 | 4 => RctPrunable::BulletProof { @@ -215,7 +215,7 @@ impl RctPrunable { }, r, )?, - mlsags: decoys.iter().map(|d| MgSig::read(*d, r)).collect::>()?, + mlsags: decoys.iter().map(|d| Mlsag::read(*d, r)).collect::>()?, pseudo_outs: read_raw_vec(read_point, decoys.len(), r)?, v2: rct_type == 4, },