From 76f5c23b7ff879af9482aa928e1244ab74a8e04e Mon Sep 17 00:00:00 2001 From: Boog900 <54e72d8a-345f-4599-bd90-c6b9bc7d0ec5@aleeas.com> Date: Tue, 30 May 2023 16:29:57 +0100 Subject: [PATCH] add mlsag --- coins/monero/src/ringct/mlsag/mod.rs | 35 +++++++++++++++++++ coins/monero/src/ringct/mod.rs | 50 ++++++++++++++++++++++++++-- 2 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 coins/monero/src/ringct/mlsag/mod.rs diff --git a/coins/monero/src/ringct/mlsag/mod.rs b/coins/monero/src/ringct/mlsag/mod.rs new file mode 100644 index 00000000..d7711453 --- /dev/null +++ b/coins/monero/src/ringct/mlsag/mod.rs @@ -0,0 +1,35 @@ +use std::io; +use std::io::{Read, Write}; + +use curve25519_dalek::edwards::EdwardsPoint; +use curve25519_dalek::scalar::Scalar; + +use crate::{ + Commitment, random_scalar, hash_to_scalar, wallet::decoys::Decoys, ringct::hash_to_point, + serialize::*, +}; + +/// MLSAG signature, as used in Monero. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Mlsag { + pub ss: Vec>, + pub cc: EdwardsPoint, +} + +impl Mlsag { + pub fn write(&self, w: &mut W) -> io::Result<()> { + for ss in self.ss.iter() { + write_raw_vec(write_scalar, ss, w)?; + } + write_point(&self.cc, w) + } + + pub fn read(decoys: usize, elements: usize, r: &mut R) -> io::Result { + Ok(Mlsag { + ss: (0 .. decoys) + .map(|_| read_raw_vec(read_scalar, elements, r)) + .collect::>()?, + cc: read_point(r)?, + }) + } +} diff --git a/coins/monero/src/ringct/mod.rs b/coins/monero/src/ringct/mod.rs index d289b6f1..020c2bc5 100644 --- a/coins/monero/src/ringct/mod.rs +++ b/coins/monero/src/ringct/mod.rs @@ -10,13 +10,15 @@ pub use hash_to_point::{raw_hash_to_point, hash_to_point}; /// CLSAG struct, along with signing and verifying functionality. pub mod clsag; +/// MLSAG struct, along with verifying functionality. +pub mod mlsag; /// Bulletproofs(+) structs, along with proving and verifying functionality. pub mod bulletproofs; use crate::{ Protocol, serialize::*, - ringct::{clsag::Clsag, bulletproofs::Bulletproofs}, + ringct::{clsag::Clsag, mlsag::Mlsag, bulletproofs::Bulletproofs}, }; /// Generate a key image for a given key. Defined as `x * hash_to_point(xG)`. @@ -71,7 +73,17 @@ impl RctBase { #[derive(Clone, PartialEq, Eq, Debug)] pub enum RctPrunable { Null, - Clsag { bulletproofs: Vec, clsags: Vec, pseudo_outs: Vec }, + BulletProof { + bulletproofs: Vec, + mlsags: Vec, + pseudo_outs: Vec, + v2: bool, + }, + Clsag { + bulletproofs: Vec, + clsags: Vec, + pseudo_outs: Vec, + }, } impl RctPrunable { @@ -79,6 +91,13 @@ impl RctPrunable { pub fn rct_type(&self) -> u8 { match self { RctPrunable::Null => 0, + RctPrunable::BulletProof { v2, .. } => { + if !v2 { + 3 + } else { + 4 + } + } RctPrunable::Clsag { bulletproofs, .. } => { if matches!(bulletproofs[0], Bulletproofs::Original { .. }) { 5 @@ -97,7 +116,17 @@ impl RctPrunable { pub fn write(&self, w: &mut W) -> io::Result<()> { match self { RctPrunable::Null => Ok(()), - RctPrunable::Clsag { bulletproofs, clsags, pseudo_outs, .. } => { + RctPrunable::BulletProof { bulletproofs, mlsags, pseudo_outs, v2 } => { + if !v2 { + w.write_all(&u32::try_from(bulletproofs.len()).unwrap().to_le_bytes())?; + } else { + write_varint(&bulletproofs.len().try_into().unwrap(), w)?; + } + write_raw_vec(Bulletproofs::write, bulletproofs, w)?; + write_raw_vec(Mlsag::write, mlsags, w)?; + write_raw_vec(write_point, pseudo_outs, w) + } + RctPrunable::Clsag { bulletproofs, clsags, pseudo_outs } => { write_vec(Bulletproofs::write, bulletproofs, w)?; write_raw_vec(Clsag::write, clsags, w)?; write_raw_vec(write_point, pseudo_outs, w) @@ -114,6 +143,20 @@ impl RctPrunable { pub fn read(rct_type: u8, decoys: &[usize], r: &mut R) -> io::Result { Ok(match rct_type { 0 => RctPrunable::Null, + 3 | 4 => RctPrunable::BulletProof { + bulletproofs: read_raw_vec( + Bulletproofs::read, + if rct_type == 3 { + read_u32(r)?.try_into().unwrap() + } else { + read_varint(r)?.try_into().unwrap() + }, + r, + )?, + mlsags: decoys.iter().map(|d| Mlsag::read(*d, 2, r)).collect::>()?, + pseudo_outs: read_raw_vec(read_point, decoys.len(), r)?, + v2: rct_type == 4, + }, 5 | 6 => RctPrunable::Clsag { bulletproofs: read_vec( if rct_type == 5 { Bulletproofs::read } else { Bulletproofs::read_plus }, @@ -129,6 +172,7 @@ impl RctPrunable { pub(crate) fn signature_write(&self, w: &mut W) -> io::Result<()> { match self { RctPrunable::Null => panic!("Serializing RctPrunable::Null for a signature"), + RctPrunable::BulletProof {..} => todo!(), RctPrunable::Clsag { bulletproofs, .. } => { bulletproofs.iter().try_for_each(|bp| bp.signature_write(w)) }