Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
[zk-token-sdk] remove non-pod structs TransferPubkeys and `Transfer…
Browse files Browse the repository at this point in the history
…WithFeePubkeys` (#32042)

* remove decoded `TransferWithFeePubkeys`

* remove decoded `TransferPubkey`

* rename `TransferPubkeys` and `TransferWithFeePubkeys` fields

* relocate `TransferPubkeys` and `TransferWithFeePubkeys`

* reorder proof verify parameters for transfer and transfer with fee

* clippy
  • Loading branch information
samkim-crypto authored Jun 19, 2023
1 parent 748223c commit d654715
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 195 deletions.
106 changes: 41 additions & 65 deletions zk-token-sdk/src/instruction/transfer/with_fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ use {
},
transcript::TranscriptProtocol,
},
arrayref::{array_ref, array_refs},
bytemuck::bytes_of,
curve25519_dalek::scalar::Scalar,
merlin::Transcript,
Expand Down Expand Up @@ -87,7 +86,7 @@ pub struct TransferWithFeeProofContext {
pub ciphertext_hi: pod::TransferAmountCiphertext, // 128 bytes

/// The public encryption keys associated with the transfer: source, dest, and auditor
pub transfer_with_fee_pubkeys: pod::TransferWithFeePubkeys, // 128 bytes
pub transfer_with_fee_pubkeys: TransferWithFeePubkeys, // 128 bytes

/// The final spendable ciphertext after the transfer,
pub new_source_ciphertext: pod::ElGamalCiphertext, // 64 bytes
Expand All @@ -102,6 +101,16 @@ pub struct TransferWithFeeProofContext {
pub fee_parameters: pod::FeeParameters, // 10 bytes
}

/// The ElGamal public keys needed for a transfer with fee
#[derive(Clone, Copy, Pod, Zeroable)]
#[repr(C)]
pub struct TransferWithFeePubkeys {
pub source: pod::ElGamalPubkey,
pub destination: pod::ElGamalPubkey,
pub auditor: pod::ElGamalPubkey,
pub withdraw_withheld_authority: pod::ElGamalPubkey,
}

#[cfg(not(target_os = "solana"))]
impl TransferWithFeeData {
pub fn new(
Expand Down Expand Up @@ -177,11 +186,11 @@ impl TransferWithFeeData {
);

// generate transcript and append all public inputs
let pod_transfer_with_fee_pubkeys = pod::TransferWithFeePubkeys {
source_pubkey: source_keypair.public.into(),
destination_pubkey: (*destination_pubkey).into(),
auditor_pubkey: (*auditor_pubkey).into(),
withdraw_withheld_authority_pubkey: (*withdraw_withheld_authority_pubkey).into(),
let pod_transfer_with_fee_pubkeys = TransferWithFeePubkeys {
source: source_keypair.public.into(),
destination: (*destination_pubkey).into(),
auditor: (*auditor_pubkey).into(),
withdraw_withheld_authority: (*withdraw_withheld_authority_pubkey).into(),
};
let pod_ciphertext_lo: pod::TransferAmountCiphertext = ciphertext_lo.into();
let pod_ciphertext_hi: pod::TransferAmountCiphertext = ciphertext_hi.into();
Expand Down Expand Up @@ -350,19 +359,34 @@ impl ZkProofData<TransferWithFeeProofContext> for TransferWithFeeData {
fn verify_proof(&self) -> Result<(), ProofError> {
let mut transcript = self.context.new_transcript();

let source_pubkey = self.context.transfer_with_fee_pubkeys.source.try_into()?;
let destination_pubkey = self
.context
.transfer_with_fee_pubkeys
.destination
.try_into()?;
let auditor_pubkey = self.context.transfer_with_fee_pubkeys.auditor.try_into()?;
let withdraw_withheld_authority_pubkey = self
.context
.transfer_with_fee_pubkeys
.withdraw_withheld_authority
.try_into()?;

let ciphertext_lo = self.context.ciphertext_lo.try_into()?;
let ciphertext_hi = self.context.ciphertext_hi.try_into()?;
let pubkeys_transfer_with_fee = self.context.transfer_with_fee_pubkeys.try_into()?;
let new_source_ciphertext = self.context.new_source_ciphertext.try_into()?;

let fee_ciphertext_lo = self.context.fee_ciphertext_lo.try_into()?;
let fee_ciphertext_hi = self.context.fee_ciphertext_hi.try_into()?;
let fee_parameters = self.context.fee_parameters.into();

self.proof.verify(
&source_pubkey,
&destination_pubkey,
&auditor_pubkey,
&withdraw_withheld_authority_pubkey,
&ciphertext_lo,
&ciphertext_hi,
&pubkeys_transfer_with_fee,
&new_source_ciphertext,
&fee_ciphertext_lo,
&fee_ciphertext_hi,
Expand Down Expand Up @@ -548,11 +572,15 @@ impl TransferWithFeeProof {
}
}

#[allow(clippy::too_many_arguments)]
pub fn verify(
&self,
source_pubkey: &ElGamalPubkey,
destination_pubkey: &ElGamalPubkey,
auditor_pubkey: &ElGamalPubkey,
withdraw_withheld_authority_pubkey: &ElGamalPubkey,
ciphertext_lo: &TransferAmountCiphertext,
ciphertext_hi: &TransferAmountCiphertext,
transfer_with_fee_pubkeys: &TransferWithFeePubkeys,
new_spendable_ciphertext: &ElGamalCiphertext,
// fee parameters
fee_ciphertext_lo: &FeeEncryption,
Expand All @@ -575,18 +603,15 @@ impl TransferWithFeeProof {

// verify equality proof
equality_proof.verify(
&transfer_with_fee_pubkeys.source_pubkey,
source_pubkey,
new_spendable_ciphertext,
&new_source_commitment,
transcript,
)?;

// verify that the transfer amount is encrypted correctly
ciphertext_amount_validity_proof.verify(
(
&transfer_with_fee_pubkeys.destination_pubkey,
&transfer_with_fee_pubkeys.auditor_pubkey,
),
(destination_pubkey, auditor_pubkey),
(
ciphertext_lo.get_commitment(),
ciphertext_hi.get_commitment(),
Expand Down Expand Up @@ -636,10 +661,7 @@ impl TransferWithFeeProof {

// verify ciphertext validity proof for fee ciphertexts
fee_ciphertext_validity_proof.verify(
(
&transfer_with_fee_pubkeys.destination_pubkey,
&transfer_with_fee_pubkeys.withdraw_withheld_authority_pubkey,
),
(destination_pubkey, withdraw_withheld_authority_pubkey),
(
fee_ciphertext_lo.get_commitment(),
fee_ciphertext_hi.get_commitment(),
Expand Down Expand Up @@ -685,52 +707,6 @@ impl TransferWithFeeProof {
}
}

/// The ElGamal public keys needed for a transfer with fee
#[derive(Clone)]
#[repr(C)]
#[cfg(not(target_os = "solana"))]
pub struct TransferWithFeePubkeys {
pub source_pubkey: ElGamalPubkey,
pub destination_pubkey: ElGamalPubkey,
pub auditor_pubkey: ElGamalPubkey,
pub withdraw_withheld_authority_pubkey: ElGamalPubkey,
}

#[cfg(not(target_os = "solana"))]
impl TransferWithFeePubkeys {
pub fn to_bytes(&self) -> [u8; 128] {
let mut bytes = [0u8; 128];
bytes[..32].copy_from_slice(&self.source_pubkey.to_bytes());
bytes[32..64].copy_from_slice(&self.destination_pubkey.to_bytes());
bytes[64..96].copy_from_slice(&self.auditor_pubkey.to_bytes());
bytes[96..128].copy_from_slice(&self.withdraw_withheld_authority_pubkey.to_bytes());
bytes
}

pub fn from_bytes(bytes: &[u8]) -> Result<Self, ProofError> {
let bytes = array_ref![bytes, 0, 128];
let (source_pubkey, destination_pubkey, auditor_pubkey, withdraw_withheld_authority_pubkey) =
array_refs![bytes, 32, 32, 32, 32];

let source_pubkey =
ElGamalPubkey::from_bytes(source_pubkey).ok_or(ProofError::PubkeyDeserialization)?;
let destination_pubkey = ElGamalPubkey::from_bytes(destination_pubkey)
.ok_or(ProofError::PubkeyDeserialization)?;
let auditor_pubkey =
ElGamalPubkey::from_bytes(auditor_pubkey).ok_or(ProofError::PubkeyDeserialization)?;
let withdraw_withheld_authority_pubkey =
ElGamalPubkey::from_bytes(withdraw_withheld_authority_pubkey)
.ok_or(ProofError::PubkeyDeserialization)?;

Ok(Self {
source_pubkey,
destination_pubkey,
auditor_pubkey,
withdraw_withheld_authority_pubkey,
})
}
}

#[cfg(not(target_os = "solana"))]
fn calculate_fee(transfer_amount: u64, fee_rate_basis_points: u16) -> Option<(u64, u64)> {
let numerator = (transfer_amount as u128).checked_mul(fee_rate_basis_points as u128)?;
Expand Down
80 changes: 26 additions & 54 deletions zk-token-sdk/src/instruction/transfer/without_fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use {
},
transcript::TranscriptProtocol,
},
arrayref::{array_ref, array_refs},
bytemuck::bytes_of,
merlin::Transcript,
std::convert::TryInto,
Expand Down Expand Up @@ -69,12 +68,21 @@ pub struct TransferProofContext {
pub ciphertext_hi: pod::TransferAmountCiphertext, // 128 bytes

/// The public encryption keys associated with the transfer: source, dest, and auditor
pub transfer_pubkeys: pod::TransferPubkeys, // 96 bytes
pub transfer_pubkeys: TransferPubkeys, // 96 bytes

/// The final spendable ciphertext after the transfer
pub new_source_ciphertext: pod::ElGamalCiphertext, // 64 bytes
}

/// The ElGamal public keys needed for a transfer
#[derive(Clone, Copy, Pod, Zeroable)]
#[repr(C)]
pub struct TransferPubkeys {
pub source: pod::ElGamalPubkey,
pub destination: pod::ElGamalPubkey,
pub auditor: pod::ElGamalPubkey,
}

#[cfg(not(target_os = "solana"))]
impl TransferData {
#[allow(clippy::too_many_arguments)]
Expand Down Expand Up @@ -124,10 +132,10 @@ impl TransferData {
);

// generate transcript and append all public inputs
let pod_transfer_pubkeys = pod::TransferPubkeys {
source_pubkey: source_keypair.public.into(),
destination_pubkey: (*destination_pubkey).into(),
auditor_pubkey: (*auditor_pubkey).into(),
let pod_transfer_pubkeys = TransferPubkeys {
source: source_keypair.public.into(),
destination: (*destination_pubkey).into(),
auditor: (*auditor_pubkey).into(),
};
let pod_ciphertext_lo: pod::TransferAmountCiphertext = ciphertext_lo.into();
let pod_ciphertext_hi: pod::TransferAmountCiphertext = ciphertext_hi.into();
Expand Down Expand Up @@ -225,15 +233,20 @@ impl ZkProofData<TransferProofContext> for TransferData {
// generate transcript and append all public inputs
let mut transcript = self.context.new_transcript();

let source_pubkey = self.context.transfer_pubkeys.source.try_into()?;
let destination_pubkey = self.context.transfer_pubkeys.destination.try_into()?;
let auditor_pubkey = self.context.transfer_pubkeys.auditor.try_into()?;

let ciphertext_lo = self.context.ciphertext_lo.try_into()?;
let ciphertext_hi = self.context.ciphertext_hi.try_into()?;
let transfer_pubkeys = self.context.transfer_pubkeys.try_into()?;
let new_spendable_ciphertext = self.context.new_source_ciphertext.try_into()?;

self.proof.verify(
&source_pubkey,
&destination_pubkey,
&auditor_pubkey,
&ciphertext_lo,
&ciphertext_hi,
&transfer_pubkeys,
&new_spendable_ciphertext,
&mut transcript,
)
Expand Down Expand Up @@ -353,9 +366,11 @@ impl TransferProof {

pub fn verify(
&self,
source_pubkey: &ElGamalPubkey,
destination_pubkey: &ElGamalPubkey,
auditor_pubkey: &ElGamalPubkey,
ciphertext_lo: &TransferAmountCiphertext,
ciphertext_hi: &TransferAmountCiphertext,
transfer_pubkeys: &TransferPubkeys,
ciphertext_new_spendable: &ElGamalCiphertext,
transcript: &mut Transcript,
) -> Result<(), ProofError> {
Expand All @@ -369,18 +384,15 @@ impl TransferProof {

// verify equality proof
equality_proof.verify(
&transfer_pubkeys.source_pubkey,
source_pubkey,
ciphertext_new_spendable,
&commitment,
transcript,
)?;

// verify validity proof
aggregated_validity_proof.verify(
(
&transfer_pubkeys.destination_pubkey,
&transfer_pubkeys.auditor_pubkey,
),
(destination_pubkey, auditor_pubkey),
(
ciphertext_lo.get_commitment(),
ciphertext_hi.get_commitment(),
Expand Down Expand Up @@ -436,46 +448,6 @@ impl TransferProof {
}
}

/// The ElGamal public keys needed for a transfer
#[derive(Clone)]
#[repr(C)]
#[cfg(not(target_os = "solana"))]
pub struct TransferPubkeys {
pub source_pubkey: ElGamalPubkey,
pub destination_pubkey: ElGamalPubkey,
pub auditor_pubkey: ElGamalPubkey,
}

#[cfg(not(target_os = "solana"))]
impl TransferPubkeys {
// TODO: use constructor instead
pub fn to_bytes(&self) -> [u8; 96] {
let mut bytes = [0u8; 96];
bytes[..32].copy_from_slice(&self.source_pubkey.to_bytes());
bytes[32..64].copy_from_slice(&self.destination_pubkey.to_bytes());
bytes[64..96].copy_from_slice(&self.auditor_pubkey.to_bytes());
bytes
}

pub fn from_bytes(bytes: &[u8]) -> Result<Self, ProofError> {
let bytes = array_ref![bytes, 0, 96];
let (source_pubkey, destination_pubkey, auditor_pubkey) = array_refs![bytes, 32, 32, 32];

let source_pubkey =
ElGamalPubkey::from_bytes(source_pubkey).ok_or(ProofError::PubkeyDeserialization)?;
let destination_pubkey = ElGamalPubkey::from_bytes(destination_pubkey)
.ok_or(ProofError::PubkeyDeserialization)?;
let auditor_pubkey =
ElGamalPubkey::from_bytes(auditor_pubkey).ok_or(ProofError::PubkeyDeserialization)?;

Ok(Self {
source_pubkey,
destination_pubkey,
auditor_pubkey,
})
}
}

#[cfg(test)]
mod test {
use {super::*, crate::encryption::elgamal::ElGamalKeypair};
Expand Down
Loading

0 comments on commit d654715

Please sign in to comment.