diff --git a/zk-token-sdk/src/instruction/mod.rs b/zk-token-sdk/src/instruction/mod.rs index d1abe9354f..29ceb1d647 100644 --- a/zk-token-sdk/src/instruction/mod.rs +++ b/zk-token-sdk/src/instruction/mod.rs @@ -4,22 +4,12 @@ pub mod ciphertext_commitment_equality; pub mod pubkey_validity; pub mod range_proof; pub mod transfer; -pub mod transfer_with_fee; pub mod withdraw; pub mod zero_balance; -use num_derive::{FromPrimitive, ToPrimitive}; #[cfg(not(target_os = "solana"))] -use { - crate::{ - encryption::{ - elgamal::ElGamalCiphertext, - pedersen::{PedersenCommitment, PedersenOpening}, - }, - errors::ProofError, - }, - curve25519_dalek::scalar::Scalar, -}; +use crate::errors::ProofError; +use num_derive::{FromPrimitive, ToPrimitive}; pub use { batched_range_proof::{ batched_range_proof_u128::BatchedRangeProofU128Data, @@ -35,8 +25,10 @@ pub use { }, pubkey_validity::{PubkeyValidityData, PubkeyValidityProofContext}, range_proof::{RangeProofContext, RangeProofU64Data}, - transfer::{TransferData, TransferProofContext}, - transfer_with_fee::{FeeParameters, TransferWithFeeData, TransferWithFeeProofContext}, + transfer::{ + FeeParameters, TransferData, TransferProofContext, TransferWithFeeData, + TransferWithFeeProofContext, + }, withdraw::{WithdrawData, WithdrawProofContext}, zero_balance::{ZeroBalanceProofContext, ZeroBalanceProofData}, }; @@ -67,65 +59,3 @@ pub trait ZkProofData { #[cfg(not(target_os = "solana"))] fn verify_proof(&self) -> Result<(), ProofError>; } - -#[cfg(not(target_os = "solana"))] -#[derive(Debug, Copy, Clone)] -pub enum Role { - Source, - Destination, - Auditor, - WithdrawWithheldAuthority, -} - -/// Takes in a 64-bit number `amount` and a bit length `bit_length`. It returns: -/// - the `bit_length` low bits of `amount` interpretted as u64 -/// - the (64 - `bit_length`) high bits of `amount` interpretted as u64 -#[cfg(not(target_os = "solana"))] -pub fn split_u64(amount: u64, bit_length: usize) -> (u64, u64) { - if bit_length == 64 { - (amount, 0) - } else { - let lo = amount << (64 - bit_length) >> (64 - bit_length); - let hi = amount >> bit_length; - (lo, hi) - } -} - -#[cfg(not(target_os = "solana"))] -pub fn combine_lo_hi_u64(amount_lo: u64, amount_hi: u64, bit_length: usize) -> u64 { - if bit_length == 64 { - amount_lo - } else { - amount_lo + (amount_hi << bit_length) - } -} - -#[cfg(not(target_os = "solana"))] -fn combine_lo_hi_ciphertexts( - ciphertext_lo: &ElGamalCiphertext, - ciphertext_hi: &ElGamalCiphertext, - bit_length: usize, -) -> ElGamalCiphertext { - let two_power = (1_u64) << bit_length; - ciphertext_lo + &(ciphertext_hi * &Scalar::from(two_power)) -} - -#[cfg(not(target_os = "solana"))] -pub fn combine_lo_hi_commitments( - comm_lo: &PedersenCommitment, - comm_hi: &PedersenCommitment, - bit_length: usize, -) -> PedersenCommitment { - let two_power = (1_u64) << bit_length; - comm_lo + comm_hi * &Scalar::from(two_power) -} - -#[cfg(not(target_os = "solana"))] -pub fn combine_lo_hi_openings( - opening_lo: &PedersenOpening, - opening_hi: &PedersenOpening, - bit_length: usize, -) -> PedersenOpening { - let two_power = (1_u64) << bit_length; - opening_lo + opening_hi * &Scalar::from(two_power) -} diff --git a/zk-token-sdk/src/instruction/transfer/encryption.rs b/zk-token-sdk/src/instruction/transfer/encryption.rs new file mode 100644 index 0000000000..91c95bb71e --- /dev/null +++ b/zk-token-sdk/src/instruction/transfer/encryption.rs @@ -0,0 +1,85 @@ +#[cfg(not(target_os = "solana"))] +use crate::{ + encryption::{ + elgamal::{DecryptHandle, ElGamalPubkey}, + pedersen::{Pedersen, PedersenCommitment, PedersenOpening}, + }, + zk_token_elgamal::pod, +}; + +// TransferAmountEncryption +#[derive(Clone)] +#[repr(C)] +#[cfg(not(target_os = "solana"))] +pub struct TransferAmountEncryption { + pub commitment: PedersenCommitment, + pub source_handle: DecryptHandle, + pub destination_handle: DecryptHandle, + pub auditor_handle: DecryptHandle, +} + +#[cfg(not(target_os = "solana"))] +impl TransferAmountEncryption { + pub fn new( + amount: u64, + source_pubkey: &ElGamalPubkey, + destination_pubkey: &ElGamalPubkey, + auditor_pubkey: &ElGamalPubkey, + ) -> (Self, PedersenOpening) { + let (commitment, opening) = Pedersen::new(amount); + let transfer_amount_encryption = Self { + commitment, + source_handle: source_pubkey.decrypt_handle(&opening), + destination_handle: destination_pubkey.decrypt_handle(&opening), + auditor_handle: auditor_pubkey.decrypt_handle(&opening), + }; + + (transfer_amount_encryption, opening) + } + + pub fn to_pod(&self) -> pod::TransferAmountEncryption { + pod::TransferAmountEncryption { + commitment: self.commitment.into(), + source_handle: self.source_handle.into(), + destination_handle: self.destination_handle.into(), + auditor_handle: self.auditor_handle.into(), + } + } +} + +// FeeEncryption +#[derive(Clone)] +#[repr(C)] +#[cfg(not(target_os = "solana"))] +pub struct FeeEncryption { + pub commitment: PedersenCommitment, + pub destination_handle: DecryptHandle, + pub withdraw_withheld_authority_handle: DecryptHandle, +} + +#[cfg(not(target_os = "solana"))] +impl FeeEncryption { + pub fn new( + amount: u64, + 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), + }; + + (fee_encryption, opening) + } + + 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(), + } + } +} diff --git a/zk-token-sdk/src/instruction/transfer/mod.rs b/zk-token-sdk/src/instruction/transfer/mod.rs new file mode 100644 index 0000000000..0fc8f134bf --- /dev/null +++ b/zk-token-sdk/src/instruction/transfer/mod.rs @@ -0,0 +1,115 @@ +mod encryption; +mod with_fee; +mod without_fee; + +#[cfg(not(target_os = "solana"))] +use { + crate::encryption::{ + elgamal::ElGamalCiphertext, + pedersen::{PedersenCommitment, PedersenOpening}, + }, + arrayref::{array_ref, array_refs}, + curve25519_dalek::scalar::Scalar, +}; +#[cfg(not(target_os = "solana"))] +pub use { + encryption::{FeeEncryption, TransferAmountEncryption}, + with_fee::TransferWithFeePubkeys, + without_fee::TransferPubkeys, +}; +pub use { + with_fee::{TransferWithFeeData, TransferWithFeeProofContext}, + without_fee::{TransferData, TransferProofContext}, +}; + +#[cfg(not(target_os = "solana"))] +#[derive(Debug, Copy, Clone)] +pub enum Role { + Source, + Destination, + Auditor, + WithdrawWithheldAuthority, +} + +/// Takes in a 64-bit number `amount` and a bit length `bit_length`. It returns: +/// - the `bit_length` low bits of `amount` interpretted as u64 +/// - the (64 - `bit_length`) high bits of `amount` interpretted as u64 +#[cfg(not(target_os = "solana"))] +pub fn split_u64(amount: u64, bit_length: usize) -> (u64, u64) { + if bit_length == 64 { + (amount, 0) + } else { + let lo = amount << (64 - bit_length) >> (64 - bit_length); + let hi = amount >> bit_length; + (lo, hi) + } +} + +#[cfg(not(target_os = "solana"))] +pub fn combine_lo_hi_u64(amount_lo: u64, amount_hi: u64, bit_length: usize) -> u64 { + if bit_length == 64 { + amount_lo + } else { + amount_lo + (amount_hi << bit_length) + } +} + +#[cfg(not(target_os = "solana"))] +fn combine_lo_hi_ciphertexts( + ciphertext_lo: &ElGamalCiphertext, + ciphertext_hi: &ElGamalCiphertext, + bit_length: usize, +) -> ElGamalCiphertext { + let two_power = (1_u64) << bit_length; + ciphertext_lo + &(ciphertext_hi * &Scalar::from(two_power)) +} + +#[cfg(not(target_os = "solana"))] +pub fn combine_lo_hi_commitments( + comm_lo: &PedersenCommitment, + comm_hi: &PedersenCommitment, + bit_length: usize, +) -> PedersenCommitment { + let two_power = (1_u64) << bit_length; + comm_lo + comm_hi * &Scalar::from(two_power) +} + +#[cfg(not(target_os = "solana"))] +pub fn combine_lo_hi_openings( + opening_lo: &PedersenOpening, + opening_hi: &PedersenOpening, + bit_length: usize, +) -> PedersenOpening { + let two_power = (1_u64) << bit_length; + opening_lo + opening_hi * &Scalar::from(two_power) +} + +#[derive(Clone, Copy)] +#[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: u16, + /// Maximum fee assessed on transfers, expressed as an amount of tokens + pub maximum_fee: u64, +} + +#[cfg(not(target_os = "solana"))] +impl FeeParameters { + pub fn to_bytes(&self) -> [u8; 10] { + let mut bytes = [0u8; 10]; + bytes[..2].copy_from_slice(&self.fee_rate_basis_points.to_le_bytes()); + bytes[2..10].copy_from_slice(&self.maximum_fee.to_le_bytes()); + + bytes + } + + pub fn from_bytes(bytes: &[u8]) -> Self { + let bytes = array_ref![bytes, 0, 10]; + let (fee_rate_basis_points, maximum_fee) = array_refs![bytes, 2, 8]; + + Self { + fee_rate_basis_points: u16::from_le_bytes(*fee_rate_basis_points), + maximum_fee: u64::from_le_bytes(*maximum_fee), + } + } +} diff --git a/zk-token-sdk/src/instruction/transfer_with_fee.rs b/zk-token-sdk/src/instruction/transfer/with_fee.rs similarity index 93% rename from zk-token-sdk/src/instruction/transfer_with_fee.rs rename to zk-token-sdk/src/instruction/transfer/with_fee.rs index b0f1c308ae..03788274d0 100644 --- a/zk-token-sdk/src/instruction/transfer_with_fee.rs +++ b/zk-token-sdk/src/instruction/transfer/with_fee.rs @@ -2,15 +2,15 @@ use { crate::{ encryption::{ - elgamal::{ - DecryptHandle, ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey, ElGamalSecretKey, - }, + elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey, ElGamalSecretKey}, pedersen::{Pedersen, PedersenCommitment, PedersenOpening}, }, errors::ProofError, - instruction::{ + instruction::transfer::{ combine_lo_hi_ciphertexts, combine_lo_hi_commitments, combine_lo_hi_openings, - combine_lo_hi_u64, split_u64, transfer::TransferAmountEncryption, Role, + combine_lo_hi_u64, + encryption::{FeeEncryption, TransferAmountEncryption}, + split_u64, FeeParameters, Role, }, range_proof::RangeProof, sigma_proofs::{ @@ -721,72 +721,6 @@ impl TransferWithFeePubkeys { } } -#[derive(Clone)] -#[repr(C)] -#[cfg(not(target_os = "solana"))] -pub struct FeeEncryption { - pub commitment: PedersenCommitment, - pub destination_handle: DecryptHandle, - pub withdraw_withheld_authority_handle: DecryptHandle, -} - -#[cfg(not(target_os = "solana"))] -impl FeeEncryption { - pub fn new( - amount: u64, - 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), - }; - - (fee_encryption, opening) - } - - 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(), - } - } -} - -#[derive(Clone, Copy)] -#[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: u16, - /// Maximum fee assessed on transfers, expressed as an amount of tokens - pub maximum_fee: u64, -} - -#[cfg(not(target_os = "solana"))] -impl FeeParameters { - pub fn to_bytes(&self) -> [u8; 10] { - let mut bytes = [0u8; 10]; - bytes[..2].copy_from_slice(&self.fee_rate_basis_points.to_le_bytes()); - bytes[2..10].copy_from_slice(&self.maximum_fee.to_le_bytes()); - - bytes - } - - pub fn from_bytes(bytes: &[u8]) -> Self { - let bytes = array_ref![bytes, 0, 10]; - let (fee_rate_basis_points, maximum_fee) = array_refs![bytes, 2, 8]; - - Self { - fee_rate_basis_points: u16::from_le_bytes(*fee_rate_basis_points), - maximum_fee: u64::from_le_bytes(*maximum_fee), - } - } -} - #[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)?; diff --git a/zk-token-sdk/src/instruction/transfer.rs b/zk-token-sdk/src/instruction/transfer/without_fee.rs similarity index 93% rename from zk-token-sdk/src/instruction/transfer.rs rename to zk-token-sdk/src/instruction/transfer/without_fee.rs index 16395dbfb7..11051b4b7a 100644 --- a/zk-token-sdk/src/instruction/transfer.rs +++ b/zk-token-sdk/src/instruction/transfer/without_fee.rs @@ -2,13 +2,13 @@ use { crate::{ encryption::{ - elgamal::{ - DecryptHandle, ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey, ElGamalSecretKey, - }, + elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey, ElGamalSecretKey}, pedersen::{Pedersen, PedersenCommitment, PedersenOpening}, }, errors::ProofError, - instruction::{combine_lo_hi_ciphertexts, split_u64, Role}, + instruction::transfer::{ + combine_lo_hi_ciphertexts, encryption::TransferAmountEncryption, split_u64, Role, + }, range_proof::RangeProof, sigma_proofs::{ ciphertext_commitment_equality_proof::CiphertextCommitmentEqualityProof, @@ -469,45 +469,6 @@ impl TransferPubkeys { } } -#[derive(Clone)] -#[repr(C)] -#[cfg(not(target_os = "solana"))] -pub struct TransferAmountEncryption { - pub commitment: PedersenCommitment, - pub source_handle: DecryptHandle, - pub destination_handle: DecryptHandle, - pub auditor_handle: DecryptHandle, -} - -#[cfg(not(target_os = "solana"))] -impl TransferAmountEncryption { - pub fn new( - amount: u64, - source_pubkey: &ElGamalPubkey, - destination_pubkey: &ElGamalPubkey, - auditor_pubkey: &ElGamalPubkey, - ) -> (Self, PedersenOpening) { - let (commitment, opening) = Pedersen::new(amount); - let transfer_amount_encryption = Self { - commitment, - source_handle: source_pubkey.decrypt_handle(&opening), - destination_handle: destination_pubkey.decrypt_handle(&opening), - auditor_handle: auditor_pubkey.decrypt_handle(&opening), - }; - - (transfer_amount_encryption, opening) - } - - pub fn to_pod(&self) -> pod::TransferAmountEncryption { - pod::TransferAmountEncryption { - commitment: self.commitment.into(), - source_handle: self.source_handle.into(), - destination_handle: self.destination_handle.into(), - auditor_handle: self.auditor_handle.into(), - } - } -} - #[cfg(test)] mod test { use {super::*, crate::encryption::elgamal::ElGamalKeypair}; diff --git a/zk-token-sdk/src/zk_token_elgamal/convert.rs b/zk-token-sdk/src/zk_token_elgamal/convert.rs index d171a873d0..8ef2977ee4 100644 --- a/zk-token-sdk/src/zk_token_elgamal/convert.rs +++ b/zk-token-sdk/src/zk_token_elgamal/convert.rs @@ -53,9 +53,9 @@ mod target_arch { crate::{ curve25519::scalar::PodScalar, errors::ProofError, - instruction::{ - transfer::{TransferAmountEncryption, TransferPubkeys}, - transfer_with_fee::{FeeEncryption, FeeParameters, TransferWithFeePubkeys}, + instruction::transfer::{ + FeeEncryption, FeeParameters, TransferAmountEncryption, TransferPubkeys, + TransferWithFeePubkeys, }, }, curve25519_dalek::{ristretto::CompressedRistretto, scalar::Scalar}, diff --git a/zk-token-sdk/src/zk_token_elgamal/ops.rs b/zk-token-sdk/src/zk_token_elgamal/ops.rs index fff1152f99..f66a0a3cd0 100644 --- a/zk-token-sdk/src/zk_token_elgamal/ops.rs +++ b/zk-token-sdk/src/zk_token_elgamal/ops.rs @@ -134,7 +134,7 @@ mod tests { elgamal::{ElGamalCiphertext, ElGamalKeypair}, pedersen::{Pedersen, PedersenOpening}, }, - instruction::split_u64, + instruction::transfer::split_u64, zk_token_elgamal::{ops, pod}, }, bytemuck::Zeroable,