Skip to content

Commit

Permalink
v1.16: [zk-token-sdk] Refactor zk-token-elgamal conversion code for…
Browse files Browse the repository at this point in the history
… authenticated encryption, range proof, and sigma proof types (backport of #31855) (#31887)

[zk-token-sdk] Refactor `zk-token-elgamal` conversion code for authenticated encryption, range proof, and sigma proof types (#31855)

* refactor convert logic for `AeCiphertext`

* refactor convert logic for `RangeProof`

* refactor convert logic for sigma proof types

* Apply suggestions from code review

Co-authored-by: Tyera <[email protected]>

---------

Co-authored-by: Tyera <[email protected]>
(cherry picked from commit e4fe933)

Co-authored-by: samkim-crypto <[email protected]>
  • Loading branch information
mergify[bot] and samkim-crypto authored May 31, 2023
1 parent 17f047c commit a3448de
Show file tree
Hide file tree
Showing 4 changed files with 282 additions and 256 deletions.
214 changes: 1 addition & 213 deletions zk-token-sdk/src/zk_token_elgamal/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,22 +52,11 @@ mod target_arch {
super::pod,
crate::{
curve25519::scalar::PodScalar,
encryption::auth_encryption::AeCiphertext,
errors::{ProofError, ProofVerificationError},
errors::ProofError,
instruction::{
transfer::{TransferAmountEncryption, TransferPubkeys},
transfer_with_fee::{FeeEncryption, FeeParameters, TransferWithFeePubkeys},
},
range_proof::{errors::RangeProofError, RangeProof},
sigma_proofs::{
ciphertext_ciphertext_equality_proof::CiphertextCiphertextEqualityProof,
ciphertext_commitment_equality_proof::CiphertextCommitmentEqualityProof,
errors::*,
fee_proof::FeeSigmaProof,
pubkey_proof::PubkeyValidityProof,
validity_proof::{AggregatedValidityProof, ValidityProof},
zero_balance_proof::ZeroBalanceProof,
},
},
curve25519_dalek::{ristretto::CompressedRistretto, scalar::Scalar},
std::convert::TryFrom,
Expand Down Expand Up @@ -99,207 +88,6 @@ mod target_arch {
}
}

impl From<AeCiphertext> for pod::AeCiphertext {
fn from(ct: AeCiphertext) -> Self {
Self(ct.to_bytes())
}
}

impl TryFrom<pod::AeCiphertext> for AeCiphertext {
type Error = ProofError;

fn try_from(ct: pod::AeCiphertext) -> Result<Self, Self::Error> {
Self::from_bytes(&ct.0).ok_or(ProofError::CiphertextDeserialization)
}
}

impl From<CiphertextCommitmentEqualityProof> for pod::CiphertextCommitmentEqualityProof {
fn from(proof: CiphertextCommitmentEqualityProof) -> Self {
Self(proof.to_bytes())
}
}

impl TryFrom<pod::CiphertextCommitmentEqualityProof> for CiphertextCommitmentEqualityProof {
type Error = EqualityProofError;

fn try_from(pod: pod::CiphertextCommitmentEqualityProof) -> Result<Self, Self::Error> {
Self::from_bytes(&pod.0)
}
}

impl From<CiphertextCiphertextEqualityProof> for pod::CiphertextCiphertextEqualityProof {
fn from(proof: CiphertextCiphertextEqualityProof) -> Self {
Self(proof.to_bytes())
}
}

impl TryFrom<pod::CiphertextCiphertextEqualityProof> for CiphertextCiphertextEqualityProof {
type Error = EqualityProofError;

fn try_from(pod: pod::CiphertextCiphertextEqualityProof) -> Result<Self, Self::Error> {
Self::from_bytes(&pod.0)
}
}

impl From<ValidityProof> for pod::ValidityProof {
fn from(proof: ValidityProof) -> Self {
Self(proof.to_bytes())
}
}

impl TryFrom<pod::ValidityProof> for ValidityProof {
type Error = ValidityProofError;

fn try_from(pod: pod::ValidityProof) -> Result<Self, Self::Error> {
Self::from_bytes(&pod.0)
}
}

impl From<AggregatedValidityProof> for pod::AggregatedValidityProof {
fn from(proof: AggregatedValidityProof) -> Self {
Self(proof.to_bytes())
}
}

impl TryFrom<pod::AggregatedValidityProof> for AggregatedValidityProof {
type Error = ValidityProofError;

fn try_from(pod: pod::AggregatedValidityProof) -> Result<Self, Self::Error> {
Self::from_bytes(&pod.0)
}
}

impl From<ZeroBalanceProof> for pod::ZeroBalanceProof {
fn from(proof: ZeroBalanceProof) -> Self {
Self(proof.to_bytes())
}
}

impl TryFrom<pod::ZeroBalanceProof> for ZeroBalanceProof {
type Error = ZeroBalanceProofError;

fn try_from(pod: pod::ZeroBalanceProof) -> Result<Self, Self::Error> {
Self::from_bytes(&pod.0)
}
}

impl From<FeeSigmaProof> for pod::FeeSigmaProof {
fn from(proof: FeeSigmaProof) -> Self {
Self(proof.to_bytes())
}
}

impl TryFrom<pod::FeeSigmaProof> for FeeSigmaProof {
type Error = FeeSigmaProofError;

fn try_from(pod: pod::FeeSigmaProof) -> Result<Self, Self::Error> {
Self::from_bytes(&pod.0)
}
}

impl From<PubkeyValidityProof> for pod::PubkeyValidityProof {
fn from(proof: PubkeyValidityProof) -> Self {
Self(proof.to_bytes())
}
}

impl TryFrom<pod::PubkeyValidityProof> for PubkeyValidityProof {
type Error = PubkeyValidityProofError;

fn try_from(pod: pod::PubkeyValidityProof) -> Result<Self, Self::Error> {
Self::from_bytes(&pod.0)
}
}

impl TryFrom<RangeProof> for pod::RangeProof64 {
type Error = RangeProofError;

fn try_from(proof: RangeProof) -> Result<Self, Self::Error> {
if proof.ipp_proof.serialized_size() != 448 {
return Err(ProofVerificationError::Deserialization.into());
}

let mut buf = [0_u8; 672];
buf[..32].copy_from_slice(proof.A.as_bytes());
buf[32..64].copy_from_slice(proof.S.as_bytes());
buf[64..96].copy_from_slice(proof.T_1.as_bytes());
buf[96..128].copy_from_slice(proof.T_2.as_bytes());
buf[128..160].copy_from_slice(proof.t_x.as_bytes());
buf[160..192].copy_from_slice(proof.t_x_blinding.as_bytes());
buf[192..224].copy_from_slice(proof.e_blinding.as_bytes());
buf[224..672].copy_from_slice(&proof.ipp_proof.to_bytes());
Ok(pod::RangeProof64(buf))
}
}

impl TryFrom<pod::RangeProof64> for RangeProof {
type Error = RangeProofError;

fn try_from(pod: pod::RangeProof64) -> Result<Self, Self::Error> {
Self::from_bytes(&pod.0)
}
}

#[cfg(not(target_os = "solana"))]
impl TryFrom<RangeProof> for pod::RangeProof128 {
type Error = RangeProofError;

fn try_from(proof: RangeProof) -> Result<Self, Self::Error> {
if proof.ipp_proof.serialized_size() != 512 {
return Err(ProofVerificationError::Deserialization.into());
}

let mut buf = [0_u8; 736];
buf[..32].copy_from_slice(proof.A.as_bytes());
buf[32..64].copy_from_slice(proof.S.as_bytes());
buf[64..96].copy_from_slice(proof.T_1.as_bytes());
buf[96..128].copy_from_slice(proof.T_2.as_bytes());
buf[128..160].copy_from_slice(proof.t_x.as_bytes());
buf[160..192].copy_from_slice(proof.t_x_blinding.as_bytes());
buf[192..224].copy_from_slice(proof.e_blinding.as_bytes());
buf[224..736].copy_from_slice(&proof.ipp_proof.to_bytes());
Ok(pod::RangeProof128(buf))
}
}

impl TryFrom<pod::RangeProof128> for RangeProof {
type Error = RangeProofError;

fn try_from(pod: pod::RangeProof128) -> Result<Self, Self::Error> {
Self::from_bytes(&pod.0)
}
}

#[cfg(not(target_os = "solana"))]
impl TryFrom<RangeProof> for pod::RangeProof256 {
type Error = RangeProofError;

fn try_from(proof: RangeProof) -> Result<Self, Self::Error> {
if proof.ipp_proof.serialized_size() != 576 {
return Err(ProofVerificationError::Deserialization.into());
}

let mut buf = [0_u8; 800];
buf[..32].copy_from_slice(proof.A.as_bytes());
buf[32..64].copy_from_slice(proof.S.as_bytes());
buf[64..96].copy_from_slice(proof.T_1.as_bytes());
buf[96..128].copy_from_slice(proof.T_2.as_bytes());
buf[128..160].copy_from_slice(proof.t_x.as_bytes());
buf[160..192].copy_from_slice(proof.t_x_blinding.as_bytes());
buf[192..224].copy_from_slice(proof.e_blinding.as_bytes());
buf[224..800].copy_from_slice(&proof.ipp_proof.to_bytes());
Ok(pod::RangeProof256(buf))
}
}

impl TryFrom<pod::RangeProof256> for RangeProof {
type Error = RangeProofError;

fn try_from(pod: pod::RangeProof256) -> Result<Self, Self::Error> {
Self::from_bytes(&pod.0)
}
}

impl From<TransferPubkeys> for pod::TransferPubkeys {
fn from(keys: TransferPubkeys) -> Self {
Self {
Expand Down
27 changes: 24 additions & 3 deletions zk-token-sdk/src/zk_token_elgamal/pod/auth_encryption.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
//! Plain Old Data types for the AES128-GCM-SIV authenticated encryption scheme.
#[cfg(not(target_os = "solana"))]
use crate::{encryption::auth_encryption as decoded, errors::ProofError};
use {
crate::zk_token_elgamal::pod::{Pod, Zeroable},
base64::{prelude::BASE64_STANDARD, Engine},
std::fmt,
};

/// Serialization for AeCiphertext
/// The `AeCiphertext` type as a `Pod`.
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct AeCiphertext(pub [u8; 36]);

// `AeCiphertext` is a Pod and Zeroable.
// Add the marker traits manually because `bytemuck` only adds them for some `u8` arrays
// `AeCiphertext` is a wrapper type for a byte array, which is both `Pod` and `Zeroable`. However,
// the marker traits `bytemuck::Pod` and `bytemuck::Zeroable` can only be derived for power-of-two
// length byte arrays. Directly implement these traits for `AeCiphertext`.
unsafe impl Zeroable for AeCiphertext {}
unsafe impl Pod for AeCiphertext {}

Expand All @@ -31,3 +36,19 @@ impl Default for AeCiphertext {
Self::zeroed()
}
}

#[cfg(not(target_os = "solana"))]
impl From<decoded::AeCiphertext> for AeCiphertext {
fn from(decoded_ciphertext: decoded::AeCiphertext) -> Self {
Self(decoded_ciphertext.to_bytes())
}
}

#[cfg(not(target_os = "solana"))]
impl TryFrom<AeCiphertext> for decoded::AeCiphertext {
type Error = ProofError;

fn try_from(pod_ciphertext: AeCiphertext) -> Result<Self, Self::Error> {
Self::from_bytes(&pod_ciphertext.0).ok_or(ProofError::CiphertextDeserialization)
}
}
Loading

0 comments on commit a3448de

Please sign in to comment.