From 7873175764f4ca8cfb2bf01dd70b23e207d943f2 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Tue, 8 Feb 2022 12:09:50 -0500 Subject: [PATCH] zk-token-sdk: fix pod for zk-token transfer (#22957) --- zk-token-sdk/src/instruction/transfer.rs | 73 ++++++------- .../src/instruction/transfer_with_fee.rs | 102 ++++++++---------- zk-token-sdk/src/zk_token_elgamal/convert.rs | 62 +++++++++-- zk-token-sdk/src/zk_token_elgamal/pod.rs | 89 +++++++++++---- 4 files changed, 196 insertions(+), 130 deletions(-) diff --git a/zk-token-sdk/src/instruction/transfer.rs b/zk-token-sdk/src/instruction/transfer.rs index 832085ebdd..df5e1fdbb6 100644 --- a/zk-token-sdk/src/instruction/transfer.rs +++ b/zk-token-sdk/src/instruction/transfer.rs @@ -52,31 +52,13 @@ impl TransferAmountEncryption { (transfer_amount_encryption, opening) } - pub fn to_bytes(&self) -> [u8; 128] { - let mut bytes = [0u8; 128]; - bytes[..32].copy_from_slice(&self.commitment.to_bytes()); - bytes[32..64].copy_from_slice(&self.source.to_bytes()); - bytes[64..96].copy_from_slice(&self.dest.to_bytes()); - bytes[96..128].copy_from_slice(&self.auditor.to_bytes()); - bytes - } - - pub fn from_bytes(bytes: &[u8]) -> Result { - let bytes = array_ref![bytes, 0, 128]; - let (commitment, source, dest, auditor) = array_refs![bytes, 32, 32, 32, 32]; - - let commitment = - PedersenCommitment::from_bytes(commitment).ok_or(ProofError::Verification)?; - let source = DecryptHandle::from_bytes(source).ok_or(ProofError::Verification)?; - let dest = DecryptHandle::from_bytes(dest).ok_or(ProofError::Verification)?; - let auditor = DecryptHandle::from_bytes(auditor).ok_or(ProofError::Verification)?; - - Ok(Self { - commitment, - source, - dest, - auditor, - }) + pub fn to_pod(&self) -> pod::TransferAmountEncryption { + pod::TransferAmountEncryption { + commitment: self.commitment.into(), + source: self.source.into(), + dest: self.dest.into(), + auditor: self.auditor.into(), + } } } @@ -143,8 +125,11 @@ impl TransferData { - combine_u32_ciphertexts(&transfer_amount_lo_source, &transfer_amount_hi_source); // generate transcript and append all public inputs - let pod_transfer_pubkeys = - pod::TransferPubkeys::new(&keypair_source.public, pubkey_dest, pubkey_auditor); + let pod_transfer_pubkeys = pod::TransferPubkeys { + source: keypair_source.public.into(), + dest: (*pubkey_dest).into(), + auditor: (*pubkey_auditor).into(), + }; let pod_ciphertext_lo: pod::TransferAmountEncryption = ciphertext_lo.into(); let pod_ciphertext_hi: pod::TransferAmountEncryption = ciphertext_hi.into(); let pod_ciphertext_new_source: pod::ElGamalCiphertext = ciphertext_new_source.into(); @@ -282,10 +267,21 @@ impl TransferProof { ) -> Transcript { let mut transcript = Transcript::new(b"transfer-proof"); - transcript.append_message(b"transfer-pubkeys", &transfer_pubkeys.0); - transcript.append_message(b"ciphertext-lo", &ciphertext_lo.0); - transcript.append_message(b"ciphertext-hi", &ciphertext_hi.0); - transcript.append_message(b"ciphertext-new-source", &ciphertext_new_source.0); + transcript.append_pubkey(b"pubkey_source", &transfer_pubkeys.source); + transcript.append_pubkey(b"pubkey_dest", &transfer_pubkeys.dest); + transcript.append_pubkey(b"pubkey_auditor", &transfer_pubkeys.auditor); + + transcript.append_commitment(b"comm-lo-amount", &ciphertext_lo.commitment); + transcript.append_handle(b"handle-lo-source", &ciphertext_lo.source); + transcript.append_handle(b"handle-lo-dest", &ciphertext_lo.dest); + transcript.append_handle(b"handle-lo-auditor", &ciphertext_lo.auditor); + + transcript.append_commitment(b"comm-hi-amount", &ciphertext_hi.commitment); + transcript.append_handle(b"handle-hi-source", &ciphertext_hi.source); + transcript.append_handle(b"handle-hi-dest", &ciphertext_hi.dest); + transcript.append_handle(b"handle-hi-auditor", &ciphertext_hi.auditor); + + transcript.append_ciphertext(b"ciphertext-new-source", ciphertext_new_source); transcript } @@ -367,6 +363,8 @@ impl TransferProof { transcript, )?; + println!("equality pass"); + // verify validity proof aggregated_validity_proof.verify( (&transfer_pubkeys.dest, &transfer_pubkeys.auditor), @@ -376,6 +374,8 @@ impl TransferProof { transcript, )?; + println!("validity pass"); + // verify range proof let commitment_new_source = self.commitment_new_source.try_into()?; range_proof.verify( @@ -429,17 +429,6 @@ impl TransferPubkeys { } } -#[cfg(not(target_arch = "bpf"))] -impl pod::TransferPubkeys { - pub fn new(source: &ElGamalPubkey, dest: &ElGamalPubkey, auditor: &ElGamalPubkey) -> Self { - let mut bytes = [0u8; 96]; - bytes[..32].copy_from_slice(&source.to_bytes()); - bytes[32..64].copy_from_slice(&dest.to_bytes()); - bytes[64..96].copy_from_slice(&auditor.to_bytes()); - Self(bytes) - } -} - #[cfg(test)] mod test { use {super::*, crate::encryption::elgamal::ElGamalKeypair}; diff --git a/zk-token-sdk/src/instruction/transfer_with_fee.rs b/zk-token-sdk/src/instruction/transfer_with_fee.rs index a04b78ed6a..1c16f115f3 100644 --- a/zk-token-sdk/src/instruction/transfer_with_fee.rs +++ b/zk-token-sdk/src/instruction/transfer_with_fee.rs @@ -123,21 +123,22 @@ impl TransferWithFeeData { FeeEncryption::new(fee_to_encrypt, pubkey_dest, pubkey_fee_collector); // generate transcript and append all public inputs - let pod_transfer_with_fee_pubkeys = pod::TransferWithFeePubkeys::new( - &keypair_source.public, - pubkey_dest, - pubkey_auditor, - pubkey_fee_collector, - ); - let pod_ciphertext_lo = pod::TransferAmountEncryption(ciphertext_lo.to_bytes()); - let pod_ciphertext_hi = pod::TransferAmountEncryption(ciphertext_hi.to_bytes()); + let pod_transfer_with_fee_pubkeys = pod::TransferWithFeePubkeys { + source: keypair_source.public.into(), + dest: (*pubkey_dest).into(), + auditor: (*pubkey_auditor).into(), + fee_collector: (*pubkey_fee_collector).into(), + }; + let pod_ciphertext_lo: pod::TransferAmountEncryption = ciphertext_lo.to_pod(); + let pod_ciphertext_hi: pod::TransferAmountEncryption = ciphertext_hi.to_pod(); let pod_ciphertext_new_source: pod::ElGamalCiphertext = ciphertext_new_source.into(); - let pod_ciphertext_fee = pod::FeeEncryption(ciphertext_fee.to_bytes()); + let pod_ciphertext_fee: pod::FeeEncryption = ciphertext_fee.to_pod(); let mut transcript = TransferWithFeeProof::transcript_new( &pod_transfer_with_fee_pubkeys, &pod_ciphertext_lo, &pod_ciphertext_hi, + &pod_ciphertext_new_source, &pod_ciphertext_fee, ); @@ -225,13 +226,14 @@ impl Verifiable for TransferWithFeeData { &self.transfer_with_fee_pubkeys, &self.ciphertext_lo, &self.ciphertext_hi, + &self.ciphertext_new_source, &self.ciphertext_fee, ); let ciphertext_lo = self.ciphertext_lo.try_into()?; let ciphertext_hi = self.ciphertext_hi.try_into()?; - let transfer_with_fee_pubkeys = self.transfer_with_fee_pubkeys.try_into()?; - let new_spendable_ciphertext = self.ciphertext_new_source.try_into()?; + let pubkeys_transfer_with_fee = self.transfer_with_fee_pubkeys.try_into()?; + let ciphertext_new_source = self.ciphertext_new_source.try_into()?; let ciphertext_fee = self.ciphertext_fee.try_into()?; let fee_parameters = self.fee_parameters.into(); @@ -239,8 +241,8 @@ impl Verifiable for TransferWithFeeData { self.proof.verify( &ciphertext_lo, &ciphertext_hi, - &transfer_with_fee_pubkeys, - &new_spendable_ciphertext, + &pubkeys_transfer_with_fee, + &ciphertext_new_source, &ciphertext_fee, fee_parameters, &mut transcript, @@ -268,14 +270,34 @@ impl TransferWithFeeProof { transfer_with_fee_pubkeys: &pod::TransferWithFeePubkeys, ciphertext_lo: &pod::TransferAmountEncryption, ciphertext_hi: &pod::TransferAmountEncryption, + ciphertext_new_source: &pod::ElGamalCiphertext, ciphertext_fee: &pod::FeeEncryption, ) -> Transcript { let mut transcript = Transcript::new(b"FeeProof"); - transcript.append_message(b"transfer-with-fee-pubkeys", &transfer_with_fee_pubkeys.0); - transcript.append_message(b"ciphertext-lo", &ciphertext_lo.0); - transcript.append_message(b"ciphertext-hi", &ciphertext_hi.0); - transcript.append_message(b"ciphertext-fee", &ciphertext_fee.0); + transcript.append_pubkey(b"pubkey_source", &transfer_with_fee_pubkeys.source); + transcript.append_pubkey(b"pubkey_dest", &transfer_with_fee_pubkeys.dest); + transcript.append_pubkey(b"pubkey_auditor", &transfer_with_fee_pubkeys.auditor); + transcript.append_pubkey( + b"pubkey_fee_collector", + &transfer_with_fee_pubkeys.fee_collector, + ); + + transcript.append_commitment(b"comm-lo-amount", &ciphertext_lo.commitment); + transcript.append_handle(b"handle-lo-source", &ciphertext_lo.source); + transcript.append_handle(b"handle-lo-dest", &ciphertext_lo.dest); + transcript.append_handle(b"handle-lo-auditor", &ciphertext_lo.auditor); + + transcript.append_commitment(b"comm-hi-amount", &ciphertext_hi.commitment); + transcript.append_handle(b"handle-hi-source", &ciphertext_hi.source); + transcript.append_handle(b"handle-hi-dest", &ciphertext_hi.dest); + transcript.append_handle(b"handle-hi-auditor", &ciphertext_hi.auditor); + + transcript.append_ciphertext(b"ctxt-new-source", ciphertext_new_source); + + transcript.append_commitment(b"comm-fee", &ciphertext_fee.commitment); + transcript.append_handle(b"handle-fee-dest", &ciphertext_fee.dest); + transcript.append_handle(b"handle-fee-auditor", &ciphertext_fee.fee_collector); transcript } @@ -510,23 +532,6 @@ impl TransferWithFeePubkeys { } } -#[cfg(not(target_arch = "bpf"))] -impl pod::TransferWithFeePubkeys { - pub fn new( - source: &ElGamalPubkey, - dest: &ElGamalPubkey, - auditor: &ElGamalPubkey, - fee_collector: &ElGamalPubkey, - ) -> Self { - let mut bytes = [0u8; 128]; - bytes[..32].copy_from_slice(&source.to_bytes()); - bytes[32..64].copy_from_slice(&dest.to_bytes()); - bytes[64..96].copy_from_slice(&auditor.to_bytes()); - bytes[96..128].copy_from_slice(&fee_collector.to_bytes()); - Self(bytes) - } -} - #[derive(Clone)] #[repr(C)] #[cfg(not(target_arch = "bpf"))] @@ -553,29 +558,12 @@ impl FeeEncryption { (fee_encryption, opening) } - pub fn to_bytes(&self) -> [u8; 96] { - let mut bytes = [0u8; 96]; - bytes[..32].copy_from_slice(&self.commitment.to_bytes()); - bytes[32..64].copy_from_slice(&self.dest.to_bytes()); - bytes[64..96].copy_from_slice(&self.fee_collector.to_bytes()); - bytes - } - - pub fn from_bytes(bytes: &[u8]) -> Result { - let bytes = array_ref![bytes, 0, 96]; - let (commitment, dest, fee_collector) = array_refs![bytes, 32, 32, 32]; - - let commitment = - PedersenCommitment::from_bytes(commitment).ok_or(ProofError::Verification)?; - let dest = DecryptHandle::from_bytes(dest).ok_or(ProofError::Verification)?; - let fee_collector = - DecryptHandle::from_bytes(fee_collector).ok_or(ProofError::Verification)?; - - Ok(Self { - commitment, - dest, - fee_collector, - }) + pub fn to_pod(&self) -> pod::FeeEncryption { + pod::FeeEncryption { + commitment: self.commitment.into(), + dest: self.dest.into(), + fee_collector: self.fee_collector.into(), + } } } diff --git a/zk-token-sdk/src/zk_token_elgamal/convert.rs b/zk-token-sdk/src/zk_token_elgamal/convert.rs index 73577854b5..2c53bb67dc 100644 --- a/zk-token-sdk/src/zk_token_elgamal/convert.rs +++ b/zk-token-sdk/src/zk_token_elgamal/convert.rs @@ -312,7 +312,11 @@ mod target_arch { impl From for pod::TransferPubkeys { fn from(keys: TransferPubkeys) -> Self { - Self(keys.to_bytes()) + Self { + source: keys.source.into(), + dest: keys.dest.into(), + auditor: keys.auditor.into(), + } } } @@ -320,13 +324,22 @@ mod target_arch { type Error = ProofError; fn try_from(pod: pod::TransferPubkeys) -> Result { - Self::from_bytes(&pod.0) + Ok(Self { + source: pod.source.try_into()?, + dest: pod.dest.try_into()?, + auditor: pod.auditor.try_into()?, + }) } } impl From for pod::TransferWithFeePubkeys { fn from(keys: TransferWithFeePubkeys) -> Self { - Self(keys.to_bytes()) + Self { + source: keys.source.into(), + dest: keys.dest.into(), + auditor: keys.auditor.into(), + fee_collector: keys.fee_collector.into(), + } } } @@ -334,13 +347,23 @@ mod target_arch { type Error = ProofError; fn try_from(pod: pod::TransferWithFeePubkeys) -> Result { - Self::from_bytes(&pod.0) + Ok(Self { + source: pod.source.try_into()?, + dest: pod.dest.try_into()?, + auditor: pod.auditor.try_into()?, + fee_collector: pod.fee_collector.try_into()?, + }) } } impl From for pod::TransferAmountEncryption { fn from(ciphertext: TransferAmountEncryption) -> Self { - Self(ciphertext.to_bytes()) + Self { + commitment: ciphertext.commitment.into(), + source: ciphertext.source.into(), + dest: ciphertext.dest.into(), + auditor: ciphertext.auditor.into(), + } } } @@ -348,13 +371,22 @@ mod target_arch { type Error = ProofError; fn try_from(pod: pod::TransferAmountEncryption) -> Result { - Self::from_bytes(&pod.0) + Ok(Self { + commitment: pod.commitment.try_into()?, + source: pod.source.try_into()?, + dest: pod.dest.try_into()?, + auditor: pod.auditor.try_into()?, + }) } } impl From for pod::FeeEncryption { fn from(ciphertext: FeeEncryption) -> Self { - Self(ciphertext.to_bytes()) + Self { + commitment: ciphertext.commitment.into(), + dest: ciphertext.dest.into(), + fee_collector: ciphertext.fee_collector.into(), + } } } @@ -362,19 +394,29 @@ mod target_arch { type Error = ProofError; fn try_from(pod: pod::FeeEncryption) -> Result { - Self::from_bytes(&pod.0) + Ok(Self { + commitment: pod.commitment.try_into()?, + dest: pod.dest.try_into()?, + fee_collector: pod.fee_collector.try_into()?, + }) } } impl From for pod::FeeParameters { fn from(parameters: FeeParameters) -> Self { - Self(parameters.to_bytes()) + Self { + fee_rate_basis_points: parameters.fee_rate_basis_points.into(), + maximum_fee: parameters.maximum_fee.into(), + } } } impl From for FeeParameters { fn from(pod: pod::FeeParameters) -> Self { - Self::from_bytes(&pod.0) + Self { + fee_rate_basis_points: pod.fee_rate_basis_points.into(), + maximum_fee: pod.maximum_fee.into(), + } } } } diff --git a/zk-token-sdk/src/zk_token_elgamal/pod.rs b/zk-token-sdk/src/zk_token_elgamal/pod.rs index 29f152cfcd..158929e0d0 100644 --- a/zk-token-sdk/src/zk_token_elgamal/pod.rs +++ b/zk-token-sdk/src/zk_token_elgamal/pod.rs @@ -1,6 +1,34 @@ pub use bytemuck::{Pod, Zeroable}; use std::fmt; +#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] +#[repr(transparent)] +pub struct PodU16([u8; 2]); +impl From for PodU16 { + fn from(n: u16) -> Self { + Self(n.to_le_bytes()) + } +} +impl From for u16 { + fn from(pod: PodU16) -> Self { + Self::from_le_bytes(pod.0) + } +} + +#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)] +#[repr(transparent)] +pub struct PodU64([u8; 8]); +impl From for PodU64 { + fn from(n: u64) -> Self { + Self(n.to_le_bytes()) + } +} +impl From for u64 { + fn from(pod: PodU64) -> Self { + Self::from_le_bytes(pod.0) + } +} + #[derive(Clone, Copy, Pod, Zeroable, PartialEq)] #[repr(transparent)] pub struct Scalar(pub [u8; 32]); @@ -153,31 +181,50 @@ impl Default for AeCiphertext { } // TODO: refactor this code into the instruction module -#[derive(Clone, Copy)] -#[repr(transparent)] -pub struct TransferPubkeys(pub [u8; 96]); +#[derive(Clone, Copy, Pod, Zeroable)] +#[repr(C)] +pub struct TransferPubkeys { + pub source: ElGamalPubkey, + pub dest: ElGamalPubkey, + pub auditor: ElGamalPubkey, +} -unsafe impl Zeroable for TransferPubkeys {} -unsafe impl Pod for TransferPubkeys {} +// pub struct TransferPubkeys(pub [u8; 96]); + +// unsafe impl Zeroable for TransferPubkeys {} +// unsafe impl Pod for TransferPubkeys {} #[derive(Clone, Copy, Pod, Zeroable)] -#[repr(transparent)] -pub struct TransferWithFeePubkeys(pub [u8; 128]); +#[repr(C)] +pub struct TransferWithFeePubkeys { + pub source: ElGamalPubkey, + pub dest: ElGamalPubkey, + pub auditor: ElGamalPubkey, + pub fee_collector: ElGamalPubkey, +} #[derive(Clone, Copy, Pod, Zeroable)] -#[repr(transparent)] -pub struct TransferAmountEncryption(pub [u8; 128]); +#[repr(C)] +pub struct TransferAmountEncryption { + pub commitment: PedersenCommitment, + pub source: DecryptHandle, + pub dest: DecryptHandle, + pub auditor: DecryptHandle, +} -#[derive(Clone, Copy)] -#[repr(transparent)] -pub struct FeeEncryption(pub [u8; 96]); +#[derive(Clone, Copy, Pod, Zeroable)] +#[repr(C)] +pub struct FeeEncryption { + pub commitment: PedersenCommitment, + pub dest: DecryptHandle, + pub fee_collector: DecryptHandle, +} -unsafe impl Zeroable for FeeEncryption {} -unsafe impl Pod for FeeEncryption {} - -#[derive(Clone, Copy)] -#[repr(transparent)] -pub struct FeeParameters(pub [u8; 10]); - -unsafe impl Zeroable for FeeParameters {} -unsafe impl Pod for FeeParameters {} +#[derive(Clone, Copy, Pod, Zeroable)] +#[repr(C)] +pub struct FeeParameters { + /// Fee rate expressed as basis points of the transfer amount, i.e. increments of 0.01% + pub fee_rate_basis_points: PodU16, + /// Maximum fee assessed on transfers, expressed as an amount of tokens + pub maximum_fee: PodU64, +}