Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[zk-sdk] Add fixed string tests for proofs #2814

Merged
merged 8 commits into from
Sep 4, 2024
4 changes: 2 additions & 2 deletions zk-sdk/src/encryption/pod/auth_encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
#[cfg(not(target_os = "solana"))]
use crate::{encryption::auth_encryption::AeCiphertext, errors::AuthenticatedEncryptionError};
use {
crate::encryption::{
crate::{
encryption::AE_CIPHERTEXT_LEN,
pod::{impl_from_bytes, impl_from_str},
AE_CIPHERTEXT_LEN,
},
base64::{prelude::BASE64_STANDARD, Engine},
bytemuck::{Pod, Zeroable},
Expand Down
35 changes: 26 additions & 9 deletions zk-sdk/src/encryption/pod/elgamal.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
//! Plain Old Data types for the ElGamal encryption scheme.

use {
crate::encryption::{
pod::{impl_from_bytes, impl_from_str},
DECRYPT_HANDLE_LEN, ELGAMAL_CIPHERTEXT_LEN, ELGAMAL_PUBKEY_LEN,
},
base64::{prelude::BASE64_STANDARD, Engine},
bytemuck::Zeroable,
std::fmt,
};
#[cfg(not(target_os = "solana"))]
use {
crate::{
Expand All @@ -17,13 +8,25 @@ use {
},
curve25519_dalek::ristretto::CompressedRistretto,
};
use {
crate::{
encryption::{DECRYPT_HANDLE_LEN, ELGAMAL_CIPHERTEXT_LEN, ELGAMAL_PUBKEY_LEN},
pod::{impl_from_bytes, impl_from_str},
},
base64::{prelude::BASE64_STANDARD, Engine},
bytemuck::Zeroable,
std::fmt,
};

/// Maximum length of a base64 encoded ElGamal public key
const ELGAMAL_PUBKEY_MAX_BASE64_LEN: usize = 44;

/// Maximum length of a base64 encoded ElGamal ciphertext
const ELGAMAL_CIPHERTEXT_MAX_BASE64_LEN: usize = 88;

/// Maximum length of a base64 encoded ElGamal decrypt handle
const DECRYPT_HANDLE_MAX_BASE64_LEN: usize = 44;

/// The `ElGamalCiphertext` type as a `Pod`.
#[derive(Clone, Copy, bytemuck_derive::Pod, bytemuck_derive::Zeroable, PartialEq, Eq)]
#[repr(transparent)]
Expand Down Expand Up @@ -150,6 +153,20 @@ impl TryFrom<PodDecryptHandle> for DecryptHandle {
}
}

impl fmt::Display for PodDecryptHandle {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", BASE64_STANDARD.encode(self.0))
}
}

impl_from_str!(
TYPE = PodDecryptHandle,
BYTES_LEN = DECRYPT_HANDLE_LEN,
BASE64_LEN = DECRYPT_HANDLE_MAX_BASE64_LEN
);

impl_from_bytes!(TYPE = PodDecryptHandle, BYTES_LEN = DECRYPT_HANDLE_LEN);

#[cfg(test)]
mod tests {
use {super::*, crate::encryption::elgamal::ElGamalKeypair, std::str::FromStr};
Expand Down
18 changes: 14 additions & 4 deletions zk-sdk/src/encryption/pod/grouped_elgamal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@ use crate::encryption::grouped_elgamal::GroupedElGamalCiphertext;
use {
crate::{
encryption::{
pod::{
elgamal::PodElGamalCiphertext, impl_from_bytes, impl_from_str,
pedersen::PodPedersenCommitment,
},
pod::{elgamal::PodElGamalCiphertext, pedersen::PodPedersenCommitment},
DECRYPT_HANDLE_LEN, ELGAMAL_CIPHERTEXT_LEN, PEDERSEN_COMMITMENT_LEN,
},
errors::ElGamalError,
pod::{impl_from_bytes, impl_from_str},
},
base64::{prelude::BASE64_STANDARD, Engine},
bytemuck::Zeroable,
Expand Down Expand Up @@ -89,6 +87,12 @@ impl Default for PodGroupedElGamalCiphertext2Handles {
}
}

impl fmt::Display for PodGroupedElGamalCiphertext2Handles {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", BASE64_STANDARD.encode(self.0))
}
}

impl_from_str!(
TYPE = PodGroupedElGamalCiphertext2Handles,
BYTES_LEN = GROUPED_ELGAMAL_CIPHERTEXT_2_HANDLES,
Expand Down Expand Up @@ -137,6 +141,12 @@ impl Default for PodGroupedElGamalCiphertext3Handles {
}
}

impl fmt::Display for PodGroupedElGamalCiphertext3Handles {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", BASE64_STANDARD.encode(self.0))
}
}

