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.
This commit is contained in:
Thomas Eizinger 2021-05-11 14:48:37 +10:00
parent 06f1ada2b1
commit 87ca636ddb
No known key found for this signature in database
GPG Key ID: 651AC83A6C6C8B96
2 changed files with 41 additions and 65 deletions

View File

@ -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

View File

@ -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<u8> {
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<const N: usize> AsByteSlice for [u8; N] {
fn as_byte_slice(&self) -> &[u8] {
self.as_ref()
impl ToCowBytes for Vec<u8> {
fn to_cow_bytes(&self) -> CowBytes<'_> {
CowBytes::Borrowed(self.as_ref())
}
}
impl AsByteSlice for &[u8] {
fn as_byte_slice(&self) -> &[u8] {
self
impl<const N: usize> 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())
}
}