zk-token-sdk: fix pod for zk-token transfer (#22957)

This commit is contained in:
samkim-crypto 2022-02-08 12:09:50 -05:00 committed by GitHub
parent 86cf226395
commit 7873175764
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 196 additions and 130 deletions

View File

@ -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<Self, ProofError> {
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};

View File

@ -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<Self, ProofError> {
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(),
}
}
}

View File

@ -312,7 +312,11 @@ mod target_arch {
impl From<TransferPubkeys> 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, Self::Error> {
Self::from_bytes(&pod.0)
Ok(Self {
source: pod.source.try_into()?,
dest: pod.dest.try_into()?,
auditor: pod.auditor.try_into()?,
})
}
}
impl From<TransferWithFeePubkeys> 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, Self::Error> {
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<TransferAmountEncryption> 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, Self::Error> {
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<FeeEncryption> 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, Self::Error> {
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<FeeParameters> 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<pod::FeeParameters> 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(),
}
}
}
}

View File

@ -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<u16> for PodU16 {
fn from(n: u16) -> Self {
Self(n.to_le_bytes())
}
}
impl From<PodU16> 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<u64> for PodU64 {
fn from(n: u64) -> Self {
Self(n.to_le_bytes())
}
}
impl From<PodU64> 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,
}