impl_from_str!(
TYPE = PodGroupedElGamalCiphertext3Handles,
BYTES_LEN = GROUPED_ELGAMAL_CIPHERTEXT_3_HANDLES,
Expand Down
35 changes: 0 additions & 35 deletions zk-sdk/src/encryption/pod/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,3 @@ pub mod auth_encryption;
pub mod elgamal;
pub mod grouped_elgamal;
pub mod pedersen;

macro_rules! impl_from_str {
(TYPE = $type:ident, BYTES_LEN = $bytes_len:expr, BASE64_LEN = $base64_len:expr) => {
impl std::str::FromStr for $type {
type Err = crate::errors::ParseError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.len() > $base64_len {
return Err(Self::Err::WrongSize);
}
let mut bytes = [0u8; $bytes_len];
let decoded_len = BASE64_STANDARD
.decode_slice(s, &mut bytes)
.map_err(|_| Self::Err::Invalid)?;
if decoded_len != $bytes_len {
Err(Self::Err::WrongSize)
} else {
Ok($type(bytes))
}
}
}
};
}
pub(crate) use impl_from_str;

macro_rules! impl_from_bytes {
(TYPE = $type:ident, BYTES_LEN = $bytes_len:expr) => {
impl std::convert::From<[u8; $bytes_len]> for $type {
fn from(bytes: [u8; $bytes_len]) -> Self {
Self(bytes)
}
}
};
}
pub(crate) use impl_from_bytes;
20 changes: 13 additions & 7 deletions zk-sdk/src/encryption/pod/pedersen.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
//! Plain Old Data type for the Pedersen commitment scheme.

#[cfg(not(target_os = "solana"))]
use {
crate::encryption::{
crate::{encryption::pedersen::PedersenCommitment, errors::ElGamalError},
curve25519_dalek::ristretto::CompressedRistretto,
};
use {
crate::{
encryption::PEDERSEN_COMMITMENT_LEN,
pod::{impl_from_bytes, impl_from_str},
PEDERSEN_COMMITMENT_LEN,
},
base64::{prelude::BASE64_STANDARD, Engine},
bytemuck_derive::{Pod, Zeroable},
std::fmt,
};
#[cfg(not(target_os = "solana"))]
use {
crate::{encryption::pedersen::PedersenCommitment, errors::ElGamalError},
curve25519_dalek::ristretto::CompressedRistretto,
};

/// Maximum length of a base64 encoded ElGamal public key
const PEDERSEN_COMMITMENT_MAX_BASE64_LEN: usize = 44;
Expand All @@ -36,6 +36,12 @@ impl From<PedersenCommitment> for PodPedersenCommitment {
}
}

impl fmt::Display for PodPedersenCommitment {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", BASE64_STANDARD.encode(self.0))
}
}

impl_from_str!(
TYPE = PodPedersenCommitment,
BYTES_LEN = PEDERSEN_COMMITMENT_LEN,
Expand Down
35 changes: 35 additions & 0 deletions zk-sdk/src/pod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,38 @@ impl From<PodU64> for u64 {
Self::from_le_bytes(pod.0)
}
}

macro_rules! impl_from_str {
(TYPE = $type:ident, BYTES_LEN = $bytes_len:expr, BASE64_LEN = $base64_len:expr) => {
impl std::str::FromStr for $type {
type Err = crate::errors::ParseError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.len() > $base64_len {
return Err(Self::Err::WrongSize);
}
let mut bytes = [0u8; $bytes_len];
let decoded_len = BASE64_STANDARD
.decode_slice(s, &mut bytes)
.map_err(|_| Self::Err::Invalid)?;
if decoded_len != $bytes_len {
Err(Self::Err::WrongSize)
} else {
Ok($type(bytes))
}
}
}
};
}
pub(crate) use impl_from_str;

macro_rules! impl_from_bytes {
(TYPE = $type:ident, BYTES_LEN = $bytes_len:expr) => {
impl std::convert::From<[u8; $bytes_len]> for $type {
fn from(bytes: [u8; $bytes_len]) -> Self {
Self(bytes)
}
}
};
}
pub(crate) use impl_from_bytes;
51 changes: 42 additions & 9 deletions zk-sdk/src/range_proof/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,21 @@ pub const INNER_PRODUCT_PROOF_U64_LEN: usize = 448;

/// Byte length of a range proof for an unsigned 64-bit number
pub const RANGE_PROOF_U64_LEN: usize =
INNER_PRODUCT_PROOF_U64_LEN + RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN;
INNER_PRODUCT_PROOF_U64_LEN + RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN; // 672 bytes

/// Byte length of an inner-product proof for a vector of length 128
pub const INNER_PRODUCT_PROOF_U128_LEN: usize = 512;

/// Byte length of a range proof for an unsigned 128-bit number
pub const RANGE_PROOF_U128_LEN: usize =
INNER_PRODUCT_PROOF_U128_LEN + RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN;
INNER_PRODUCT_PROOF_U128_LEN + RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN; // 736 bytes

/// Byte length of an inner-product proof for a vector of length 256
pub const INNER_PRODUCT_PROOF_U256_LEN: usize = 576;

/// Byte length of a range proof for an unsigned 256-bit number
pub const RANGE_PROOF_U256_LEN: usize =
INNER_PRODUCT_PROOF_U256_LEN + RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN;
INNER_PRODUCT_PROOF_U256_LEN + RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN; // 800 bytes

