From 62f08ecb8bf738c77ccc7596201338fdc0194603 Mon Sep 17 00:00:00 2001 From: samkim-crypto Date: Fri, 16 Jun 2023 17:53:36 +0900 Subject: [PATCH] [zk-token-sdk] Define `FeeEncryption` as a wrapper around `GroupedElGamalCiphertext` (#32144) * define `FeeEncryption` as a wrapper around `GroupedElGamalCiphertext` * define pod `FeeEncryption` as a wrapper around `GroupedElGamalCiphertext2Handles` * update proof data computation * add comments about unwraps (cherry picked from commit 37f51e8376248ab3c8fc26f4ca8483fbada37da1) --- .../src/instruction/transfer/encryption.rs | 55 +++++++++---------- .../src/instruction/transfer/with_fee.rs | 45 ++++++++------- zk-token-sdk/src/zk_token_elgamal/convert.rs | 30 +--------- .../src/zk_token_elgamal/pod/instruction.rs | 24 ++++++-- 4 files changed, 70 insertions(+), 84 deletions(-) diff --git a/zk-token-sdk/src/instruction/transfer/encryption.rs b/zk-token-sdk/src/instruction/transfer/encryption.rs index a8d9e669a200c4..f9d40c0889b0e0 100644 --- a/zk-token-sdk/src/instruction/transfer/encryption.rs +++ b/zk-token-sdk/src/instruction/transfer/encryption.rs @@ -1,11 +1,8 @@ #[cfg(not(target_os = "solana"))] -use crate::{ - encryption::{ - elgamal::{DecryptHandle, ElGamalPubkey}, - grouped_elgamal::{GroupedElGamal, GroupedElGamalCiphertext}, - pedersen::{Pedersen, PedersenCommitment, PedersenOpening}, - }, - zk_token_elgamal::pod, +use crate::encryption::{ + elgamal::{DecryptHandle, ElGamalPubkey}, + grouped_elgamal::{GroupedElGamal, GroupedElGamalCiphertext}, + pedersen::{PedersenCommitment, PedersenOpening}, }; #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -54,15 +51,10 @@ impl TransferAmountCiphertext { } } -// FeeEncryption -#[derive(Clone)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(C)] #[cfg(not(target_os = "solana"))] -pub struct FeeEncryption { - pub commitment: PedersenCommitment, - pub destination_handle: DecryptHandle, - pub withdraw_withheld_authority_handle: DecryptHandle, -} +pub struct FeeEncryption(pub(crate) GroupedElGamalCiphertext<2>); #[cfg(not(target_os = "solana"))] impl FeeEncryption { @@ -71,22 +63,29 @@ impl FeeEncryption { destination_pubkey: &ElGamalPubkey, withdraw_withheld_authority_pubkey: &ElGamalPubkey, ) -> (Self, PedersenOpening) { - let (commitment, opening) = Pedersen::new(amount); - let fee_encryption = Self { - commitment, - destination_handle: destination_pubkey.decrypt_handle(&opening), - withdraw_withheld_authority_handle: withdraw_withheld_authority_pubkey - .decrypt_handle(&opening), - }; + let opening = PedersenOpening::new_rand(); + let grouped_ciphertext = GroupedElGamal::<2>::encrypt_with( + [destination_pubkey, withdraw_withheld_authority_pubkey], + amount, + &opening, + ); + + (Self(grouped_ciphertext), opening) + } + + pub fn get_commitment(&self) -> &PedersenCommitment { + &self.0.commitment + } - (fee_encryption, opening) + pub fn get_destination_handle(&self) -> &DecryptHandle { + // `FeeEncryption` is a wrapper for `GroupedElGamalCiphertext<2>`, which holds + // exactly two decryption handles. + self.0.handles.get(0).unwrap() } - pub fn to_pod(&self) -> pod::FeeEncryption { - pod::FeeEncryption { - commitment: self.commitment.into(), - destination_handle: self.destination_handle.into(), - withdraw_withheld_authority_handle: self.withdraw_withheld_authority_handle.into(), - } + pub fn get_withdraw_withheld_authority_handle(&self) -> &DecryptHandle { + // `FeeEncryption` is a wrapper for `GroupedElGamalCiphertext<2>`, which holds + // exactly two decryption handles. + self.0.handles.get(1).unwrap() } } diff --git a/zk-token-sdk/src/instruction/transfer/with_fee.rs b/zk-token-sdk/src/instruction/transfer/with_fee.rs index 331d4aa317913f..2946e085382ceb 100644 --- a/zk-token-sdk/src/instruction/transfer/with_fee.rs +++ b/zk-token-sdk/src/instruction/transfer/with_fee.rs @@ -186,8 +186,8 @@ impl TransferWithFeeData { let pod_ciphertext_lo: pod::TransferAmountCiphertext = ciphertext_lo.into(); let pod_ciphertext_hi: pod::TransferAmountCiphertext = ciphertext_hi.into(); let pod_new_source_ciphertext: pod::ElGamalCiphertext = new_source_ciphertext.into(); - let pod_fee_ciphertext_lo: pod::FeeEncryption = fee_ciphertext_lo.to_pod(); - let pod_fee_ciphertext_hi: pod::FeeEncryption = fee_ciphertext_hi.to_pod(); + let pod_fee_ciphertext_lo: pod::FeeEncryption = fee_ciphertext_lo.into(); + let pod_fee_ciphertext_hi: pod::FeeEncryption = fee_ciphertext_hi.into(); let context = TransferWithFeeProofContext { ciphertext_lo: pod_ciphertext_lo, @@ -266,17 +266,17 @@ impl TransferWithFeeData { let fee_handle_lo = match role { Role::Source => None, - Role::Destination => Some(fee_ciphertext_lo.destination_handle), + Role::Destination => Some(fee_ciphertext_lo.get_destination_handle()), Role::Auditor => None, Role::WithdrawWithheldAuthority => { - Some(fee_ciphertext_lo.withdraw_withheld_authority_handle) + Some(fee_ciphertext_lo.get_withdraw_withheld_authority_handle()) } }; if let Some(handle) = fee_handle_lo { Ok(ElGamalCiphertext { - commitment: fee_ciphertext_lo.commitment, - handle, + commitment: *fee_ciphertext_lo.get_commitment(), + handle: *handle, }) } else { Err(ProofError::MissingCiphertext) @@ -289,17 +289,17 @@ impl TransferWithFeeData { let fee_handle_hi = match role { Role::Source => None, - Role::Destination => Some(fee_ciphertext_hi.destination_handle), + Role::Destination => Some(fee_ciphertext_hi.get_destination_handle()), Role::Auditor => None, Role::WithdrawWithheldAuthority => { - Some(fee_ciphertext_hi.withdraw_withheld_authority_handle) + Some(fee_ciphertext_hi.get_withdraw_withheld_authority_handle()) } }; if let Some(handle) = fee_handle_hi { Ok(ElGamalCiphertext { - commitment: fee_ciphertext_hi.commitment, - handle, + commitment: *fee_ciphertext_hi.get_commitment(), + handle: *handle, }) } else { Err(ProofError::MissingCiphertext) @@ -467,8 +467,8 @@ impl TransferWithFeeProof { let combined_fee_amount = combine_lo_hi_u64(fee_amount_lo, fee_amount_hi, TRANSFER_AMOUNT_LO_BITS); let combined_fee_commitment = combine_lo_hi_commitments( - &fee_ciphertext_lo.commitment, - &fee_ciphertext_hi.commitment, + fee_ciphertext_lo.get_commitment(), + fee_ciphertext_hi.get_commitment(), TRANSFER_AMOUNT_LO_BITS, ); let combined_fee_opening = @@ -611,8 +611,8 @@ impl TransferWithFeeProof { TRANSFER_AMOUNT_LO_BITS, ); let combined_fee_commitment = combine_lo_hi_commitments( - &fee_ciphertext_lo.commitment, - &fee_ciphertext_hi.commitment, + fee_ciphertext_lo.get_commitment(), + fee_ciphertext_hi.get_commitment(), TRANSFER_AMOUNT_LO_BITS, ); @@ -640,14 +640,17 @@ impl TransferWithFeeProof { &transfer_with_fee_pubkeys.destination_pubkey, &transfer_with_fee_pubkeys.withdraw_withheld_authority_pubkey, ), - (&fee_ciphertext_lo.commitment, &fee_ciphertext_hi.commitment), ( - &fee_ciphertext_lo.destination_handle, - &fee_ciphertext_hi.destination_handle, + fee_ciphertext_lo.get_commitment(), + fee_ciphertext_hi.get_commitment(), + ), + ( + fee_ciphertext_lo.get_destination_handle(), + fee_ciphertext_hi.get_destination_handle(), ), ( - &fee_ciphertext_lo.withdraw_withheld_authority_handle, - &fee_ciphertext_hi.withdraw_withheld_authority_handle, + fee_ciphertext_lo.get_withdraw_withheld_authority_handle(), + fee_ciphertext_hi.get_withdraw_withheld_authority_handle(), ), transcript, )?; @@ -663,8 +666,8 @@ impl TransferWithFeeProof { ciphertext_hi.get_commitment(), &claimed_commitment, &claimed_commitment_negated, - &fee_ciphertext_lo.commitment, - &fee_ciphertext_hi.commitment, + fee_ciphertext_lo.get_commitment(), + fee_ciphertext_hi.get_commitment(), ], vec![ TRANSFER_SOURCE_AMOUNT_BITS, // 64 diff --git a/zk-token-sdk/src/zk_token_elgamal/convert.rs b/zk-token-sdk/src/zk_token_elgamal/convert.rs index bbb0a528030528..b892875251f96d 100644 --- a/zk-token-sdk/src/zk_token_elgamal/convert.rs +++ b/zk-token-sdk/src/zk_token_elgamal/convert.rs @@ -53,9 +53,7 @@ mod target_arch { crate::{ curve25519::scalar::PodScalar, errors::ProofError, - instruction::transfer::{ - FeeEncryption, FeeParameters, TransferPubkeys, TransferWithFeePubkeys, - }, + instruction::transfer::{FeeParameters, TransferPubkeys, TransferWithFeePubkeys}, }, curve25519_dalek::{ristretto::CompressedRistretto, scalar::Scalar}, std::convert::TryFrom, @@ -135,32 +133,6 @@ mod target_arch { } } - impl From for pod::FeeEncryption { - fn from(ciphertext: FeeEncryption) -> Self { - Self { - commitment: ciphertext.commitment.into(), - destination_handle: ciphertext.destination_handle.into(), - withdraw_withheld_authority_handle: ciphertext - .withdraw_withheld_authority_handle - .into(), - } - } - } - - impl TryFrom for FeeEncryption { - type Error = ProofError; - - fn try_from(pod: pod::FeeEncryption) -> Result { - Ok(Self { - commitment: pod.commitment.try_into()?, - destination_handle: pod.destination_handle.try_into()?, - withdraw_withheld_authority_handle: pod - .withdraw_withheld_authority_handle - .try_into()?, - }) - } - } - impl From for pod::FeeParameters { fn from(parameters: FeeParameters) -> Self { Self { diff --git a/zk-token-sdk/src/zk_token_elgamal/pod/instruction.rs b/zk-token-sdk/src/zk_token_elgamal/pod/instruction.rs index f350785495ab91..763c9f42ba85d4 100644 --- a/zk-token-sdk/src/zk_token_elgamal/pod/instruction.rs +++ b/zk-token-sdk/src/zk_token_elgamal/pod/instruction.rs @@ -1,6 +1,6 @@ use crate::zk_token_elgamal::pod::{ - DecryptHandle, ElGamalPubkey, GroupedElGamalCiphertext3Handles, PedersenCommitment, Pod, - PodU16, PodU64, Zeroable, + ElGamalPubkey, GroupedElGamalCiphertext2Handles, GroupedElGamalCiphertext3Handles, Pod, PodU16, + PodU64, Zeroable, }; #[cfg(not(target_os = "solana"))] use crate::{errors::ProofError, instruction::transfer as decoded}; @@ -44,10 +44,22 @@ impl TryFrom for decoded::TransferAmountCiphertext { #[derive(Clone, Copy, Pod, Zeroable)] #[repr(C)] -pub struct FeeEncryption { - pub commitment: PedersenCommitment, - pub destination_handle: DecryptHandle, - pub withdraw_withheld_authority_handle: DecryptHandle, +pub struct FeeEncryption(pub GroupedElGamalCiphertext2Handles); + +#[cfg(not(target_os = "solana"))] +impl From for FeeEncryption { + fn from(decoded_ciphertext: decoded::FeeEncryption) -> Self { + Self(decoded_ciphertext.0.into()) + } +} + +#[cfg(not(target_os = "solana"))] +impl TryFrom for decoded::FeeEncryption { + type Error = ProofError; + + fn try_from(pod_ciphertext: FeeEncryption) -> Result { + Ok(Self(pod_ciphertext.0.try_into()?)) + } } #[derive(Clone, Copy, Pod, Zeroable)]