From 87ca636ddb201d28fc920c468025cc9b1ee0a423 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 11 May 2021 14:48:37 +1000 Subject: [PATCH] Use Cow to compress EdwardsPoint on the fly in hash function This allows us to pass EdwardsPoint to hash_to_scalar without compressing them a priori. As a result, we can remove a bunch of intermediary variables. --- monero-adaptor/src/clsag.rs | 57 ++++++++---------------------------- monero-adaptor/src/macros.rs | 49 ++++++++++++++++++------------- 2 files changed, 41 insertions(+), 65 deletions(-) diff --git a/monero-adaptor/src/clsag.rs b/monero-adaptor/src/clsag.rs index 65015112..d9278eb2 100644 --- a/monero-adaptor/src/clsag.rs +++ b/monero-adaptor/src/clsag.rs @@ -29,37 +29,16 @@ pub fn sign( let D_inv_8 = D * INV_EIGHT; let ring = Ring::new(ring); let commitment_ring = Ring::new(commitment_ring); - let compressed_pseudo_output_commitment = pseudo_output_commitment.compress(); - let L_0 = L_0.compress(); - let R_0 = R_0.compress(); - let compressed_I = I.compress(); - let H_p_pk = H_p_pk.compress(); let mu_P = hash_to_scalar!( - b"CLSAG_agg_0" - || ring - || commitment_ring - || compressed_I - || H_p_pk - || compressed_pseudo_output_commitment + b"CLSAG_agg_0" || ring || commitment_ring || I || H_p_pk || pseudo_output_commitment ); let mu_C = hash_to_scalar!( - b"CLSAG_agg_1" - || ring - || commitment_ring - || compressed_I - || H_p_pk - || compressed_pseudo_output_commitment + b"CLSAG_agg_1" || ring || commitment_ring || I || H_p_pk || pseudo_output_commitment ); let h_0 = hash_to_scalar!( - b"CLSAG_round" - || ring - || commitment_ring - || compressed_pseudo_output_commitment - || msg - || L_0 - || R_0 + b"CLSAG_round" || ring || commitment_ring || pseudo_output_commitment || msg || L_0 || R_0 ); let h_last = fake_responses @@ -69,14 +48,14 @@ pub fn sign( let pk_i = ring[i + 1]; let adjusted_commitment_i = commitment_ring[i] - pseudo_output_commitment; - let L_i = compute_L(h_prev, mu_P, mu_C, *s_i, pk_i, adjusted_commitment_i).compress(); - let R_i = compute_R(h_prev, mu_P, mu_C, pk_i, *s_i, I, D_inv_8).compress(); + let L_i = compute_L(h_prev, mu_P, mu_C, *s_i, pk_i, adjusted_commitment_i); + let R_i = compute_R(h_prev, mu_P, mu_C, pk_i, *s_i, I, D_inv_8); hash_to_scalar!( b"CLSAG_round" || ring || commitment_ring - || compressed_pseudo_output_commitment + || pseudo_output_commitment || msg || L_i || R_i @@ -116,25 +95,13 @@ pub fn verify( ) -> bool { let ring = Ring::new(ring); let commitment_ring = Ring::new(commitment_ring); - let compressed_pseudo_output_commitment = pseudo_output_commitment.compress(); - let I = sig.I.compress(); - let H_p_pk = H_p_pk.compress(); + let I = sig.I; let mu_P = hash_to_scalar!( - b"CLSAG_agg_0" - || ring - || commitment_ring - || I - || H_p_pk - || compressed_pseudo_output_commitment + b"CLSAG_agg_0" || ring || commitment_ring || I || H_p_pk || pseudo_output_commitment ); let mu_C = hash_to_scalar!( - b"CLSAG_agg_1" - || ring - || commitment_ring - || I - || H_p_pk - || compressed_pseudo_output_commitment + b"CLSAG_agg_1" || ring || commitment_ring || I || H_p_pk || pseudo_output_commitment ); let mut h = sig.h_0; @@ -143,14 +110,14 @@ pub fn verify( let pk_i = ring[(i + 1) % RING_SIZE]; let adjusted_commitment_i = commitment_ring[i] - pseudo_output_commitment; - let L_i = compute_L(h, mu_P, mu_C, *s_i, pk_i, adjusted_commitment_i).compress(); - let R_i = compute_R(h, mu_P, mu_C, pk_i, *s_i, sig.I, sig.D).compress(); + let L_i = compute_L(h, mu_P, mu_C, *s_i, pk_i, adjusted_commitment_i); + let R_i = compute_R(h, mu_P, mu_C, pk_i, *s_i, sig.I, sig.D); h = hash_to_scalar!( b"CLSAG_round" || ring || commitment_ring - || compressed_pseudo_output_commitment + || pseudo_output_commitment || msg || L_i || R_i diff --git a/monero-adaptor/src/macros.rs b/monero-adaptor/src/macros.rs index 9e836a70..2010326e 100644 --- a/monero-adaptor/src/macros.rs +++ b/monero-adaptor/src/macros.rs @@ -1,16 +1,17 @@ use crate::ring::Ring; -use curve25519_dalek::edwards::CompressedEdwardsY; +use curve25519_dalek::edwards::{CompressedEdwardsY, EdwardsPoint}; +use std::borrow::Cow; macro_rules! hash_to_scalar { ($($e:tt) || +) => { { - use crate::macros::AsByteSlice as _; + use crate::macros::ToCowBytes as _; use tiny_keccak::Hasher as _; let mut hasher = tiny_keccak::Keccak::v256(); $( - hasher.update($e.as_byte_slice()); + hasher.update($e.to_cow_bytes().as_ref()); )+ let mut hash = [0u8; 32]; @@ -21,36 +22,44 @@ macro_rules! hash_to_scalar { }; } -pub(crate) trait AsByteSlice { - fn as_byte_slice(&self) -> &[u8]; +type CowBytes<'a> = Cow<'a, [u8]>; + +pub(crate) trait ToCowBytes { + fn to_cow_bytes(&self) -> CowBytes<'_>; } -impl AsByteSlice for CompressedEdwardsY { - fn as_byte_slice(&self) -> &[u8] { - self.0.as_ref() +impl ToCowBytes for CompressedEdwardsY { + fn to_cow_bytes(&self) -> CowBytes<'_> { + CowBytes::Borrowed(self.0.as_ref()) } } -impl AsByteSlice for Vec { - fn as_byte_slice(&self) -> &[u8] { - self.as_ref() +impl ToCowBytes for EdwardsPoint { + fn to_cow_bytes(&self) -> CowBytes<'_> { + CowBytes::Owned(self.compress().0.to_vec()) } } -impl AsByteSlice for [u8; N] { - fn as_byte_slice(&self) -> &[u8] { - self.as_ref() +impl ToCowBytes for Vec { + fn to_cow_bytes(&self) -> CowBytes<'_> { + CowBytes::Borrowed(self.as_ref()) } } -impl AsByteSlice for &[u8] { - fn as_byte_slice(&self) -> &[u8] { - self +impl ToCowBytes for [u8; N] { + fn to_cow_bytes(&self) -> CowBytes<'_> { + CowBytes::Borrowed(self.as_ref()) } } -impl<'a> AsByteSlice for Ring<'a> { - fn as_byte_slice(&self) -> &[u8] { - self.as_ref() +impl ToCowBytes for &[u8] { + fn to_cow_bytes(&self) -> CowBytes<'_> { + CowBytes::Borrowed(self) + } +} + +impl<'a> ToCowBytes for Ring<'a> { + fn to_cow_bytes(&self) -> CowBytes<'_> { + CowBytes::Borrowed(self.as_ref()) } }