#[allow(non_snake_case)]
#[cfg(not(target_os = "solana"))]
Expand Down Expand Up @@ -463,7 +463,13 @@ fn delta(bit_lengths: &[usize], y: &Scalar, z: &Scalar) -> Scalar {

#[cfg(test)]
mod tests {
use super::*;
use {
super::*,
crate::{
encryption::pod::pedersen::PodPedersenCommitment, range_proof::pod::PodRangeProofU128,
},
std::str::FromStr,
};

#[test]
fn test_single_rangeproof() {
Expand All @@ -475,9 +481,9 @@ mod tests {
let proof =
RangeProof::new(vec![55], vec![32], vec![&open], &mut transcript_create).unwrap();

assert!(proof
proof
.verify(vec![&comm], vec![32], &mut transcript_verify)
.is_ok());
.unwrap();
}

#[test]
Expand All @@ -497,14 +503,41 @@ mod tests {
)
.unwrap();

assert!(proof
proof
.verify(
vec![&comm_1, &comm_2, &comm_3],
vec![64, 32, 32],
&mut transcript_verify,
)
.is_ok());
.unwrap();
}

// TODO: write test for serialization/deserialization
#[test]
fn test_range_proof_string() {
let commitment_1_str = "dDaa/MTEDlyI0Nxx+iu1tOteZsTWmPXAfn9QI0W9mSc=";
let pod_commitment_1 = PodPedersenCommitment::from_str(commitment_1_str).unwrap();
let commitment_1: PedersenCommitment = pod_commitment_1.try_into().unwrap();

let commitment_2_str = "tnRILjKpogi2sXxLgZzMqlqPMLnCJmrSjZ5SPQYhtgg=";
let pod_commitment_2 = PodPedersenCommitment::from_str(commitment_2_str).unwrap();
let commitment_2: PedersenCommitment = pod_commitment_2.try_into().unwrap();

let commitment_3_str = "ZAC5ZLXotsMOVExtrr56D/EZNeyo9iWepNbeH22EuRo=";
let pod_commitment_3 = PodPedersenCommitment::from_str(commitment_3_str).unwrap();
let commitment_3: PedersenCommitment = pod_commitment_3.try_into().unwrap();

let proof_str = "AvvBQL63pXMXsmuvuNbs/CqXdzeyrMpEIO2O/cI6/SyqU4N+7HUU3LmXai9st+DxqTnuKsm0SgnADfpLpQCEbDDupMb09NY8oHT8Bx8WQhv9eyoBlrPRd7DVhOUsio02gBshe3p2Wj7+yDCpFaZ7/PMypFBX6+E+EqCiPI6yUk4ztslWY0Ksac41eJgcPzXyIx2kvmSTsVBKLb7U01PWBC+AUyUmK3/IdvmJ4DnlS3xFrdg/mxSsYJFd3OZA3cwDb0jePQf/P43/2VVqPRixMVO7+VGoMKPoRTEEVbClsAlW6stGTFPcrimu3c+geASgvwElkIKNGtYcjoj3SS+/VeqIG9Ei1j+TJtPhOE9SG4KNw9xBGwecpliDbQhKjO950EVcnOts+a525/frZV1jHJmOOrZtKRV4pvk37dtQkx4sv+pxRmfVrjwOcKQeg+BzcuF0vaQbqa4SUbzbO9z3RwIMlYIBaz0bqZgJmtPOFuFmNyCJaeB29vlcEAfYbn5gdlgtWP50tKmhoskndulziKZjz4qHSA9rbG2ZtoMHoCsAobHKu2H9OxcaK4Scj1QGwst+zXBEY8uePNbxvU5DMJLVFORtLUXkVdPCmCSsm1Bz4TRbnls8LOVW6wqTgShQMhjNM3RtwdHXENPn5uDnhyvfduAcL+DtI8AIJyRneROefk7i7gjal8dLdMM/QnXT7ctpMQU6uNlpsNzq65xlOQKXO71vQ3c2mE/DmxVJi6BTS5WCzavvhiqdhQyRL61ESCALQpaP0/d0DLwLikVH3ypuDLEnVXe9Pmkxdd0xCzO6QcfyK50CPnV/dVgHeLg8EVag2O83+/7Ys5oLxrDad9TJTDcrT2xsRqECFnSA+z9uZtDPujhQL0ogS5RH4agnQN4mVGTwOLV8OKpn+AvWq6+j1/9EXFkLPBTU5wT0FQuT2VZ8xp5GeqdI13Zey1uPrxc6CZZ407y9OINED4IdBQ==";
let pod_proof = PodRangeProofU128::from_str(proof_str).unwrap();
let proof: RangeProof = pod_proof.try_into().unwrap();

let mut transcript_verify = Transcript::new(b"Test");

proof
.verify(
vec![&commitment_1, &commitment_2, &commitment_3],
vec![64, 32, 32],
&mut transcript_verify,
)
.unwrap()
}
}
Loading