Bläddra i källkod

[zk-sdk] Remove zk-sdk from the repo (#7126)

* remove zk-sdk

* additional clean up in `Cargo.toml`

* remove `solana-zk-sdk` dependency from `solana-bpf-programs` since it is not used
samkim-crypto 3 månader sedan
förälder
incheckning
a2ce908cfa
68 ändrade filer med 10 tillägg och 12949 borttagningar
  1. 2 2
      Cargo.lock
  2. 1 3
      Cargo.toml
  3. 2 0
      programs/sbf/Cargo.lock
  4. 0 2
      programs/sbf/Cargo.toml
  5. 0 2
      scripts/patch-crates.sh
  6. 2 0
      svm/examples/Cargo.lock
  7. 0 1
      svm/examples/Cargo.toml
  8. 0 57
      zk-sdk/Cargo.toml
  9. 3 0
      zk-sdk/README.md
  10. 0 353
      zk-sdk/src/encryption/auth_encryption.rs
  11. BIN
      zk-sdk/src/encryption/decode_u32_precomputation_for_G.bincode
  12. 0 353
      zk-sdk/src/encryption/discrete_log.rs
  13. 0 1150
      zk-sdk/src/encryption/elgamal.rs
  14. 0 388
      zk-sdk/src/encryption/grouped_elgamal.rs
  15. 0 74
      zk-sdk/src/encryption/macros.rs
  16. 0 56
      zk-sdk/src/encryption/mod.rs
  17. 0 365
      zk-sdk/src/encryption/pedersen.rs
  18. 0 90
      zk-sdk/src/encryption/pod/auth_encryption.rs
  19. 0 210
      zk-sdk/src/encryption/pod/elgamal.rs
  20. 0 272
      zk-sdk/src/encryption/pod/grouped_elgamal.rs
  21. 0 4
      zk-sdk/src/encryption/pod/mod.rs
  22. 0 74
      zk-sdk/src/encryption/pod/pedersen.rs
  23. 0 46
      zk-sdk/src/errors.rs
  24. 0 36
      zk-sdk/src/lib.rs
  25. 0 143
      zk-sdk/src/pod.rs
  26. 0 46
      zk-sdk/src/range_proof/errors.rs
  27. 0 155
      zk-sdk/src/range_proof/generators.rs
  28. 0 508
      zk-sdk/src/range_proof/inner_product.rs
  29. 0 553
      zk-sdk/src/range_proof/mod.rs
  30. 0 187
      zk-sdk/src/range_proof/pod.rs
  31. 0 139
      zk-sdk/src/range_proof/util.rs
  32. 0 246
      zk-sdk/src/sigma_proofs/batched_grouped_ciphertext_validity/handles_2.rs
  33. 0 281
      zk-sdk/src/sigma_proofs/batched_grouped_ciphertext_validity/handles_3.rs
  34. 0 7
      zk-sdk/src/sigma_proofs/batched_grouped_ciphertext_validity/mod.rs
  35. 0 389
      zk-sdk/src/sigma_proofs/ciphertext_ciphertext_equality.rs
  36. 0 469
      zk-sdk/src/sigma_proofs/ciphertext_commitment_equality.rs
  37. 0 49
      zk-sdk/src/sigma_proofs/errors.rs
  38. 0 445
      zk-sdk/src/sigma_proofs/grouped_ciphertext_validity/handles_2.rs
  39. 0 513
      zk-sdk/src/sigma_proofs/grouped_ciphertext_validity/handles_3.rs
  40. 0 7
      zk-sdk/src/sigma_proofs/grouped_ciphertext_validity/mod.rs
  41. 0 93
      zk-sdk/src/sigma_proofs/mod.rs
  42. 0 751
      zk-sdk/src/sigma_proofs/percentage_with_cap.rs
  43. 0 445
      zk-sdk/src/sigma_proofs/pod.rs
  44. 0 194
      zk-sdk/src/sigma_proofs/pubkey_validity.rs
  45. 0 315
      zk-sdk/src/sigma_proofs/zero_ciphertext.rs
  46. 0 129
      zk-sdk/src/transcript.rs
  47. 0 88
      zk-sdk/src/zk_elgamal_proof_program/errors.rs
  48. 0 383
      zk-sdk/src/zk_elgamal_proof_program/instruction.rs
  49. 0 16
      zk-sdk/src/zk_elgamal_proof_program/mod.rs
  50. 0 263
      zk-sdk/src/zk_elgamal_proof_program/proof_data/batched_grouped_ciphertext_validity/handles_2.rs
  51. 0 290
      zk-sdk/src/zk_elgamal_proof_program/proof_data/batched_grouped_ciphertext_validity/handles_3.rs
  52. 0 13
      zk-sdk/src/zk_elgamal_proof_program/proof_data/batched_grouped_ciphertext_validity/mod.rs
  53. 0 199
      zk-sdk/src/zk_elgamal_proof_program/proof_data/batched_range_proof/batched_range_proof_u128.rs
  54. 0 213
      zk-sdk/src/zk_elgamal_proof_program/proof_data/batched_range_proof/batched_range_proof_u256.rs
  55. 0 198
      zk-sdk/src/zk_elgamal_proof_program/proof_data/batched_range_proof/batched_range_proof_u64.rs
  56. 0 126
      zk-sdk/src/zk_elgamal_proof_program/proof_data/batched_range_proof/mod.rs
  57. 0 222
      zk-sdk/src/zk_elgamal_proof_program/proof_data/ciphertext_ciphertext_equality.rs
  58. 0 161
      zk-sdk/src/zk_elgamal_proof_program/proof_data/ciphertext_commitment_equality.rs
  59. 0 26
      zk-sdk/src/zk_elgamal_proof_program/proof_data/errors.rs
  60. 0 221
      zk-sdk/src/zk_elgamal_proof_program/proof_data/grouped_ciphertext_validity/handles_2.rs
  61. 0 243
      zk-sdk/src/zk_elgamal_proof_program/proof_data/grouped_ciphertext_validity/handles_3.rs
  62. 0 11
      zk-sdk/src/zk_elgamal_proof_program/proof_data/grouped_ciphertext_validity/mod.rs
  63. 0 72
      zk-sdk/src/zk_elgamal_proof_program/proof_data/mod.rs
  64. 0 239
      zk-sdk/src/zk_elgamal_proof_program/proof_data/percentage_with_cap.rs
  65. 0 42
      zk-sdk/src/zk_elgamal_proof_program/proof_data/pod.rs
  66. 0 114
      zk-sdk/src/zk_elgamal_proof_program/proof_data/pubkey_validity.rs
  67. 0 137
      zk-sdk/src/zk_elgamal_proof_program/proof_data/zero_ciphertext.rs
  68. 0 70
      zk-sdk/src/zk_elgamal_proof_program/state.rs

+ 2 - 2
Cargo.lock

@@ -11985,6 +11985,8 @@ dependencies = [
 [[package]]
 [[package]]
 name = "solana-zk-sdk"
 name = "solana-zk-sdk"
 version = "3.0.0"
 version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dffbd0b7537f4249d69b74c632f8eac1d2726572022791f9ead65a67d3f6905"
 dependencies = [
 dependencies = [
  "aes-gcm-siv",
  "aes-gcm-siv",
  "base64 0.22.1",
  "base64 0.22.1",
@@ -12004,7 +12006,6 @@ dependencies = [
  "sha3",
  "sha3",
  "solana-derivation-path",
  "solana-derivation-path",
  "solana-instruction",
  "solana-instruction",
- "solana-keypair",
  "solana-pubkey",
  "solana-pubkey",
  "solana-sdk-ids",
  "solana-sdk-ids",
  "solana-seed-derivable",
  "solana-seed-derivable",
@@ -12013,7 +12014,6 @@ dependencies = [
  "solana-signer",
  "solana-signer",
  "subtle",
  "subtle",
  "thiserror 2.0.12",
  "thiserror 2.0.12",
- "tiny-bip39",
  "wasm-bindgen",
  "wasm-bindgen",
  "zeroize",
  "zeroize",
 ]
 ]

+ 1 - 3
Cargo.toml

@@ -140,7 +140,6 @@ members = [
     "wen-restart",
     "wen-restart",
     "xdp",
     "xdp",
     "zk-keygen",
     "zk-keygen",
-    "zk-sdk",
     "zk-token-sdk",
     "zk-token-sdk",
 ]
 ]
 
 
@@ -562,7 +561,7 @@ solana-vote-program = { path = "programs/vote", version = "=3.0.0", default-feat
 solana-wen-restart = { path = "wen-restart", version = "=3.0.0" }
 solana-wen-restart = { path = "wen-restart", version = "=3.0.0" }
 solana-zk-elgamal-proof-program = { path = "programs/zk-elgamal-proof", version = "=3.0.0" }
 solana-zk-elgamal-proof-program = { path = "programs/zk-elgamal-proof", version = "=3.0.0" }
 solana-zk-keygen = { path = "zk-keygen", version = "=3.0.0" }
 solana-zk-keygen = { path = "zk-keygen", version = "=3.0.0" }
-solana-zk-sdk = { path = "zk-sdk", version = "=3.0.0" }
+solana-zk-sdk = "3.0.0"
 solana-zk-token-proof-program = { path = "programs/zk-token-proof", version = "=3.0.0" }
 solana-zk-token-proof-program = { path = "programs/zk-token-proof", version = "=3.0.0" }
 solana-zk-token-sdk = { path = "zk-token-sdk", version = "=3.0.0" }
 solana-zk-token-sdk = { path = "zk-token-sdk", version = "=3.0.0" }
 spl-associated-token-account = "7.0.0"
 spl-associated-token-account = "7.0.0"
@@ -678,4 +677,3 @@ crossbeam-epoch = { git = "https://github.com/anza-xyz/crossbeam", rev = "fd279d
 # There is a similar override in `programs/sbf/Cargo.toml`.  Please keep both
 # There is a similar override in `programs/sbf/Cargo.toml`.  Please keep both
 # comments and the overrides in sync.
 # comments and the overrides in sync.
 solana-curve25519 = { path = "curves/curve25519" }
 solana-curve25519 = { path = "curves/curve25519" }
-solana-zk-sdk = { path = "zk-sdk" }

+ 2 - 0
programs/sbf/Cargo.lock

@@ -9915,6 +9915,8 @@ dependencies = [
 [[package]]
 [[package]]
 name = "solana-zk-sdk"
 name = "solana-zk-sdk"
 version = "3.0.0"
 version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dffbd0b7537f4249d69b74c632f8eac1d2726572022791f9ead65a67d3f6905"
 dependencies = [
 dependencies = [
  "aes-gcm-siv",
  "aes-gcm-siv",
  "base64 0.22.1",
  "base64 0.22.1",

+ 0 - 2
programs/sbf/Cargo.toml

@@ -169,7 +169,6 @@ solana-transaction-status = { path = "../../transaction-status", version = "=3.0
 solana-type-overrides = { path = "../../type-overrides", version = "=3.0.0" }
 solana-type-overrides = { path = "../../type-overrides", version = "=3.0.0" }
 solana-vote = { path = "../../vote", version = "=3.0.0" }
 solana-vote = { path = "../../vote", version = "=3.0.0" }
 solana-vote-program = { path = "../../programs/vote", version = "=3.0.0" }
 solana-vote-program = { path = "../../programs/vote", version = "=3.0.0" }
-solana-zk-sdk = { path = "../../zk-sdk", version = "=3.0.0" }
 thiserror = "1.0"
 thiserror = "1.0"
 
 
 [features]
 [features]
@@ -301,4 +300,3 @@ name = "bpf_loader"
 # There is a similar override in `../../Cargo.toml`.  Please keep both comments
 # There is a similar override in `../../Cargo.toml`.  Please keep both comments
 # and the overrides in sync.
 # and the overrides in sync.
 solana-curve25519 = { path = "../../curves/curve25519" }
 solana-curve25519 = { path = "../../curves/curve25519" }
-solana-zk-sdk = { path = "../../zk-sdk" }

+ 0 - 2
scripts/patch-crates.sh

@@ -71,7 +71,6 @@ update_solana_dependencies() {
     solana-udp-client
     solana-udp-client
     solana-version
     solana-version
     solana-zk-token-sdk
     solana-zk-token-sdk
-    solana-zk-sdk
     solana-curve25519
     solana-curve25519
   )
   )
 
 
@@ -160,7 +159,6 @@ patch_crates_io_solana_no_header() {
   crates_map+=("solana-udp-client udp-client")
   crates_map+=("solana-udp-client udp-client")
   crates_map+=("solana-version version")
   crates_map+=("solana-version version")
   crates_map+=("solana-zk-token-sdk zk-token-sdk")
   crates_map+=("solana-zk-token-sdk zk-token-sdk")
-  crates_map+=("solana-zk-sdk zk-sdk")
   crates_map+=("solana-bn254 curves/bn254")
   crates_map+=("solana-bn254 curves/bn254")
   crates_map+=("solana-curve25519 curves/curve25519")
   crates_map+=("solana-curve25519 curves/curve25519")
   crates_map+=("solana-secp256k1-recover curves/secp256k1-recover")
   crates_map+=("solana-secp256k1-recover curves/secp256k1-recover")

+ 2 - 0
svm/examples/Cargo.lock

@@ -8999,6 +8999,8 @@ dependencies = [
 [[package]]
 [[package]]
 name = "solana-zk-sdk"
 name = "solana-zk-sdk"
 version = "3.0.0"
 version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dffbd0b7537f4249d69b74c632f8eac1d2726572022791f9ead65a67d3f6905"
 dependencies = [
 dependencies = [
  "aes-gcm-siv",
  "aes-gcm-siv",
  "base64 0.22.1",
  "base64 0.22.1",

+ 0 - 1
svm/examples/Cargo.toml

@@ -80,4 +80,3 @@ yaml-rust = "0.4"
 [patch.crates-io]
 [patch.crates-io]
 crossbeam-epoch = { git = "https://github.com/anza-xyz/crossbeam", rev = "fd279d707025f0e60951e429bf778b4813d1b6bf" }
 crossbeam-epoch = { git = "https://github.com/anza-xyz/crossbeam", rev = "fd279d707025f0e60951e429bf778b4813d1b6bf" }
 solana-curve25519 = { path = "../../curves/curve25519" }
 solana-curve25519 = { path = "../../curves/curve25519" }
-solana-zk-sdk = { path = "../../zk-sdk" }

+ 0 - 57
zk-sdk/Cargo.toml

@@ -1,57 +0,0 @@
-[package]
-name = "solana-zk-sdk"
-description = "Solana ZK SDK"
-documentation = "https://docs.rs/solana-zk-sdk"
-version = { workspace = true }
-authors = { workspace = true }
-repository = { workspace = true }
-homepage = { workspace = true }
-license = { workspace = true }
-edition = { workspace = true }
-
-[lib]
-crate-type = ["cdylib", "rlib"]
-
-[dependencies]
-base64 = { workspace = true }
-bytemuck = { workspace = true }
-bytemuck_derive = { workspace = true }
-merlin = { workspace = true }
-num-derive = { workspace = true }
-num-traits = { workspace = true }
-solana-instruction = { workspace = true, features = ["std"] }
-solana-pubkey = { workspace = true, features = ["bytemuck"] }
-solana-sdk-ids = { workspace = true }
-thiserror = { workspace = true }
-
-[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
-solana-pubkey = { workspace = true, features = ["bytemuck"] }
-
-[target.'cfg(not(target_os = "solana"))'.dependencies]
-aes-gcm-siv = { workspace = true }
-bincode = { workspace = true }
-curve25519-dalek = { workspace = true, features = ["serde"] }
-itertools = { workspace = true }
-rand = { workspace = true }
-serde = { workspace = true }
-serde_derive = { workspace = true }
-serde_json = { workspace = true }
-sha3 = { workspace = true }
-solana-derivation-path = { workspace = true }
-solana-seed-derivable = { workspace = true }
-solana-seed-phrase = { workspace = true }
-solana-signature = { workspace = true }
-solana-signer = { workspace = true }
-subtle = { workspace = true }
-zeroize = { workspace = true, features = ["zeroize_derive"] }
-
-[target.'cfg(target_arch = "wasm32")'.dependencies]
-js-sys = { workspace = true }
-wasm-bindgen = { workspace = true }
-
-[dev-dependencies]
-solana-keypair = { workspace = true }
-tiny-bip39 = { workspace = true }
-
-[lints]
-workspace = true

+ 3 - 0
zk-sdk/README.md

@@ -0,0 +1,3 @@
+# PLEASE READ: This repo no longer contains the Solana ZK-SDK
+
+The solana-zk-sdk is currently developed at https://github.com/solana-program/zk-elgamal-proof.

+ 0 - 353
zk-sdk/src/encryption/auth_encryption.rs

@@ -1,353 +0,0 @@
-//! Authenticated encryption implementation.
-//!
-//! This module is a simple wrapper of the `Aes128GcmSiv` implementation specialized for SPL
-//! token-2022 where the plaintext is always `u64`.
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-use {
-    crate::{
-        encryption::{AE_CIPHERTEXT_LEN, AE_KEY_LEN},
-        errors::AuthenticatedEncryptionError,
-    },
-    aes_gcm_siv::{
-        aead::{Aead, KeyInit},
-        Aes128GcmSiv,
-    },
-    base64::{prelude::BASE64_STANDARD, Engine},
-    rand::{rngs::OsRng, Rng},
-    std::{convert::TryInto, fmt},
-    zeroize::Zeroize,
-};
-// Currently, `wasm_bindgen` exports types and functions included in the current crate, but all
-// types and functions exported for wasm targets in all of its dependencies
-// (https://github.com/rustwasm/wasm-bindgen/issues/3759). We specifically exclude some of the
-// dependencies that will cause unnecessary bloat to the wasm binary.
-#[cfg(not(target_arch = "wasm32"))]
-use {
-    sha3::Digest,
-    sha3::Sha3_512,
-    solana_derivation_path::DerivationPath,
-    solana_seed_derivable::SeedDerivable,
-    solana_seed_phrase::generate_seed_from_seed_phrase_and_passphrase,
-    solana_signature::Signature,
-    solana_signer::{EncodableKey, Signer, SignerError},
-    std::{
-        error,
-        io::{Read, Write},
-    },
-    subtle::ConstantTimeEq,
-};
-
-/// Byte length of an authenticated encryption nonce component
-const NONCE_LEN: usize = 12;
-
-/// Byte length of an authenticated encryption ciphertext component
-const CIPHERTEXT_LEN: usize = 24;
-
-struct AuthenticatedEncryption;
-impl AuthenticatedEncryption {
-    /// Generates an authenticated encryption key.
-    ///
-    /// This function is randomized. It internally samples a 128-bit key using `OsRng`.
-    fn keygen() -> AeKey {
-        AeKey(OsRng.gen::<[u8; AE_KEY_LEN]>())
-    }
-
-    /// On input of an authenticated encryption key and an amount, the function returns a
-    /// corresponding authenticated encryption ciphertext.
-    fn encrypt(key: &AeKey, balance: u64) -> AeCiphertext {
-        let mut plaintext = balance.to_le_bytes();
-        let nonce: Nonce = OsRng.gen::<[u8; NONCE_LEN]>();
-
-        // The balance and the nonce have fixed length and therefore, encryption should not fail.
-        let ciphertext = Aes128GcmSiv::new(&key.0.into())
-            .encrypt(&nonce.into(), plaintext.as_ref())
-            .expect("authenticated encryption");
-
-        plaintext.zeroize();
-
-        AeCiphertext {
-            nonce,
-            ciphertext: ciphertext.try_into().unwrap(),
-        }
-    }
-
-    /// On input of an authenticated encryption key and a ciphertext, the function returns the
-    /// originally encrypted amount.
-    fn decrypt(key: &AeKey, ciphertext: &AeCiphertext) -> Option<u64> {
-        let plaintext = Aes128GcmSiv::new(&key.0.into())
-            .decrypt(&ciphertext.nonce.into(), ciphertext.ciphertext.as_ref());
-
-        if let Ok(plaintext) = plaintext {
-            let amount_bytes: [u8; 8] = plaintext.try_into().unwrap();
-            Some(u64::from_le_bytes(amount_bytes))
-        } else {
-            None
-        }
-    }
-}
-
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Debug, Zeroize, Eq, PartialEq)]
-pub struct AeKey([u8; AE_KEY_LEN]);
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-impl AeKey {
-    /// Generates a random authenticated encryption key.
-    ///
-    /// This function is randomized. It internally samples a scalar element using `OsRng`.
-    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = newRand))]
-    pub fn new_rand() -> Self {
-        AuthenticatedEncryption::keygen()
-    }
-
-    /// Encrypts an amount under the authenticated encryption key.
-    pub fn encrypt(&self, amount: u64) -> AeCiphertext {
-        AuthenticatedEncryption::encrypt(self, amount)
-    }
-
-    pub fn decrypt(&self, ciphertext: &AeCiphertext) -> Option<u64> {
-        AuthenticatedEncryption::decrypt(self, ciphertext)
-    }
-}
-
-#[cfg(not(target_arch = "wasm32"))]
-impl AeKey {
-    /// Deterministically derives an authenticated encryption key from a Solana signer and a public
-    /// seed.
-    ///
-    /// This function exists for applications where a user may not wish to maintain a Solana signer
-    /// and an authenticated encryption key separately. Instead, a user can derive the ElGamal
-    /// keypair on-the-fly whenever encrytion/decryption is needed.
-    pub fn new_from_signer(
-        signer: &dyn Signer,
-        public_seed: &[u8],
-    ) -> Result<Self, Box<dyn error::Error>> {
-        let seed = Self::seed_from_signer(signer, public_seed)?;
-        Self::from_seed(&seed)
-    }
-
-    /// Derive a seed from a Solana signer used to generate an authenticated encryption key.
-    ///
-    /// The seed is derived as the hash of the signature of a public seed.
-    pub fn seed_from_signer(
-        signer: &dyn Signer,
-        public_seed: &[u8],
-    ) -> Result<Vec<u8>, SignerError> {
-        let message = [b"AeKey", public_seed].concat();
-        let signature = signer.try_sign_message(&message)?;
-
-        // Some `Signer` implementations return the default signature, which is not suitable for
-        // use as key material
-        if bool::from(signature.as_ref().ct_eq(Signature::default().as_ref())) {
-            return Err(SignerError::Custom("Rejecting default signature".into()));
-        }
-
-        Ok(Self::seed_from_signature(&signature))
-    }
-
-    /// Derive an authenticated encryption key from a signature.
-    pub fn new_from_signature(signature: &Signature) -> Result<Self, Box<dyn error::Error>> {
-        let seed = Self::seed_from_signature(signature);
-        Self::from_seed(&seed)
-    }
-
-    /// Derive a seed from a signature used to generate an authenticated encryption key.
-    pub fn seed_from_signature(signature: &Signature) -> Vec<u8> {
-        let mut hasher = Sha3_512::new();
-        hasher.update(signature);
-        let result = hasher.finalize();
-
-        result.to_vec()
-    }
-}
-
-#[cfg(not(target_arch = "wasm32"))]
-impl EncodableKey for AeKey {
-    fn read<R: Read>(reader: &mut R) -> Result<Self, Box<dyn error::Error>> {
-        let bytes: [u8; AE_KEY_LEN] = serde_json::from_reader(reader)?;
-        Ok(Self(bytes))
-    }
-
-    fn write<W: Write>(&self, writer: &mut W) -> Result<String, Box<dyn error::Error>> {
-        let bytes = self.0;
-        let json = serde_json::to_string(&bytes.to_vec())?;
-        writer.write_all(&json.clone().into_bytes())?;
-        Ok(json)
-    }
-}
-
-#[cfg(not(target_arch = "wasm32"))]
-impl SeedDerivable for AeKey {
-    fn from_seed(seed: &[u8]) -> Result<Self, Box<dyn error::Error>> {
-        const MINIMUM_SEED_LEN: usize = AE_KEY_LEN;
-        const MAXIMUM_SEED_LEN: usize = 65535;
-
-        if seed.len() < MINIMUM_SEED_LEN {
-            return Err(AuthenticatedEncryptionError::SeedLengthTooShort.into());
-        }
-        if seed.len() > MAXIMUM_SEED_LEN {
-            return Err(AuthenticatedEncryptionError::SeedLengthTooLong.into());
-        }
-
-        let mut hasher = Sha3_512::new();
-        hasher.update(seed);
-        let result = hasher.finalize();
-
-        Ok(Self(result[..AE_KEY_LEN].try_into()?))
-    }
-
-    fn from_seed_and_derivation_path(
-        _seed: &[u8],
-        _derivation_path: Option<DerivationPath>,
-    ) -> Result<Self, Box<dyn error::Error>> {
-        Err(AuthenticatedEncryptionError::DerivationMethodNotSupported.into())
-    }
-
-    fn from_seed_phrase_and_passphrase(
-        seed_phrase: &str,
-        passphrase: &str,
-    ) -> Result<Self, Box<dyn error::Error>> {
-        Self::from_seed(&generate_seed_from_seed_phrase_and_passphrase(
-            seed_phrase,
-            passphrase,
-        ))
-    }
-}
-
-impl From<[u8; AE_KEY_LEN]> for AeKey {
-    fn from(bytes: [u8; AE_KEY_LEN]) -> Self {
-        Self(bytes)
-    }
-}
-
-impl From<AeKey> for [u8; AE_KEY_LEN] {
-    fn from(key: AeKey) -> Self {
-        key.0
-    }
-}
-
-impl TryFrom<&[u8]> for AeKey {
-    type Error = AuthenticatedEncryptionError;
-    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
-        if bytes.len() != AE_KEY_LEN {
-            return Err(AuthenticatedEncryptionError::Deserialization);
-        }
-        bytes
-            .try_into()
-            .map(Self)
-            .map_err(|_| AuthenticatedEncryptionError::Deserialization)
-    }
-}
-
-/// For the purpose of encrypting balances for the spl token accounts, the nonce and ciphertext
-/// sizes should always be fixed.
-type Nonce = [u8; NONCE_LEN];
-type Ciphertext = [u8; CIPHERTEXT_LEN];
-
-/// Authenticated encryption nonce and ciphertext
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Debug, Default)]
-pub struct AeCiphertext {
-    nonce: Nonce,
-    ciphertext: Ciphertext,
-}
-impl AeCiphertext {
-    pub fn decrypt(&self, key: &AeKey) -> Option<u64> {
-        AuthenticatedEncryption::decrypt(key, self)
-    }
-
-    pub fn to_bytes(&self) -> [u8; AE_CIPHERTEXT_LEN] {
-        let mut buf = [0_u8; AE_CIPHERTEXT_LEN];
-        buf[..NONCE_LEN].copy_from_slice(&self.nonce);
-        buf[NONCE_LEN..].copy_from_slice(&self.ciphertext);
-        buf
-    }
-
-    pub fn from_bytes(bytes: &[u8]) -> Option<AeCiphertext> {
-        if bytes.len() != AE_CIPHERTEXT_LEN {
-            return None;
-        }
-
-        let nonce = bytes[..NONCE_LEN].try_into().ok()?;
-        let ciphertext = bytes[NONCE_LEN..].try_into().ok()?;
-
-        Some(AeCiphertext { nonce, ciphertext })
-    }
-}
-
-impl fmt::Display for AeCiphertext {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.to_bytes()))
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use {
-        super::*, solana_keypair::Keypair, solana_pubkey::Pubkey,
-        solana_signer::null_signer::NullSigner,
-    };
-
-    #[test]
-    fn test_aes_encrypt_decrypt_correctness() {
-        let key = AeKey::new_rand();
-        let amount = 55;
-
-        let ciphertext = key.encrypt(amount);
-        let decrypted_amount = ciphertext.decrypt(&key).unwrap();
-
-        assert_eq!(amount, decrypted_amount);
-    }
-
-    #[test]
-    fn test_aes_new() {
-        let keypair1 = Keypair::new();
-        let keypair2 = Keypair::new();
-
-        assert_ne!(
-            AeKey::new_from_signer(&keypair1, Pubkey::default().as_ref())
-                .unwrap()
-                .0,
-            AeKey::new_from_signer(&keypair2, Pubkey::default().as_ref())
-                .unwrap()
-                .0,
-        );
-
-        let null_signer = NullSigner::new(&Pubkey::default());
-        assert!(AeKey::new_from_signer(&null_signer, Pubkey::default().as_ref()).is_err());
-    }
-
-    #[test]
-    fn test_aes_key_from_seed() {
-        let good_seed = vec![0; 32];
-        assert!(AeKey::from_seed(&good_seed).is_ok());
-
-        let too_short_seed = vec![0; 15];
-        assert!(AeKey::from_seed(&too_short_seed).is_err());
-
-        let too_long_seed = vec![0; 65536];
-        assert!(AeKey::from_seed(&too_long_seed).is_err());
-    }
-
-    #[test]
-    fn test_aes_key_from() {
-        let key = AeKey::from_seed(&[0; 32]).unwrap();
-        let key_bytes: [u8; AE_KEY_LEN] = AeKey::from_seed(&[0; 32]).unwrap().into();
-
-        assert_eq!(key, AeKey::from(key_bytes));
-    }
-
-    #[test]
-    fn test_aes_key_try_from() {
-        let key = AeKey::from_seed(&[0; 32]).unwrap();
-        let key_bytes: [u8; AE_KEY_LEN] = AeKey::from_seed(&[0; 32]).unwrap().into();
-
-        assert_eq!(key, AeKey::try_from(key_bytes.as_slice()).unwrap());
-    }
-
-    #[test]
-    fn test_aes_key_try_from_error() {
-        let too_many_bytes = vec![0_u8; 32];
-        assert!(AeKey::try_from(too_many_bytes.as_slice()).is_err());
-    }
-}

BIN
zk-sdk/src/encryption/decode_u32_precomputation_for_G.bincode


+ 0 - 353
zk-sdk/src/encryption/discrete_log.rs

@@ -1,353 +0,0 @@
-//! The discrete log implementation for the twisted ElGamal decryption.
-//!
-//! The implementation uses the baby-step giant-step method, which consists of a precomputation
-//! step and an online step. The precomputation step involves computing a hash table of a number
-//! of Ristretto points that is independent of a discrete log instance. The online phase computes
-//! the final discrete log solution using the discrete log instance and the pre-computed hash
-//! table. More details on the baby-step giant-step algorithm and the implementation can be found
-//! in the [spl documentation](https://spl.solana.com).
-//!
-//! The implementation is NOT intended to run in constant-time. There are some measures to prevent
-//! straightforward timing attacks. For instance, it does not short-circuit the search when a
-//! solution is found. However, the use of hashtables, batching, and threads make the
-//! implementation inherently not constant-time. This may theoretically allow an adversary to gain
-//! information on a discrete log solution depending on the execution time of the implementation.
-//!
-
-#[cfg(not(target_arch = "wasm32"))]
-use std::thread;
-use {
-    crate::RISTRETTO_POINT_LEN,
-    curve25519_dalek::{
-        constants::RISTRETTO_BASEPOINT_POINT as G,
-        ristretto::RistrettoPoint,
-        scalar::Scalar,
-        traits::{Identity, IsIdentity},
-    },
-    itertools::Itertools,
-    serde::{Deserialize, Serialize},
-    std::{collections::HashMap, num::NonZeroUsize},
-    thiserror::Error,
-};
-
-const TWO16: u64 = 65536; // 2^16
-const TWO17: u64 = 131072; // 2^17
-
-/// Maximum number of threads permitted for discrete log computation
-#[cfg(not(target_arch = "wasm32"))]
-const MAX_THREAD: usize = 65536;
-
-#[derive(Error, Clone, Debug, Eq, PartialEq)]
-pub enum DiscreteLogError {
-    #[error("discrete log number of threads not power-of-two")]
-    DiscreteLogThreads,
-    #[error("discrete log batch size too large")]
-    DiscreteLogBatchSize,
-}
-
-/// Type that captures a discrete log challenge.
-///
-/// The goal of discrete log is to find x such that x * generator = target.
-#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq)]
-pub struct DiscreteLog {
-    /// Generator point for discrete log
-    pub generator: RistrettoPoint,
-    /// Target point for discrete log
-    pub target: RistrettoPoint,
-    /// Number of threads used for discrete log computation
-    num_threads: Option<NonZeroUsize>,
-    /// Range bound for discrete log search derived from the max value to search for and
-    /// `num_threads`
-    range_bound: NonZeroUsize,
-    /// Ristretto point representing each step of the discrete log search
-    step_point: RistrettoPoint,
-    /// Ristretto point compression batch size
-    compression_batch_size: NonZeroUsize,
-}
-
-#[derive(Serialize, Deserialize, Default)]
-pub struct DecodePrecomputation(HashMap<[u8; RISTRETTO_POINT_LEN], u16>);
-
-/// Builds a HashMap of 2^16 elements
-#[allow(dead_code)]
-fn decode_u32_precomputation(generator: RistrettoPoint) -> DecodePrecomputation {
-    let mut hashmap = HashMap::new();
-
-    let two17_scalar = Scalar::from(TWO17);
-    let identity = RistrettoPoint::identity(); // 0 * G
-    let generator = two17_scalar * generator; // 2^17 * G
-
-    // iterator for 2^17*0G , 2^17*1G, 2^17*2G, ...
-    let ristretto_iter = RistrettoIterator::new((identity, 0), (generator, 1));
-    for (point, x_hi) in ristretto_iter.take(TWO16 as usize) {
-        let key = point.compress().to_bytes();
-        hashmap.insert(key, x_hi as u16);
-    }
-
-    DecodePrecomputation(hashmap)
-}
-
-/// Pre-computed HashMap needed for decryption. The HashMap is independent of (works for) any key.
-pub static DECODE_PRECOMPUTATION_FOR_G: std::sync::LazyLock<DecodePrecomputation> =
-    std::sync::LazyLock::new(|| {
-        static DECODE_PRECOMPUTATION_FOR_G_BINCODE: &[u8] =
-            include_bytes!("decode_u32_precomputation_for_G.bincode");
-        bincode::deserialize(DECODE_PRECOMPUTATION_FOR_G_BINCODE).unwrap_or_default()
-    });
-
-/// Solves the discrete log instance using a 16/16 bit offline/online split
-impl DiscreteLog {
-    /// Discrete log instance constructor.
-    ///
-    /// Default number of threads set to 1.
-    pub fn new(generator: RistrettoPoint, target: RistrettoPoint) -> Self {
-        Self {
-            generator,
-            target,
-            num_threads: None,
-            range_bound: (TWO16 as usize).try_into().unwrap(),
-            step_point: G,
-            compression_batch_size: 32.try_into().unwrap(),
-        }
-    }
-
-    /// Adjusts number of threads in a discrete log instance.
-    #[cfg(not(target_arch = "wasm32"))]
-    pub fn num_threads(&mut self, num_threads: NonZeroUsize) -> Result<(), DiscreteLogError> {
-        // number of threads must be a positive power-of-two integer
-        if !num_threads.is_power_of_two() || num_threads.get() > MAX_THREAD {
-            return Err(DiscreteLogError::DiscreteLogThreads);
-        }
-
-        self.num_threads = Some(num_threads);
-        self.range_bound = (TWO16 as usize)
-            .checked_div(num_threads.get())
-            .and_then(|range_bound| range_bound.try_into().ok())
-            .unwrap(); // `num_threads` cannot exceed `TWO16`, so `range_bound` always non-zero
-        self.step_point = Scalar::from(num_threads.get() as u64) * G;
-
-        Ok(())
-    }
-
-    /// Adjusts inversion batch size in a discrete log instance.
-    pub fn set_compression_batch_size(
-        &mut self,
-        compression_batch_size: NonZeroUsize,
-    ) -> Result<(), DiscreteLogError> {
-        if compression_batch_size.get() >= TWO16 as usize {
-            return Err(DiscreteLogError::DiscreteLogBatchSize);
-        }
-        self.compression_batch_size = compression_batch_size;
-
-        Ok(())
-    }
-
-    /// Solves the discrete log problem under the assumption that the solution
-    /// is a positive 32-bit number.
-    pub fn decode_u32(self) -> Option<u64> {
-        #[allow(unused_variables)]
-        if let Some(num_threads) = self.num_threads {
-            #[cfg(not(target_arch = "wasm32"))]
-            {
-                let mut starting_point = self.target;
-                let handles = (0..num_threads.get())
-                    .map(|i| {
-                        let ristretto_iterator = RistrettoIterator::new(
-                            (starting_point, i as u64),
-                            (-(&self.step_point), num_threads.get() as u64),
-                        );
-
-                        let handle = thread::spawn(move || {
-                            Self::decode_range(
-                                ristretto_iterator,
-                                self.range_bound,
-                                self.compression_batch_size,
-                            )
-                        });
-
-                        starting_point -= G;
-                        handle
-                    })
-                    .collect::<Vec<_>>();
-
-                handles
-                    .into_iter()
-                    .map_while(|h| h.join().ok())
-                    .find(|x| x.is_some())
-                    .flatten()
-            }
-            #[cfg(target_arch = "wasm32")]
-            unreachable!() // `self.num_threads` always `None` on wasm target
-        } else {
-            let ristretto_iterator =
-                RistrettoIterator::new((self.target, 0_u64), (-(&self.step_point), 1u64));
-
-            Self::decode_range(
-                ristretto_iterator,
-                self.range_bound,
-                self.compression_batch_size,
-            )
-        }
-    }
-
-    fn decode_range(
-        ristretto_iterator: RistrettoIterator,
-        range_bound: NonZeroUsize,
-        compression_batch_size: NonZeroUsize,
-    ) -> Option<u64> {
-        let hashmap = &DECODE_PRECOMPUTATION_FOR_G;
-        let mut decoded = None;
-
-        for batch in &ristretto_iterator
-            .take(range_bound.get())
-            .chunks(compression_batch_size.get())
-        {
-            // batch compression currently errors if any point in the batch is the identity point
-            let (batch_points, batch_indices): (Vec<_>, Vec<_>) = batch
-                .filter(|(point, index)| {
-                    if point.is_identity() {
-                        decoded = Some(*index);
-                        return false;
-                    }
-                    true
-                })
-                .unzip();
-
-            let batch_compressed = RistrettoPoint::double_and_compress_batch(&batch_points);
-
-            for (point, x_lo) in batch_compressed.iter().zip(batch_indices.iter()) {
-                let key = point.to_bytes();
-                if hashmap.0.contains_key(&key) {
-                    let x_hi = hashmap.0[&key];
-                    decoded = Some(x_lo + TWO16 * x_hi as u64);
-                }
-            }
-        }
-
-        decoded
-    }
-}
-
-/// Hashable Ristretto iterator.
-///
-/// Given an initial point X and a stepping point P, the iterator iterates through
-/// X + 0*P, X + 1*P, X + 2*P, X + 3*P, ...
-struct RistrettoIterator {
-    pub current: (RistrettoPoint, u64),
-    pub step: (RistrettoPoint, u64),
-}
-
-impl RistrettoIterator {
-    fn new(current: (RistrettoPoint, u64), step: (RistrettoPoint, u64)) -> Self {
-        RistrettoIterator { current, step }
-    }
-}
-
-impl Iterator for RistrettoIterator {
-    type Item = (RistrettoPoint, u64);
-
-    fn next(&mut self) -> Option<Self::Item> {
-        let r = self.current;
-        self.current = (self.current.0 + self.step.0, self.current.1 + self.step.1);
-        Some(r)
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use {super::*, std::time::Instant};
-
-    #[test]
-    #[allow(non_snake_case)]
-    fn test_serialize_decode_u32_precomputation_for_G() {
-        let decode_u32_precomputation_for_G = decode_u32_precomputation(G);
-        // let decode_u32_precomputation_for_G = decode_u32_precomputation(G);
-
-        if decode_u32_precomputation_for_G.0 != DECODE_PRECOMPUTATION_FOR_G.0 {
-            use std::{fs::File, io::Write, path::PathBuf};
-            let mut f = File::create(PathBuf::from(
-                "src/encryption/decode_u32_precomputation_for_G.bincode",
-            ))
-            .unwrap();
-            f.write_all(&bincode::serialize(&decode_u32_precomputation_for_G).unwrap())
-                .unwrap();
-            panic!("Rebuild and run this test again");
-        }
-    }
-
-    #[test]
-    fn test_decode_correctness() {
-        // general case
-        let amount: u64 = 4294967295;
-
-        let instance = DiscreteLog::new(G, Scalar::from(amount) * G);
-
-        // Very informal measurements for now
-        let start_computation = Instant::now();
-        let decoded = instance.decode_u32();
-        let computation_secs = start_computation.elapsed().as_secs_f64();
-
-        assert_eq!(amount, decoded.unwrap());
-
-        println!("single thread discrete log computation secs: {computation_secs:?} sec");
-    }
-
-    #[cfg(not(target_arch = "wasm32"))]
-    #[test]
-    fn test_decode_correctness_threaded() {
-        // general case
-        let amount: u64 = 55;
-
-        let mut instance = DiscreteLog::new(G, Scalar::from(amount) * G);
-        instance.num_threads(4.try_into().unwrap()).unwrap();
-
-        // Very informal measurements for now
-        let start_computation = Instant::now();
-        let decoded = instance.decode_u32();
-        let computation_secs = start_computation.elapsed().as_secs_f64();
-
-        assert_eq!(amount, decoded.unwrap());
-
-        println!("4 thread discrete log computation: {computation_secs:?} sec");
-
-        // amount 0
-        let amount: u64 = 0;
-
-        let instance = DiscreteLog::new(G, Scalar::from(amount) * G);
-
-        let decoded = instance.decode_u32();
-        assert_eq!(amount, decoded.unwrap());
-
-        // amount 1
-        let amount: u64 = 1;
-
-        let instance = DiscreteLog::new(G, Scalar::from(amount) * G);
-
-        let decoded = instance.decode_u32();
-        assert_eq!(amount, decoded.unwrap());
-
-        // amount 2
-        let amount: u64 = 2;
-
-        let instance = DiscreteLog::new(G, Scalar::from(amount) * G);
-
-        let decoded = instance.decode_u32();
-        assert_eq!(amount, decoded.unwrap());
-
-        // amount 3
-        let amount: u64 = 3;
-
-        let instance = DiscreteLog::new(G, Scalar::from(amount) * G);
-
-        let decoded = instance.decode_u32();
-        assert_eq!(amount, decoded.unwrap());
-
-        // max amount
-        let amount: u64 = (1_u64 << 32) - 1;
-
-        let instance = DiscreteLog::new(G, Scalar::from(amount) * G);
-
-        let decoded = instance.decode_u32();
-        assert_eq!(amount, decoded.unwrap());
-    }
-}

+ 0 - 1150
zk-sdk/src/encryption/elgamal.rs

@@ -1,1150 +0,0 @@
-//! The twisted ElGamal encryption implementation.
-//!
-//! The message space consists of any number that is representable as a scalar (a.k.a. "exponent")
-//! for Curve25519.
-//!
-//! A twisted ElGamal ciphertext consists of two components:
-//! - A Pedersen commitment that encodes a message to be encrypted
-//! - A "decryption handle" that binds the Pedersen opening to a specific public key
-//!
-//! In contrast to the traditional ElGamal encryption scheme, the twisted ElGamal encodes messages
-//! directly as a Pedersen commitment. Therefore, proof systems that are designed specifically for
-//! Pedersen commitments can be used on the twisted ElGamal ciphertexts.
-//!
-//! As the messages are encrypted as scalar elements (a.k.a. in the "exponent"), one must solve the
-//! discrete log to recover the originally encrypted value.
-
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-// Currently, `wasm_bindgen` exports types and functions included in the current crate, but all
-// types and functions exported for wasm targets in all of its dependencies
-// (https://github.com/rustwasm/wasm-bindgen/issues/3759). We specifically exclude some of the
-// dependencies that will cause unnecessary bloat to the wasm binary.
-use {
-    crate::{
-        encryption::{
-            discrete_log::DiscreteLog,
-            pedersen::{Pedersen, PedersenCommitment, PedersenOpening, G, H},
-            DECRYPT_HANDLE_LEN, ELGAMAL_CIPHERTEXT_LEN, ELGAMAL_KEYPAIR_LEN, ELGAMAL_PUBKEY_LEN,
-            ELGAMAL_SECRET_KEY_LEN, PEDERSEN_COMMITMENT_LEN,
-        },
-        errors::ElGamalError,
-    },
-    base64::{prelude::BASE64_STANDARD, Engine},
-    core::ops::{Add, Mul, Sub},
-    curve25519_dalek::{
-        ristretto::{CompressedRistretto, RistrettoPoint},
-        scalar::Scalar,
-        traits::Identity,
-    },
-    rand::rngs::OsRng,
-    serde::{Deserialize, Serialize},
-    sha3::Sha3_512,
-    std::{convert::TryInto, fmt},
-    subtle::{Choice, ConstantTimeEq},
-    zeroize::Zeroize,
-};
-#[cfg(not(target_arch = "wasm32"))]
-use {
-    sha3::Digest,
-    solana_derivation_path::DerivationPath,
-    solana_seed_derivable::SeedDerivable,
-    solana_seed_phrase::generate_seed_from_seed_phrase_and_passphrase,
-    solana_signature::Signature,
-    solana_signer::{EncodableKey, EncodableKeypair, Signer, SignerError},
-    std::{
-        error,
-        io::{Read, Write},
-        path::Path,
-    },
-};
-
-/// Algorithm handle for the twisted ElGamal encryption scheme
-pub struct ElGamal;
-impl ElGamal {
-    /// Generates an ElGamal keypair.
-    ///
-    /// This function is randomized. It internally samples a scalar element using `OsRng`.
-    fn keygen() -> ElGamalKeypair {
-        // secret scalar should be non-zero except with negligible probability
-        let mut s = Scalar::random(&mut OsRng);
-        let keypair = Self::keygen_with_scalar(&s);
-
-        s.zeroize();
-        keypair
-    }
-
-    /// Generates an ElGamal keypair from a scalar input that determines the ElGamal private key.
-    ///
-    /// This function panics if the input scalar is zero, which is not a valid key.
-    fn keygen_with_scalar(s: &Scalar) -> ElGamalKeypair {
-        let secret = ElGamalSecretKey(*s);
-        let public = ElGamalPubkey::new(&secret);
-
-        ElGamalKeypair { public, secret }
-    }
-
-    /// On input an ElGamal public key and an amount to be encrypted, the function returns a
-    /// corresponding ElGamal ciphertext.
-    ///
-    /// This function is randomized. It internally samples a scalar element using `OsRng`.
-    fn encrypt<T: Into<Scalar>>(public: &ElGamalPubkey, amount: T) -> ElGamalCiphertext {
-        let (commitment, opening) = Pedersen::new(amount);
-        let handle = public.decrypt_handle(&opening);
-
-        ElGamalCiphertext { commitment, handle }
-    }
-
-    /// On input a public key, amount, and Pedersen opening, the function returns the corresponding
-    /// ElGamal ciphertext.
-    fn encrypt_with<T: Into<Scalar>>(
-        amount: T,
-        public: &ElGamalPubkey,
-        opening: &PedersenOpening,
-    ) -> ElGamalCiphertext {
-        let commitment = Pedersen::with(amount, opening);
-        let handle = public.decrypt_handle(opening);
-
-        ElGamalCiphertext { commitment, handle }
-    }
-
-    /// On input an amount, the function returns a twisted ElGamal ciphertext where the associated
-    /// Pedersen opening is always zero. Since the opening is zero, any twisted ElGamal ciphertext
-    /// of this form is a valid ciphertext under any ElGamal public key.
-    pub fn encode<T: Into<Scalar>>(amount: T) -> ElGamalCiphertext {
-        let commitment = Pedersen::encode(amount);
-        let handle = DecryptHandle(RistrettoPoint::identity());
-
-        ElGamalCiphertext { commitment, handle }
-    }
-
-    /// On input a secret key and a ciphertext, the function returns the discrete log encoding of
-    /// original amount.
-    ///
-    /// The output of this function is of type `DiscreteLog`. To recover, the originally encrypted
-    /// amount, use `DiscreteLog::decode`.
-    fn decrypt(secret: &ElGamalSecretKey, ciphertext: &ElGamalCiphertext) -> DiscreteLog {
-        DiscreteLog::new(
-            G,
-            ciphertext.commitment.get_point() - &(&secret.0 * &ciphertext.handle.0),
-        )
-    }
-
-    /// On input a secret key and a ciphertext, the function returns the decrypted amount
-    /// interpreted as a positive 32-bit number (but still of type `u64`).
-    ///
-    /// If the originally encrypted amount is not a positive 32-bit number, then the function
-    /// returns `None`.
-    fn decrypt_u32(secret: &ElGamalSecretKey, ciphertext: &ElGamalCiphertext) -> Option<u64> {
-        let discrete_log_instance = Self::decrypt(secret, ciphertext);
-        discrete_log_instance.decode_u32()
-    }
-}
-
-/// A (twisted) ElGamal encryption keypair.
-///
-/// The instances of the secret key are zeroized on drop.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, Zeroize)]
-pub struct ElGamalKeypair {
-    /// The public half of this keypair.
-    public: ElGamalPubkey,
-    /// The secret half of this keypair.
-    secret: ElGamalSecretKey,
-}
-
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-impl ElGamalKeypair {
-    /// Generates the public and secret keys for ElGamal encryption.
-    ///
-    /// This function is randomized. It internally samples a scalar element using `OsRng`.
-    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = newRand))]
-    pub fn new_rand() -> Self {
-        ElGamal::keygen()
-    }
-
-    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = pubkeyOwned))]
-    pub fn pubkey_owned(&self) -> ElGamalPubkey {
-        self.public
-    }
-}
-
-impl ElGamalKeypair {
-    pub fn pubkey(&self) -> &ElGamalPubkey {
-        &self.public
-    }
-
-    pub fn secret(&self) -> &ElGamalSecretKey {
-        &self.secret
-    }
-}
-
-#[cfg(not(target_arch = "wasm32"))]
-impl ElGamalKeypair {
-    /// Create an ElGamal keypair from an ElGamal public key and an ElGamal secret key.
-    ///
-    /// An ElGamal keypair should never be instantiated manually; `ElGamalKeypair::new`,
-    /// `ElGamalKeypair::new_rand` or `ElGamalKeypair::new_from_signer` should be used instead.
-    /// This function exists to create custom ElGamal keypairs for tests.
-    pub fn new_for_tests(public: ElGamalPubkey, secret: ElGamalSecretKey) -> Self {
-        Self { public, secret }
-    }
-
-    /// Convert an ElGamal secret key to an ElGamal keypair.
-    pub fn new(secret: ElGamalSecretKey) -> Self {
-        let public = ElGamalPubkey::new(&secret);
-        Self { public, secret }
-    }
-
-    /// Deterministically derives an ElGamal keypair from a Solana signer and a public seed.
-    ///
-    /// This function exists for applications where a user may not wish to maintain a Solana signer
-    /// and an ElGamal keypair separately. Instead, a user can derive the ElGamal keypair
-    /// on-the-fly whenever encryption/decryption is needed.
-    ///
-    /// For the spl-token-2022 confidential extension, the ElGamal public key is specified in a
-    /// token account. A natural way to derive an ElGamal keypair is to define it from the hash of
-    /// a Solana keypair and a Solana address as the public seed. However, for general hardware
-    /// wallets, the signing key is not exposed in the API. Therefore, this function uses a signer
-    /// to sign a public seed and the resulting signature is then hashed to derive an ElGamal
-    /// keypair.
-    pub fn new_from_signer(
-        signer: &dyn Signer,
-        public_seed: &[u8],
-    ) -> Result<Self, Box<dyn error::Error>> {
-        let secret = ElGamalSecretKey::new_from_signer(signer, public_seed)?;
-        Ok(Self::new(secret))
-    }
-
-    /// Derive an ElGamal keypair from a signature.
-    pub fn new_from_signature(signature: &Signature) -> Result<Self, Box<dyn error::Error>> {
-        let secret = ElGamalSecretKey::new_from_signature(signature)?;
-        Ok(Self::new(secret))
-    }
-
-    /// Reads a JSON-encoded keypair from a `Reader` implementor
-    pub fn read_json<R: Read>(reader: &mut R) -> Result<Self, Box<dyn error::Error>> {
-        let bytes: Vec<u8> = serde_json::from_reader(reader)?;
-        Self::try_from(bytes.as_slice())
-            .ok()
-            .ok_or_else(|| std::io::Error::other("Invalid ElGamalKeypair").into())
-    }
-
-    /// Reads keypair from a file
-    pub fn read_json_file<F: AsRef<Path>>(path: F) -> Result<Self, Box<dyn error::Error>> {
-        Self::read_from_file(path)
-    }
-
-    /// Writes to a `Write` implementer with JSON-encoding
-    pub fn write_json<W: Write>(&self, writer: &mut W) -> Result<String, Box<dyn error::Error>> {
-        let json =
-            serde_json::to_string(&Into::<[u8; ELGAMAL_KEYPAIR_LEN]>::into(self).as_slice())?;
-        writer.write_all(&json.clone().into_bytes())?;
-        Ok(json)
-    }
-
-    /// Write keypair to a file with JSON-encoding
-    pub fn write_json_file<F: AsRef<Path>>(
-        &self,
-        outfile: F,
-    ) -> Result<String, Box<dyn std::error::Error>> {
-        self.write_to_file(outfile)
-    }
-}
-
-#[cfg(not(target_arch = "wasm32"))]
-impl EncodableKey for ElGamalKeypair {
-    fn read<R: Read>(reader: &mut R) -> Result<Self, Box<dyn error::Error>> {
-        Self::read_json(reader)
-    }
-
-    fn write<W: Write>(&self, writer: &mut W) -> Result<String, Box<dyn error::Error>> {
-        self.write_json(writer)
-    }
-}
-
-impl TryFrom<&[u8]> for ElGamalKeypair {
-    type Error = ElGamalError;
-    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
-        if bytes.len() != ELGAMAL_KEYPAIR_LEN {
-            return Err(ElGamalError::KeypairDeserialization);
-        }
-
-        Ok(Self {
-            public: ElGamalPubkey::try_from(&bytes[..ELGAMAL_PUBKEY_LEN])?,
-            secret: ElGamalSecretKey::try_from(&bytes[ELGAMAL_PUBKEY_LEN..])?,
-        })
-    }
-}
-
-impl From<ElGamalKeypair> for [u8; ELGAMAL_KEYPAIR_LEN] {
-    fn from(keypair: ElGamalKeypair) -> Self {
-        let mut bytes = [0u8; ELGAMAL_KEYPAIR_LEN];
-        bytes[..ELGAMAL_PUBKEY_LEN]
-            .copy_from_slice(&Into::<[u8; ELGAMAL_PUBKEY_LEN]>::into(keypair.public));
-        bytes[ELGAMAL_PUBKEY_LEN..].copy_from_slice(keypair.secret.as_bytes());
-        bytes
-    }
-}
-
-impl From<&ElGamalKeypair> for [u8; ELGAMAL_KEYPAIR_LEN] {
-    fn from(keypair: &ElGamalKeypair) -> Self {
-        let mut bytes = [0u8; ELGAMAL_KEYPAIR_LEN];
-        bytes[..ELGAMAL_PUBKEY_LEN]
-            .copy_from_slice(&Into::<[u8; ELGAMAL_PUBKEY_LEN]>::into(keypair.public));
-        bytes[ELGAMAL_PUBKEY_LEN..].copy_from_slice(keypair.secret.as_bytes());
-        bytes
-    }
-}
-
-#[cfg(not(target_arch = "wasm32"))]
-impl SeedDerivable for ElGamalKeypair {
-    fn from_seed(seed: &[u8]) -> Result<Self, Box<dyn error::Error>> {
-        let secret = ElGamalSecretKey::from_seed(seed)?;
-        let public = ElGamalPubkey::new(&secret);
-        Ok(ElGamalKeypair { public, secret })
-    }
-
-    fn from_seed_and_derivation_path(
-        _seed: &[u8],
-        _derivation_path: Option<DerivationPath>,
-    ) -> Result<Self, Box<dyn error::Error>> {
-        Err(ElGamalError::DerivationMethodNotSupported.into())
-    }
-
-    fn from_seed_phrase_and_passphrase(
-        seed_phrase: &str,
-        passphrase: &str,
-    ) -> Result<Self, Box<dyn error::Error>> {
-        Self::from_seed(&generate_seed_from_seed_phrase_and_passphrase(
-            seed_phrase,
-            passphrase,
-        ))
-    }
-}
-
-#[cfg(not(target_arch = "wasm32"))]
-impl EncodableKeypair for ElGamalKeypair {
-    type Pubkey = ElGamalPubkey;
-
-    fn encodable_pubkey(&self) -> Self::Pubkey {
-        self.public
-    }
-}
-
-/// Public key for the ElGamal encryption scheme.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, Zeroize)]
-pub struct ElGamalPubkey(RistrettoPoint);
-impl ElGamalPubkey {
-    /// Derives the `ElGamalPubkey` that uniquely corresponds to an `ElGamalSecretKey`.
-    pub fn new(secret: &ElGamalSecretKey) -> Self {
-        let s = &secret.0;
-        assert!(s != &Scalar::ZERO);
-
-        ElGamalPubkey(s.invert() * &(*H))
-    }
-
-    pub fn get_point(&self) -> &RistrettoPoint {
-        &self.0
-    }
-
-    /// Encrypts an amount under the public key.
-    ///
-    /// This function is randomized. It internally samples a scalar element using `OsRng`.
-    pub fn encrypt<T: Into<Scalar>>(&self, amount: T) -> ElGamalCiphertext {
-        ElGamal::encrypt(self, amount)
-    }
-
-    /// Encrypts an amount under the public key and an input Pedersen opening.
-    pub fn encrypt_with<T: Into<Scalar>>(
-        &self,
-        amount: T,
-        opening: &PedersenOpening,
-    ) -> ElGamalCiphertext {
-        ElGamal::encrypt_with(amount, self, opening)
-    }
-
-    /// Generates a decryption handle for an ElGamal public key under a Pedersen
-    /// opening.
-    pub fn decrypt_handle(self, opening: &PedersenOpening) -> DecryptHandle {
-        DecryptHandle::new(&self, opening)
-    }
-}
-
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-impl ElGamalPubkey {
-    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = encryptU64))]
-    pub fn encrypt_u64(&self, amount: u64) -> ElGamalCiphertext {
-        ElGamal::encrypt(self, amount)
-    }
-
-    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = encryptWithU64))]
-    pub fn encrypt_with_u64(&self, amount: u64, opening: &PedersenOpening) -> ElGamalCiphertext {
-        ElGamal::encrypt_with(amount, self, opening)
-    }
-}
-
-#[cfg(not(target_arch = "wasm32"))]
-impl EncodableKey for ElGamalPubkey {
-    fn read<R: Read>(reader: &mut R) -> Result<Self, Box<dyn error::Error>> {
-        let bytes: Vec<u8> = serde_json::from_reader(reader)?;
-        Self::try_from(bytes.as_slice())
-            .ok()
-            .ok_or_else(|| std::io::Error::other("Invalid ElGamalPubkey").into())
-    }
-
-    fn write<W: Write>(&self, writer: &mut W) -> Result<String, Box<dyn error::Error>> {
-        let bytes = Into::<[u8; ELGAMAL_PUBKEY_LEN]>::into(*self);
-        let json = serde_json::to_string(&bytes.to_vec())?;
-        writer.write_all(&json.clone().into_bytes())?;
-        Ok(json)
-    }
-}
-
-impl fmt::Display for ElGamalPubkey {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(
-            f,
-            "{}",
-            BASE64_STANDARD.encode(Into::<[u8; ELGAMAL_PUBKEY_LEN]>::into(*self))
-        )
-    }
-}
-
-impl TryFrom<&[u8]> for ElGamalPubkey {
-    type Error = ElGamalError;
-    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
-        if bytes.len() != ELGAMAL_PUBKEY_LEN {
-            return Err(ElGamalError::PubkeyDeserialization);
-        }
-        let Ok(compressed_ristretto) = CompressedRistretto::from_slice(bytes) else {
-            return Err(ElGamalError::PubkeyDeserialization);
-        };
-
-        Ok(ElGamalPubkey(
-            compressed_ristretto
-                .decompress()
-                .ok_or(ElGamalError::PubkeyDeserialization)?,
-        ))
-    }
-}
-
-impl From<ElGamalPubkey> for [u8; ELGAMAL_PUBKEY_LEN] {
-    fn from(pubkey: ElGamalPubkey) -> Self {
-        pubkey.0.compress().to_bytes()
-    }
-}
-
-impl From<&ElGamalPubkey> for [u8; ELGAMAL_PUBKEY_LEN] {
-    fn from(pubkey: &ElGamalPubkey) -> Self {
-        pubkey.0.compress().to_bytes()
-    }
-}
-
-/// Secret key for the ElGamal encryption scheme.
-///
-/// Instances of ElGamal secret key are zeroized on drop.
-#[derive(Clone, Debug, Deserialize, Serialize, Zeroize)]
-#[zeroize(drop)]
-pub struct ElGamalSecretKey(Scalar);
-impl ElGamalSecretKey {
-    /// Randomly samples an ElGamal secret key.
-    ///
-    /// This function is randomized. It internally samples a scalar element using `OsRng`.
-    pub fn new_rand() -> Self {
-        ElGamalSecretKey(Scalar::random(&mut OsRng))
-    }
-
-    /// Derive an ElGamal secret key from an entropy seed.
-    pub fn from_seed(seed: &[u8]) -> Result<Self, ElGamalError> {
-        const MINIMUM_SEED_LEN: usize = ELGAMAL_SECRET_KEY_LEN;
-        const MAXIMUM_SEED_LEN: usize = 65535;
-
-        if seed.len() < MINIMUM_SEED_LEN {
-            return Err(ElGamalError::SeedLengthTooShort);
-        }
-        if seed.len() > MAXIMUM_SEED_LEN {
-            return Err(ElGamalError::SeedLengthTooLong);
-        }
-        Ok(ElGamalSecretKey(Scalar::hash_from_bytes::<Sha3_512>(seed)))
-    }
-
-    pub fn get_scalar(&self) -> &Scalar {
-        &self.0
-    }
-
-    pub fn as_bytes(&self) -> &[u8; ELGAMAL_SECRET_KEY_LEN] {
-        self.0.as_bytes()
-    }
-
-    /// Decrypts a ciphertext using the ElGamal secret key.
-    ///
-    /// The output of this function is of type `DiscreteLog`. To recover, the originally encrypted
-    /// message, use `DiscreteLog::decode`.
-    pub fn decrypt(&self, ciphertext: &ElGamalCiphertext) -> DiscreteLog {
-        ElGamal::decrypt(self, ciphertext)
-    }
-
-    /// Decrypts a ciphertext using the ElGamal secret key interpreting the message as type `u32`.
-    pub fn decrypt_u32(&self, ciphertext: &ElGamalCiphertext) -> Option<u64> {
-        ElGamal::decrypt_u32(self, ciphertext)
-    }
-}
-
-#[cfg(not(target_arch = "wasm32"))]
-impl ElGamalSecretKey {
-    /// Deterministically derives an ElGamal secret key from a Solana signer and a public seed.
-    ///
-    /// See `ElGamalKeypair::new_from_signer` for more context on the key derivation.
-    pub fn new_from_signer(
-        signer: &dyn Signer,
-        public_seed: &[u8],
-    ) -> Result<Self, Box<dyn error::Error>> {
-        let seed = Self::seed_from_signer(signer, public_seed)?;
-        let key = Self::from_seed(&seed)?;
-        Ok(key)
-    }
-
-    /// Derive a seed from a Solana signer used to generate an ElGamal secret key.
-    ///
-    /// The seed is derived as the hash of the signature of a public seed.
-    pub fn seed_from_signer(
-        signer: &dyn Signer,
-        public_seed: &[u8],
-    ) -> Result<Vec<u8>, SignerError> {
-        let message = [b"ElGamalSecretKey", public_seed].concat();
-        let signature = signer.try_sign_message(&message)?;
-
-        // Some `Signer` implementations return the default signature, which is not suitable for
-        // use as key material
-        if bool::from(signature.as_ref().ct_eq(Signature::default().as_ref())) {
-            return Err(SignerError::Custom("Rejecting default signatures".into()));
-        }
-
-        Ok(Self::seed_from_signature(&signature))
-    }
-
-    /// Derive an ElGamal secret key from a signature.
-    pub fn new_from_signature(signature: &Signature) -> Result<Self, Box<dyn error::Error>> {
-        let seed = Self::seed_from_signature(signature);
-        let key = Self::from_seed(&seed)?;
-        Ok(key)
-    }
-
-    /// Derive an ElGamal secret key from a signature.
-    pub fn seed_from_signature(signature: &Signature) -> Vec<u8> {
-        let mut hasher = Sha3_512::new();
-        hasher.update(signature.as_ref());
-        let result = hasher.finalize();
-
-        result.to_vec()
-    }
-}
-
-#[cfg(not(target_arch = "wasm32"))]
-impl EncodableKey for ElGamalSecretKey {
-    fn read<R: Read>(reader: &mut R) -> Result<Self, Box<dyn error::Error>> {
-        let bytes: Vec<u8> = serde_json::from_reader(reader)?;
-        Self::try_from(bytes.as_slice())
-            .ok()
-            .ok_or_else(|| std::io::Error::other("Invalid ElGamalSecretKey").into())
-    }
-
-    fn write<W: Write>(&self, writer: &mut W) -> Result<String, Box<dyn error::Error>> {
-        let bytes = Into::<[u8; ELGAMAL_SECRET_KEY_LEN]>::into(self);
-        let json = serde_json::to_string(&bytes.to_vec())?;
-        writer.write_all(&json.clone().into_bytes())?;
-        Ok(json)
-    }
-}
-
-#[cfg(not(target_arch = "wasm32"))]
-impl SeedDerivable for ElGamalSecretKey {
-    fn from_seed(seed: &[u8]) -> Result<Self, Box<dyn error::Error>> {
-        let key = Self::from_seed(seed)?;
-        Ok(key)
-    }
-
-    fn from_seed_and_derivation_path(
-        _seed: &[u8],
-        _derivation_path: Option<DerivationPath>,
-    ) -> Result<Self, Box<dyn error::Error>> {
-        Err(ElGamalError::DerivationMethodNotSupported.into())
-    }
-
-    fn from_seed_phrase_and_passphrase(
-        seed_phrase: &str,
-        passphrase: &str,
-    ) -> Result<Self, Box<dyn error::Error>> {
-        let key = Self::from_seed(&generate_seed_from_seed_phrase_and_passphrase(
-            seed_phrase,
-            passphrase,
-        ))?;
-        Ok(key)
-    }
-}
-
-impl From<Scalar> for ElGamalSecretKey {
-    fn from(scalar: Scalar) -> ElGamalSecretKey {
-        ElGamalSecretKey(scalar)
-    }
-}
-
-impl TryFrom<&[u8]> for ElGamalSecretKey {
-    type Error = ElGamalError;
-    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
-        match bytes.try_into() {
-            Ok(bytes) => Ok(ElGamalSecretKey::from(
-                Scalar::from_canonical_bytes(bytes)
-                    .into_option()
-                    .ok_or(ElGamalError::SecretKeyDeserialization)?,
-            )),
-            _ => Err(ElGamalError::SecretKeyDeserialization),
-        }
-    }
-}
-
-impl From<ElGamalSecretKey> for [u8; ELGAMAL_SECRET_KEY_LEN] {
-    fn from(secret_key: ElGamalSecretKey) -> Self {
-        secret_key.0.to_bytes()
-    }
-}
-
-impl From<&ElGamalSecretKey> for [u8; ELGAMAL_SECRET_KEY_LEN] {
-    fn from(secret_key: &ElGamalSecretKey) -> Self {
-        secret_key.0.to_bytes()
-    }
-}
-
-impl Eq for ElGamalSecretKey {}
-impl PartialEq for ElGamalSecretKey {
-    fn eq(&self, other: &Self) -> bool {
-        self.ct_eq(other).unwrap_u8() == 1u8
-    }
-}
-impl ConstantTimeEq for ElGamalSecretKey {
-    fn ct_eq(&self, other: &Self) -> Choice {
-        self.0.ct_eq(&other.0)
-    }
-}
-
-/// Ciphertext for the ElGamal encryption scheme.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
-pub struct ElGamalCiphertext {
-    pub commitment: PedersenCommitment,
-    pub handle: DecryptHandle,
-}
-impl ElGamalCiphertext {
-    pub fn add_amount<T: Into<Scalar>>(&self, amount: T) -> Self {
-        let point = amount.into() * G;
-        let commitment_to_add = PedersenCommitment::new(point);
-        ElGamalCiphertext {
-            commitment: &self.commitment + &commitment_to_add,
-            handle: self.handle,
-        }
-    }
-
-    pub fn subtract_amount<T: Into<Scalar>>(&self, amount: T) -> Self {
-        let point = amount.into() * &G;
-        let commitment_to_subtract = PedersenCommitment::new(point);
-        ElGamalCiphertext {
-            commitment: &self.commitment - &commitment_to_subtract,
-            handle: self.handle,
-        }
-    }
-
-    pub fn to_bytes(&self) -> [u8; ELGAMAL_CIPHERTEXT_LEN] {
-        let mut bytes = [0u8; ELGAMAL_CIPHERTEXT_LEN];
-        bytes[..PEDERSEN_COMMITMENT_LEN].copy_from_slice(&self.commitment.to_bytes());
-        bytes[PEDERSEN_COMMITMENT_LEN..].copy_from_slice(&self.handle.to_bytes());
-        bytes
-    }
-
-    pub fn from_bytes(bytes: &[u8]) -> Option<ElGamalCiphertext> {
-        if bytes.len() != ELGAMAL_CIPHERTEXT_LEN {
-            return None;
-        }
-
-        Some(ElGamalCiphertext {
-            commitment: PedersenCommitment::from_bytes(&bytes[..PEDERSEN_COMMITMENT_LEN])?,
-            handle: DecryptHandle::from_bytes(&bytes[PEDERSEN_COMMITMENT_LEN..])?,
-        })
-    }
-
-    /// Decrypts the ciphertext using an ElGamal secret key.
-    ///
-    /// The output of this function is of type `DiscreteLog`. To recover, the originally encrypted
-    /// amount, use `DiscreteLog::decode`.
-    pub fn decrypt(&self, secret: &ElGamalSecretKey) -> DiscreteLog {
-        ElGamal::decrypt(secret, self)
-    }
-
-    /// Decrypts the ciphertext using an ElGamal secret key assuming that the message is a positive
-    /// 32-bit number.
-    ///
-    /// If the originally encrypted amount is not a positive 32-bit number, then the function
-    /// returns `None`.
-    pub fn decrypt_u32(&self, secret: &ElGamalSecretKey) -> Option<u64> {
-        ElGamal::decrypt_u32(secret, self)
-    }
-}
-
-impl fmt::Display for ElGamalCiphertext {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.to_bytes()))
-    }
-}
-
-impl<'b> Add<&'b ElGamalCiphertext> for &ElGamalCiphertext {
-    type Output = ElGamalCiphertext;
-
-    fn add(self, ciphertext: &'b ElGamalCiphertext) -> ElGamalCiphertext {
-        ElGamalCiphertext {
-            commitment: &self.commitment + &ciphertext.commitment,
-            handle: &self.handle + &ciphertext.handle,
-        }
-    }
-}
-
-define_add_variants!(
-    LHS = ElGamalCiphertext,
-    RHS = ElGamalCiphertext,
-    Output = ElGamalCiphertext
-);
-
-impl<'b> Sub<&'b ElGamalCiphertext> for &ElGamalCiphertext {
-    type Output = ElGamalCiphertext;
-
-    fn sub(self, ciphertext: &'b ElGamalCiphertext) -> ElGamalCiphertext {
-        ElGamalCiphertext {
-            commitment: &self.commitment - &ciphertext.commitment,
-            handle: &self.handle - &ciphertext.handle,
-        }
-    }
-}
-
-define_sub_variants!(
-    LHS = ElGamalCiphertext,
-    RHS = ElGamalCiphertext,
-    Output = ElGamalCiphertext
-);
-
-impl<'b> Mul<&'b Scalar> for &ElGamalCiphertext {
-    type Output = ElGamalCiphertext;
-
-    fn mul(self, scalar: &'b Scalar) -> ElGamalCiphertext {
-        ElGamalCiphertext {
-            commitment: &self.commitment * scalar,
-            handle: &self.handle * scalar,
-        }
-    }
-}
-
-define_mul_variants!(
-    LHS = ElGamalCiphertext,
-    RHS = Scalar,
-    Output = ElGamalCiphertext
-);
-
-impl<'b> Mul<&'b ElGamalCiphertext> for &Scalar {
-    type Output = ElGamalCiphertext;
-
-    fn mul(self, ciphertext: &'b ElGamalCiphertext) -> ElGamalCiphertext {
-        ElGamalCiphertext {
-            commitment: self * &ciphertext.commitment,
-            handle: self * &ciphertext.handle,
-        }
-    }
-}
-
-define_mul_variants!(
-    LHS = Scalar,
-    RHS = ElGamalCiphertext,
-    Output = ElGamalCiphertext
-);
-
-/// Decryption handle for Pedersen commitment.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
-pub struct DecryptHandle(RistrettoPoint);
-impl DecryptHandle {
-    pub fn new(public: &ElGamalPubkey, opening: &PedersenOpening) -> Self {
-        Self(&public.0 * opening.get_scalar())
-    }
-
-    pub fn get_point(&self) -> &RistrettoPoint {
-        &self.0
-    }
-
-    pub fn to_bytes(&self) -> [u8; DECRYPT_HANDLE_LEN] {
-        self.0.compress().to_bytes()
-    }
-
-    pub fn from_bytes(bytes: &[u8]) -> Option<DecryptHandle> {
-        if bytes.len() != DECRYPT_HANDLE_LEN {
-            return None;
-        }
-        let Ok(compressed_ristretto) = CompressedRistretto::from_slice(bytes) else {
-            return None;
-        };
-
-        compressed_ristretto.decompress().map(DecryptHandle)
-    }
-}
-
-impl<'b> Add<&'b DecryptHandle> for &DecryptHandle {
-    type Output = DecryptHandle;
-
-    fn add(self, handle: &'b DecryptHandle) -> DecryptHandle {
-        DecryptHandle(&self.0 + &handle.0)
-    }
-}
-
-define_add_variants!(
-    LHS = DecryptHandle,
-    RHS = DecryptHandle,
-    Output = DecryptHandle
-);
-
-impl<'b> Sub<&'b DecryptHandle> for &DecryptHandle {
-    type Output = DecryptHandle;
-
-    fn sub(self, handle: &'b DecryptHandle) -> DecryptHandle {
-        DecryptHandle(&self.0 - &handle.0)
-    }
-}
-
-define_sub_variants!(
-    LHS = DecryptHandle,
-    RHS = DecryptHandle,
-    Output = DecryptHandle
-);
-
-impl<'b> Mul<&'b Scalar> for &DecryptHandle {
-    type Output = DecryptHandle;
-
-    fn mul(self, scalar: &'b Scalar) -> DecryptHandle {
-        DecryptHandle(&self.0 * scalar)
-    }
-}
-
-define_mul_variants!(LHS = DecryptHandle, RHS = Scalar, Output = DecryptHandle);
-
-impl<'b> Mul<&'b DecryptHandle> for &Scalar {
-    type Output = DecryptHandle;
-
-    fn mul(self, handle: &'b DecryptHandle) -> DecryptHandle {
-        DecryptHandle(self * &handle.0)
-    }
-}
-
-define_mul_variants!(LHS = Scalar, RHS = DecryptHandle, Output = DecryptHandle);
-
-#[cfg(test)]
-mod tests {
-    use {
-        super::*,
-        crate::encryption::pedersen::Pedersen,
-        bip39::{Language, Mnemonic, MnemonicType, Seed},
-        solana_keypair::Keypair,
-        solana_pubkey::Pubkey,
-        solana_signer::null_signer::NullSigner,
-        std::fs::{self, File},
-    };
-
-    #[test]
-    fn test_encrypt_decrypt_correctness() {
-        let ElGamalKeypair { public, secret } = ElGamalKeypair::new_rand();
-        let amount: u32 = 57;
-        let ciphertext = ElGamal::encrypt(&public, amount);
-
-        let expected_instance = DiscreteLog::new(G, Scalar::from(amount) * &G);
-
-        assert_eq!(expected_instance, ElGamal::decrypt(&secret, &ciphertext));
-        assert_eq!(57_u64, secret.decrypt_u32(&ciphertext).unwrap());
-    }
-
-    #[cfg(not(target_arch = "wasm32"))]
-    #[test]
-    fn test_encrypt_decrypt_correctness_multithreaded() {
-        let ElGamalKeypair { public, secret } = ElGamalKeypair::new_rand();
-        let amount: u32 = 57;
-        let ciphertext = ElGamal::encrypt(&public, amount);
-
-        let mut instance = ElGamal::decrypt(&secret, &ciphertext);
-        instance.num_threads(4.try_into().unwrap()).unwrap();
-        assert_eq!(57_u64, instance.decode_u32().unwrap());
-    }
-
-    #[test]
-    fn test_decrypt_handle() {
-        let ElGamalKeypair {
-            public: public_0,
-            secret: secret_0,
-        } = ElGamalKeypair::new_rand();
-        let ElGamalKeypair {
-            public: public_1,
-            secret: secret_1,
-        } = ElGamalKeypair::new_rand();
-
-        let amount: u32 = 77;
-        let (commitment, opening) = Pedersen::new(amount);
-
-        let handle_0 = public_0.decrypt_handle(&opening);
-        let handle_1 = public_1.decrypt_handle(&opening);
-
-        let ciphertext_0 = ElGamalCiphertext {
-            commitment,
-            handle: handle_0,
-        };
-        let ciphertext_1 = ElGamalCiphertext {
-            commitment,
-            handle: handle_1,
-        };
-
-        let expected_instance = DiscreteLog::new(G, Scalar::from(amount) * &G);
-
-        assert_eq!(expected_instance, secret_0.decrypt(&ciphertext_0));
-        assert_eq!(expected_instance, secret_1.decrypt(&ciphertext_1));
-    }
-
-    #[test]
-    fn test_homomorphic_addition() {
-        let ElGamalKeypair { public, secret: _ } = ElGamalKeypair::new_rand();
-        let amount_0: u64 = 57;
-        let amount_1: u64 = 77;
-
-        // Add two ElGamal ciphertexts
-        let opening_0 = PedersenOpening::new_rand();
-        let opening_1 = PedersenOpening::new_rand();
-
-        let ciphertext_0 = ElGamal::encrypt_with(amount_0, &public, &opening_0);
-        let ciphertext_1 = ElGamal::encrypt_with(amount_1, &public, &opening_1);
-
-        let ciphertext_sum =
-            ElGamal::encrypt_with(amount_0 + amount_1, &public, &(&opening_0 + &opening_1));
-
-        assert_eq!(ciphertext_sum, ciphertext_0 + ciphertext_1);
-
-        // Add to ElGamal ciphertext
-        let opening = PedersenOpening::new_rand();
-        let ciphertext = ElGamal::encrypt_with(amount_0, &public, &opening);
-        let ciphertext_sum = ElGamal::encrypt_with(amount_0 + amount_1, &public, &opening);
-
-        assert_eq!(ciphertext_sum, ciphertext.add_amount(amount_1));
-    }
-
-    #[test]
-    fn test_homomorphic_subtraction() {
-        let ElGamalKeypair { public, secret: _ } = ElGamalKeypair::new_rand();
-        let amount_0: u64 = 77;
-        let amount_1: u64 = 55;
-
-        // Subtract two ElGamal ciphertexts
-        let opening_0 = PedersenOpening::new_rand();
-        let opening_1 = PedersenOpening::new_rand();
-
-        let ciphertext_0 = ElGamal::encrypt_with(amount_0, &public, &opening_0);
-        let ciphertext_1 = ElGamal::encrypt_with(amount_1, &public, &opening_1);
-
-        let ciphertext_sub =
-            ElGamal::encrypt_with(amount_0 - amount_1, &public, &(&opening_0 - &opening_1));
-
-        assert_eq!(ciphertext_sub, ciphertext_0 - ciphertext_1);
-
-        // Subtract to ElGamal ciphertext
-        let opening = PedersenOpening::new_rand();
-        let ciphertext = ElGamal::encrypt_with(amount_0, &public, &opening);
-        let ciphertext_sub = ElGamal::encrypt_with(amount_0 - amount_1, &public, &opening);
-
-        assert_eq!(ciphertext_sub, ciphertext.subtract_amount(amount_1));
-    }
-
-    #[test]
-    fn test_homomorphic_multiplication() {
-        let ElGamalKeypair { public, secret: _ } = ElGamalKeypair::new_rand();
-        let amount_0: u64 = 57;
-        let amount_1: u64 = 77;
-
-        let opening = PedersenOpening::new_rand();
-
-        let ciphertext = ElGamal::encrypt_with(amount_0, &public, &opening);
-        let scalar = Scalar::from(amount_1);
-
-        let ciphertext_prod =
-            ElGamal::encrypt_with(amount_0 * amount_1, &public, &(&opening * scalar));
-
-        assert_eq!(ciphertext_prod, ciphertext * scalar);
-        assert_eq!(ciphertext_prod, scalar * ciphertext);
-    }
-
-    #[test]
-    fn test_serde_ciphertext() {
-        let ElGamalKeypair { public, secret: _ } = ElGamalKeypair::new_rand();
-        let amount: u64 = 77;
-        let ciphertext = public.encrypt(amount);
-
-        let encoded = bincode::serialize(&ciphertext).unwrap();
-        let decoded: ElGamalCiphertext = bincode::deserialize(&encoded).unwrap();
-
-        assert_eq!(ciphertext, decoded);
-    }
-
-    #[test]
-    fn test_serde_pubkey() {
-        let ElGamalKeypair { public, secret: _ } = ElGamalKeypair::new_rand();
-
-        let encoded = bincode::serialize(&public).unwrap();
-        let decoded: ElGamalPubkey = bincode::deserialize(&encoded).unwrap();
-
-        assert_eq!(public, decoded);
-    }
-
-    #[test]
-    fn test_serde_secretkey() {
-        let ElGamalKeypair { public: _, secret } = ElGamalKeypair::new_rand();
-
-        let encoded = bincode::serialize(&secret).unwrap();
-        let decoded: ElGamalSecretKey = bincode::deserialize(&encoded).unwrap();
-
-        assert_eq!(secret, decoded);
-    }
-
-    fn tmp_file_path(name: &str) -> String {
-        use std::env;
-        let out_dir = env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_string());
-        let keypair = ElGamalKeypair::new_rand();
-        format!("{}/tmp/{}-{}", out_dir, name, keypair.public)
-    }
-
-    #[test]
-    fn test_write_keypair_file() {
-        let outfile = tmp_file_path("test_write_keypair_file.json");
-        let serialized_keypair = ElGamalKeypair::new_rand()
-            .write_json_file(&outfile)
-            .unwrap();
-        let keypair_vec: Vec<u8> = serde_json::from_str(&serialized_keypair).unwrap();
-        assert!(Path::new(&outfile).exists());
-        assert_eq!(
-            keypair_vec,
-            Into::<[u8; ELGAMAL_KEYPAIR_LEN]>::into(
-                ElGamalKeypair::read_json_file(&outfile).unwrap()
-            )
-            .to_vec()
-        );
-
-        #[cfg(unix)]
-        {
-            use std::os::unix::fs::PermissionsExt;
-            assert_eq!(
-                File::open(&outfile)
-                    .expect("open")
-                    .metadata()
-                    .expect("metadata")
-                    .permissions()
-                    .mode()
-                    & 0o777,
-                0o600
-            );
-        }
-        fs::remove_file(&outfile).unwrap();
-    }
-
-    #[test]
-    fn test_write_keypair_file_overwrite_ok() {
-        let outfile = tmp_file_path("test_write_keypair_file_overwrite_ok.json");
-
-        ElGamalKeypair::new_rand()
-            .write_json_file(&outfile)
-            .unwrap();
-        ElGamalKeypair::new_rand()
-            .write_json_file(&outfile)
-            .unwrap();
-    }
-
-    #[test]
-    fn test_write_keypair_file_truncate() {
-        let outfile = tmp_file_path("test_write_keypair_file_truncate.json");
-
-        ElGamalKeypair::new_rand()
-            .write_json_file(&outfile)
-            .unwrap();
-        ElGamalKeypair::read_json_file(&outfile).unwrap();
-
-        // Ensure outfile is truncated
-        {
-            let mut f = File::create(&outfile).unwrap();
-            f.write_all(String::from_utf8([b'a'; 2048].to_vec()).unwrap().as_bytes())
-                .unwrap();
-        }
-        ElGamalKeypair::new_rand()
-            .write_json_file(&outfile)
-            .unwrap();
-        ElGamalKeypair::read_json_file(&outfile).unwrap();
-    }
-
-    #[test]
-    fn test_secret_key_new_from_signer() {
-        let keypair1 = Keypair::new();
-        let keypair2 = Keypair::new();
-
-        assert_ne!(
-            ElGamalSecretKey::new_from_signer(&keypair1, Pubkey::default().as_ref())
-                .unwrap()
-                .0,
-            ElGamalSecretKey::new_from_signer(&keypair2, Pubkey::default().as_ref())
-                .unwrap()
-                .0,
-        );
-
-        let null_signer = NullSigner::new(&Pubkey::default());
-        assert!(
-            ElGamalSecretKey::new_from_signer(&null_signer, Pubkey::default().as_ref()).is_err()
-        );
-    }
-
-    #[test]
-    fn test_keypair_from_seed() {
-        let good_seed = vec![0; 32];
-        assert!(ElGamalKeypair::from_seed(&good_seed).is_ok());
-
-        let too_short_seed = vec![0; 31];
-        assert!(ElGamalKeypair::from_seed(&too_short_seed).is_err());
-
-        let too_long_seed = vec![0; 65536];
-        assert!(ElGamalKeypair::from_seed(&too_long_seed).is_err());
-    }
-
-    #[test]
-    fn test_keypair_from_seed_phrase_and_passphrase() {
-        let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English);
-        let passphrase = "42";
-        let seed = Seed::new(&mnemonic, passphrase);
-        let expected_keypair = ElGamalKeypair::from_seed(seed.as_bytes()).unwrap();
-        let keypair =
-            ElGamalKeypair::from_seed_phrase_and_passphrase(mnemonic.phrase(), passphrase).unwrap();
-        assert_eq!(keypair.public, expected_keypair.public);
-    }
-
-    #[test]
-    fn test_decrypt_handle_bytes() {
-        let handle = DecryptHandle(RistrettoPoint::default());
-
-        let encoded = handle.to_bytes();
-        let decoded = DecryptHandle::from_bytes(&encoded).unwrap();
-
-        assert_eq!(handle, decoded);
-    }
-
-    #[test]
-    fn test_serde_decrypt_handle() {
-        let handle = DecryptHandle(RistrettoPoint::default());
-
-        let encoded = bincode::serialize(&handle).unwrap();
-        let decoded: DecryptHandle = bincode::deserialize(&encoded).unwrap();
-
-        assert_eq!(handle, decoded);
-    }
-}

+ 0 - 388
zk-sdk/src/encryption/grouped_elgamal.rs

@@ -1,388 +0,0 @@
-//! The twisted ElGamal group encryption implementation.
-//!
-//! The message space consists of any number that is representable as a scalar (a.k.a. "exponent")
-//! for Curve25519.
-//!
-//! A regular twisted ElGamal ciphertext consists of two components:
-//! - A Pedersen commitment that encodes a message to be encrypted
-//! - A "decryption handle" that binds the Pedersen opening to a specific public key
-//!
-//! The ciphertext can be generalized to hold not a single decryption handle, but multiple handles
-//! pertaining to multiple ElGamal public keys. These ciphertexts are referred to as a "grouped"
-//! ElGamal ciphertext.
-//!
-
-#[cfg(not(target_arch = "wasm32"))]
-use crate::encryption::{discrete_log::DiscreteLog, elgamal::ElGamalSecretKey};
-#[cfg(target_arch = "wasm32")]
-pub use grouped_elgamal_wasm::*;
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-use {
-    crate::{
-        encryption::{
-            elgamal::{DecryptHandle, ElGamalCiphertext, ElGamalPubkey},
-            pedersen::{Pedersen, PedersenCommitment, PedersenOpening},
-        },
-        RISTRETTO_POINT_LEN,
-    },
-    curve25519_dalek::scalar::Scalar,
-    thiserror::Error,
-};
-
-#[derive(Error, Clone, Debug, Eq, PartialEq)]
-pub enum GroupedElGamalError {
-    #[error("index out of bounds")]
-    IndexOutOfBounds,
-}
-
-/// Algorithm handle for the grouped ElGamal encryption
-pub struct GroupedElGamal<const N: usize>;
-impl<const N: usize> GroupedElGamal<N> {
-    /// Encrypts an amount under an array of ElGamal public keys.
-    ///
-    /// This function is randomized. It internally samples a scalar element using `OsRng`.
-    pub fn encrypt<T: Into<Scalar>>(
-        pubkeys: [&ElGamalPubkey; N],
-        amount: T,
-    ) -> GroupedElGamalCiphertext<N> {
-        let (commitment, opening) = Pedersen::new(amount);
-        let handles: [DecryptHandle; N] = pubkeys
-            .iter()
-            .map(|handle| handle.decrypt_handle(&opening))
-            .collect::<Vec<DecryptHandle>>()
-            .try_into()
-            .unwrap();
-
-        GroupedElGamalCiphertext {
-            commitment,
-            handles,
-        }
-    }
-
-    /// Encrypts an amount under an array of ElGamal public keys using a specified Pedersen
-    /// opening.
-    pub fn encrypt_with<T: Into<Scalar>>(
-        pubkeys: [&ElGamalPubkey; N],
-        amount: T,
-        opening: &PedersenOpening,
-    ) -> GroupedElGamalCiphertext<N> {
-        let commitment = Pedersen::with(amount, opening);
-        let handles: [DecryptHandle; N] = pubkeys
-            .iter()
-            .map(|handle| handle.decrypt_handle(opening))
-            .collect::<Vec<DecryptHandle>>()
-            .try_into()
-            .unwrap();
-
-        GroupedElGamalCiphertext {
-            commitment,
-            handles,
-        }
-    }
-
-    /// Converts a grouped ElGamal ciphertext into a regular ElGamal ciphertext using the decrypt
-    /// handle at a specified index.
-    fn to_elgamal_ciphertext(
-        grouped_ciphertext: &GroupedElGamalCiphertext<N>,
-        index: usize,
-    ) -> Result<ElGamalCiphertext, GroupedElGamalError> {
-        let handle = grouped_ciphertext
-            .handles
-            .get(index)
-            .ok_or(GroupedElGamalError::IndexOutOfBounds)?;
-
-        Ok(ElGamalCiphertext {
-            commitment: grouped_ciphertext.commitment,
-            handle: *handle,
-        })
-    }
-}
-
-#[cfg(not(target_arch = "wasm32"))]
-impl<const N: usize> GroupedElGamal<N> {
-    /// Decrypts a grouped ElGamal ciphertext using an ElGamal secret key pertaining to a
-    /// decryption handle at a specified index.
-    ///
-    /// The output of this function is of type `DiscreteLog`. To recover the originally encrypted
-    /// amount, use `DiscreteLog::decode`.
-    fn decrypt(
-        grouped_ciphertext: &GroupedElGamalCiphertext<N>,
-        secret: &ElGamalSecretKey,
-        index: usize,
-    ) -> Result<DiscreteLog, GroupedElGamalError> {
-        Self::to_elgamal_ciphertext(grouped_ciphertext, index)
-            .map(|ciphertext| ciphertext.decrypt(secret))
-    }
-
-    /// Decrypts a grouped ElGamal ciphertext to a number that is interpreted as a positive 32-bit
-    /// number (but still of type `u64`).
-    ///
-    /// If the originally encrypted amount is not a positive 32-bit number, then the function
-    /// Result contains `None`.
-    fn decrypt_u32(
-        grouped_ciphertext: &GroupedElGamalCiphertext<N>,
-        secret: &ElGamalSecretKey,
-        index: usize,
-    ) -> Result<Option<u64>, GroupedElGamalError> {
-        Self::to_elgamal_ciphertext(grouped_ciphertext, index)
-            .map(|ciphertext| ciphertext.decrypt_u32(secret))
-    }
-}
-
-/// A grouped ElGamal ciphertext.
-///
-/// The type is defined with a generic constant parameter that specifies the number of
-/// decryption handles that the ciphertext holds.
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub struct GroupedElGamalCiphertext<const N: usize> {
-    pub commitment: PedersenCommitment,
-    pub handles: [DecryptHandle; N],
-}
-
-impl<const N: usize> GroupedElGamalCiphertext<N> {
-    /// Converts a grouped ElGamal ciphertext into a regular ElGamal ciphertext using the decrypt
-    /// handle at a specified index.
-    pub fn to_elgamal_ciphertext(
-        &self,
-        index: usize,
-    ) -> Result<ElGamalCiphertext, GroupedElGamalError> {
-        GroupedElGamal::to_elgamal_ciphertext(self, index)
-    }
-
-    /// The expected length of a serialized grouped ElGamal ciphertext.
-    ///
-    /// A grouped ElGamal ciphertext consists of a Pedersen commitment and an array of decryption
-    /// handles. The commitment and decryption handles are each a single Curve25519 group element
-    /// that is serialized as 32 bytes. Therefore, the total byte length of a grouped ciphertext is
-    /// `(N+1) * 32`.
-    fn expected_byte_length() -> usize {
-        N.checked_add(1)
-            .and_then(|length| length.checked_mul(RISTRETTO_POINT_LEN))
-            .unwrap()
-    }
-
-    pub fn to_bytes(&self) -> Vec<u8> {
-        let mut buf = Vec::with_capacity(Self::expected_byte_length());
-        buf.extend_from_slice(&self.commitment.to_bytes());
-        self.handles
-            .iter()
-            .for_each(|handle| buf.extend_from_slice(&handle.to_bytes()));
-        buf
-    }
-
-    pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
-        if bytes.len() != Self::expected_byte_length() {
-            return None;
-        }
-
-        let mut iter = bytes.chunks(RISTRETTO_POINT_LEN);
-        let commitment = PedersenCommitment::from_bytes(iter.next()?)?;
-
-        let mut handles = Vec::with_capacity(N);
-        for handle_bytes in iter {
-            handles.push(DecryptHandle::from_bytes(handle_bytes)?);
-        }
-
-        Some(Self {
-            commitment,
-            handles: handles.try_into().unwrap(),
-        })
-    }
-}
-
-#[cfg(not(target_arch = "wasm32"))]
-impl<const N: usize> GroupedElGamalCiphertext<N> {
-    /// Decrypts the grouped ElGamal ciphertext using an ElGamal secret key pertaining to a
-    /// specified index.
-    ///
-    /// The output of this function is of type `DiscreteLog`. To recover the originally encrypted
-    /// amount, use `DiscreteLog::decode`.
-    pub fn decrypt(
-        &self,
-        secret: &ElGamalSecretKey,
-        index: usize,
-    ) -> Result<DiscreteLog, GroupedElGamalError> {
-        GroupedElGamal::decrypt(self, secret, index)
-    }
-
-    /// Decrypts the grouped ElGamal ciphertext to a number that is interpreted as a positive 32-bit
-    /// number (but still of type `u64`).
-    ///
-    /// If the originally encrypted amount is not a positive 32-bit number, then the function
-    /// returns `None`.
-    pub fn decrypt_u32(
-        &self,
-        secret: &ElGamalSecretKey,
-        index: usize,
-    ) -> Result<Option<u64>, GroupedElGamalError> {
-        GroupedElGamal::decrypt_u32(self, secret, index)
-    }
-}
-
-// Define specific grouped ElGamal ciphertext types for 2 and 3 handles since
-// `wasm_bindgen` do not yet support the export of types that take on generic
-// type parameters.
-#[cfg(target_arch = "wasm32")]
-mod grouped_elgamal_wasm {
-    use super::*;
-
-    #[wasm_bindgen]
-    pub struct GroupedElGamalCiphertext2Handles(pub(crate) GroupedElGamalCiphertext<2>);
-
-    #[wasm_bindgen]
-    impl GroupedElGamalCiphertext2Handles {
-        #[wasm_bindgen(js_name = encryptU64)]
-        pub fn encrypt_u64(
-            first_pubkey: &ElGamalPubkey,
-            second_pubkey: &ElGamalPubkey,
-            amount: u64,
-        ) -> Self {
-            Self(GroupedElGamal::<2>::encrypt(
-                [first_pubkey, second_pubkey],
-                amount,
-            ))
-        }
-
-        #[wasm_bindgen(js_name = encryptionWithU64)]
-        pub fn encryption_with_u64(
-            first_pubkey: &ElGamalPubkey,
-            second_pubkey: &ElGamalPubkey,
-            amount: u64,
-            opening: &PedersenOpening,
-        ) -> Self {
-            Self(GroupedElGamal::<2>::encrypt_with(
-                [first_pubkey, second_pubkey],
-                amount,
-                opening,
-            ))
-        }
-    }
-
-    #[wasm_bindgen]
-    pub struct GroupedElGamalCiphertext3Handles(pub(crate) GroupedElGamalCiphertext<3>);
-
-    #[wasm_bindgen]
-    impl GroupedElGamalCiphertext3Handles {
-        #[wasm_bindgen(js_name = encryptU64)]
-        pub fn encrypt_u64(
-            first_pubkey: &ElGamalPubkey,
-            second_pubkey: &ElGamalPubkey,
-            third_pubkey: &ElGamalPubkey,
-            amount: u64,
-        ) -> Self {
-            Self(GroupedElGamal::<3>::encrypt(
-                [first_pubkey, second_pubkey, third_pubkey],
-                amount,
-            ))
-        }
-
-        #[wasm_bindgen(js_name = encryptionWithU64)]
-        pub fn encryption_with_u64(
-            first_pubkey: &ElGamalPubkey,
-            second_pubkey: &ElGamalPubkey,
-            third_pubkey: &ElGamalPubkey,
-            amount: u64,
-            opening: &PedersenOpening,
-        ) -> Self {
-            Self(GroupedElGamal::<3>::encrypt_with(
-                [first_pubkey, second_pubkey, third_pubkey],
-                amount,
-                opening,
-            ))
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use {super::*, crate::encryption::elgamal::ElGamalKeypair};
-
-    #[test]
-    fn test_grouped_elgamal_encrypt_decrypt_correctness() {
-        let elgamal_keypair_0 = ElGamalKeypair::new_rand();
-        let elgamal_keypair_1 = ElGamalKeypair::new_rand();
-        let elgamal_keypair_2 = ElGamalKeypair::new_rand();
-
-        let amount: u64 = 10;
-        let grouped_ciphertext = GroupedElGamal::encrypt(
-            [
-                elgamal_keypair_0.pubkey(),
-                elgamal_keypair_1.pubkey(),
-                elgamal_keypair_2.pubkey(),
-            ],
-            amount,
-        );
-
-        assert_eq!(
-            Some(amount),
-            grouped_ciphertext
-                .decrypt_u32(elgamal_keypair_0.secret(), 0)
-                .unwrap()
-        );
-
-        assert_eq!(
-            Some(amount),
-            grouped_ciphertext
-                .decrypt_u32(elgamal_keypair_1.secret(), 1)
-                .unwrap()
-        );
-
-        assert_eq!(
-            Some(amount),
-            grouped_ciphertext
-                .decrypt_u32(elgamal_keypair_2.secret(), 2)
-                .unwrap()
-        );
-
-        assert_eq!(
-            GroupedElGamalError::IndexOutOfBounds,
-            grouped_ciphertext
-                .decrypt_u32(elgamal_keypair_0.secret(), 3)
-                .unwrap_err()
-        );
-    }
-
-    #[test]
-    fn test_grouped_ciphertext_bytes() {
-        let elgamal_keypair_0 = ElGamalKeypair::new_rand();
-        let elgamal_keypair_1 = ElGamalKeypair::new_rand();
-        let elgamal_keypair_2 = ElGamalKeypair::new_rand();
-
-        let amount: u64 = 10;
-        let grouped_ciphertext = GroupedElGamal::encrypt(
-            [
-                elgamal_keypair_0.pubkey(),
-                elgamal_keypair_1.pubkey(),
-                elgamal_keypair_2.pubkey(),
-            ],
-            amount,
-        );
-
-        let produced_bytes = grouped_ciphertext.to_bytes();
-        assert_eq!(produced_bytes.len(), 128);
-
-        let decoded_grouped_ciphertext =
-            GroupedElGamalCiphertext::<3>::from_bytes(&produced_bytes).unwrap();
-        assert_eq!(
-            Some(amount),
-            decoded_grouped_ciphertext
-                .decrypt_u32(elgamal_keypair_0.secret(), 0)
-                .unwrap()
-        );
-
-        assert_eq!(
-            Some(amount),
-            decoded_grouped_ciphertext
-                .decrypt_u32(elgamal_keypair_1.secret(), 1)
-                .unwrap()
-        );
-
-        assert_eq!(
-            Some(amount),
-            decoded_grouped_ciphertext
-                .decrypt_u32(elgamal_keypair_2.secret(), 2)
-                .unwrap()
-        );
-    }
-}

+ 0 - 74
zk-sdk/src/encryption/macros.rs

@@ -1,74 +0,0 @@
-macro_rules! define_add_variants {
-    (LHS = $lhs:ty, RHS = $rhs:ty, Output = $out:ty) => {
-        impl<'b> Add<&'b $rhs> for $lhs {
-            type Output = $out;
-            fn add(self, rhs: &'b $rhs) -> $out {
-                &self + rhs
-            }
-        }
-
-        impl<'a> Add<$rhs> for &'a $lhs {
-            type Output = $out;
-            fn add(self, rhs: $rhs) -> $out {
-                self + &rhs
-            }
-        }
-
-        impl Add<$rhs> for $lhs {
-            type Output = $out;
-            fn add(self, rhs: $rhs) -> $out {
-                &self + &rhs
-            }
-        }
-    };
-}
-
-macro_rules! define_sub_variants {
-    (LHS = $lhs:ty, RHS = $rhs:ty, Output = $out:ty) => {
-        impl<'b> Sub<&'b $rhs> for $lhs {
-            type Output = $out;
-            fn sub(self, rhs: &'b $rhs) -> $out {
-                &self - rhs
-            }
-        }
-
-        impl<'a> Sub<$rhs> for &'a $lhs {
-            type Output = $out;
-            fn sub(self, rhs: $rhs) -> $out {
-                self - &rhs
-            }
-        }
-
-        impl Sub<$rhs> for $lhs {
-            type Output = $out;
-            fn sub(self, rhs: $rhs) -> $out {
-                &self - &rhs
-            }
-        }
-    };
-}
-
-macro_rules! define_mul_variants {
-    (LHS = $lhs:ty, RHS = $rhs:ty, Output = $out:ty) => {
-        impl<'b> Mul<&'b $rhs> for $lhs {
-            type Output = $out;
-            fn mul(self, rhs: &'b $rhs) -> $out {
-                &self * rhs
-            }
-        }
-
-        impl<'a> Mul<$rhs> for &'a $lhs {
-            type Output = $out;
-            fn mul(self, rhs: $rhs) -> $out {
-                self * &rhs
-            }
-        }
-
-        impl Mul<$rhs> for $lhs {
-            type Output = $out;
-            fn mul(self, rhs: $rhs) -> $out {
-                &self * &rhs
-            }
-        }
-    };
-}

+ 0 - 56
zk-sdk/src/encryption/mod.rs

@@ -1,56 +0,0 @@
-//! Collection of encryption-related data structures and algorithms used in the Solana zk-token
-//! protocol.
-//!
-//! The module contains implementations of the following cryptographic objects:
-//! - Pedersen commitments that uses the prime-order Ristretto representation of Curve25519.
-//!   [curve25519-dalek](https://docs.rs/curve25519-dalek/latest/curve25519_dalek/ristretto/index.html)
-//!   is used for the Ristretto group implementation.
-//! - The twisted ElGamal scheme, which converts Pedersen commitments into a public-key encryption
-//!   scheme.
-//! - Basic type-wrapper around the AES-GCM-SIV symmetric authenticated encryption scheme
-//!   implemented by [aes-gcm-siv](https://docs.rs/aes-gcm-siv/latest/aes_gcm_siv/) crate.
-
-use crate::{RISTRETTO_POINT_LEN, SCALAR_LEN};
-
-#[cfg(not(target_os = "solana"))]
-#[macro_use]
-pub(crate) mod macros;
-#[cfg(not(target_os = "solana"))]
-pub mod auth_encryption;
-#[cfg(not(target_os = "solana"))]
-pub mod discrete_log;
-#[cfg(not(target_os = "solana"))]
-pub mod elgamal;
-#[cfg(not(target_os = "solana"))]
-pub mod grouped_elgamal;
-#[cfg(not(target_os = "solana"))]
-pub mod pedersen;
-pub mod pod;
-
-/// Byte length of an authenticated encryption secret key
-pub const AE_KEY_LEN: usize = 16;
-
-/// Byte length of a complete authenticated encryption ciphertext component that includes the
-/// ciphertext and nonce components
-pub const AE_CIPHERTEXT_LEN: usize = 36;
-
-/// Byte length of a decrypt handle
-pub const DECRYPT_HANDLE_LEN: usize = RISTRETTO_POINT_LEN;
-
-/// Byte length of an ElGamal ciphertext
-pub const ELGAMAL_CIPHERTEXT_LEN: usize = PEDERSEN_COMMITMENT_LEN + DECRYPT_HANDLE_LEN;
-
-/// Byte length of an ElGamal public key
-pub const ELGAMAL_PUBKEY_LEN: usize = RISTRETTO_POINT_LEN;
-
-/// Byte length of an ElGamal secret key
-pub const ELGAMAL_SECRET_KEY_LEN: usize = SCALAR_LEN;
-
-/// Byte length of an ElGamal keypair
-pub const ELGAMAL_KEYPAIR_LEN: usize = ELGAMAL_PUBKEY_LEN + ELGAMAL_SECRET_KEY_LEN;
-
-/// Byte length of a Pedersen opening.
-pub const PEDERSEN_OPENING_LEN: usize = SCALAR_LEN;
-
-/// Byte length of a Pedersen commitment.
-pub const PEDERSEN_COMMITMENT_LEN: usize = RISTRETTO_POINT_LEN;

+ 0 - 365
zk-sdk/src/encryption/pedersen.rs

@@ -1,365 +0,0 @@
-//! Pedersen commitment implementation using the Ristretto prime-order group.
-
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-use {
-    crate::encryption::{PEDERSEN_COMMITMENT_LEN, PEDERSEN_OPENING_LEN},
-    core::ops::{Add, Mul, Sub},
-    curve25519_dalek::{
-        constants::{RISTRETTO_BASEPOINT_COMPRESSED, RISTRETTO_BASEPOINT_POINT},
-        ristretto::{CompressedRistretto, RistrettoPoint},
-        scalar::Scalar,
-        traits::MultiscalarMul,
-    },
-    rand::rngs::OsRng,
-    serde::{Deserialize, Serialize},
-    sha3::Sha3_512,
-    std::convert::TryInto,
-    subtle::{Choice, ConstantTimeEq},
-    zeroize::Zeroize,
-};
-
-/// Pedersen base point for encoding messages to be committed.
-pub const G: RistrettoPoint = RISTRETTO_BASEPOINT_POINT;
-/// Pedersen base point for encoding the commitment openings.
-pub static H: std::sync::LazyLock<RistrettoPoint> = std::sync::LazyLock::new(|| {
-    RistrettoPoint::hash_from_bytes::<Sha3_512>(RISTRETTO_BASEPOINT_COMPRESSED.as_bytes())
-});
-
-/// Algorithm handle for the Pedersen commitment scheme.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-pub struct Pedersen;
-impl Pedersen {
-    /// On input a message (numeric amount), the function returns a Pedersen commitment of the
-    /// message and the corresponding opening.
-    ///
-    /// This function is randomized. It internally samples a Pedersen opening using `OsRng`.
-    #[allow(clippy::new_ret_no_self)]
-    pub fn new<T: Into<Scalar>>(amount: T) -> (PedersenCommitment, PedersenOpening) {
-        let opening = PedersenOpening::new_rand();
-        let commitment = Pedersen::with(amount, &opening);
-
-        (commitment, opening)
-    }
-
-    /// On input a message (numeric amount) and a Pedersen opening, the function returns the
-    /// corresponding Pedersen commitment.
-    ///
-    /// This function is deterministic.
-    pub fn with<T: Into<Scalar>>(amount: T, opening: &PedersenOpening) -> PedersenCommitment {
-        let x: Scalar = amount.into();
-        let r = opening.get_scalar();
-
-        PedersenCommitment(RistrettoPoint::multiscalar_mul(&[x, *r], &[G, *H]))
-    }
-
-    /// On input a message (numeric amount), the function returns a Pedersen commitment with zero
-    /// as the opening.
-    ///
-    /// This function is deterministic.
-    pub fn encode<T: Into<Scalar>>(amount: T) -> PedersenCommitment {
-        PedersenCommitment(amount.into() * &G)
-    }
-}
-
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-impl Pedersen {
-    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = withU64))]
-    pub fn with_u64(amount: u64, opening: &PedersenOpening) -> PedersenCommitment {
-        Pedersen::with(amount, opening)
-    }
-}
-
-/// Pedersen opening type.
-///
-/// Instances of Pedersen openings are zeroized on drop.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Debug, Default, Serialize, Deserialize, Zeroize)]
-#[zeroize(drop)]
-pub struct PedersenOpening(Scalar);
-
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-impl PedersenOpening {
-    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = newRand))]
-    pub fn new_rand() -> Self {
-        PedersenOpening(Scalar::random(&mut OsRng))
-    }
-}
-
-impl PedersenOpening {
-    pub fn new(scalar: Scalar) -> Self {
-        Self(scalar)
-    }
-
-    pub fn get_scalar(&self) -> &Scalar {
-        &self.0
-    }
-
-    pub fn as_bytes(&self) -> &[u8; PEDERSEN_OPENING_LEN] {
-        self.0.as_bytes()
-    }
-
-    pub fn to_bytes(&self) -> [u8; PEDERSEN_OPENING_LEN] {
-        self.0.to_bytes()
-    }
-
-    pub fn from_bytes(bytes: &[u8]) -> Option<PedersenOpening> {
-        match bytes.try_into() {
-            Ok(bytes) => Scalar::from_canonical_bytes(bytes)
-                .into_option()
-                .map(PedersenOpening),
-            _ => None,
-        }
-    }
-}
-impl Eq for PedersenOpening {}
-impl PartialEq for PedersenOpening {
-    fn eq(&self, other: &Self) -> bool {
-        self.ct_eq(other).unwrap_u8() == 1u8
-    }
-}
-impl ConstantTimeEq for PedersenOpening {
-    fn ct_eq(&self, other: &Self) -> Choice {
-        self.0.ct_eq(&other.0)
-    }
-}
-
-impl<'b> Add<&'b PedersenOpening> for &PedersenOpening {
-    type Output = PedersenOpening;
-
-    fn add(self, opening: &'b PedersenOpening) -> PedersenOpening {
-        PedersenOpening(&self.0 + &opening.0)
-    }
-}
-
-define_add_variants!(
-    LHS = PedersenOpening,
-    RHS = PedersenOpening,
-    Output = PedersenOpening
-);
-
-impl<'b> Sub<&'b PedersenOpening> for &PedersenOpening {
-    type Output = PedersenOpening;
-
-    fn sub(self, opening: &'b PedersenOpening) -> PedersenOpening {
-        PedersenOpening(&self.0 - &opening.0)
-    }
-}
-
-define_sub_variants!(
-    LHS = PedersenOpening,
-    RHS = PedersenOpening,
-    Output = PedersenOpening
-);
-
-impl<'b> Mul<&'b Scalar> for &PedersenOpening {
-    type Output = PedersenOpening;
-
-    fn mul(self, scalar: &'b Scalar) -> PedersenOpening {
-        PedersenOpening(&self.0 * scalar)
-    }
-}
-
-define_mul_variants!(
-    LHS = PedersenOpening,
-    RHS = Scalar,
-    Output = PedersenOpening
-);
-
-impl<'b> Mul<&'b PedersenOpening> for &Scalar {
-    type Output = PedersenOpening;
-
-    fn mul(self, opening: &'b PedersenOpening) -> PedersenOpening {
-        PedersenOpening(self * &opening.0)
-    }
-}
-
-define_mul_variants!(
-    LHS = Scalar,
-    RHS = PedersenOpening,
-    Output = PedersenOpening
-);
-
-/// Pedersen commitment type.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
-pub struct PedersenCommitment(RistrettoPoint);
-impl PedersenCommitment {
-    pub fn new(point: RistrettoPoint) -> Self {
-        Self(point)
-    }
-
-    pub fn get_point(&self) -> &RistrettoPoint {
-        &self.0
-    }
-
-    pub fn to_bytes(&self) -> [u8; PEDERSEN_COMMITMENT_LEN] {
-        self.0.compress().to_bytes()
-    }
-
-    pub fn from_bytes(bytes: &[u8]) -> Option<PedersenCommitment> {
-        if bytes.len() != PEDERSEN_COMMITMENT_LEN {
-            return None;
-        }
-
-        let Ok(compressed_ristretto) = CompressedRistretto::from_slice(bytes) else {
-            return None;
-        };
-
-        compressed_ristretto.decompress().map(PedersenCommitment)
-    }
-}
-
-impl<'b> Add<&'b PedersenCommitment> for &PedersenCommitment {
-    type Output = PedersenCommitment;
-
-    fn add(self, commitment: &'b PedersenCommitment) -> PedersenCommitment {
-        PedersenCommitment(&self.0 + &commitment.0)
-    }
-}
-
-define_add_variants!(
-    LHS = PedersenCommitment,
-    RHS = PedersenCommitment,
-    Output = PedersenCommitment
-);
-
-impl<'b> Sub<&'b PedersenCommitment> for &PedersenCommitment {
-    type Output = PedersenCommitment;
-
-    fn sub(self, commitment: &'b PedersenCommitment) -> PedersenCommitment {
-        PedersenCommitment(&self.0 - &commitment.0)
-    }
-}
-
-define_sub_variants!(
-    LHS = PedersenCommitment,
-    RHS = PedersenCommitment,
-    Output = PedersenCommitment
-);
-
-impl<'b> Mul<&'b Scalar> for &PedersenCommitment {
-    type Output = PedersenCommitment;
-
-    fn mul(self, scalar: &'b Scalar) -> PedersenCommitment {
-        PedersenCommitment(scalar * &self.0)
-    }
-}
-
-define_mul_variants!(
-    LHS = PedersenCommitment,
-    RHS = Scalar,
-    Output = PedersenCommitment
-);
-
-impl<'b> Mul<&'b PedersenCommitment> for &Scalar {
-    type Output = PedersenCommitment;
-
-    fn mul(self, commitment: &'b PedersenCommitment) -> PedersenCommitment {
-        PedersenCommitment(self * &commitment.0)
-    }
-}
-
-define_mul_variants!(
-    LHS = Scalar,
-    RHS = PedersenCommitment,
-    Output = PedersenCommitment
-);
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn test_pedersen_homomorphic_addition() {
-        let amount_0: u64 = 77;
-        let amount_1: u64 = 57;
-
-        let rng = &mut OsRng;
-        let opening_0 = PedersenOpening(Scalar::random(rng));
-        let opening_1 = PedersenOpening(Scalar::random(rng));
-
-        let commitment_0 = Pedersen::with(amount_0, &opening_0);
-        let commitment_1 = Pedersen::with(amount_1, &opening_1);
-        let commitment_addition = Pedersen::with(amount_0 + amount_1, &(opening_0 + opening_1));
-
-        assert_eq!(commitment_addition, commitment_0 + commitment_1);
-    }
-
-    #[test]
-    fn test_pedersen_homomorphic_subtraction() {
-        let amount_0: u64 = 77;
-        let amount_1: u64 = 57;
-
-        let rng = &mut OsRng;
-        let opening_0 = PedersenOpening(Scalar::random(rng));
-        let opening_1 = PedersenOpening(Scalar::random(rng));
-
-        let commitment_0 = Pedersen::with(amount_0, &opening_0);
-        let commitment_1 = Pedersen::with(amount_1, &opening_1);
-        let commitment_addition = Pedersen::with(amount_0 - amount_1, &(opening_0 - opening_1));
-
-        assert_eq!(commitment_addition, commitment_0 - commitment_1);
-    }
-
-    #[test]
-    fn test_pedersen_homomorphic_multiplication() {
-        let amount_0: u64 = 77;
-        let amount_1: u64 = 57;
-
-        let (commitment, opening) = Pedersen::new(amount_0);
-        let scalar = Scalar::from(amount_1);
-        let commitment_addition = Pedersen::with(amount_0 * amount_1, &(opening * scalar));
-
-        assert_eq!(commitment_addition, commitment * scalar);
-        assert_eq!(commitment_addition, scalar * commitment);
-    }
-
-    #[test]
-    fn test_pedersen_commitment_bytes() {
-        let amount: u64 = 77;
-        let (commitment, _) = Pedersen::new(amount);
-
-        let encoded = commitment.to_bytes();
-        let decoded = PedersenCommitment::from_bytes(&encoded).unwrap();
-
-        assert_eq!(commitment, decoded);
-
-        // incorrect length encoding
-        assert_eq!(PedersenCommitment::from_bytes(&[0; 33]), None);
-    }
-
-    #[test]
-    fn test_pedersen_opening_bytes() {
-        let opening = PedersenOpening(Scalar::random(&mut OsRng));
-
-        let encoded = opening.to_bytes();
-        let decoded = PedersenOpening::from_bytes(&encoded).unwrap();
-
-        assert_eq!(opening, decoded);
-
-        // incorrect length encoding
-        assert_eq!(PedersenOpening::from_bytes(&[0; 33]), None);
-    }
-
-    #[test]
-    fn test_serde_pedersen_commitment() {
-        let amount: u64 = 77;
-        let (commitment, _) = Pedersen::new(amount);
-
-        let encoded = bincode::serialize(&commitment).unwrap();
-        let decoded: PedersenCommitment = bincode::deserialize(&encoded).unwrap();
-
-        assert_eq!(commitment, decoded);
-    }
-
-    #[test]
-    fn test_serde_pedersen_opening() {
-        let opening = PedersenOpening(Scalar::random(&mut OsRng));
-
-        let encoded = bincode::serialize(&opening).unwrap();
-        let decoded: PedersenOpening = bincode::deserialize(&encoded).unwrap();
-
-        assert_eq!(opening, decoded);
-    }
-}

+ 0 - 90
zk-sdk/src/encryption/pod/auth_encryption.rs

@@ -1,90 +0,0 @@
-//! Plain Old Data types for the AES128-GCM-SIV authenticated encryption scheme.
-
-#[cfg(not(target_os = "solana"))]
-use crate::{encryption::auth_encryption::AeCiphertext, errors::AuthenticatedEncryptionError};
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-use {
-    crate::{
-        encryption::AE_CIPHERTEXT_LEN,
-        pod::{impl_from_bytes, impl_from_str, impl_wasm_bindings},
-    },
-    base64::{prelude::BASE64_STANDARD, Engine},
-    bytemuck::{Pod, Zeroable},
-    std::fmt,
-};
-
-/// Maximum length of a base64 encoded authenticated encryption ciphertext
-const AE_CIPHERTEXT_MAX_BASE64_LEN: usize = 48;
-
-/// The `AeCiphertext` type as a `Pod`.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, PartialEq, Eq)]
-#[repr(transparent)]
-pub struct PodAeCiphertext(pub(crate) [u8; AE_CIPHERTEXT_LEN]);
-
-impl_wasm_bindings!(POD_TYPE = PodAeCiphertext, DECODED_TYPE = AeCiphertext);
-
-// `PodAeCiphertext` is a wrapper type for a byte array, which is both `Pod` and `Zeroable`. However,
-// the marker traits `bytemuck::Pod` and `bytemuck::Zeroable` can only be derived for power-of-two
-// length byte arrays. Directly implement these traits for `PodAeCiphertext`.
-unsafe impl Zeroable for PodAeCiphertext {}
-unsafe impl Pod for PodAeCiphertext {}
-
-impl fmt::Debug for PodAeCiphertext {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{:?}", self.0)
-    }
-}
-
-impl fmt::Display for PodAeCiphertext {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodAeCiphertext,
-    BYTES_LEN = AE_CIPHERTEXT_LEN,
-    BASE64_LEN = AE_CIPHERTEXT_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(TYPE = PodAeCiphertext, BYTES_LEN = AE_CIPHERTEXT_LEN);
-
-impl Default for PodAeCiphertext {
-    fn default() -> Self {
-        Self::zeroed()
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl From<AeCiphertext> for PodAeCiphertext {
-    fn from(decoded_ciphertext: AeCiphertext) -> Self {
-        Self(decoded_ciphertext.to_bytes())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodAeCiphertext> for AeCiphertext {
-    type Error = AuthenticatedEncryptionError;
-
-    fn try_from(pod_ciphertext: PodAeCiphertext) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_ciphertext.0).ok_or(AuthenticatedEncryptionError::Deserialization)
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use {super::*, crate::encryption::auth_encryption::AeKey, std::str::FromStr};
-
-    #[test]
-    fn ae_ciphertext_fromstr() {
-        let ae_key = AeKey::new_rand();
-        let expected_ae_ciphertext: PodAeCiphertext = ae_key.encrypt(0_u64).into();
-
-        let ae_ciphertext_base64_str = format!("{expected_ae_ciphertext}");
-        let computed_ae_ciphertext = PodAeCiphertext::from_str(&ae_ciphertext_base64_str).unwrap();
-
-        assert_eq!(expected_ae_ciphertext, computed_ae_ciphertext);
-    }
-}

+ 0 - 210
zk-sdk/src/encryption/pod/elgamal.rs

@@ -1,210 +0,0 @@
-//! Plain Old Data types for the ElGamal encryption scheme.
-
-#[cfg(not(target_arch = "wasm32"))]
-use bytemuck::Zeroable;
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::elgamal::{DecryptHandle, ElGamalCiphertext, ElGamalPubkey},
-        errors::ElGamalError,
-    },
-    curve25519_dalek::ristretto::CompressedRistretto,
-};
-use {
-    crate::{
-        encryption::{DECRYPT_HANDLE_LEN, ELGAMAL_CIPHERTEXT_LEN, ELGAMAL_PUBKEY_LEN},
-        pod::{impl_from_bytes, impl_from_str, impl_wasm_bindings},
-    },
-    base64::{prelude::BASE64_STANDARD, Engine},
-    std::fmt,
-};
-
-/// Maximum length of a base64 encoded ElGamal public key
-const ELGAMAL_PUBKEY_MAX_BASE64_LEN: usize = 44;
-
-/// Maximum length of a base64 encoded ElGamal ciphertext
-const ELGAMAL_CIPHERTEXT_MAX_BASE64_LEN: usize = 88;
-
-/// Maximum length of a base64 encoded ElGamal decrypt handle
-const DECRYPT_HANDLE_MAX_BASE64_LEN: usize = 44;
-
-/// The `ElGamalCiphertext` type as a `Pod`.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, bytemuck_derive::Pod, bytemuck_derive::Zeroable, PartialEq, Eq)]
-#[repr(transparent)]
-pub struct PodElGamalCiphertext(pub(crate) [u8; ELGAMAL_CIPHERTEXT_LEN]);
-
-impl_wasm_bindings!(
-    POD_TYPE = PodElGamalCiphertext,
-    DECODED_TYPE = ElGamalCiphertext
-);
-
-impl fmt::Debug for PodElGamalCiphertext {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{:?}", self.0)
-    }
-}
-
-impl fmt::Display for PodElGamalCiphertext {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl Default for PodElGamalCiphertext {
-    fn default() -> Self {
-        Self::zeroed()
-    }
-}
-
-impl_from_str!(
-    TYPE = PodElGamalCiphertext,
-    BYTES_LEN = ELGAMAL_CIPHERTEXT_LEN,
-    BASE64_LEN = ELGAMAL_CIPHERTEXT_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(
-    TYPE = PodElGamalCiphertext,
-    BYTES_LEN = ELGAMAL_CIPHERTEXT_LEN
-);
-
-#[cfg(not(target_os = "solana"))]
-impl From<ElGamalCiphertext> for PodElGamalCiphertext {
-    fn from(decoded_ciphertext: ElGamalCiphertext) -> Self {
-        Self(decoded_ciphertext.to_bytes())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodElGamalCiphertext> for ElGamalCiphertext {
-    type Error = ElGamalError;
-
-    fn try_from(pod_ciphertext: PodElGamalCiphertext) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_ciphertext.0).ok_or(ElGamalError::CiphertextDeserialization)
-    }
-}
-
-/// The `ElGamalPubkey` type as a `Pod`.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Default, bytemuck_derive::Pod, bytemuck_derive::Zeroable, PartialEq, Eq)]
-#[repr(transparent)]
-pub struct PodElGamalPubkey(pub(crate) [u8; ELGAMAL_PUBKEY_LEN]);
-
-impl_wasm_bindings!(POD_TYPE = PodElGamalPubkey, DECODED_TYPE = ElGamalPubkey);
-
-impl fmt::Debug for PodElGamalPubkey {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{:?}", self.0)
-    }
-}
-
-impl fmt::Display for PodElGamalPubkey {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodElGamalPubkey,
-    BYTES_LEN = ELGAMAL_PUBKEY_LEN,
-    BASE64_LEN = ELGAMAL_PUBKEY_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(TYPE = PodElGamalPubkey, BYTES_LEN = ELGAMAL_PUBKEY_LEN);
-
-#[cfg(not(target_os = "solana"))]
-impl From<ElGamalPubkey> for PodElGamalPubkey {
-    fn from(decoded_pubkey: ElGamalPubkey) -> Self {
-        Self(decoded_pubkey.into())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodElGamalPubkey> for ElGamalPubkey {
-    type Error = ElGamalError;
-
-    fn try_from(pod_pubkey: PodElGamalPubkey) -> Result<Self, Self::Error> {
-        Self::try_from(pod_pubkey.0.as_slice())
-    }
-}
-
-/// The `DecryptHandle` type as a `Pod`.
-#[derive(Clone, Copy, Default, bytemuck_derive::Pod, bytemuck_derive::Zeroable, PartialEq, Eq)]
-#[repr(transparent)]
-pub struct PodDecryptHandle(pub(crate) [u8; DECRYPT_HANDLE_LEN]);
-
-impl fmt::Debug for PodDecryptHandle {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{:?}", self.0)
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl From<DecryptHandle> for PodDecryptHandle {
-    fn from(decoded_handle: DecryptHandle) -> Self {
-        Self(decoded_handle.to_bytes())
-    }
-}
-
-// For proof verification, interpret pod::DecryptHandle as CompressedRistretto
-#[cfg(not(target_os = "solana"))]
-impl From<PodDecryptHandle> for CompressedRistretto {
-    fn from(pod_handle: PodDecryptHandle) -> Self {
-        Self(pod_handle.0)
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodDecryptHandle> for DecryptHandle {
-    type Error = ElGamalError;
-
-    fn try_from(pod_handle: PodDecryptHandle) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_handle.0).ok_or(ElGamalError::CiphertextDeserialization)
-    }
-}
-
-impl fmt::Display for PodDecryptHandle {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodDecryptHandle,
-    BYTES_LEN = DECRYPT_HANDLE_LEN,
-    BASE64_LEN = DECRYPT_HANDLE_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(TYPE = PodDecryptHandle, BYTES_LEN = DECRYPT_HANDLE_LEN);
-
-#[cfg(test)]
-mod tests {
-    use {super::*, crate::encryption::elgamal::ElGamalKeypair, std::str::FromStr};
-
-    #[test]
-    fn elgamal_pubkey_fromstr() {
-        let elgamal_keypair = ElGamalKeypair::new_rand();
-        let expected_elgamal_pubkey: PodElGamalPubkey = (*elgamal_keypair.pubkey()).into();
-
-        let elgamal_pubkey_base64_str = format!("{expected_elgamal_pubkey}");
-        let computed_elgamal_pubkey =
-            PodElGamalPubkey::from_str(&elgamal_pubkey_base64_str).unwrap();
-
-        assert_eq!(expected_elgamal_pubkey, computed_elgamal_pubkey);
-    }
-
-    #[test]
-    fn elgamal_ciphertext_fromstr() {
-        let elgamal_keypair = ElGamalKeypair::new_rand();
-        let expected_elgamal_ciphertext: PodElGamalCiphertext =
-            elgamal_keypair.pubkey().encrypt(0_u64).into();
-
-        let elgamal_ciphertext_base64_str = format!("{expected_elgamal_ciphertext}");
-        let computed_elgamal_ciphertext =
-            PodElGamalCiphertext::from_str(&elgamal_ciphertext_base64_str).unwrap();
-
-        assert_eq!(expected_elgamal_ciphertext, computed_elgamal_ciphertext);
-    }
-}

+ 0 - 272
zk-sdk/src/encryption/pod/grouped_elgamal.rs

@@ -1,272 +0,0 @@
-//! Plain Old Data types for the Grouped ElGamal encryption scheme.
-
-#[cfg(not(target_os = "solana"))]
-use crate::encryption::grouped_elgamal::GroupedElGamalCiphertext;
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-use {
-    crate::{
-        encryption::{
-            pod::{elgamal::PodElGamalCiphertext, pedersen::PodPedersenCommitment},
-            DECRYPT_HANDLE_LEN, ELGAMAL_CIPHERTEXT_LEN, PEDERSEN_COMMITMENT_LEN,
-        },
-        errors::ElGamalError,
-        pod::{impl_from_bytes, impl_from_str},
-    },
-    base64::{prelude::BASE64_STANDARD, Engine},
-    bytemuck::Zeroable,
-    std::fmt,
-};
-
-/// Maximum length of a base64 encoded grouped ElGamal ciphertext with 2 handles
-const GROUPED_ELGAMAL_CIPHERTEXT_2_HANDLES_MAX_BASE64_LEN: usize = 132;
-
-/// Maximum length of a base64 encoded grouped ElGamal ciphertext with 3 handles
-const GROUPED_ELGAMAL_CIPHERTEXT_3_HANDLES_MAX_BASE64_LEN: usize = 176;
-
-macro_rules! impl_extract {
-    (TYPE = $type:ident) => {
-        impl $type {
-            /// Extract the commitment component from a grouped ciphertext
-            pub fn extract_commitment(&self) -> PodPedersenCommitment {
-                // `GROUPED_ELGAMAL_CIPHERTEXT_2_HANDLES` guaranteed to be at least `PEDERSEN_COMMITMENT_LEN`
-                let commitment = self.0[..PEDERSEN_COMMITMENT_LEN].try_into().unwrap();
-                PodPedersenCommitment(commitment)
-            }
-
-            /// Extract a regular ElGamal ciphertext using the decrypt handle at a specified index.
-            pub fn try_extract_ciphertext(
-                &self,
-                index: usize,
-            ) -> Result<PodElGamalCiphertext, ElGamalError> {
-                let mut ciphertext_bytes = [0u8; ELGAMAL_CIPHERTEXT_LEN];
-                ciphertext_bytes[..PEDERSEN_COMMITMENT_LEN]
-                    .copy_from_slice(&self.0[..PEDERSEN_COMMITMENT_LEN]);
-
-                let handle_start = DECRYPT_HANDLE_LEN
-                    .checked_mul(index)
-                    .and_then(|n| n.checked_add(PEDERSEN_COMMITMENT_LEN))
-                    .ok_or(ElGamalError::CiphertextDeserialization)?;
-                let handle_end = handle_start
-                    .checked_add(DECRYPT_HANDLE_LEN)
-                    .ok_or(ElGamalError::CiphertextDeserialization)?;
-                ciphertext_bytes[PEDERSEN_COMMITMENT_LEN..].copy_from_slice(
-                    self.0
-                        .get(handle_start..handle_end)
-                        .ok_or(ElGamalError::CiphertextDeserialization)?,
-                );
-
-                Ok(PodElGamalCiphertext(ciphertext_bytes))
-            }
-        }
-    };
-}
-
-/// Byte length of a grouped ElGamal ciphertext with 2 handles
-const GROUPED_ELGAMAL_CIPHERTEXT_2_HANDLES: usize =
-    PEDERSEN_COMMITMENT_LEN + DECRYPT_HANDLE_LEN + DECRYPT_HANDLE_LEN;
-
-/// Byte length of a grouped ElGamal ciphertext with 3 handles
-const GROUPED_ELGAMAL_CIPHERTEXT_3_HANDLES: usize =
-    PEDERSEN_COMMITMENT_LEN + DECRYPT_HANDLE_LEN + DECRYPT_HANDLE_LEN + DECRYPT_HANDLE_LEN;
-
-/// The `GroupedElGamalCiphertext` type with two decryption handles as a `Pod`
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, bytemuck_derive::Pod, bytemuck_derive::Zeroable, PartialEq, Eq)]
-#[repr(transparent)]
-pub struct PodGroupedElGamalCiphertext2Handles(
-    pub(crate) [u8; GROUPED_ELGAMAL_CIPHERTEXT_2_HANDLES],
-);
-
-impl fmt::Debug for PodGroupedElGamalCiphertext2Handles {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{:?}", self.0)
-    }
-}
-
-impl Default for PodGroupedElGamalCiphertext2Handles {
-    fn default() -> Self {
-        Self::zeroed()
-    }
-}
-
-impl fmt::Display for PodGroupedElGamalCiphertext2Handles {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodGroupedElGamalCiphertext2Handles,
-    BYTES_LEN = GROUPED_ELGAMAL_CIPHERTEXT_2_HANDLES,
-    BASE64_LEN = GROUPED_ELGAMAL_CIPHERTEXT_2_HANDLES_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(
-    TYPE = PodGroupedElGamalCiphertext2Handles,
-    BYTES_LEN = GROUPED_ELGAMAL_CIPHERTEXT_2_HANDLES
-);
-
-#[cfg(not(target_os = "solana"))]
-impl From<GroupedElGamalCiphertext<2>> for PodGroupedElGamalCiphertext2Handles {
-    fn from(decoded_ciphertext: GroupedElGamalCiphertext<2>) -> Self {
-        Self(decoded_ciphertext.to_bytes().try_into().unwrap())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodGroupedElGamalCiphertext2Handles> for GroupedElGamalCiphertext<2> {
-    type Error = ElGamalError;
-
-    fn try_from(pod_ciphertext: PodGroupedElGamalCiphertext2Handles) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_ciphertext.0).ok_or(ElGamalError::CiphertextDeserialization)
-    }
-}
-
-impl_extract!(TYPE = PodGroupedElGamalCiphertext2Handles);
-
-/// The `GroupedElGamalCiphertext` type with three decryption handles as a `Pod`
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, bytemuck_derive::Pod, bytemuck_derive::Zeroable, PartialEq, Eq)]
-#[repr(transparent)]
-pub struct PodGroupedElGamalCiphertext3Handles(
-    pub(crate) [u8; GROUPED_ELGAMAL_CIPHERTEXT_3_HANDLES],
-);
-
-impl fmt::Debug for PodGroupedElGamalCiphertext3Handles {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{:?}", self.0)
-    }
-}
-
-impl Default for PodGroupedElGamalCiphertext3Handles {
-    fn default() -> Self {
-        Self::zeroed()
-    }
-}
-
-impl fmt::Display for PodGroupedElGamalCiphertext3Handles {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodGroupedElGamalCiphertext3Handles,
-    BYTES_LEN = GROUPED_ELGAMAL_CIPHERTEXT_3_HANDLES,
-    BASE64_LEN = GROUPED_ELGAMAL_CIPHERTEXT_3_HANDLES_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(
-    TYPE = PodGroupedElGamalCiphertext3Handles,
-    BYTES_LEN = GROUPED_ELGAMAL_CIPHERTEXT_3_HANDLES
-);
-
-#[cfg(not(target_os = "solana"))]
-impl From<GroupedElGamalCiphertext<3>> for PodGroupedElGamalCiphertext3Handles {
-    fn from(decoded_ciphertext: GroupedElGamalCiphertext<3>) -> Self {
-        Self(decoded_ciphertext.to_bytes().try_into().unwrap())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodGroupedElGamalCiphertext3Handles> for GroupedElGamalCiphertext<3> {
-    type Error = ElGamalError;
-
-    fn try_from(pod_ciphertext: PodGroupedElGamalCiphertext3Handles) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_ciphertext.0).ok_or(ElGamalError::CiphertextDeserialization)
-    }
-}
-
-impl_extract!(TYPE = PodGroupedElGamalCiphertext3Handles);
-
-#[cfg(test)]
-mod tests {
-    use {
-        super::*,
-        crate::encryption::{
-            elgamal::ElGamalKeypair, grouped_elgamal::GroupedElGamal, pedersen::Pedersen,
-            pod::pedersen::PodPedersenCommitment,
-        },
-    };
-
-    #[test]
-    fn test_2_handles_ciphertext_extraction() {
-        let elgamal_keypair_0 = ElGamalKeypair::new_rand();
-        let elgamal_keypair_1 = ElGamalKeypair::new_rand();
-
-        let amount: u64 = 10;
-        let (commitment, opening) = Pedersen::new(amount);
-
-        let grouped_ciphertext = GroupedElGamal::encrypt_with(
-            [elgamal_keypair_0.pubkey(), elgamal_keypair_1.pubkey()],
-            amount,
-            &opening,
-        );
-        let pod_grouped_ciphertext: PodGroupedElGamalCiphertext2Handles = grouped_ciphertext.into();
-
-        let expected_pod_commitment: PodPedersenCommitment = commitment.into();
-        let actual_pod_commitment = pod_grouped_ciphertext.extract_commitment();
-        assert_eq!(expected_pod_commitment, actual_pod_commitment);
-
-        let expected_ciphertext_0 = elgamal_keypair_0.pubkey().encrypt_with(amount, &opening);
-        let expected_pod_ciphertext_0: PodElGamalCiphertext = expected_ciphertext_0.into();
-        let actual_pod_ciphertext_0 = pod_grouped_ciphertext.try_extract_ciphertext(0).unwrap();
-        assert_eq!(expected_pod_ciphertext_0, actual_pod_ciphertext_0);
-
-        let expected_ciphertext_1 = elgamal_keypair_1.pubkey().encrypt_with(amount, &opening);
-        let expected_pod_ciphertext_1: PodElGamalCiphertext = expected_ciphertext_1.into();
-        let actual_pod_ciphertext_1 = pod_grouped_ciphertext.try_extract_ciphertext(1).unwrap();
-        assert_eq!(expected_pod_ciphertext_1, actual_pod_ciphertext_1);
-
-        let err = pod_grouped_ciphertext
-            .try_extract_ciphertext(2)
-            .unwrap_err();
-        assert_eq!(err, ElGamalError::CiphertextDeserialization);
-    }
-
-    #[test]
-    fn test_3_handles_ciphertext_extraction() {
-        let elgamal_keypair_0 = ElGamalKeypair::new_rand();
-        let elgamal_keypair_1 = ElGamalKeypair::new_rand();
-        let elgamal_keypair_2 = ElGamalKeypair::new_rand();
-
-        let amount: u64 = 10;
-        let (commitment, opening) = Pedersen::new(amount);
-
-        let grouped_ciphertext = GroupedElGamal::encrypt_with(
-            [
-                elgamal_keypair_0.pubkey(),
-                elgamal_keypair_1.pubkey(),
-                elgamal_keypair_2.pubkey(),
-            ],
-            amount,
-            &opening,
-        );
-        let pod_grouped_ciphertext: PodGroupedElGamalCiphertext3Handles = grouped_ciphertext.into();
-
-        let expected_pod_commitment: PodPedersenCommitment = commitment.into();
-        let actual_pod_commitment = pod_grouped_ciphertext.extract_commitment();
-        assert_eq!(expected_pod_commitment, actual_pod_commitment);
-
-        let expected_ciphertext_0 = elgamal_keypair_0.pubkey().encrypt_with(amount, &opening);
-        let expected_pod_ciphertext_0: PodElGamalCiphertext = expected_ciphertext_0.into();
-        let actual_pod_ciphertext_0 = pod_grouped_ciphertext.try_extract_ciphertext(0).unwrap();
-        assert_eq!(expected_pod_ciphertext_0, actual_pod_ciphertext_0);
-
-        let expected_ciphertext_1 = elgamal_keypair_1.pubkey().encrypt_with(amount, &opening);
-        let expected_pod_ciphertext_1: PodElGamalCiphertext = expected_ciphertext_1.into();
-        let actual_pod_ciphertext_1 = pod_grouped_ciphertext.try_extract_ciphertext(1).unwrap();
-        assert_eq!(expected_pod_ciphertext_1, actual_pod_ciphertext_1);
-
-        let expected_ciphertext_2 = elgamal_keypair_2.pubkey().encrypt_with(amount, &opening);
-        let expected_pod_ciphertext_2: PodElGamalCiphertext = expected_ciphertext_2.into();
-        let actual_pod_ciphertext_2 = pod_grouped_ciphertext.try_extract_ciphertext(2).unwrap();
-        assert_eq!(expected_pod_ciphertext_2, actual_pod_ciphertext_2);
-
-        let err = pod_grouped_ciphertext
-            .try_extract_ciphertext(3)
-            .unwrap_err();
-        assert_eq!(err, ElGamalError::CiphertextDeserialization);
-    }
-}

+ 0 - 4
zk-sdk/src/encryption/pod/mod.rs

@@ -1,4 +0,0 @@
-pub mod auth_encryption;
-pub mod elgamal;
-pub mod grouped_elgamal;
-pub mod pedersen;

+ 0 - 74
zk-sdk/src/encryption/pod/pedersen.rs

@@ -1,74 +0,0 @@
-//! Plain Old Data type for the Pedersen commitment scheme.
-
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{encryption::pedersen::PedersenCommitment, errors::ElGamalError},
-    curve25519_dalek::ristretto::CompressedRistretto,
-};
-use {
-    crate::{
-        encryption::PEDERSEN_COMMITMENT_LEN,
-        pod::{impl_from_bytes, impl_from_str},
-    },
-    base64::{prelude::BASE64_STANDARD, Engine},
-    bytemuck_derive::{Pod, Zeroable},
-    std::fmt,
-};
-
-/// Maximum length of a base64 encoded ElGamal public key
-const PEDERSEN_COMMITMENT_MAX_BASE64_LEN: usize = 44;
-
-/// The `PedersenCommitment` type as a `Pod`.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Default, Pod, Zeroable, PartialEq, Eq)]
-#[repr(transparent)]
-pub struct PodPedersenCommitment(pub(crate) [u8; PEDERSEN_COMMITMENT_LEN]);
-
-impl fmt::Debug for PodPedersenCommitment {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{:?}", self.0)
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl From<PedersenCommitment> for PodPedersenCommitment {
-    fn from(decoded_commitment: PedersenCommitment) -> Self {
-        Self(decoded_commitment.to_bytes())
-    }
-}
-
-impl fmt::Display for PodPedersenCommitment {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodPedersenCommitment,
-    BYTES_LEN = PEDERSEN_COMMITMENT_LEN,
-    BASE64_LEN = PEDERSEN_COMMITMENT_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(
-    TYPE = PodPedersenCommitment,
-    BYTES_LEN = PEDERSEN_COMMITMENT_LEN
-);
-
-// For proof verification, interpret pod::PedersenCommitment directly as CompressedRistretto
-#[cfg(not(target_os = "solana"))]
-impl From<PodPedersenCommitment> for CompressedRistretto {
-    fn from(pod_commitment: PodPedersenCommitment) -> Self {
-        Self(pod_commitment.0)
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodPedersenCommitment> for PedersenCommitment {
-    type Error = ElGamalError;
-
-    fn try_from(pod_commitment: PodPedersenCommitment) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_commitment.0).ok_or(ElGamalError::CiphertextDeserialization)
-    }
-}

+ 0 - 46
zk-sdk/src/errors.rs

@@ -1,46 +0,0 @@
-//! Errors related to proving and verifying proofs.
-use thiserror::Error;
-
-#[derive(Error, Clone, Debug, Eq, PartialEq)]
-pub enum AuthenticatedEncryptionError {
-    #[error("key derivation method not supported")]
-    DerivationMethodNotSupported,
-    #[error("seed length too short for derivation")]
-    SeedLengthTooShort,
-    #[error("seed length too long for derivation")]
-    SeedLengthTooLong,
-    #[error("failed to deserialize")]
-    Deserialization,
-}
-
-#[derive(Error, Clone, Debug, Eq, PartialEq)]
-pub enum ElGamalError {
-    #[error("key derivation method not supported")]
-    DerivationMethodNotSupported,
-    #[error("seed length too short for derivation")]
-    SeedLengthTooShort,
-    #[error("seed length too long for derivation")]
-    SeedLengthTooLong,
-    #[error("failed to deserialize ciphertext")]
-    CiphertextDeserialization,
-    #[error("failed to deserialize public key")]
-    PubkeyDeserialization,
-    #[error("failed to deserialize keypair")]
-    KeypairDeserialization,
-    #[error("failed to deserialize secret key")]
-    SecretKeyDeserialization,
-}
-
-#[derive(Error, Clone, Debug, Eq, PartialEq)]
-pub enum TranscriptError {
-    #[error("point is the identity")]
-    ValidationError,
-}
-
-#[derive(Error, Debug, Clone, Eq, PartialEq)]
-pub enum ParseError {
-    #[error("String is the wrong size")]
-    WrongSize,
-    #[error("Invalid Base64 string")]
-    Invalid,
-}

+ 0 - 36
zk-sdk/src/lib.rs

@@ -1,36 +0,0 @@
-//! The `solana-zk-sdk` crate contains tools to create and verify zero-knowledge proofs on
-//! encrypted data.
-
-// The warning `clippy::op_ref` is disabled to allow efficient operator arithmetic of structs that
-// implement the `Copy` trait.
-//
-// ```
-// let opening_0: PedersenOpening = PedersenOpening::new_rand();
-// let opening_1: PedersenOpening = PedersenOpening::new_rand();
-//
-// // since PedersenOpening implement `Copy`, `opening_0` and `opening_1` will be copied as
-// // parameters before `opening_sum` is computed.
-// let opening_sum = opening_0 + opening_1;
-//
-// // if passed in as references, the extra copies will not occur
-// let opening_sum = &opening_0 + &opening_1;
-// ```
-//
-// `clippy::op_ref` is turned off to prevent clippy from warning that this is not idiomatic code.
-#![allow(clippy::arithmetic_side_effects, clippy::op_ref)]
-
-pub mod encryption;
-pub mod errors;
-pub mod pod;
-mod range_proof;
-mod sigma_proofs;
-#[cfg(not(target_os = "solana"))]
-mod transcript;
-pub mod zk_elgamal_proof_program;
-
-/// Byte length of a compressed Ristretto point or scalar in Curve255519
-const UNIT_LEN: usize = 32;
-/// Byte length of a compressed Ristretto point in Curve25519
-const RISTRETTO_POINT_LEN: usize = UNIT_LEN;
-/// Byte length of a scalar in Curve25519
-const SCALAR_LEN: usize = UNIT_LEN;

+ 0 - 143
zk-sdk/src/pod.rs

@@ -1,143 +0,0 @@
-use bytemuck_derive::{Pod, Zeroable};
-
-#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, 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)
-    }
-}
-
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)]
-#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, 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)
-    }
-}
-
-macro_rules! impl_from_str {
-    (TYPE = $type:ident, BYTES_LEN = $bytes_len:expr, BASE64_LEN = $base64_len:expr) => {
-        impl std::str::FromStr for $type {
-            type Err = crate::errors::ParseError;
-
-            fn from_str(s: &str) -> Result<Self, Self::Err> {
-                if s.len() > $base64_len {
-                    return Err(Self::Err::WrongSize);
-                }
-                let mut bytes = [0u8; $bytes_len];
-                let decoded_len = BASE64_STANDARD
-                    .decode_slice(s, &mut bytes)
-                    .map_err(|_| Self::Err::Invalid)?;
-                if decoded_len != $bytes_len {
-                    Err(Self::Err::WrongSize)
-                } else {
-                    Ok($type(bytes))
-                }
-            }
-        }
-    };
-}
-pub(crate) use impl_from_str;
-
-macro_rules! impl_from_bytes {
-    (TYPE = $type:ident, BYTES_LEN = $bytes_len:expr) => {
-        impl std::convert::From<[u8; $bytes_len]> for $type {
-            fn from(bytes: [u8; $bytes_len]) -> Self {
-                Self(bytes)
-            }
-        }
-    };
-}
-pub(crate) use impl_from_bytes;
-
-macro_rules! impl_wasm_bindings {
-    (POD_TYPE = $pod_type:ident, DECODED_TYPE = $decoded_type: ident) => {
-        #[cfg(target_arch = "wasm32")]
-        #[allow(non_snake_case)]
-        #[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)]
-        impl $pod_type {
-            #[wasm_bindgen::prelude::wasm_bindgen(constructor)]
-            pub fn constructor(
-                value: wasm_bindgen::JsValue,
-            ) -> Result<$pod_type, wasm_bindgen::JsValue> {
-                if let Some(base64_str) = value.as_string() {
-                    base64_str
-                        .parse::<$pod_type>()
-                        .map_err(|e| e.to_string().into())
-                } else if let Some(uint8_array) = value.dyn_ref::<js_sys::Uint8Array>() {
-                    bytemuck::try_from_bytes(&uint8_array.to_vec())
-                        .map_err(|err| {
-                            wasm_bindgen::JsValue::from(format!("Invalid Uint8Array: {err:?}"))
-                        })
-                        .map(|value| *value)
-                } else if let Some(array) = value.dyn_ref::<js_sys::Array>() {
-                    let mut bytes = vec![];
-                    let iterator =
-                        js_sys::try_iter(&array.values())?.expect("array to be iterable");
-                    for x in iterator {
-                        let x = x?;
-
-                        if let Some(n) = x.as_f64() {
-                            if (0. ..=255.).contains(&n) {
-                                bytes.push(n as u8);
-                                continue;
-                            }
-                        }
-                        return Err(format!("Invalid array argument: {:?}", x).into());
-                    }
-
-                    bytemuck::try_from_bytes(&bytes)
-                        .map_err(|err| {
-                            wasm_bindgen::JsValue::from(format!("Invalid Array: {err:?}"))
-                        })
-                        .map(|value| *value)
-                } else if value.is_undefined() {
-                    Ok($pod_type::default())
-                } else {
-                    Err("Unsupported argument".into())
-                }
-            }
-
-            pub fn toString(&self) -> String {
-                self.to_string()
-            }
-
-            pub fn equals(&self, other: &$pod_type) -> bool {
-                self == other
-            }
-
-            pub fn toBytes(&self) -> Box<[u8]> {
-                self.0.into()
-            }
-
-            pub fn zeroed() -> Self {
-                Self::default()
-            }
-
-            pub fn encode(decoded: &$decoded_type) -> $pod_type {
-                (*decoded).into()
-            }
-
-            pub fn decode(&self) -> Result<$decoded_type, wasm_bindgen::JsValue> {
-                (*self)
-                    .try_into()
-                    .map_err(|err| JsValue::from(format!("Invalid encoding: {err:?}")))
-            }
-        }
-    };
-}
-pub(crate) use impl_wasm_bindings;

+ 0 - 46
zk-sdk/src/range_proof/errors.rs

@@ -1,46 +0,0 @@
-//! Errors related to proving and verifying range proofs.
-use {crate::errors::TranscriptError, thiserror::Error};
-
-#[cfg(not(target_os = "solana"))]
-#[derive(Error, Clone, Debug, Eq, PartialEq)]
-pub enum RangeProofGenerationError {
-    #[error("maximum generator length exceeded")]
-    MaximumGeneratorLengthExceeded,
-    #[error("amounts, commitments, openings, or bit lengths vectors have different lengths")]
-    VectorLengthMismatch,
-    #[error("invalid bit size")]
-    InvalidBitSize,
-    #[error("insufficient generators for the proof")]
-    GeneratorLengthMismatch,
-    #[error("inner product length mismatch")]
-    InnerProductLengthMismatch,
-}
-
-#[derive(Error, Clone, Debug, Eq, PartialEq)]
-pub enum RangeProofVerificationError {
-    #[error("required algebraic relation does not hold")]
-    AlgebraicRelation,
-    #[error("malformed proof")]
-    Deserialization,
-    #[error("multiscalar multiplication failed")]
-    MultiscalarMul,
-    #[error("transcript failed to produce a challenge")]
-    Transcript(#[from] TranscriptError),
-    #[error(
-        "attempted to verify range proof with a non-power-of-two bit size or bit size is too big"
-    )]
-    InvalidBitSize,
-    #[error("insufficient generators for the proof")]
-    InvalidGeneratorsLength,
-    #[error("maximum generator length exceeded")]
-    MaximumGeneratorLengthExceeded,
-    #[error("commitments and bit lengths vectors have different lengths")]
-    VectorLengthMismatch,
-}
-
-#[cfg(not(target_os = "solana"))]
-#[derive(Error, Clone, Debug, Eq, PartialEq)]
-pub enum RangeProofGeneratorError {
-    #[error("maximum generator length exceeded")]
-    MaximumGeneratorLengthExceeded,
-}

+ 0 - 155
zk-sdk/src/range_proof/generators.rs

@@ -1,155 +0,0 @@
-use {
-    crate::range_proof::errors::RangeProofGeneratorError,
-    curve25519_dalek::{
-        digest::{ExtendableOutput, Update, XofReader},
-        ristretto::RistrettoPoint,
-    },
-    sha3::{Shake256, Shake256Reader},
-};
-
-const MAX_GENERATOR_LENGTH: usize = u32::MAX as usize;
-
-/// Generators for Pedersen vector commitments that are used for inner-product proofs.
-struct GeneratorsChain {
-    reader: Shake256Reader,
-}
-
-impl GeneratorsChain {
-    /// Creates a chain of generators, determined by the hash of `label`.
-    fn new(label: &[u8]) -> Self {
-        let mut shake = Shake256::default();
-        shake.update(b"GeneratorsChain");
-        shake.update(label);
-
-        GeneratorsChain {
-            reader: shake.finalize_xof(),
-        }
-    }
-
-    /// Advances the reader n times, squeezing and discarding
-    /// the result.
-    fn fast_forward(mut self, n: usize) -> Self {
-        for _ in 0..n {
-            let mut buf = [0u8; 64];
-            self.reader.read(&mut buf);
-        }
-        self
-    }
-}
-
-impl Default for GeneratorsChain {
-    fn default() -> Self {
-        Self::new(&[])
-    }
-}
-
-impl Iterator for GeneratorsChain {
-    type Item = RistrettoPoint;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        let mut uniform_bytes = [0u8; 64];
-        self.reader.read(&mut uniform_bytes);
-
-        Some(RistrettoPoint::from_uniform_bytes(&uniform_bytes))
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        (usize::MAX, None)
-    }
-}
-
-#[allow(non_snake_case)]
-#[derive(Clone)]
-pub struct RangeProofGens {
-    /// The maximum number of usable generators.
-    pub gens_capacity: usize,
-    /// Precomputed \\(\mathbf G\\) generators.
-    G_vec: Vec<RistrettoPoint>,
-    /// Precomputed \\(\mathbf H\\) generators.
-    H_vec: Vec<RistrettoPoint>,
-}
-
-impl RangeProofGens {
-    pub fn new(gens_capacity: usize) -> Result<Self, RangeProofGeneratorError> {
-        let mut gens = RangeProofGens {
-            gens_capacity: 0,
-            G_vec: Vec::new(),
-            H_vec: Vec::new(),
-        };
-        gens.increase_capacity(gens_capacity)?;
-        Ok(gens)
-    }
-
-    /// Increases the generators' capacity to the amount specified.
-    /// If less than or equal to the current capacity, does nothing.
-    pub fn increase_capacity(
-        &mut self,
-        new_capacity: usize,
-    ) -> Result<(), RangeProofGeneratorError> {
-        if self.gens_capacity >= new_capacity {
-            return Ok(());
-        }
-
-        if new_capacity > MAX_GENERATOR_LENGTH {
-            return Err(RangeProofGeneratorError::MaximumGeneratorLengthExceeded);
-        }
-
-        self.G_vec.extend(
-            &mut GeneratorsChain::new(b"G")
-                .fast_forward(self.gens_capacity)
-                .take(new_capacity - self.gens_capacity),
-        );
-
-        self.H_vec.extend(
-            &mut GeneratorsChain::new(b"H")
-                .fast_forward(self.gens_capacity)
-                .take(new_capacity - self.gens_capacity),
-        );
-
-        self.gens_capacity = new_capacity;
-        Ok(())
-    }
-
-    #[allow(non_snake_case)]
-    pub(crate) fn G(&self, n: usize) -> impl Iterator<Item = &RistrettoPoint> {
-        GensIter {
-            array: &self.G_vec,
-            n,
-            gen_idx: 0,
-        }
-    }
-
-    #[allow(non_snake_case)]
-    pub(crate) fn H(&self, n: usize) -> impl Iterator<Item = &RistrettoPoint> {
-        GensIter {
-            array: &self.H_vec,
-            n,
-            gen_idx: 0,
-        }
-    }
-}
-
-struct GensIter<'a> {
-    array: &'a Vec<RistrettoPoint>,
-    n: usize,
-    gen_idx: usize,
-}
-
-impl<'a> Iterator for GensIter<'a> {
-    type Item = &'a RistrettoPoint;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        if self.gen_idx >= self.n {
-            None
-        } else {
-            let cur_gen = self.gen_idx;
-            self.gen_idx += 1;
-            Some(&self.array[cur_gen])
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let size = self.n - self.gen_idx;
-        (size, Some(size))
-    }
-}

+ 0 - 508
zk-sdk/src/range_proof/inner_product.rs

@@ -1,508 +0,0 @@
-use {
-    crate::{
-        range_proof::{
-            errors::{RangeProofGenerationError, RangeProofVerificationError},
-            util,
-        },
-        transcript::TranscriptProtocol,
-    },
-    core::iter,
-    curve25519_dalek::{
-        ristretto::{CompressedRistretto, RistrettoPoint},
-        scalar::Scalar,
-        traits::{MultiscalarMul, VartimeMultiscalarMul},
-    },
-    merlin::Transcript,
-    std::borrow::Borrow,
-};
-
-#[allow(non_snake_case)]
-#[derive(Clone)]
-pub struct InnerProductProof {
-    pub(crate) L_vec: Vec<CompressedRistretto>, // 32 * log(bit_length)
-    pub(crate) R_vec: Vec<CompressedRistretto>, // 32 * log(bit_length)
-    pub(crate) a: Scalar,                       // 32 bytes
-    pub(crate) b: Scalar,                       // 32 bytes
-}
-
-#[allow(non_snake_case)]
-impl InnerProductProof {
-    /// Create an inner-product proof.
-    ///
-    /// The proof is created with respect to the bases \\(G\\), \\(H'\\),
-    /// where \\(H'\_i = H\_i \cdot \texttt{Hprime\\_factors}\_i\\).
-    ///
-    /// The `verifier` is passed in as a parameter so that the
-    /// challenges depend on the *entire* transcript (including parent
-    /// protocols).
-    ///
-    /// The lengths of the vectors must all be the same, and must all be
-    /// a power of 2.
-    #[allow(clippy::too_many_arguments)]
-    pub fn new(
-        Q: &RistrettoPoint,
-        G_factors: &[Scalar],
-        H_factors: &[Scalar],
-        mut G_vec: Vec<RistrettoPoint>,
-        mut H_vec: Vec<RistrettoPoint>,
-        mut a_vec: Vec<Scalar>,
-        mut b_vec: Vec<Scalar>,
-        transcript: &mut Transcript,
-    ) -> Result<Self, RangeProofGenerationError> {
-        // Create slices G, H, a, b backed by their respective
-        // vectors.  This lets us reslice as we compress the lengths
-        // of the vectors in the main loop below.
-        let mut G = &mut G_vec[..];
-        let mut H = &mut H_vec[..];
-        let mut a = &mut a_vec[..];
-        let mut b = &mut b_vec[..];
-
-        let mut n = G.len();
-
-        // All of the input vectors must have the same length.
-        if G.len() != n
-            || H.len() != n
-            || a.len() != n
-            || b.len() != n
-            || G_factors.len() != n
-            || H_factors.len() != n
-        {
-            return Err(RangeProofGenerationError::GeneratorLengthMismatch);
-        }
-
-        // All of the input vectors must have a length that is a power of two.
-        if !n.is_power_of_two() {
-            return Err(RangeProofGenerationError::InvalidBitSize);
-        }
-
-        transcript.inner_product_proof_domain_separator(n as u64);
-
-        let lg_n = n.next_power_of_two().trailing_zeros() as usize;
-        let mut L_vec = Vec::with_capacity(lg_n);
-        let mut R_vec = Vec::with_capacity(lg_n);
-
-        // If it's the first iteration, unroll the Hprime = H*y_inv scalar mults
-        // into multiscalar muls, for performance.
-        if n != 1 {
-            n = n.checked_div(2).unwrap();
-            let (a_L, a_R) = a.split_at_mut(n);
-            let (b_L, b_R) = b.split_at_mut(n);
-            let (G_L, G_R) = G.split_at_mut(n);
-            let (H_L, H_R) = H.split_at_mut(n);
-
-            let c_L = util::inner_product(a_L, b_R)
-                .ok_or(RangeProofGenerationError::InnerProductLengthMismatch)?;
-            let c_R = util::inner_product(a_R, b_L)
-                .ok_or(RangeProofGenerationError::InnerProductLengthMismatch)?;
-
-            let L = RistrettoPoint::multiscalar_mul(
-                a_L.iter()
-                    // `n` was previously divided in half and therefore, it cannot overflow.
-                    .zip(G_factors[n..n.checked_mul(2).unwrap()].iter())
-                    .map(|(a_L_i, g)| a_L_i * g)
-                    .chain(
-                        b_R.iter()
-                            .zip(H_factors[0..n].iter())
-                            .map(|(b_R_i, h)| b_R_i * h),
-                    )
-                    .chain(iter::once(c_L)),
-                G_R.iter().chain(H_L.iter()).chain(iter::once(Q)),
-            )
-            .compress();
-
-            let R = RistrettoPoint::multiscalar_mul(
-                a_R.iter()
-                    .zip(G_factors[0..n].iter())
-                    .map(|(a_R_i, g)| a_R_i * g)
-                    .chain(
-                        b_L.iter()
-                            .zip(H_factors[n..n.checked_mul(2).unwrap()].iter())
-                            .map(|(b_L_i, h)| b_L_i * h),
-                    )
-                    .chain(iter::once(c_R)),
-                G_L.iter().chain(H_R.iter()).chain(iter::once(Q)),
-            )
-            .compress();
-
-            L_vec.push(L);
-            R_vec.push(R);
-
-            transcript.append_point(b"L", &L);
-            transcript.append_point(b"R", &R);
-
-            let u = transcript.challenge_scalar(b"u");
-            let u_inv = u.invert();
-
-            for i in 0..n {
-                a_L[i] = a_L[i] * u + u_inv * a_R[i];
-                b_L[i] = b_L[i] * u_inv + u * b_R[i];
-                G_L[i] = RistrettoPoint::multiscalar_mul(
-                    &[
-                        u_inv * G_factors[i],
-                        u * G_factors[n.checked_add(i).unwrap()],
-                    ],
-                    &[G_L[i], G_R[i]],
-                );
-                H_L[i] = RistrettoPoint::multiscalar_mul(
-                    &[
-                        u * H_factors[i],
-                        u_inv * H_factors[n.checked_add(i).unwrap()],
-                    ],
-                    &[H_L[i], H_R[i]],
-                )
-            }
-
-            a = a_L;
-            b = b_L;
-            G = G_L;
-            H = H_L;
-        }
-
-        while n != 1 {
-            n = n.checked_div(2).unwrap();
-            let (a_L, a_R) = a.split_at_mut(n);
-            let (b_L, b_R) = b.split_at_mut(n);
-            let (G_L, G_R) = G.split_at_mut(n);
-            let (H_L, H_R) = H.split_at_mut(n);
-
-            let c_L = util::inner_product(a_L, b_R)
-                .ok_or(RangeProofGenerationError::InnerProductLengthMismatch)?;
-            let c_R = util::inner_product(a_R, b_L)
-                .ok_or(RangeProofGenerationError::InnerProductLengthMismatch)?;
-
-            let L = RistrettoPoint::multiscalar_mul(
-                a_L.iter().chain(b_R.iter()).chain(iter::once(&c_L)),
-                G_R.iter().chain(H_L.iter()).chain(iter::once(Q)),
-            )
-            .compress();
-
-            let R = RistrettoPoint::multiscalar_mul(
-                a_R.iter().chain(b_L.iter()).chain(iter::once(&c_R)),
-                G_L.iter().chain(H_R.iter()).chain(iter::once(Q)),
-            )
-            .compress();
-
-            L_vec.push(L);
-            R_vec.push(R);
-
-            transcript.append_point(b"L", &L);
-            transcript.append_point(b"R", &R);
-
-            let u = transcript.challenge_scalar(b"u");
-            let u_inv = u.invert();
-
-            for i in 0..n {
-                a_L[i] = a_L[i] * u + u_inv * a_R[i];
-                b_L[i] = b_L[i] * u_inv + u * b_R[i];
-                G_L[i] = RistrettoPoint::multiscalar_mul(&[u_inv, u], &[G_L[i], G_R[i]]);
-                H_L[i] = RistrettoPoint::multiscalar_mul(&[u, u_inv], &[H_L[i], H_R[i]]);
-            }
-
-            a = a_L;
-            b = b_L;
-            G = G_L;
-            H = H_L;
-        }
-
-        Ok(InnerProductProof {
-            L_vec,
-            R_vec,
-            a: a[0],
-            b: b[0],
-        })
-    }
-
-    /// Computes three vectors of verification scalars \\([u\_{i}^{2}]\\), \\([u\_{i}^{-2}]\\) and
-    /// \\([s\_{i}]\\) for combined multiscalar multiplication in a parent protocol. See [inner
-    /// product protocol notes](index.html#verification-equation) for details. The verifier must
-    /// provide the input length \\(n\\) explicitly to avoid unbounded allocation within the inner
-    /// product proof.
-    #[allow(clippy::type_complexity)]
-    pub(crate) fn verification_scalars(
-        &self,
-        n: usize,
-        transcript: &mut Transcript,
-    ) -> Result<(Vec<Scalar>, Vec<Scalar>, Vec<Scalar>), RangeProofVerificationError> {
-        let lg_n = self.L_vec.len();
-        if lg_n == 0 || lg_n >= 32 {
-            // 4 billion multiplications should be enough for anyone
-            // and this check prevents overflow in 1<<lg_n below.
-            return Err(RangeProofVerificationError::InvalidBitSize);
-        }
-        if n != (1_usize.checked_shl(lg_n as u32).unwrap()) {
-            return Err(RangeProofVerificationError::InvalidBitSize);
-        }
-
-        transcript.inner_product_proof_domain_separator(n as u64);
-
-        // 1. Recompute x_k,...,x_1 based on the proof transcript
-
-        let mut challenges = Vec::with_capacity(lg_n);
-        for (L, R) in self.L_vec.iter().zip(self.R_vec.iter()) {
-            transcript.validate_and_append_point(b"L", L)?;
-            transcript.validate_and_append_point(b"R", R)?;
-            challenges.push(transcript.challenge_scalar(b"u"));
-        }
-
-        // 2. Compute 1/(u_k...u_1) and 1/u_k, ..., 1/u_1
-
-        let mut challenges_inv = challenges.clone();
-        let allinv = Scalar::batch_invert(&mut challenges_inv);
-
-        // 3. Compute u_i^2 and (1/u_i)^2
-
-        for i in 0..lg_n {
-            challenges[i] = challenges[i] * challenges[i];
-            challenges_inv[i] = challenges_inv[i] * challenges_inv[i];
-        }
-        let challenges_sq = challenges;
-        let challenges_inv_sq = challenges_inv;
-
-        // 4. Compute s values inductively.
-
-        let mut s = Vec::with_capacity(n);
-        s.push(allinv);
-        for i in 1..n {
-            let lg_i = 31_u32.checked_sub((i as u32).leading_zeros()).unwrap() as usize;
-            let k = 1_usize.checked_shl(lg_i as u32).unwrap();
-            // The challenges are stored in "creation order" as [u_k,...,u_1],
-            // so u_{lg(i)+1} = is indexed by (lg_n-1) - lg_i
-            let u_lg_i_sq = challenges_sq[lg_n
-                .checked_sub(1)
-                .and_then(|x| x.checked_sub(lg_i))
-                .unwrap()];
-            s.push(s[i - k] * u_lg_i_sq);
-        }
-
-        Ok((challenges_sq, challenges_inv_sq, s))
-    }
-
-    /// This method is for testing that proof generation work, but for efficiency the actual
-    /// protocols would use `verification_scalars` method to combine inner product verification
-    /// with other checks in a single multiscalar multiplication.
-    #[allow(clippy::too_many_arguments)]
-    pub fn verify<IG, IH>(
-        &self,
-        n: usize,
-        G_factors: IG,
-        H_factors: IH,
-        P: &RistrettoPoint,
-        Q: &RistrettoPoint,
-        G: &[RistrettoPoint],
-        H: &[RistrettoPoint],
-        transcript: &mut Transcript,
-    ) -> Result<(), RangeProofVerificationError>
-    where
-        IG: IntoIterator,
-        IG::Item: Borrow<Scalar>,
-        IH: IntoIterator,
-        IH::Item: Borrow<Scalar>,
-    {
-        let (u_sq, u_inv_sq, s) = self.verification_scalars(n, transcript)?;
-
-        let g_times_a_times_s = G_factors
-            .into_iter()
-            .zip(s.iter())
-            .map(|(g_i, s_i)| (self.a * s_i) * g_i.borrow())
-            .take(G.len());
-
-        // 1/s[i] is s[!i], and !i runs from n-1 to 0 as i runs from 0 to n-1
-        let inv_s = s.iter().rev();
-
-        let h_times_b_div_s = H_factors
-            .into_iter()
-            .zip(inv_s)
-            .map(|(h_i, s_i_inv)| (self.b * s_i_inv) * h_i.borrow());
-
-        let neg_u_sq = u_sq.iter().map(|ui| -ui);
-        let neg_u_inv_sq = u_inv_sq.iter().map(|ui| -ui);
-
-        let Ls = self
-            .L_vec
-            .iter()
-            .map(|p| {
-                p.decompress()
-                    .ok_or(RangeProofVerificationError::Deserialization)
-            })
-            .collect::<Result<Vec<_>, _>>()?;
-
-        let Rs = self
-            .R_vec
-            .iter()
-            .map(|p| {
-                p.decompress()
-                    .ok_or(RangeProofVerificationError::Deserialization)
-            })
-            .collect::<Result<Vec<_>, _>>()?;
-
-        let expect_P = RistrettoPoint::vartime_multiscalar_mul(
-            iter::once(self.a * self.b)
-                .chain(g_times_a_times_s)
-                .chain(h_times_b_div_s)
-                .chain(neg_u_sq)
-                .chain(neg_u_inv_sq),
-            iter::once(Q)
-                .chain(G.iter())
-                .chain(H.iter())
-                .chain(Ls.iter())
-                .chain(Rs.iter()),
-        );
-
-        if expect_P == *P {
-            Ok(())
-        } else {
-            Err(RangeProofVerificationError::AlgebraicRelation)
-        }
-    }
-
-    /// Returns the size in bytes required to serialize the inner
-    /// product proof.
-    ///
-    /// For vectors of length `n` the proof size is
-    /// \\(32 \cdot (2\lg n+2)\\) bytes.
-    pub fn serialized_size(&self) -> usize {
-        (self.L_vec.len() * 2 + 2) * 32
-    }
-
-    /// Serializes the proof into a byte array of \\(2n+2\\) 32-byte elements.
-    /// The layout of the inner product proof is:
-    /// * \\(n\\) pairs of compressed Ristretto points \\(L_0, R_0 \dots, L_{n-1}, R_{n-1}\\),
-    /// * two scalars \\(a, b\\).
-    pub fn to_bytes(&self) -> Vec<u8> {
-        let mut buf = Vec::with_capacity(self.serialized_size());
-        for (l, r) in self.L_vec.iter().zip(self.R_vec.iter()) {
-            buf.extend_from_slice(l.as_bytes());
-            buf.extend_from_slice(r.as_bytes());
-        }
-        buf.extend_from_slice(self.a.as_bytes());
-        buf.extend_from_slice(self.b.as_bytes());
-        buf
-    }
-
-    /// Deserializes the proof from a byte slice.
-    /// Returns an error in the following cases:
-    /// * the slice does not have \\(2n+2\\) 32-byte elements,
-    /// * \\(n\\) is larger or equal to 32 (proof is too big),
-    /// * any of \\(2n\\) points are not valid compressed Ristretto points,
-    /// * any of 2 scalars are not canonical scalars modulo Ristretto group order.
-    pub fn from_bytes(slice: &[u8]) -> Result<InnerProductProof, RangeProofVerificationError> {
-        let b = slice.len();
-        if b % 32 != 0 {
-            return Err(RangeProofVerificationError::Deserialization);
-        }
-        let num_elements = b / 32;
-        if num_elements < 2 {
-            return Err(RangeProofVerificationError::Deserialization);
-        }
-        if (num_elements - 2) % 2 != 0 {
-            return Err(RangeProofVerificationError::Deserialization);
-        }
-        let lg_n = (num_elements - 2) / 2;
-        if lg_n >= 32 {
-            return Err(RangeProofVerificationError::Deserialization);
-        }
-
-        let mut L_vec: Vec<CompressedRistretto> = Vec::with_capacity(lg_n);
-        let mut R_vec: Vec<CompressedRistretto> = Vec::with_capacity(lg_n);
-        for i in 0..lg_n {
-            let pos = 2 * i * 32;
-            L_vec.push(CompressedRistretto(util::read32(&slice[pos..])));
-            R_vec.push(CompressedRistretto(util::read32(&slice[pos + 32..])));
-        }
-
-        let pos = 2 * lg_n * 32;
-        let a = Scalar::from_canonical_bytes(util::read32(&slice[pos..]))
-            .into_option()
-            .ok_or(RangeProofVerificationError::Deserialization)?;
-        let b = Scalar::from_canonical_bytes(util::read32(&slice[pos + 32..]))
-            .into_option()
-            .ok_or(RangeProofVerificationError::Deserialization)?;
-
-        Ok(InnerProductProof { L_vec, R_vec, a, b })
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use {
-        super::*, crate::range_proof::generators::RangeProofGens, rand::rngs::OsRng, sha3::Sha3_512,
-    };
-
-    #[test]
-    #[allow(non_snake_case)]
-    fn test_basic_correctness() {
-        let n = 32;
-
-        let bp_gens = RangeProofGens::new(n).unwrap();
-        let G: Vec<RistrettoPoint> = bp_gens.G(n).cloned().collect();
-        let H: Vec<RistrettoPoint> = bp_gens.H(n).cloned().collect();
-
-        let Q = RistrettoPoint::hash_from_bytes::<Sha3_512>(b"test point");
-
-        let a: Vec<_> = (0..n).map(|_| Scalar::random(&mut OsRng)).collect();
-        let b: Vec<_> = (0..n).map(|_| Scalar::random(&mut OsRng)).collect();
-        let c = util::inner_product(&a, &b).unwrap();
-
-        let G_factors: Vec<Scalar> = iter::repeat_n(Scalar::ONE, n).collect();
-
-        let y_inv = Scalar::random(&mut OsRng);
-        let H_factors: Vec<Scalar> = util::exp_iter(y_inv).take(n).collect();
-
-        // P would be determined upstream, but we need a correct P to check the proof.
-        //
-        // To generate P = <a,G> + <b,H'> + <a,b> Q, compute
-        //             P = <a,G> + <b',H> + <a,b> Q,
-        // where b' = b \circ y^(-n)
-        let b_prime = b.iter().zip(util::exp_iter(y_inv)).map(|(bi, yi)| bi * yi);
-        // a.iter() has Item=&Scalar, need Item=Scalar to chain with b_prime
-        let a_prime = a.iter().cloned();
-
-        let P = RistrettoPoint::vartime_multiscalar_mul(
-            a_prime.chain(b_prime).chain(iter::once(c)),
-            G.iter().chain(H.iter()).chain(iter::once(&Q)),
-        );
-
-        let mut prover_transcript = Transcript::new(b"innerproducttest");
-        let mut verifier_transcript = Transcript::new(b"innerproducttest");
-
-        let proof = InnerProductProof::new(
-            &Q,
-            &G_factors,
-            &H_factors,
-            G.clone(),
-            H.clone(),
-            a.clone(),
-            b.clone(),
-            &mut prover_transcript,
-        )
-        .unwrap();
-
-        assert!(proof
-            .verify(
-                n,
-                iter::repeat_n(Scalar::ONE, n),
-                util::exp_iter(y_inv).take(n),
-                &P,
-                &Q,
-                &G,
-                &H,
-                &mut verifier_transcript,
-            )
-            .is_ok());
-
-        let proof = InnerProductProof::from_bytes(proof.to_bytes().as_slice()).unwrap();
-        let mut verifier_transcript = Transcript::new(b"innerproducttest");
-        assert!(proof
-            .verify(
-                n,
-                iter::repeat_n(Scalar::ONE, n),
-                util::exp_iter(y_inv).take(n),
-                &P,
-                &Q,
-                &G,
-                &H,
-                &mut verifier_transcript,
-            )
-            .is_ok());
-    }
-}

+ 0 - 553
zk-sdk/src/range_proof/mod.rs

@@ -1,553 +0,0 @@
-//! The Bulletproofs range-proof implementation over Curve25519 Ristretto points.
-//!
-//! The implementation is based on the dalek-cryptography bulletproofs
-//! [implementation](https://github.com/dalek-cryptography/bulletproofs). Compared to the original
-//! implementation by dalek-cryptography:
-//! - This implementation focuses on the range proof implementation, while the dalek-cryptography
-//!   crate additionally implements the general bulletproofs implementation for languages that can be
-//!   represented by arithmetic circuits as well as MPC.
-//! - This implementation implements a non-interactive range proof aggregation that is specified in
-//!   the original Bulletproofs [paper](https://eprint.iacr.org/2017/1066) (Section 4.3).
-//!
-
-#![allow(dead_code)]
-
-use crate::{RISTRETTO_POINT_LEN, SCALAR_LEN};
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::pedersen::{Pedersen, PedersenCommitment, PedersenOpening, G, H},
-        range_proof::{
-            errors::{RangeProofGenerationError, RangeProofVerificationError},
-            generators::RangeProofGens,
-            inner_product::InnerProductProof,
-        },
-        transcript::TranscriptProtocol,
-    },
-    core::iter,
-    curve25519_dalek::traits::MultiscalarMul,
-    curve25519_dalek::{
-        ristretto::{CompressedRistretto, RistrettoPoint},
-        scalar::Scalar,
-        traits::{IsIdentity, VartimeMultiscalarMul},
-    },
-    merlin::Transcript,
-    rand::rngs::OsRng,
-    subtle::{Choice, ConditionallySelectable},
-};
-
-pub mod errors;
-pub mod pod;
-
-#[cfg(not(target_os = "solana"))]
-pub mod generators;
-#[cfg(not(target_os = "solana"))]
-pub mod inner_product;
-#[cfg(not(target_os = "solana"))]
-pub mod util;
-
-/// Byte length of a range proof excluding the inner-product proof component
-pub const RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN: usize =
-    5 * RISTRETTO_POINT_LEN + 2 * SCALAR_LEN;
-
-/// Byte length of an inner-product proof for a vector of length 64
-pub const INNER_PRODUCT_PROOF_U64_LEN: usize = 448;
-
-/// Byte length of a range proof for an unsigned 64-bit number
-pub const RANGE_PROOF_U64_LEN: usize =
-    INNER_PRODUCT_PROOF_U64_LEN + RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN; // 672 bytes
-
-/// Byte length of an inner-product proof for a vector of length 128
-pub const INNER_PRODUCT_PROOF_U128_LEN: usize = 512;
-
-/// Byte length of a range proof for an unsigned 128-bit number
-pub const RANGE_PROOF_U128_LEN: usize =
-    INNER_PRODUCT_PROOF_U128_LEN + RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN; // 736 bytes
-
-/// Byte length of an inner-product proof for a vector of length 256
-pub const INNER_PRODUCT_PROOF_U256_LEN: usize = 576;
-
-/// Byte length of a range proof for an unsigned 256-bit number
-pub const RANGE_PROOF_U256_LEN: usize =
-    INNER_PRODUCT_PROOF_U256_LEN + RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN; // 800 bytes
-
-#[allow(non_snake_case)]
-#[cfg(not(target_os = "solana"))]
-#[derive(Clone)]
-pub struct RangeProof {
-    pub(crate) A: CompressedRistretto,       // 32 bytes
-    pub(crate) S: CompressedRistretto,       // 32 bytes
-    pub(crate) T_1: CompressedRistretto,     // 32 bytes
-    pub(crate) T_2: CompressedRistretto,     // 32 bytes
-    pub(crate) t_x: Scalar,                  // 32 bytes
-    pub(crate) t_x_blinding: Scalar,         // 32 bytes
-    pub(crate) e_blinding: Scalar,           // 32 bytes
-    pub(crate) ipp_proof: InnerProductProof, // 448 bytes for withdraw; 512 for transfer
-}
-
-#[allow(non_snake_case)]
-#[cfg(not(target_os = "solana"))]
-impl RangeProof {
-    /// Create an aggregated range proof.
-    ///
-    /// The proof is created with respect to a vector of Pedersen commitments C_1, ..., C_m. The
-    /// method itself does not take in these commitments, but the values associated with the commitments:
-    /// - vector of committed amounts v_1, ..., v_m represented as u64
-    /// - bit-lengths of the committed amounts
-    /// - Pedersen openings for each commitments
-    ///
-    /// The sum of the bit-lengths of the commitments amounts must be a power-of-two
-    #[allow(clippy::many_single_char_names)]
-    #[cfg(not(target_os = "solana"))]
-    pub fn new(
-        amounts: Vec<u64>,
-        bit_lengths: Vec<usize>,
-        openings: Vec<&PedersenOpening>,
-        transcript: &mut Transcript,
-    ) -> Result<Self, RangeProofGenerationError> {
-        // amounts, bit-lengths, openings must be same length vectors
-        let m = amounts.len();
-        if bit_lengths.len() != m || openings.len() != m {
-            return Err(RangeProofGenerationError::VectorLengthMismatch);
-        }
-
-        // each bit length must be greater than 0 for the proof to make sense
-        if bit_lengths
-            .iter()
-            .any(|bit_length| *bit_length == 0 || *bit_length > u64::BITS as usize)
-        {
-            return Err(RangeProofGenerationError::InvalidBitSize);
-        }
-
-        // total vector dimension to compute the ultimate inner product proof for
-        let nm: usize = bit_lengths.iter().sum();
-        if !nm.is_power_of_two() {
-            return Err(RangeProofGenerationError::VectorLengthMismatch);
-        }
-
-        let bp_gens = RangeProofGens::new(nm)
-            .map_err(|_| RangeProofGenerationError::MaximumGeneratorLengthExceeded)?;
-
-        transcript.range_proof_domain_separator(nm as u64);
-
-        // bit-decompose values and generate their Pedersen vector commitment
-        let a_blinding = Scalar::random(&mut OsRng);
-        let mut A = a_blinding * &(*H);
-
-        let mut gens_iter = bp_gens.G(nm).zip(bp_gens.H(nm));
-        for (amount_i, n_i) in amounts.iter().zip(bit_lengths.iter()) {
-            for j in 0..(*n_i) {
-                let (G_ij, H_ij) = gens_iter.next().unwrap();
-
-                // `j` is guaranteed to be at most `u64::BITS` (a 6-bit number) and therefore,
-                // casting is lossless and right shift can be safely unwrapped
-                let v_ij = Choice::from((amount_i.checked_shr(j as u32).unwrap() & 1) as u8);
-                let mut point = -H_ij;
-                point.conditional_assign(G_ij, v_ij);
-                A += point;
-            }
-        }
-        let A = A.compress();
-
-        // generate blinding factors and generate their Pedersen vector commitment
-        let s_L: Vec<Scalar> = (0..nm).map(|_| Scalar::random(&mut OsRng)).collect();
-        let s_R: Vec<Scalar> = (0..nm).map(|_| Scalar::random(&mut OsRng)).collect();
-
-        // generate blinding factor for Pedersen commitment; `s_blinding` should not to be confused
-        // with blinding factors for the actual inner product vector
-        let s_blinding = Scalar::random(&mut OsRng);
-
-        let S = RistrettoPoint::multiscalar_mul(
-            iter::once(&s_blinding).chain(s_L.iter()).chain(s_R.iter()),
-            iter::once(&(*H)).chain(bp_gens.G(nm)).chain(bp_gens.H(nm)),
-        )
-        .compress();
-
-        // add the Pedersen vector commitments to the transcript (send the commitments to the verifier)
-        transcript.append_point(b"A", &A);
-        transcript.append_point(b"S", &S);
-
-        // derive challenge scalars from the transcript (receive challenge from the verifier): `y`
-        // and `z` used for merge multiple inner product relations into one single inner product
-        let y = transcript.challenge_scalar(b"y");
-        let z = transcript.challenge_scalar(b"z");
-
-        // define blinded vectors:
-        // - l(x) = (a_L - z*1) + s_L*x
-        // - r(x) = (y^n * (a_R + z*1) + [z^2*2^n | z^3*2^n | ... | z^m*2^n]) + y^n * s_R*x
-        let mut l_poly = util::VecPoly1::zero(nm);
-        let mut r_poly = util::VecPoly1::zero(nm);
-
-        let mut i = 0;
-        let mut exp_z = z * z;
-        let mut exp_y = Scalar::ONE;
-
-        for (amount_i, n_i) in amounts.iter().zip(bit_lengths.iter()) {
-            let mut exp_2 = Scalar::ONE;
-
-            for j in 0..(*n_i) {
-                // `j` is guaranteed to be at most `u64::BITS` (a 6-bit number) and therefore,
-                // casting is lossless and right shift can be safely unwrapped
-                let a_L_j = Scalar::from(amount_i.checked_shr(j as u32).unwrap() & 1);
-                let a_R_j = a_L_j - Scalar::ONE;
-
-                l_poly.0[i] = a_L_j - z;
-                l_poly.1[i] = s_L[i];
-                r_poly.0[i] = exp_y * (a_R_j + z) + exp_z * exp_2;
-                r_poly.1[i] = exp_y * s_R[i];
-
-                exp_y *= y;
-                exp_2 = exp_2 + exp_2;
-
-                // `i` is capped by the sum of vectors in `bit_lengths`
-                i = i.checked_add(1).unwrap();
-            }
-            exp_z *= z;
-        }
-
-        // define t(x) = <l(x), r(x)> = t_0 + t_1*x + t_2*x
-        let t_poly = l_poly
-            .inner_product(&r_poly)
-            .ok_or(RangeProofGenerationError::InnerProductLengthMismatch)?;
-
-        // generate Pedersen commitment for the coefficients t_1 and t_2
-        let (T_1, t_1_blinding) = Pedersen::new(t_poly.1);
-        let (T_2, t_2_blinding) = Pedersen::new(t_poly.2);
-
-        let T_1 = T_1.get_point().compress();
-        let T_2 = T_2.get_point().compress();
-
-        transcript.append_point(b"T_1", &T_1);
-        transcript.append_point(b"T_2", &T_2);
-
-        // evaluate t(x) on challenge x and homomorphically compute the openings for
-        // z^2 * V_1 + z^3 * V_2 + ... + z^{m+1} * V_m + delta(y, z)*G + x*T_1 + x^2*T_2
-        let x = transcript.challenge_scalar(b"x");
-
-        let mut agg_opening = Scalar::ZERO;
-        let mut exp_z = z;
-        for opening in openings {
-            exp_z *= z;
-            agg_opening += exp_z * opening.get_scalar();
-        }
-
-        let t_blinding_poly = util::Poly2(
-            agg_opening,
-            *t_1_blinding.get_scalar(),
-            *t_2_blinding.get_scalar(),
-        );
-
-        let t_x = t_poly.eval(x);
-        let t_x_blinding = t_blinding_poly.eval(x);
-
-        transcript.append_scalar(b"t_x", &t_x);
-        transcript.append_scalar(b"t_x_blinding", &t_x_blinding);
-
-        // homomorphically compuate the openings for A + x*S
-        let e_blinding = a_blinding + s_blinding * x;
-        let l_vec = l_poly.eval(x);
-        let r_vec = r_poly.eval(x);
-
-        transcript.append_scalar(b"e_blinding", &e_blinding);
-
-        // compute the inner product argument on the commitment:
-        // P = <l(x), G> + <r(x), H'> + <l(x), r(x)>*Q
-        let w = transcript.challenge_scalar(b"w");
-        let Q = w * &G;
-
-        let G_factors: Vec<Scalar> = iter::repeat_n(Scalar::ONE, nm).collect();
-        let H_factors: Vec<Scalar> = util::exp_iter(y.invert()).take(nm).collect();
-
-        // generate challenge `c` for consistency with the verifier's transcript
-        transcript.challenge_scalar(b"c");
-
-        let ipp_proof = InnerProductProof::new(
-            &Q,
-            &G_factors,
-            &H_factors,
-            bp_gens.G(nm).cloned().collect(),
-            bp_gens.H(nm).cloned().collect(),
-            l_vec,
-            r_vec,
-            transcript,
-        )?;
-
-        Ok(RangeProof {
-            A,
-            S,
-            T_1,
-            T_2,
-            t_x,
-            t_x_blinding,
-            e_blinding,
-            ipp_proof,
-        })
-    }
-
-    #[allow(clippy::many_single_char_names)]
-    pub fn verify(
-        &self,
-        comms: Vec<&PedersenCommitment>,
-        bit_lengths: Vec<usize>,
-        transcript: &mut Transcript,
-    ) -> Result<(), RangeProofVerificationError> {
-        // commitments and bit-lengths must be same length vectors
-        if comms.len() != bit_lengths.len() {
-            return Err(RangeProofVerificationError::VectorLengthMismatch);
-        }
-
-        let m = bit_lengths.len();
-        let nm: usize = bit_lengths.iter().sum();
-        let bp_gens = RangeProofGens::new(nm)
-            .map_err(|_| RangeProofVerificationError::MaximumGeneratorLengthExceeded)?;
-
-        if !nm.is_power_of_two() {
-            return Err(RangeProofVerificationError::InvalidBitSize);
-        }
-
-        transcript.range_proof_domain_separator(nm as u64);
-
-        // append proof data to transcript and derive appropriate challenge scalars
-        transcript.validate_and_append_point(b"A", &self.A)?;
-        transcript.validate_and_append_point(b"S", &self.S)?;
-
-        let y = transcript.challenge_scalar(b"y");
-        let z = transcript.challenge_scalar(b"z");
-
-        let zz = z * z;
-        let minus_z = -z;
-
-        transcript.validate_and_append_point(b"T_1", &self.T_1)?;
-        transcript.validate_and_append_point(b"T_2", &self.T_2)?;
-
-        let x = transcript.challenge_scalar(b"x");
-
-        transcript.append_scalar(b"t_x", &self.t_x);
-        transcript.append_scalar(b"t_x_blinding", &self.t_x_blinding);
-        transcript.append_scalar(b"e_blinding", &self.e_blinding);
-
-        let w = transcript.challenge_scalar(b"w");
-
-        // this variable exists for backwards compatibility
-        let _c = transcript.challenge_scalar(b"c");
-
-        // verify inner product proof
-        let (x_sq, x_inv_sq, s) = self.ipp_proof.verification_scalars(nm, transcript)?;
-        let s_inv = s.iter().rev();
-
-        let a = self.ipp_proof.a;
-        let b = self.ipp_proof.b;
-
-        transcript.append_scalar(b"ipp_a", &a);
-        transcript.append_scalar(b"ipp_b", &b);
-
-        let d = transcript.challenge_scalar(b"d"); // challenge value for batching multiscalar mul
-
-        // construct concat_z_and_2, an iterator of the values of
-        // z^0 * \vec(2)^n || z^1 * \vec(2)^n || ... || z^(m-1) * \vec(2)^n
-        let concat_z_and_2: Vec<Scalar> = util::exp_iter(z)
-            .zip(bit_lengths.iter())
-            .flat_map(|(exp_z, n_i)| {
-                util::exp_iter(Scalar::from(2u64))
-                    .take(*n_i)
-                    .map(move |exp_2| exp_2 * exp_z)
-            })
-            .collect();
-
-        let gs = s.iter().map(|s_i| minus_z - a * s_i);
-        let hs = s_inv
-            .zip(util::exp_iter(y.invert()))
-            .zip(concat_z_and_2.iter())
-            .map(|((s_i_inv, exp_y_inv), z_and_2)| z + exp_y_inv * (zz * z_and_2 - b * s_i_inv));
-
-        let basepoint_scalar =
-            w * (self.t_x - a * b) + d * (delta(&bit_lengths, &y, &z) - self.t_x);
-        let value_commitment_scalars = util::exp_iter(z).take(m).map(|z_exp| d * zz * z_exp);
-
-        let mega_check = RistrettoPoint::optional_multiscalar_mul(
-            iter::once(Scalar::ONE)
-                .chain(iter::once(x))
-                .chain(iter::once(d * x))
-                .chain(iter::once(d * x * x))
-                .chain(iter::once(-self.e_blinding - d * self.t_x_blinding))
-                .chain(iter::once(basepoint_scalar))
-                .chain(x_sq.iter().cloned())
-                .chain(x_inv_sq.iter().cloned())
-                .chain(gs)
-                .chain(hs)
-                .chain(value_commitment_scalars),
-            iter::once(self.A.decompress())
-                .chain(iter::once(self.S.decompress()))
-                .chain(iter::once(self.T_1.decompress()))
-                .chain(iter::once(self.T_2.decompress()))
-                .chain(iter::once(Some(*H)))
-                .chain(iter::once(Some(G)))
-                .chain(self.ipp_proof.L_vec.iter().map(|L| L.decompress()))
-                .chain(self.ipp_proof.R_vec.iter().map(|R| R.decompress()))
-                .chain(bp_gens.G(nm).map(|&x| Some(x)))
-                .chain(bp_gens.H(nm).map(|&x| Some(x)))
-                .chain(comms.iter().map(|V| Some(*V.get_point()))),
-        )
-        .ok_or(RangeProofVerificationError::MultiscalarMul)?;
-
-        if mega_check.is_identity() {
-            Ok(())
-        } else {
-            Err(RangeProofVerificationError::AlgebraicRelation)
-        }
-    }
-
-    // Following the dalek rangeproof library signature for now. The exact method signature can be
-    // changed.
-    pub fn to_bytes(&self) -> Vec<u8> {
-        let mut buf = Vec::with_capacity(7 * 32 + self.ipp_proof.serialized_size());
-        buf.extend_from_slice(self.A.as_bytes());
-        buf.extend_from_slice(self.S.as_bytes());
-        buf.extend_from_slice(self.T_1.as_bytes());
-        buf.extend_from_slice(self.T_2.as_bytes());
-        buf.extend_from_slice(self.t_x.as_bytes());
-        buf.extend_from_slice(self.t_x_blinding.as_bytes());
-        buf.extend_from_slice(self.e_blinding.as_bytes());
-        buf.extend_from_slice(&self.ipp_proof.to_bytes());
-        buf
-    }
-
-    // Following the dalek rangeproof library signature for now. The exact method signature can be
-    // changed.
-    pub fn from_bytes(slice: &[u8]) -> Result<RangeProof, RangeProofVerificationError> {
-        if slice.len() % 32 != 0 {
-            return Err(RangeProofVerificationError::Deserialization);
-        }
-        if slice.len() < 7 * 32 {
-            return Err(RangeProofVerificationError::Deserialization);
-        }
-
-        let A = CompressedRistretto(util::read32(&slice[0..]));
-        let S = CompressedRistretto(util::read32(&slice[32..]));
-        let T_1 = CompressedRistretto(util::read32(&slice[2 * 32..]));
-        let T_2 = CompressedRistretto(util::read32(&slice[3 * 32..]));
-
-        let t_x = Scalar::from_canonical_bytes(util::read32(&slice[4 * 32..]))
-            .into_option()
-            .ok_or(RangeProofVerificationError::Deserialization)?;
-        let t_x_blinding = Scalar::from_canonical_bytes(util::read32(&slice[5 * 32..]))
-            .into_option()
-            .ok_or(RangeProofVerificationError::Deserialization)?;
-        let e_blinding = Scalar::from_canonical_bytes(util::read32(&slice[6 * 32..]))
-            .into_option()
-            .ok_or(RangeProofVerificationError::Deserialization)?;
-
-        let ipp_proof = InnerProductProof::from_bytes(&slice[7 * 32..])?;
-
-        Ok(RangeProof {
-            A,
-            S,
-            T_1,
-            T_2,
-            t_x,
-            t_x_blinding,
-            e_blinding,
-            ipp_proof,
-        })
-    }
-}
-
-/// Compute
-/// \\[
-/// \delta(y,z) = (z - z^{2}) \langle \mathbf{1}, {\mathbf{y}}^{n \cdot m} \rangle - \sum_{j=0}^{m-1} z^{j+3} \cdot \langle \mathbf{1}, {\mathbf{2}}^{n \cdot m} \rangle
-/// \\]
-#[cfg(not(target_os = "solana"))]
-fn delta(bit_lengths: &[usize], y: &Scalar, z: &Scalar) -> Scalar {
-    let nm: usize = bit_lengths.iter().sum();
-    let sum_y = util::sum_of_powers(y, nm);
-
-    let mut agg_delta = (z - z * z) * sum_y;
-    let mut exp_z = z * z * z;
-    for n_i in bit_lengths.iter() {
-        let sum_2 = util::sum_of_powers(&Scalar::from(2u64), *n_i);
-        agg_delta -= exp_z * sum_2;
-        exp_z *= z;
-    }
-    agg_delta
-}
-
-#[cfg(test)]
-mod tests {
-    use {
-        super::*,
-        crate::{
-            encryption::pod::pedersen::PodPedersenCommitment, range_proof::pod::PodRangeProofU128,
-        },
-        std::str::FromStr,
-    };
-
-    #[test]
-    fn test_single_rangeproof() {
-        let (comm, open) = Pedersen::new(55_u64);
-
-        let mut transcript_create = Transcript::new(b"Test");
-        let mut transcript_verify = Transcript::new(b"Test");
-
-        let proof =
-            RangeProof::new(vec![55], vec![32], vec![&open], &mut transcript_create).unwrap();
-
-        proof
-            .verify(vec![&comm], vec![32], &mut transcript_verify)
-            .unwrap();
-    }
-
-    #[test]
-    fn test_aggregated_rangeproof() {
-        let (comm_1, open_1) = Pedersen::new(55_u64);
-        let (comm_2, open_2) = Pedersen::new(77_u64);
-        let (comm_3, open_3) = Pedersen::new(99_u64);
-
-        let mut transcript_create = Transcript::new(b"Test");
-        let mut transcript_verify = Transcript::new(b"Test");
-
-        let proof = RangeProof::new(
-            vec![55, 77, 99],
-            vec![64, 32, 32],
-            vec![&open_1, &open_2, &open_3],
-            &mut transcript_create,
-        )
-        .unwrap();
-
-        proof
-            .verify(
-                vec![&comm_1, &comm_2, &comm_3],
-                vec![64, 32, 32],
-                &mut transcript_verify,
-            )
-            .unwrap();
-    }
-
-    #[test]
-    fn test_range_proof_string() {
-        let commitment_1_str = "dDaa/MTEDlyI0Nxx+iu1tOteZsTWmPXAfn9QI0W9mSc=";
-        let pod_commitment_1 = PodPedersenCommitment::from_str(commitment_1_str).unwrap();
-        let commitment_1: PedersenCommitment = pod_commitment_1.try_into().unwrap();
-
-        let commitment_2_str = "tnRILjKpogi2sXxLgZzMqlqPMLnCJmrSjZ5SPQYhtgg=";
-        let pod_commitment_2 = PodPedersenCommitment::from_str(commitment_2_str).unwrap();
-        let commitment_2: PedersenCommitment = pod_commitment_2.try_into().unwrap();
-
-        let commitment_3_str = "ZAC5ZLXotsMOVExtrr56D/EZNeyo9iWepNbeH22EuRo=";
-        let pod_commitment_3 = PodPedersenCommitment::from_str(commitment_3_str).unwrap();
-        let commitment_3: PedersenCommitment = pod_commitment_3.try_into().unwrap();
-
-        let proof_str = "AvvBQL63pXMXsmuvuNbs/CqXdzeyrMpEIO2O/cI6/SyqU4N+7HUU3LmXai9st+DxqTnuKsm0SgnADfpLpQCEbDDupMb09NY8oHT8Bx8WQhv9eyoBlrPRd7DVhOUsio02gBshe3p2Wj7+yDCpFaZ7/PMypFBX6+E+EqCiPI6yUk4ztslWY0Ksac41eJgcPzXyIx2kvmSTsVBKLb7U01PWBC+AUyUmK3/IdvmJ4DnlS3xFrdg/mxSsYJFd3OZA3cwDb0jePQf/P43/2VVqPRixMVO7+VGoMKPoRTEEVbClsAlW6stGTFPcrimu3c+geASgvwElkIKNGtYcjoj3SS+/VeqIG9Ei1j+TJtPhOE9SG4KNw9xBGwecpliDbQhKjO950EVcnOts+a525/frZV1jHJmOOrZtKRV4pvk37dtQkx4sv+pxRmfVrjwOcKQeg+BzcuF0vaQbqa4SUbzbO9z3RwIMlYIBaz0bqZgJmtPOFuFmNyCJaeB29vlcEAfYbn5gdlgtWP50tKmhoskndulziKZjz4qHSA9rbG2ZtoMHoCsAobHKu2H9OxcaK4Scj1QGwst+zXBEY8uePNbxvU5DMJLVFORtLUXkVdPCmCSsm1Bz4TRbnls8LOVW6wqTgShQMhjNM3RtwdHXENPn5uDnhyvfduAcL+DtI8AIJyRneROefk7i7gjal8dLdMM/QnXT7ctpMQU6uNlpsNzq65xlOQKXO71vQ3c2mE/DmxVJi6BTS5WCzavvhiqdhQyRL61ESCALQpaP0/d0DLwLikVH3ypuDLEnVXe9Pmkxdd0xCzO6QcfyK50CPnV/dVgHeLg8EVag2O83+/7Ys5oLxrDad9TJTDcrT2xsRqECFnSA+z9uZtDPujhQL0ogS5RH4agnQN4mVGTwOLV8OKpn+AvWq6+j1/9EXFkLPBTU5wT0FQuT2VZ8xp5GeqdI13Zey1uPrxc6CZZ407y9OINED4IdBQ==";
-        let pod_proof = PodRangeProofU128::from_str(proof_str).unwrap();
-        let proof: RangeProof = pod_proof.try_into().unwrap();
-
-        let mut transcript_verify = Transcript::new(b"Test");
-
-        proof
-            .verify(
-                vec![&commitment_1, &commitment_2, &commitment_3],
-                vec![64, 32, 32],
-                &mut transcript_verify,
-            )
-            .unwrap()
-    }
-}

+ 0 - 187
zk-sdk/src/range_proof/pod.rs

@@ -1,187 +0,0 @@
-//! Plain Old Data types for range proofs.
-
-#[cfg(not(target_os = "solana"))]
-use crate::{
-    range_proof::{errors::RangeProofVerificationError, RangeProof},
-    UNIT_LEN,
-};
-use {
-    crate::{
-        pod::{impl_from_bytes, impl_from_str},
-        range_proof::*,
-    },
-    base64::{prelude::BASE64_STANDARD, Engine},
-    bytemuck::{Pod, Zeroable},
-    std::fmt,
-};
-
-/// The `RangeProof` type as a `Pod` restricted to proofs on 64-bit numbers.
-#[derive(Clone, Copy)]
-#[repr(transparent)]
-pub struct PodRangeProofU64(pub(crate) [u8; RANGE_PROOF_U64_LEN]);
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<RangeProof> for PodRangeProofU64 {
-    type Error = RangeProofVerificationError;
-
-    fn try_from(decoded_proof: RangeProof) -> Result<Self, Self::Error> {
-        if decoded_proof.ipp_proof.serialized_size() != INNER_PRODUCT_PROOF_U64_LEN {
-            return Err(RangeProofVerificationError::Deserialization);
-        }
-
-        let mut buf = [0_u8; RANGE_PROOF_U64_LEN];
-        copy_range_proof_modulo_inner_product_proof(&decoded_proof, &mut buf);
-        buf[RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN..RANGE_PROOF_U64_LEN]
-            .copy_from_slice(&decoded_proof.ipp_proof.to_bytes());
-        Ok(PodRangeProofU64(buf))
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodRangeProofU64> for RangeProof {
-    type Error = RangeProofVerificationError;
-
-    fn try_from(pod_proof: PodRangeProofU64) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_proof.0)
-    }
-}
-
-const RANGE_PROOF_U64_MAX_BASE64_LEN: usize = 896;
-
-impl fmt::Display for PodRangeProofU64 {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodRangeProofU64,
-    BYTES_LEN = RANGE_PROOF_U64_LEN,
-    BASE64_LEN = RANGE_PROOF_U64_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(TYPE = PodRangeProofU64, BYTES_LEN = RANGE_PROOF_U64_LEN);
-
-/// The `RangeProof` type as a `Pod` restricted to proofs on 128-bit numbers.
-#[derive(Clone, Copy)]
-#[repr(transparent)]
-pub struct PodRangeProofU128(pub(crate) [u8; RANGE_PROOF_U128_LEN]);
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<RangeProof> for PodRangeProofU128 {
-    type Error = RangeProofVerificationError;
-
-    fn try_from(decoded_proof: RangeProof) -> Result<Self, Self::Error> {
-        if decoded_proof.ipp_proof.serialized_size() != INNER_PRODUCT_PROOF_U128_LEN {
-            return Err(RangeProofVerificationError::Deserialization);
-        }
-
-        let mut buf = [0_u8; RANGE_PROOF_U128_LEN];
-        copy_range_proof_modulo_inner_product_proof(&decoded_proof, &mut buf);
-        buf[RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN..RANGE_PROOF_U128_LEN]
-            .copy_from_slice(&decoded_proof.ipp_proof.to_bytes());
-        Ok(PodRangeProofU128(buf))
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodRangeProofU128> for RangeProof {
-    type Error = RangeProofVerificationError;
-
-    fn try_from(pod_proof: PodRangeProofU128) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_proof.0)
-    }
-}
-
-const RANGE_PROOF_U128_MAX_BASE64_LEN: usize = 984;
-
-impl fmt::Display for PodRangeProofU128 {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodRangeProofU128,
-    BYTES_LEN = RANGE_PROOF_U128_LEN,
-    BASE64_LEN = RANGE_PROOF_U128_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(TYPE = PodRangeProofU128, BYTES_LEN = RANGE_PROOF_U128_LEN);
-
-/// The `RangeProof` type as a `Pod` restricted to proofs on 256-bit numbers.
-#[derive(Clone, Copy)]
-#[repr(transparent)]
-pub struct PodRangeProofU256(pub(crate) [u8; RANGE_PROOF_U256_LEN]);
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<RangeProof> for PodRangeProofU256 {
-    type Error = RangeProofVerificationError;
-
-    fn try_from(decoded_proof: RangeProof) -> Result<Self, Self::Error> {
-        if decoded_proof.ipp_proof.serialized_size() != INNER_PRODUCT_PROOF_U256_LEN {
-            return Err(RangeProofVerificationError::Deserialization);
-        }
-
-        let mut buf = [0_u8; RANGE_PROOF_U256_LEN];
-        copy_range_proof_modulo_inner_product_proof(&decoded_proof, &mut buf);
-        buf[RANGE_PROOF_MODULO_INNER_PRODUCT_PROOF_LEN..RANGE_PROOF_U256_LEN]
-            .copy_from_slice(&decoded_proof.ipp_proof.to_bytes());
-        Ok(PodRangeProofU256(buf))
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodRangeProofU256> for RangeProof {
-    type Error = RangeProofVerificationError;
-
-    fn try_from(pod_proof: PodRangeProofU256) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_proof.0)
-    }
-}
-
-const RANGE_PROOF_U256_MAX_BASE64_LEN: usize = 1068;
-
-impl fmt::Display for PodRangeProofU256 {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodRangeProofU256,
-    BYTES_LEN = RANGE_PROOF_U256_LEN,
-    BASE64_LEN = RANGE_PROOF_U256_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(TYPE = PodRangeProofU256, BYTES_LEN = RANGE_PROOF_U256_LEN);
-
-#[cfg(not(target_os = "solana"))]
-fn copy_range_proof_modulo_inner_product_proof(proof: &RangeProof, buf: &mut [u8]) {
-    let mut chunks = buf.chunks_mut(UNIT_LEN);
-    chunks.next().unwrap().copy_from_slice(proof.A.as_bytes());
-    chunks.next().unwrap().copy_from_slice(proof.S.as_bytes());
-    chunks.next().unwrap().copy_from_slice(proof.T_1.as_bytes());
-    chunks.next().unwrap().copy_from_slice(proof.T_2.as_bytes());
-    chunks.next().unwrap().copy_from_slice(proof.t_x.as_bytes());
-    chunks
-        .next()
-        .unwrap()
-        .copy_from_slice(proof.t_x_blinding.as_bytes());
-    chunks
-        .next()
-        .unwrap()
-        .copy_from_slice(proof.e_blinding.as_bytes());
-}
-
-// The range proof pod types are wrappers for byte arrays, which are both `Pod` and `Zeroable`. However,
-// the marker traits `bytemuck::Pod` and `bytemuck::Zeroable` can only be derived for power-of-two
-// length byte arrays. Directly implement these traits for the range proof pod types.
-unsafe impl Zeroable for PodRangeProofU64 {}
-unsafe impl Pod for PodRangeProofU64 {}
-
-unsafe impl Zeroable for PodRangeProofU128 {}
-unsafe impl Pod for PodRangeProofU128 {}
-
-unsafe impl Zeroable for PodRangeProofU256 {}
-unsafe impl Pod for PodRangeProofU256 {}

+ 0 - 139
zk-sdk/src/range_proof/util.rs

@@ -1,139 +0,0 @@
-/// Utility functions for Bulletproofs.
-///
-/// The code is adapted from the `utility` module in the dalek bulletproof implementation
-/// https://github.com/dalek-cryptography/bulletproofs.
-use curve25519_dalek::scalar::Scalar;
-
-/// Represents a degree-1 vector polynomial \\(\mathbf{a} + \mathbf{b} \cdot x\\).
-pub struct VecPoly1(pub Vec<Scalar>, pub Vec<Scalar>);
-
-impl VecPoly1 {
-    pub fn zero(n: usize) -> Self {
-        VecPoly1(vec![Scalar::ZERO; n], vec![Scalar::ZERO; n])
-    }
-
-    pub fn inner_product(&self, rhs: &VecPoly1) -> Option<Poly2> {
-        // Uses Karatsuba's method
-        let l = self;
-        let r = rhs;
-
-        let t0 = inner_product(&l.0, &r.0)?;
-        let t2 = inner_product(&l.1, &r.1)?;
-
-        let l0_plus_l1 = add_vec(&l.0, &l.1);
-        let r0_plus_r1 = add_vec(&r.0, &r.1);
-
-        let t1 = inner_product(&l0_plus_l1, &r0_plus_r1)? - t0 - t2;
-
-        Some(Poly2(t0, t1, t2))
-    }
-
-    pub fn eval(&self, x: Scalar) -> Vec<Scalar> {
-        let n = self.0.len();
-        let mut out = vec![Scalar::ZERO; n];
-        #[allow(clippy::needless_range_loop)]
-        for i in 0..n {
-            out[i] = self.0[i] + self.1[i] * x;
-        }
-        out
-    }
-}
-
-/// Represents a degree-2 scalar polynomial \\(a + b \cdot x + c \cdot x^2\\)
-pub struct Poly2(pub Scalar, pub Scalar, pub Scalar);
-
-impl Poly2 {
-    pub fn eval(&self, x: Scalar) -> Scalar {
-        self.0 + x * (self.1 + x * self.2)
-    }
-}
-
-/// Provides an iterator over the powers of a `Scalar`.
-///
-/// This struct is created by the `exp_iter` function.
-pub struct ScalarExp {
-    x: Scalar,
-    next_exp_x: Scalar,
-}
-
-impl Iterator for ScalarExp {
-    type Item = Scalar;
-
-    fn next(&mut self) -> Option<Scalar> {
-        let exp_x = self.next_exp_x;
-        self.next_exp_x *= self.x;
-        Some(exp_x)
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        (usize::MAX, None)
-    }
-}
-
-/// Return an iterator of the powers of `x`.
-pub fn exp_iter(x: Scalar) -> ScalarExp {
-    let next_exp_x = Scalar::ONE;
-    ScalarExp { x, next_exp_x }
-}
-
-pub fn add_vec(a: &[Scalar], b: &[Scalar]) -> Vec<Scalar> {
-    if a.len() != b.len() {
-        // throw some error
-        //println!("lengths of vectors don't match for vector addition");
-    }
-    let mut out = vec![Scalar::ZERO; b.len()];
-    for i in 0..a.len() {
-        out[i] = a[i] + b[i];
-    }
-    out
-}
-
-/// Given `data` with `len >= 32`, return the first 32 bytes.
-pub fn read32(data: &[u8]) -> [u8; 32] {
-    let mut buf32 = [0u8; 32];
-    buf32[..].copy_from_slice(&data[..32]);
-    buf32
-}
-
-/// Computes an inner product of two vectors
-/// \\[
-///    {\langle {\mathbf{a}}, {\mathbf{b}} \rangle} = \sum\_{i=0}^{n-1} a\_i \cdot b\_i.
-/// \\]
-/// Errors if the lengths of \\(\mathbf{a}\\) and \\(\mathbf{b}\\) are not equal.
-pub fn inner_product(a: &[Scalar], b: &[Scalar]) -> Option<Scalar> {
-    let mut out = Scalar::ZERO;
-    if a.len() != b.len() {
-        return None;
-    }
-    for i in 0..a.len() {
-        out += a[i] * b[i];
-    }
-    Some(out)
-}
-
-/// Takes the sum of all the powers of `x`, up to `n`
-/// If `n` is a power of 2, it uses the efficient algorithm with `2*lg n` multiplications and additions.
-/// If `n` is not a power of 2, it uses the slow algorithm with `n` multiplications and additions.
-/// In the Bulletproofs case, all calls to `sum_of_powers` should have `n` as a power of 2.
-pub fn sum_of_powers(x: &Scalar, n: usize) -> Scalar {
-    if !n.is_power_of_two() {
-        return sum_of_powers_slow(x, n);
-    }
-    if n == 0 || n == 1 {
-        return Scalar::from(n as u64);
-    }
-    let mut m = n;
-    let mut result = Scalar::ONE + x;
-    let mut factor = *x;
-    while m > 2 {
-        factor = factor * factor;
-        result = result + factor * result;
-        m /= 2;
-    }
-    result
-}
-
-// takes the sum of all of the powers of x, up to n
-fn sum_of_powers_slow(x: &Scalar, n: usize) -> Scalar {
-    exp_iter(*x).take(n).sum()
-}

+ 0 - 246
zk-sdk/src/sigma_proofs/batched_grouped_ciphertext_validity/handles_2.rs

@@ -1,246 +0,0 @@
-//! The ciphertext validity sigma proof system.
-//!
-//! The ciphertext validity proof is defined with respect to a Pedersen commitment and two
-//! decryption handles. The proof certifies that a given Pedersen commitment can be decrypted using
-//! ElGamal private keys that are associated with each of the two decryption handles. To generate
-//! the proof, a prover must provide the Pedersen opening associated with the commitment.
-//!
-//! The protocol guarantees computational soundness (by the hardness of discrete log) and perfect
-//! zero-knowledge in the random oracle model.
-
-#[cfg(not(target_os = "solana"))]
-use crate::encryption::{
-    elgamal::{DecryptHandle, ElGamalPubkey},
-    pedersen::{PedersenCommitment, PedersenOpening},
-};
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-use {
-    crate::{
-        sigma_proofs::{
-            errors::ValidityProofVerificationError,
-            grouped_ciphertext_validity::GroupedCiphertext2HandlesValidityProof,
-        },
-        transcript::TranscriptProtocol,
-    },
-    curve25519_dalek::scalar::Scalar,
-    merlin::Transcript,
-};
-
-/// Batched grouped ciphertext validity proof with two handles.
-///
-/// A batched grouped ciphertext validity proof certifies the validity of two instances of a
-/// standard ciphertext validity proof. An instance of a standard validity proof consists of one
-/// ciphertext and two decryption handles: `(commitment, first_handle, second_handle)`. An
-/// instance of a batched ciphertext validity proof is a pair `(commitment_0,
-/// first_handle_0, second_handle_0)` and `(commitment_1, first_handle_1,
-/// second_handle_1)`. The proof certifies the analogous decryptable properties for each one of
-/// these pairs of commitment and decryption handles.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[allow(non_snake_case)]
-#[derive(Clone)]
-pub struct BatchedGroupedCiphertext2HandlesValidityProof(GroupedCiphertext2HandlesValidityProof);
-
-#[allow(non_snake_case)]
-#[cfg(not(target_os = "solana"))]
-impl BatchedGroupedCiphertext2HandlesValidityProof {
-    /// Creates a batched grouped ciphertext validity proof.
-    ///
-    /// The function simply batches the input openings and invokes the standard grouped ciphertext
-    /// validity proof constructor.
-    ///
-    /// This function is randomized. It uses `OsRng` internally to generate random scalars.
-    pub fn new<T: Into<Scalar>>(
-        first_pubkey: &ElGamalPubkey,
-        second_pubkey: &ElGamalPubkey,
-        amount_lo: T,
-        amount_hi: T,
-        opening_lo: &PedersenOpening,
-        opening_hi: &PedersenOpening,
-        transcript: &mut Transcript,
-    ) -> Self {
-        transcript.batched_grouped_ciphertext_validity_proof_domain_separator(2);
-
-        let t = transcript.challenge_scalar(b"t");
-
-        let batched_message = amount_lo.into() + amount_hi.into() * t;
-        let batched_opening = opening_lo + &(opening_hi * &t);
-
-        BatchedGroupedCiphertext2HandlesValidityProof(GroupedCiphertext2HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            batched_message,
-            &batched_opening,
-            transcript,
-        ))
-    }
-
-    /// Verifies a batched grouped ciphertext validity proof.
-    ///
-    /// The function does *not* hash the public keys, commitment, or decryption handles into the
-    /// transcript. For security, the caller (the main protocol) should hash these public
-    /// components prior to invoking this constructor.
-    #[allow(clippy::too_many_arguments)]
-    pub fn verify(
-        self,
-        first_pubkey: &ElGamalPubkey,
-        second_pubkey: &ElGamalPubkey,
-        commitment_lo: &PedersenCommitment,
-        commitment_hi: &PedersenCommitment,
-        first_handle_lo: &DecryptHandle,
-        first_handle_hi: &DecryptHandle,
-        second_handle_lo: &DecryptHandle,
-        second_handle_hi: &DecryptHandle,
-        transcript: &mut Transcript,
-    ) -> Result<(), ValidityProofVerificationError> {
-        transcript.batched_grouped_ciphertext_validity_proof_domain_separator(2);
-
-        let t = transcript.challenge_scalar(b"t");
-
-        let batched_commitment = commitment_lo + commitment_hi * t;
-        let first_batched_handle = first_handle_lo + first_handle_hi * t;
-        let second_batched_handle = second_handle_lo + second_handle_hi * t;
-
-        let BatchedGroupedCiphertext2HandlesValidityProof(validity_proof) = self;
-
-        validity_proof.verify(
-            &batched_commitment,
-            first_pubkey,
-            second_pubkey,
-            &first_batched_handle,
-            &second_batched_handle,
-            transcript,
-        )
-    }
-
-    pub fn to_bytes(&self) -> [u8; 160] {
-        self.0.to_bytes()
-    }
-
-    pub fn from_bytes(bytes: &[u8]) -> Result<Self, ValidityProofVerificationError> {
-        GroupedCiphertext2HandlesValidityProof::from_bytes(bytes).map(Self)
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use {
-        super::*,
-        crate::{
-            encryption::{
-                elgamal::ElGamalKeypair,
-                pedersen::Pedersen,
-                pod::{
-                    elgamal::{PodDecryptHandle, PodElGamalPubkey},
-                    pedersen::PodPedersenCommitment,
-                },
-            },
-            sigma_proofs::pod::PodBatchedGroupedCiphertext2HandlesValidityProof,
-        },
-        std::str::FromStr,
-    };
-
-    #[test]
-    fn test_batched_grouped_ciphertext_2_handles_validity_proof() {
-        let first_keypair = ElGamalKeypair::new_rand();
-        let first_pubkey = first_keypair.pubkey();
-
-        let second_keypair = ElGamalKeypair::new_rand();
-        let second_pubkey = second_keypair.pubkey();
-
-        let amount_lo: u64 = 55;
-        let amount_hi: u64 = 77;
-
-        let (commitment_lo, open_lo) = Pedersen::new(amount_lo);
-        let (commitment_hi, open_hi) = Pedersen::new(amount_hi);
-
-        let first_handle_lo = first_pubkey.decrypt_handle(&open_lo);
-        let first_handle_hi = first_pubkey.decrypt_handle(&open_hi);
-
-        let second_handle_lo = second_pubkey.decrypt_handle(&open_lo);
-        let second_handle_hi = second_pubkey.decrypt_handle(&open_hi);
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = BatchedGroupedCiphertext2HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            amount_lo,
-            amount_hi,
-            &open_lo,
-            &open_hi,
-            &mut prover_transcript,
-        );
-
-        proof
-            .verify(
-                first_pubkey,
-                second_pubkey,
-                &commitment_lo,
-                &commitment_hi,
-                &first_handle_lo,
-                &first_handle_hi,
-                &second_handle_lo,
-                &second_handle_hi,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-    }
-
-    #[test]
-    fn test_batched_grouped_ciphertext_2_handles_validity_proof_string() {
-        let first_pubkey_str = "3FQGicS6AgVkRnX5Sau8ybxJDvlehmbdvBUdo+o+oE4=";
-        let pod_first_pubkey = PodElGamalPubkey::from_str(first_pubkey_str).unwrap();
-        let first_pubkey: ElGamalPubkey = pod_first_pubkey.try_into().unwrap();
-
-        let second_pubkey_str = "IieU/fJCRksbDNvIJZvg/N/safpnIWAGT/xpUAG7YUg=";
-        let pod_second_pubkey = PodElGamalPubkey::from_str(second_pubkey_str).unwrap();
-        let second_pubkey: ElGamalPubkey = pod_second_pubkey.try_into().unwrap();
-
-        let commitment_lo_str = "Lq0z7bx3ccyxIB0rRHoWzcba8W1azvAhMfnJogxcz2I=";
-        let pod_commitment_lo = PodPedersenCommitment::from_str(commitment_lo_str).unwrap();
-        let commitment_lo: PedersenCommitment = pod_commitment_lo.try_into().unwrap();
-
-        let commitment_hi_str = "dLPLdQrcl5ZWb0EaJcmebAlJA6RrzKpMSYPDVMJdOm0=";
-        let pod_commitment_hi = PodPedersenCommitment::from_str(commitment_hi_str).unwrap();
-        let commitment_hi: PedersenCommitment = pod_commitment_hi.try_into().unwrap();
-
-        let first_handle_lo_str = "GizvHRUmu6CMjhH7qWg5Rqu43V69Nyjq4QsN/yXBHT8=";
-        let pod_first_handle_lo_str = PodDecryptHandle::from_str(first_handle_lo_str).unwrap();
-        let first_handle_lo: DecryptHandle = pod_first_handle_lo_str.try_into().unwrap();
-
-        let first_handle_hi_str = "qMuR929bbkKiVJfRvYxnb90rbh2btjNDjaXpeLCvQWk=";
-        let pod_first_handle_hi_str = PodDecryptHandle::from_str(first_handle_hi_str).unwrap();
-        let first_handle_hi: DecryptHandle = pod_first_handle_hi_str.try_into().unwrap();
-
-        let second_handle_lo_str = "MmDbMo2l/jAcXUIm09AQZsBXa93lI2BapAiGZ6f9zRs=";
-        let pod_second_handle_lo_str = PodDecryptHandle::from_str(second_handle_lo_str).unwrap();
-        let second_handle_lo: DecryptHandle = pod_second_handle_lo_str.try_into().unwrap();
-
-        let second_handle_hi_str = "gKhb0o3d22XcUcQl5hENF4l1SJwg1vpgiw2RDYqXOxY=";
-        let pod_second_handle_hi_str = PodDecryptHandle::from_str(second_handle_hi_str).unwrap();
-        let second_handle_hi: DecryptHandle = pod_second_handle_hi_str.try_into().unwrap();
-
-        let proof_str = "2n2mADpkNrop+eHJj1sAryXWcTtC/7QKcxMp7FdHeh8wjGKLAa9kC89QLGrphv7pZdb2J25kKXqhWUzRBsJWU0izi5vxau9XX6cyd72F3Q9hMXBfjk3htOHI0VnGAalZ/3dZ6C7erjGQDoeTVGOd1vewQ+NObAbfZwcry3+VhQNpkhL17E1dUgZZ+mb5K0tXAjWCmVh1OfN9h3sGltTUCg==";
-        let pod_proof =
-            PodBatchedGroupedCiphertext2HandlesValidityProof::from_str(proof_str).unwrap();
-        let proof: BatchedGroupedCiphertext2HandlesValidityProof = pod_proof.try_into().unwrap();
-
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        proof
-            .verify(
-                &first_pubkey,
-                &second_pubkey,
-                &commitment_lo,
-                &commitment_hi,
-                &first_handle_lo,
-                &first_handle_hi,
-                &second_handle_lo,
-                &second_handle_hi,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-    }
-}

+ 0 - 281
zk-sdk/src/sigma_proofs/batched_grouped_ciphertext_validity/handles_3.rs

@@ -1,281 +0,0 @@
-//! The batched ciphertext with 3 handles validity sigma proof system.
-//!
-//! A batched grouped ciphertext validity proof certifies the validity of two instances of a
-//! standard grouped ciphertext validity proof. An instance of a standard grouped ciphertext
-//! with 3 handles validity proof consists of one ciphertext and three decryption handles:
-//! `(commitment, first_handle, second_handle, third_handle)`. An instance of a batched
-//! grouped ciphertext with 3 handles validity proof consist of a pair of `(commitment_0,
-//! first_handle_0, second_handle_0, third_handle_0)` and `(commitment_1, first_handle_1,
-//! second_handle_1, third_handle_1)`. The proof certifies the anagolous decryptable
-//! properties for each one of these pairs of commitment and decryption handles.
-//!
-//! The protocol guarantees computational soundness (by the hardness of discrete log) and perfect
-//! zero-knowledge in the random oracle model.
-
-#[cfg(not(target_os = "solana"))]
-use crate::encryption::{
-    elgamal::{DecryptHandle, ElGamalPubkey},
-    pedersen::{PedersenCommitment, PedersenOpening},
-};
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-use {
-    crate::{
-        sigma_proofs::{
-            errors::ValidityProofVerificationError,
-            grouped_ciphertext_validity::GroupedCiphertext3HandlesValidityProof,
-        },
-        transcript::TranscriptProtocol,
-        UNIT_LEN,
-    },
-    curve25519_dalek::scalar::Scalar,
-    merlin::Transcript,
-};
-
-/// Byte length of a batched grouped ciphertext validity proof for 3 handles
-#[allow(dead_code)]
-const BATCHED_GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_LEN: usize = UNIT_LEN * 6;
-
-/// Batched grouped ciphertext validity proof with two handles.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[allow(non_snake_case)]
-#[derive(Clone)]
-pub struct BatchedGroupedCiphertext3HandlesValidityProof(GroupedCiphertext3HandlesValidityProof);
-
-#[allow(non_snake_case)]
-#[allow(dead_code)]
-#[cfg(not(target_os = "solana"))]
-impl BatchedGroupedCiphertext3HandlesValidityProof {
-    /// Creates a batched grouped ciphertext validity proof.
-    ///
-    /// The function simply batches the input openings and invokes the standard grouped ciphertext
-    /// validity proof constructor.
-    pub fn new<T: Into<Scalar>>(
-        first_pubkey: &ElGamalPubkey,
-        second_pubkey: &ElGamalPubkey,
-        third_pubkey: &ElGamalPubkey,
-        amount_lo: T,
-        amount_hi: T,
-        opening_lo: &PedersenOpening,
-        opening_hi: &PedersenOpening,
-        transcript: &mut Transcript,
-    ) -> Self {
-        transcript.batched_grouped_ciphertext_validity_proof_domain_separator(3);
-
-        let t = transcript.challenge_scalar(b"t");
-
-        let batched_message = amount_lo.into() + amount_hi.into() * t;
-        let batched_opening = opening_lo + &(opening_hi * &t);
-
-        BatchedGroupedCiphertext3HandlesValidityProof(GroupedCiphertext3HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            third_pubkey,
-            batched_message,
-            &batched_opening,
-            transcript,
-        ))
-    }
-
-    /// Verifies a batched grouped ciphertext validity proof.
-    ///
-    /// The function does *not* hash the public keys, commitment, or decryption handles into the
-    /// transcript. For security, the caller (the main protocol) should hash these public
-    /// components prior to invoking this constructor.
-    ///
-    /// This function is randomized. It uses `OsRng` internally to generate random scalars.
-    #[allow(clippy::too_many_arguments)]
-    pub fn verify(
-        self,
-        first_pubkey: &ElGamalPubkey,
-        second_pubkey: &ElGamalPubkey,
-        third_pubkey: &ElGamalPubkey,
-        commitment_lo: &PedersenCommitment,
-        commitment_hi: &PedersenCommitment,
-        first_handle_lo: &DecryptHandle,
-        first_handle_hi: &DecryptHandle,
-        second_handle_lo: &DecryptHandle,
-        second_handle_hi: &DecryptHandle,
-        third_handle_lo: &DecryptHandle,
-        third_handle_hi: &DecryptHandle,
-        transcript: &mut Transcript,
-    ) -> Result<(), ValidityProofVerificationError> {
-        transcript.batched_grouped_ciphertext_validity_proof_domain_separator(3);
-
-        let t = transcript.challenge_scalar(b"t");
-
-        let batched_commitment = commitment_lo + commitment_hi * t;
-        let first_batched_handle = first_handle_lo + first_handle_hi * t;
-        let second_batched_handle = second_handle_lo + second_handle_hi * t;
-        let third_batched_handle = third_handle_lo + third_handle_hi * t;
-
-        let BatchedGroupedCiphertext3HandlesValidityProof(validity_proof) = self;
-
-        validity_proof.verify(
-            &batched_commitment,
-            first_pubkey,
-            second_pubkey,
-            third_pubkey,
-            &first_batched_handle,
-            &second_batched_handle,
-            &third_batched_handle,
-            transcript,
-        )
-    }
-
-    pub fn to_bytes(&self) -> [u8; BATCHED_GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_LEN] {
-        self.0.to_bytes()
-    }
-
-    pub fn from_bytes(bytes: &[u8]) -> Result<Self, ValidityProofVerificationError> {
-        GroupedCiphertext3HandlesValidityProof::from_bytes(bytes).map(Self)
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use {
-        super::*,
-        crate::{
-            encryption::{
-                elgamal::ElGamalKeypair,
-                pedersen::Pedersen,
-                pod::{
-                    elgamal::{PodDecryptHandle, PodElGamalPubkey},
-                    pedersen::PodPedersenCommitment,
-                },
-            },
-            sigma_proofs::pod::PodBatchedGroupedCiphertext3HandlesValidityProof,
-        },
-        std::str::FromStr,
-    };
-
-    #[test]
-    fn test_batched_grouped_ciphertext_3_handles_validity_proof() {
-        let first_keypair = ElGamalKeypair::new_rand();
-        let first_pubkey = first_keypair.pubkey();
-
-        let second_keyapir = ElGamalKeypair::new_rand();
-        let second_pubkey = second_keyapir.pubkey();
-
-        let third_keypair = ElGamalKeypair::new_rand();
-        let third_pubkey = third_keypair.pubkey();
-
-        let amount_lo: u64 = 55;
-        let amount_hi: u64 = 77;
-
-        let (commitment_lo, open_lo) = Pedersen::new(amount_lo);
-        let (commitment_hi, open_hi) = Pedersen::new(amount_hi);
-
-        let first_handle_lo = first_pubkey.decrypt_handle(&open_lo);
-        let first_handle_hi = first_pubkey.decrypt_handle(&open_hi);
-
-        let second_handle_lo = second_pubkey.decrypt_handle(&open_lo);
-        let second_handle_hi = second_pubkey.decrypt_handle(&open_hi);
-
-        let third_handle_lo = third_pubkey.decrypt_handle(&open_lo);
-        let third_handle_hi = third_pubkey.decrypt_handle(&open_hi);
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = BatchedGroupedCiphertext3HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            third_pubkey,
-            amount_lo,
-            amount_hi,
-            &open_lo,
-            &open_hi,
-            &mut prover_transcript,
-        );
-
-        proof
-            .verify(
-                first_pubkey,
-                second_pubkey,
-                third_pubkey,
-                &commitment_lo,
-                &commitment_hi,
-                &first_handle_lo,
-                &first_handle_hi,
-                &second_handle_lo,
-                &second_handle_hi,
-                &third_handle_lo,
-                &third_handle_hi,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-    }
-
-    #[test]
-    fn test_batched_grouped_ciphertext_3_handles_validity_proof_string() {
-        let first_pubkey_str = "PFQ4AD4W/Y4BEg3nI/qckFLhnjMQ12xPHyaMg9Bkg3w=";
-        let pod_first_pubkey = PodElGamalPubkey::from_str(first_pubkey_str).unwrap();
-        let first_pubkey: ElGamalPubkey = pod_first_pubkey.try_into().unwrap();
-
-        let second_pubkey_str = "2CZ4h5oK7zh4/3P6s/kCQoNlpUPk1IrsrAtTWjCtfFo=";
-        let pod_second_pubkey = PodElGamalPubkey::from_str(second_pubkey_str).unwrap();
-        let second_pubkey: ElGamalPubkey = pod_second_pubkey.try_into().unwrap();
-
-        let third_pubkey_str = "yonKhqkoXNvMbN/tU6fjHFhfZuNPpvMj8L55aP2bBG4=";
-        let pod_third_pubkey = PodElGamalPubkey::from_str(third_pubkey_str).unwrap();
-        let third_pubkey: ElGamalPubkey = pod_third_pubkey.try_into().unwrap();
-
-        let commitment_lo_str = "atIteiveexponnuF2Z1nbovZYYtcGWjglpEA3caMShM=";
-        let pod_commitment_lo = PodPedersenCommitment::from_str(commitment_lo_str).unwrap();
-        let commitment_lo: PedersenCommitment = pod_commitment_lo.try_into().unwrap();
-
-        let commitment_hi_str = "IoZlSj7spae2ogiAUiEuuwAjYA5khgBH8FhaHzkh+lc=";
-        let pod_commitment_hi = PodPedersenCommitment::from_str(commitment_hi_str).unwrap();
-        let commitment_hi: PedersenCommitment = pod_commitment_hi.try_into().unwrap();
-
-        let first_handle_lo_str = "6PlKiitdapVZnh7VccQNbskXop9nmITGppLsV42UMkU=";
-        let pod_first_handle_lo_str = PodDecryptHandle::from_str(first_handle_lo_str).unwrap();
-        let first_handle_lo: DecryptHandle = pod_first_handle_lo_str.try_into().unwrap();
-
-        let first_handle_hi_str = "vF+oZ3WWnrJyJ95Wl8EW+aVJiFmruiuRw6+TT3QVMBI=";
-        let pod_first_handle_hi_str = PodDecryptHandle::from_str(first_handle_hi_str).unwrap();
-        let first_handle_hi: DecryptHandle = pod_first_handle_hi_str.try_into().unwrap();
-
-        let second_handle_lo_str = "rvxzo5ZyrD6YTm7X3GjplgOGJjx6PtoZ+DKbL4LsQWA=";
-        let pod_second_handle_lo_str = PodDecryptHandle::from_str(second_handle_lo_str).unwrap();
-        let second_handle_lo: DecryptHandle = pod_second_handle_lo_str.try_into().unwrap();
-
-        let second_handle_hi_str = "0mdZSGiWQhOjqsExqFMD8hfgUlRRRrF/G3CJ7d0LEEk=";
-        let pod_second_handle_hi_str = PodDecryptHandle::from_str(second_handle_hi_str).unwrap();
-        let second_handle_hi: DecryptHandle = pod_second_handle_hi_str.try_into().unwrap();
-
-        let third_handle_lo_str = "bpT2LuFektFhI/sacjSsqNtCsO8ac5qn0jWeMeQq4WM=";
-        let pod_third_handle_lo_str = PodDecryptHandle::from_str(third_handle_lo_str).unwrap();
-        let third_handle_lo: DecryptHandle = pod_third_handle_lo_str.try_into().unwrap();
-
-        let third_handle_hi_str = "OE8z7Bbv2AHnjxebK6ASJfkJbOlYQdnN6ZPkG2u4SnA=";
-        let pod_third_handle_hi_str = PodDecryptHandle::from_str(third_handle_hi_str).unwrap();
-        let third_handle_hi: DecryptHandle = pod_third_handle_hi_str.try_into().unwrap();
-
-        let proof_str = "GkjZ7QKcJq5X/OU8wb26wZ7p2D9thVK+Cb11CzRjWUoihYvGfuCbVG1vr4qtnfx65SS4jVK1H0q/948A9wy8ZPTrOZJA122G4+cpt5mKnSrKq/vbv4ZRha0oR9RGJFZ2SPT3gx2jysKDKRAQgBLOzSGfQg9Hsbz57i55SQfliUF5mByZKuzGKHSIHi81BDqbrFAj6x5bOeMAaLqsCboCA5XGDUZ2HMPUGuAd9F+OaVH+eJZnuoDjwwcBQ2eANgMB";
-        let pod_proof =
-            PodBatchedGroupedCiphertext3HandlesValidityProof::from_str(proof_str).unwrap();
-        let proof: BatchedGroupedCiphertext3HandlesValidityProof = pod_proof.try_into().unwrap();
-
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        proof
-            .verify(
-                &first_pubkey,
-                &second_pubkey,
-                &third_pubkey,
-                &commitment_lo,
-                &commitment_hi,
-                &first_handle_lo,
-                &first_handle_hi,
-                &second_handle_lo,
-                &second_handle_hi,
-                &third_handle_lo,
-                &third_handle_hi,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-    }
-}

+ 0 - 7
zk-sdk/src/sigma_proofs/batched_grouped_ciphertext_validity/mod.rs

@@ -1,7 +0,0 @@
-mod handles_2;
-mod handles_3;
-
-pub use {
-    handles_2::BatchedGroupedCiphertext2HandlesValidityProof,
-    handles_3::BatchedGroupedCiphertext3HandlesValidityProof,
-};

+ 0 - 389
zk-sdk/src/sigma_proofs/ciphertext_ciphertext_equality.rs

@@ -1,389 +0,0 @@
-//! The ciphertext-ciphertext equality sigma proof system.
-//!
-//! The protocol guarantees computational soundness (by the hardness of discrete log) and perfect
-//! zero-knowledge in the random oracle model.
-
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::{
-            elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey},
-            pedersen::{PedersenOpening, G, H},
-        },
-        sigma_proofs::{canonical_scalar_from_optional_slice, ristretto_point_from_optional_slice},
-        UNIT_LEN,
-    },
-    curve25519_dalek::traits::MultiscalarMul,
-    rand::rngs::OsRng,
-    zeroize::Zeroize,
-};
-use {
-    crate::{
-        sigma_proofs::errors::{EqualityProofVerificationError, SigmaProofVerificationError},
-        transcript::TranscriptProtocol,
-    },
-    curve25519_dalek::{
-        ristretto::{CompressedRistretto, RistrettoPoint},
-        scalar::Scalar,
-        traits::{IsIdentity, VartimeMultiscalarMul},
-    },
-    merlin::Transcript,
-};
-
-/// Byte length of a ciphertext-ciphertext equality proof.
-const CIPHERTEXT_CIPHERTEXT_EQUALITY_PROOF_LEN: usize = UNIT_LEN * 7;
-
-/// The ciphertext-ciphertext equality proof.
-///
-/// Contains all the elliptic curve and scalar components that make up the sigma protocol.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[allow(non_snake_case)]
-#[derive(Clone)]
-pub struct CiphertextCiphertextEqualityProof {
-    Y_0: CompressedRistretto,
-    Y_1: CompressedRistretto,
-    Y_2: CompressedRistretto,
-    Y_3: CompressedRistretto,
-    z_s: Scalar,
-    z_x: Scalar,
-    z_r: Scalar,
-}
-
-#[allow(non_snake_case)]
-#[cfg(not(target_os = "solana"))]
-impl CiphertextCiphertextEqualityProof {
-    /// Creates a ciphertext-ciphertext equality proof.
-    ///
-    /// The function does *not* hash the public keys, first ciphertext, or second ciphertext into the transcript.
-    /// For security, the caller (the main protocol) should hash these public components prior to
-    /// invoking this constructor.
-    ///
-    /// This function is randomized. It uses `OsRng` internally to generate random scalars.
-    ///
-    /// * `first_keypair` - The ElGamal keypair associated with the first ciphertext to be proved
-    /// * `second_pubkey` - The ElGamal pubkey associated with the second ElGamal ciphertext
-    /// * `first_ciphertext` - The first ElGamal ciphertext for which the prover knows a
-    ///   decryption key for
-    /// * `second_opening` - The opening (randomness) associated with the second ElGamal ciphertext
-    /// * `amount` - The message associated with the ElGamal ciphertext and Pedersen commitment
-    /// * `transcript` - The transcript that does the bookkeeping for the Fiat-Shamir heuristic
-    pub fn new(
-        first_keypair: &ElGamalKeypair,
-        second_pubkey: &ElGamalPubkey,
-        first_ciphertext: &ElGamalCiphertext,
-        second_opening: &PedersenOpening,
-        amount: u64,
-        transcript: &mut Transcript,
-    ) -> Self {
-        transcript.ciphertext_ciphertext_equality_proof_domain_separator();
-
-        // extract the relevant scalar and Ristretto points from the inputs
-        let P_first = first_keypair.pubkey().get_point();
-        let D_first = first_ciphertext.handle.get_point();
-        let P_second = second_pubkey.get_point();
-
-        let s = first_keypair.secret().get_scalar();
-        let x = Scalar::from(amount);
-        let r = second_opening.get_scalar();
-
-        // generate random masking factors that also serves as nonces
-        let mut y_s = Scalar::random(&mut OsRng);
-        let mut y_x = Scalar::random(&mut OsRng);
-        let mut y_r = Scalar::random(&mut OsRng);
-
-        let Y_0 = (&y_s * P_first).compress();
-        let Y_1 = RistrettoPoint::multiscalar_mul(vec![&y_x, &y_s], vec![&G, D_first]).compress();
-        let Y_2 = RistrettoPoint::multiscalar_mul(vec![&y_x, &y_r], vec![&G, &(*H)]).compress();
-        let Y_3 = (&y_r * P_second).compress();
-
-        // record masking factors in the transcript
-        transcript.append_point(b"Y_0", &Y_0);
-        transcript.append_point(b"Y_1", &Y_1);
-        transcript.append_point(b"Y_2", &Y_2);
-        transcript.append_point(b"Y_3", &Y_3);
-
-        let c = transcript.challenge_scalar(b"c");
-        transcript.challenge_scalar(b"w");
-
-        // compute the masked values
-        let z_s = &(&c * s) + &y_s;
-        let z_x = &(&c * &x) + &y_x;
-        let z_r = &(&c * r) + &y_r;
-
-        // zeroize random scalars
-        y_s.zeroize();
-        y_x.zeroize();
-        y_r.zeroize();
-
-        CiphertextCiphertextEqualityProof {
-            Y_0,
-            Y_1,
-            Y_2,
-            Y_3,
-            z_s,
-            z_x,
-            z_r,
-        }
-    }
-
-    /// Verifies a ciphertext-ciphertext equality proof.
-    ///
-    /// * `first_pubkey` - The ElGamal pubkey associated with the first ciphertext to be proved
-    /// * `second_pubkey` - The ElGamal pubkey associated with the second ciphertext to be proved
-    /// * `first_ciphertext` - The first ElGamal ciphertext to be proved
-    /// * `second_ciphertext` - The second ElGamal ciphertext to be proved
-    /// * `transcript` - The transcript that does the bookkeeping for the Fiat-Shamir heuristic
-    pub fn verify(
-        self,
-        first_pubkey: &ElGamalPubkey,
-        second_pubkey: &ElGamalPubkey,
-        first_ciphertext: &ElGamalCiphertext,
-        second_ciphertext: &ElGamalCiphertext,
-        transcript: &mut Transcript,
-    ) -> Result<(), EqualityProofVerificationError> {
-        transcript.ciphertext_ciphertext_equality_proof_domain_separator();
-
-        // extract the relevant scalar and Ristretto points from the inputs
-        let P_first = first_pubkey.get_point();
-        let C_first = first_ciphertext.commitment.get_point();
-        let D_first = first_ciphertext.handle.get_point();
-
-        let P_second = second_pubkey.get_point();
-        let C_second = second_ciphertext.commitment.get_point();
-        let D_second = second_ciphertext.handle.get_point();
-
-        // include Y_0, Y_1, Y_2 to transcript and extract challenges
-        transcript.validate_and_append_point(b"Y_0", &self.Y_0)?;
-        transcript.validate_and_append_point(b"Y_1", &self.Y_1)?;
-        transcript.validate_and_append_point(b"Y_2", &self.Y_2)?;
-        transcript.validate_and_append_point(b"Y_3", &self.Y_3)?;
-
-        let c = transcript.challenge_scalar(b"c");
-
-        transcript.append_scalar(b"z_s", &self.z_s);
-        transcript.append_scalar(b"z_x", &self.z_x);
-        transcript.append_scalar(b"z_r", &self.z_r);
-        let w = transcript.challenge_scalar(b"w"); // w used for batch verification
-        let ww = &w * &w;
-        let www = &w * &ww;
-
-        let w_negated = -&w;
-        let ww_negated = -&ww;
-        let www_negated = -&www;
-
-        // check that the required algebraic condition holds
-        let Y_0 = self
-            .Y_0
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-        let Y_1 = self
-            .Y_1
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-        let Y_2 = self
-            .Y_2
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-        let Y_3 = self
-            .Y_3
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-
-        let check = RistrettoPoint::vartime_multiscalar_mul(
-            vec![
-                &self.z_s,            // z_s
-                &(-&c),               // -c
-                &(-&Scalar::ONE),     // -identity
-                &(&w * &self.z_x),    // w * z_x
-                &(&w * &self.z_s),    // w * z_s
-                &(&w_negated * &c),   // -w * c
-                &w_negated,           // -w
-                &(&ww * &self.z_x),   // ww * z_x
-                &(&ww * &self.z_r),   // ww * z_r
-                &(&ww_negated * &c),  // -ww * c
-                &ww_negated,          // -ww
-                &(&www * &self.z_r),  // z_r
-                &(&www_negated * &c), // -www * c
-                &www_negated,
-            ],
-            vec![
-                P_first,  // P_first
-                &(*H),    // H
-                &Y_0,     // Y_0
-                &G,       // G
-                D_first,  // D_first
-                C_first,  // C_first
-                &Y_1,     // Y_1
-                &G,       // G
-                &(*H),    // H
-                C_second, // C_second
-                &Y_2,     // Y_2
-                P_second, // P_second
-                D_second, // D_second
-                &Y_3,     // Y_3
-            ],
-        );
-
-        if check.is_identity() {
-            Ok(())
-        } else {
-            Err(SigmaProofVerificationError::AlgebraicRelation.into())
-        }
-    }
-
-    pub fn to_bytes(&self) -> [u8; CIPHERTEXT_CIPHERTEXT_EQUALITY_PROOF_LEN] {
-        let mut buf = [0_u8; CIPHERTEXT_CIPHERTEXT_EQUALITY_PROOF_LEN];
-        let mut chunks = buf.chunks_mut(UNIT_LEN);
-
-        chunks.next().unwrap().copy_from_slice(self.Y_0.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.Y_1.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.Y_2.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.Y_3.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.z_s.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.z_x.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.z_r.as_bytes());
-
-        buf
-    }
-
-    pub fn from_bytes(bytes: &[u8]) -> Result<Self, EqualityProofVerificationError> {
-        let mut chunks = bytes.chunks(UNIT_LEN);
-
-        let Y_0 = ristretto_point_from_optional_slice(chunks.next())?;
-        let Y_1 = ristretto_point_from_optional_slice(chunks.next())?;
-        let Y_2 = ristretto_point_from_optional_slice(chunks.next())?;
-        let Y_3 = ristretto_point_from_optional_slice(chunks.next())?;
-        let z_s = canonical_scalar_from_optional_slice(chunks.next())?;
-        let z_x = canonical_scalar_from_optional_slice(chunks.next())?;
-        let z_r = canonical_scalar_from_optional_slice(chunks.next())?;
-
-        Ok(CiphertextCiphertextEqualityProof {
-            Y_0,
-            Y_1,
-            Y_2,
-            Y_3,
-            z_s,
-            z_x,
-            z_r,
-        })
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use {
-        super::*,
-        crate::{
-            encryption::pod::elgamal::{PodElGamalCiphertext, PodElGamalPubkey},
-            sigma_proofs::pod::PodCiphertextCiphertextEqualityProof,
-        },
-        std::str::FromStr,
-    };
-
-    #[test]
-    fn test_ciphertext_ciphertext_equality_proof_correctness() {
-        // success case
-        let first_keypair = ElGamalKeypair::new_rand();
-        let second_keypair = ElGamalKeypair::new_rand();
-        let message: u64 = 55;
-
-        let first_ciphertext = first_keypair.pubkey().encrypt(message);
-
-        let second_opening = PedersenOpening::new_rand();
-        let second_ciphertext = second_keypair
-            .pubkey()
-            .encrypt_with(message, &second_opening);
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = CiphertextCiphertextEqualityProof::new(
-            &first_keypair,
-            second_keypair.pubkey(),
-            &first_ciphertext,
-            &second_opening,
-            message,
-            &mut prover_transcript,
-        );
-
-        proof
-            .verify(
-                first_keypair.pubkey(),
-                second_keypair.pubkey(),
-                &first_ciphertext,
-                &second_ciphertext,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-
-        // fail case: encrypted and committed messages are different
-        let first_message: u64 = 55;
-        let second_message: u64 = 77;
-
-        let first_ciphertext = first_keypair.pubkey().encrypt(first_message);
-
-        let second_opening = PedersenOpening::new_rand();
-        let second_ciphertext = second_keypair
-            .pubkey()
-            .encrypt_with(second_message, &second_opening);
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = CiphertextCiphertextEqualityProof::new(
-            &first_keypair,
-            second_keypair.pubkey(),
-            &first_ciphertext,
-            &second_opening,
-            message,
-            &mut prover_transcript,
-        );
-
-        assert!(proof
-            .verify(
-                first_keypair.pubkey(),
-                second_keypair.pubkey(),
-                &first_ciphertext,
-                &second_ciphertext,
-                &mut verifier_transcript
-            )
-            .is_err());
-    }
-
-    #[test]
-    fn test_ciphertext_ciphertext_equality_proof_string() {
-        let first_pubkey_str = "VOPKaqo4nsX4XnbgGjCKHkLkR6JG1jX9D5G/e0EuYmM=";
-        let pod_first_pubkey = PodElGamalPubkey::from_str(first_pubkey_str).unwrap();
-        let first_pubkey: ElGamalPubkey = pod_first_pubkey.try_into().unwrap();
-
-        let second_pubkey_str = "JnVhtKo9B7g9c8Obo/5/EqvA59i3TvtuOcQWf17T7SU=";
-        let pod_second_pubkey = PodElGamalPubkey::from_str(second_pubkey_str).unwrap();
-        let second_pubkey: ElGamalPubkey = pod_second_pubkey.try_into().unwrap();
-
-        let first_ciphertext_str = "oKv6zxN051MXdk2cISD+CUsH2+FINoH1iB4WZyuy6nNkE7Q+eLiY9JB8itJhgKHJEA/1sAzDvpnRlLL06OXvIg==";
-        let pod_first_ciphertext = PodElGamalCiphertext::from_str(first_ciphertext_str).unwrap();
-        let first_ciphertext: ElGamalCiphertext = pod_first_ciphertext.try_into().unwrap();
-
-        let second_ciphertext_str = "ooSA2cQDqutgyCBoMiQktM1Cu4NDNEbphF010gjG4iF0iMK1N+u/Qxqk0wwO/+w+5S6RiicwPs4mEKRJpFiHEw==";
-        let pod_second_ciphertext = PodElGamalCiphertext::from_str(second_ciphertext_str).unwrap();
-        let second_ciphertext: ElGamalCiphertext = pod_second_ciphertext.try_into().unwrap();
-
-        let proof_str = "MlfRDO4sBPbpciEXci3QfVSLVABAJ0s8wMZ/Uz3AyETmGJ1BUE961fHIiNQXPD0j1uu1Josj//E8loPD1w+4E3bfDBJ3Mp2YqeOv41Bdec02YXlAotTGjq/UfncGdUhyampkuXUmSvnmkf5BIp4nr3X18cR9KHTAzBrKv6erjAxIckyRnACaZGEx+ZboEb3FBEXqTklytT1nrebbwkjvDUWbcpZrE+xxBWYek3qeq1x1debzxVhtS2yx44cvR5UIGLzGYa2ec/xh7wvyNEbnX80rZju2dztr4bN5f2vrTgk=";
-        let pod_proof = PodCiphertextCiphertextEqualityProof::from_str(proof_str).unwrap();
-        let proof: CiphertextCiphertextEqualityProof = pod_proof.try_into().unwrap();
-
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        proof
-            .verify(
-                &first_pubkey,
-                &second_pubkey,
-                &first_ciphertext,
-                &second_ciphertext,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-    }
-}

+ 0 - 469
zk-sdk/src/sigma_proofs/ciphertext_commitment_equality.rs

@@ -1,469 +0,0 @@
-//! The ciphertext-commitment equality sigma proof system.
-//!
-//! A ciphertext-commitment equality proof is defined with respect to a twisted ElGamal ciphertext
-//! and a Pedersen commitment. The proof certifies that a given ciphertext and a commitment pair
-//! encrypts/encodes the same message. To generate the proof, a prover must provide the decryption
-//! key for the first ciphertext and the Pedersen opening for the commitment.
-//!
-//! The protocol guarantees computational soundness (by the hardness of discrete log) and perfect
-//! zero-knowledge in the random oracle model.
-
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::{
-            elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey},
-            pedersen::{PedersenCommitment, PedersenOpening, G, H},
-        },
-        sigma_proofs::{canonical_scalar_from_optional_slice, ristretto_point_from_optional_slice},
-        UNIT_LEN,
-    },
-    curve25519_dalek::traits::MultiscalarMul,
-    rand::rngs::OsRng,
-    zeroize::Zeroize,
-};
-use {
-    crate::{
-        sigma_proofs::errors::{EqualityProofVerificationError, SigmaProofVerificationError},
-        transcript::TranscriptProtocol,
-    },
-    curve25519_dalek::{
-        ristretto::{CompressedRistretto, RistrettoPoint},
-        scalar::Scalar,
-        traits::{IsIdentity, VartimeMultiscalarMul},
-    },
-    merlin::Transcript,
-};
-
-/// Byte length of a ciphertext-commitment equality proof.
-const CIPHERTEXT_COMMITMENT_EQUALITY_PROOF_LEN: usize = UNIT_LEN * 6;
-
-/// Equality proof.
-///
-/// Contains all the elliptic curve and scalar components that make up the sigma protocol.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[allow(non_snake_case)]
-#[derive(Clone)]
-pub struct CiphertextCommitmentEqualityProof {
-    Y_0: CompressedRistretto,
-    Y_1: CompressedRistretto,
-    Y_2: CompressedRistretto,
-    z_s: Scalar,
-    z_x: Scalar,
-    z_r: Scalar,
-}
-
-#[allow(non_snake_case)]
-#[cfg(not(target_os = "solana"))]
-impl CiphertextCommitmentEqualityProof {
-    /// Creates a ciphertext-commitment equality proof.
-    ///
-    /// The function does *not* hash the public key, ciphertext, or commitment into the transcript.
-    /// For security, the caller (the main protocol) should hash these public components prior to
-    /// invoking this constructor.
-    ///
-    /// This function is randomized. It uses `OsRng` internally to generate random scalars.
-    ///
-    /// Note that the proof constructor does not take the actual Pedersen commitment as input; it
-    /// takes the associated Pedersen opening instead.
-    ///
-    /// * `keypair` - The ElGamal keypair associated with the first to be proved
-    /// * `ciphertext` - The main ElGamal ciphertext to be proved
-    /// * `opening` - The opening associated with the main Pedersen commitment to be proved
-    /// * `amount` - The message associated with the ElGamal ciphertext and Pedersen commitment
-    /// * `transcript` - The transcript that does the bookkeeping for the Fiat-Shamir heuristic
-    pub fn new(
-        keypair: &ElGamalKeypair,
-        ciphertext: &ElGamalCiphertext,
-        opening: &PedersenOpening,
-        amount: u64,
-        transcript: &mut Transcript,
-    ) -> Self {
-        transcript.ciphertext_commitment_equality_proof_domain_separator();
-
-        // extract the relevant scalar and Ristretto points from the inputs
-        let P = keypair.pubkey().get_point();
-        let D = ciphertext.handle.get_point();
-
-        let s = keypair.secret().get_scalar();
-        let x = Scalar::from(amount);
-        let r = opening.get_scalar();
-
-        // generate random masking factors that also serves as nonces
-        let mut y_s = Scalar::random(&mut OsRng);
-        let mut y_x = Scalar::random(&mut OsRng);
-        let mut y_r = Scalar::random(&mut OsRng);
-
-        let Y_0 = (&y_s * P).compress();
-        let Y_1 = RistrettoPoint::multiscalar_mul(vec![&y_x, &y_s], vec![&G, D]).compress();
-        let Y_2 = RistrettoPoint::multiscalar_mul(vec![&y_x, &y_r], vec![&G, &(*H)]).compress();
-
-        // record masking factors in the transcript
-        transcript.append_point(b"Y_0", &Y_0);
-        transcript.append_point(b"Y_1", &Y_1);
-        transcript.append_point(b"Y_2", &Y_2);
-
-        let c = transcript.challenge_scalar(b"c");
-        transcript.challenge_scalar(b"w");
-
-        // compute the masked values
-        let z_s = &(&c * s) + &y_s;
-        let z_x = &(&c * &x) + &y_x;
-        let z_r = &(&c * r) + &y_r;
-
-        // zeroize random scalars
-        y_s.zeroize();
-        y_x.zeroize();
-        y_r.zeroize();
-
-        CiphertextCommitmentEqualityProof {
-            Y_0,
-            Y_1,
-            Y_2,
-            z_s,
-            z_x,
-            z_r,
-        }
-    }
-
-    /// Verifies a ciphertext-commitment equality proof.
-    ///
-    /// * `pubkey` - The ElGamal pubkey associated with the ciphertext to be proved
-    /// * `ciphertext` - The main ElGamal ciphertext to be proved
-    /// * `commitment` - The main Pedersen commitment to be proved
-    /// * `transcript` - The transcript that does the bookkeeping for the Fiat-Shamir heuristic
-    pub fn verify(
-        self,
-        pubkey: &ElGamalPubkey,
-        ciphertext: &ElGamalCiphertext,
-        commitment: &PedersenCommitment,
-        transcript: &mut Transcript,
-    ) -> Result<(), EqualityProofVerificationError> {
-        transcript.ciphertext_commitment_equality_proof_domain_separator();
-
-        // extract the relevant scalar and Ristretto points from the inputs
-        let P = pubkey.get_point();
-        let C_ciphertext = ciphertext.commitment.get_point();
-        let D = ciphertext.handle.get_point();
-        let C_commitment = commitment.get_point();
-
-        // include Y_0, Y_1, Y_2 to transcript and extract challenges
-        transcript.validate_and_append_point(b"Y_0", &self.Y_0)?;
-        transcript.validate_and_append_point(b"Y_1", &self.Y_1)?;
-        transcript.validate_and_append_point(b"Y_2", &self.Y_2)?;
-
-        let c = transcript.challenge_scalar(b"c");
-
-        transcript.append_scalar(b"z_s", &self.z_s);
-        transcript.append_scalar(b"z_x", &self.z_x);
-        transcript.append_scalar(b"z_r", &self.z_r);
-        let w = transcript.challenge_scalar(b"w"); // w used for batch verification
-        let ww = &w * &w;
-
-        let w_negated = -&w;
-        let ww_negated = -&ww;
-
-        // check that the required algebraic condition holds
-        let Y_0 = self
-            .Y_0
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-        let Y_1 = self
-            .Y_1
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-        let Y_2 = self
-            .Y_2
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-
-        let check = RistrettoPoint::vartime_multiscalar_mul(
-            vec![
-                &self.z_s,           // z_s
-                &(-&c),              // -c
-                &(-&Scalar::ONE),    // -identity
-                &(&w * &self.z_x),   // w * z_x
-                &(&w * &self.z_s),   // w * z_s
-                &(&w_negated * &c),  // -w * c
-                &w_negated,          // -w
-                &(&ww * &self.z_x),  // ww * z_x
-                &(&ww * &self.z_r),  // ww * z_r
-                &(&ww_negated * &c), // -ww * c
-                &ww_negated,         // -ww
-            ],
-            vec![
-                P,            // P
-                &(*H),        // H
-                &Y_0,         // Y_0
-                &G,           // G
-                D,            // D
-                C_ciphertext, // C_ciphertext
-                &Y_1,         // Y_1
-                &G,           // G
-                &(*H),        // H
-                C_commitment, // C_commitment
-                &Y_2,         // Y_2
-            ],
-        );
-
-        if check.is_identity() {
-            Ok(())
-        } else {
-            Err(SigmaProofVerificationError::AlgebraicRelation.into())
-        }
-    }
-
-    pub fn to_bytes(&self) -> [u8; CIPHERTEXT_COMMITMENT_EQUALITY_PROOF_LEN] {
-        let mut buf = [0_u8; CIPHERTEXT_COMMITMENT_EQUALITY_PROOF_LEN];
-        let mut chunks = buf.chunks_mut(UNIT_LEN);
-        chunks.next().unwrap().copy_from_slice(self.Y_0.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.Y_1.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.Y_2.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.z_s.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.z_x.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.z_r.as_bytes());
-        buf
-    }
-
-    pub fn from_bytes(bytes: &[u8]) -> Result<Self, EqualityProofVerificationError> {
-        let mut chunks = bytes.chunks(UNIT_LEN);
-        let Y_0 = ristretto_point_from_optional_slice(chunks.next())?;
-        let Y_1 = ristretto_point_from_optional_slice(chunks.next())?;
-        let Y_2 = ristretto_point_from_optional_slice(chunks.next())?;
-        let z_s = canonical_scalar_from_optional_slice(chunks.next())?;
-        let z_x = canonical_scalar_from_optional_slice(chunks.next())?;
-        let z_r = canonical_scalar_from_optional_slice(chunks.next())?;
-
-        Ok(CiphertextCommitmentEqualityProof {
-            Y_0,
-            Y_1,
-            Y_2,
-            z_s,
-            z_x,
-            z_r,
-        })
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use {
-        super::*,
-        crate::{
-            encryption::{
-                elgamal::ElGamalSecretKey,
-                pedersen::Pedersen,
-                pod::{
-                    elgamal::{PodElGamalCiphertext, PodElGamalPubkey},
-                    pedersen::PodPedersenCommitment,
-                },
-            },
-            sigma_proofs::pod::PodCiphertextCommitmentEqualityProof,
-        },
-        std::str::FromStr,
-    };
-
-    #[test]
-    fn test_ciphertext_commitment_equality_proof_correctness() {
-        // success case
-        let keypair = ElGamalKeypair::new_rand();
-        let message: u64 = 55;
-
-        let ciphertext = keypair.pubkey().encrypt(message);
-        let (commitment, opening) = Pedersen::new(message);
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = CiphertextCommitmentEqualityProof::new(
-            &keypair,
-            &ciphertext,
-            &opening,
-            message,
-            &mut prover_transcript,
-        );
-
-        proof
-            .verify(
-                keypair.pubkey(),
-                &ciphertext,
-                &commitment,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-
-        // fail case: encrypted and committed messages are different
-        let keypair = ElGamalKeypair::new_rand();
-        let encrypted_message: u64 = 55;
-        let committed_message: u64 = 77;
-
-        let ciphertext = keypair.pubkey().encrypt(encrypted_message);
-        let (commitment, opening) = Pedersen::new(committed_message);
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = CiphertextCommitmentEqualityProof::new(
-            &keypair,
-            &ciphertext,
-            &opening,
-            encrypted_message,
-            &mut prover_transcript,
-        );
-
-        assert!(proof
-            .verify(
-                keypair.pubkey(),
-                &ciphertext,
-                &commitment,
-                &mut verifier_transcript
-            )
-            .is_err());
-    }
-
-    #[test]
-    fn test_ciphertext_commitment_equality_proof_edge_cases() {
-        // if ElGamal public key zero (public key is invalid), then the proof should always reject
-        let public = ElGamalPubkey::try_from([0u8; 32].as_slice()).unwrap();
-        let secret = ElGamalSecretKey::new_rand();
-
-        let elgamal_keypair = ElGamalKeypair::new_for_tests(public, secret);
-
-        let message: u64 = 55;
-        let ciphertext = elgamal_keypair.pubkey().encrypt(message);
-        let (commitment, opening) = Pedersen::new(message);
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = CiphertextCommitmentEqualityProof::new(
-            &elgamal_keypair,
-            &ciphertext,
-            &opening,
-            message,
-            &mut prover_transcript,
-        );
-
-        assert!(proof
-            .verify(
-                elgamal_keypair.pubkey(),
-                &ciphertext,
-                &commitment,
-                &mut verifier_transcript
-            )
-            .is_err());
-
-        // if ciphertext is all-zero (valid commitment of 0) and commitment is also all-zero, then
-        // the proof should still accept
-        let elgamal_keypair = ElGamalKeypair::new_rand();
-
-        let message: u64 = 0;
-        let ciphertext = ElGamalCiphertext::from_bytes(&[0u8; 64]).unwrap();
-        let commitment = PedersenCommitment::from_bytes(&[0u8; 32]).unwrap();
-        let opening = PedersenOpening::from_bytes(&[0u8; 32]).unwrap();
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = CiphertextCommitmentEqualityProof::new(
-            &elgamal_keypair,
-            &ciphertext,
-            &opening,
-            message,
-            &mut prover_transcript,
-        );
-
-        proof
-            .verify(
-                elgamal_keypair.pubkey(),
-                &ciphertext,
-                &commitment,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-
-        // if commitment is all-zero and the ciphertext is a correct encryption of 0, then the
-        // proof should still accept
-        let elgamal_keypair = ElGamalKeypair::new_rand();
-
-        let message: u64 = 0;
-        let ciphertext = elgamal_keypair.pubkey().encrypt(message);
-        let commitment = PedersenCommitment::from_bytes(&[0u8; 32]).unwrap();
-        let opening = PedersenOpening::from_bytes(&[0u8; 32]).unwrap();
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = CiphertextCommitmentEqualityProof::new(
-            &elgamal_keypair,
-            &ciphertext,
-            &opening,
-            message,
-            &mut prover_transcript,
-        );
-
-        proof
-            .verify(
-                elgamal_keypair.pubkey(),
-                &ciphertext,
-                &commitment,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-
-        // if ciphertext is all zero and commitment correctly encodes 0, then the proof should
-        // still accept
-        let elgamal_keypair = ElGamalKeypair::new_rand();
-
-        let message: u64 = 0;
-        let ciphertext = ElGamalCiphertext::from_bytes(&[0u8; 64]).unwrap();
-        let (commitment, opening) = Pedersen::new(message);
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = CiphertextCommitmentEqualityProof::new(
-            &elgamal_keypair,
-            &ciphertext,
-            &opening,
-            message,
-            &mut prover_transcript,
-        );
-
-        proof
-            .verify(
-                elgamal_keypair.pubkey(),
-                &ciphertext,
-                &commitment,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-    }
-
-    #[test]
-    fn test_ciphertext_commitment_equality_proof_string() {
-        let pubkey_str = "JNa7rRrDm35laU7f8HPds1PmHoZEPSHFK/M+aTtEhAk=";
-        let pod_pubkey = PodElGamalPubkey::from_str(pubkey_str).unwrap();
-        let pubkey: ElGamalPubkey = pod_pubkey.try_into().unwrap();
-
-        let ciphertext_str = "RAXnbQ/DPRlYAWmD+iHRNqMDv7oQcPgQ7OejRzj4bxVy2qOJNziqqDOC7VP3iTW1+z/jckW4smA3EUF7i/r8Rw==";
-        let pod_ciphertext = PodElGamalCiphertext::from_str(ciphertext_str).unwrap();
-        let ciphertext: ElGamalCiphertext = pod_ciphertext.try_into().unwrap();
-
-        let commitment_str = "ngPTYvbY9P5l6aOfr7bLQiI+0HZsw8GBgiumdW3tNzw=";
-        let pod_commitment = PodPedersenCommitment::from_str(commitment_str).unwrap();
-        let commitment: PedersenCommitment = pod_commitment.try_into().unwrap();
-
-        let proof_str = "cCZySLxB2XJdGyDvckVBm2OWiXqf7Jf54IFoDuLJ4G+ySj+lh5DbaDMHDhuozQC9tDWtk2mFITuaXOc5Zw3nZ2oEvVYpqv5hN+k5dx9k8/nZKabUCkZwx310z7x4fE4Np5SY9PYia1hkrq9AWq0b3v97XvW1+XCSSxuflvBk5wsdaQQ+ZgcmPnKWKjHfRwmU2k5iVgYzs2VmvZa5E3OWBoM/M2yFNvukY+FCC2YMnspO0c4lNBr/vDFQuHdW0OgJ";
-        let pod_proof = PodCiphertextCommitmentEqualityProof::from_str(proof_str).unwrap();
-        let proof: CiphertextCommitmentEqualityProof = pod_proof.try_into().unwrap();
-
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        proof
-            .verify(&pubkey, &ciphertext, &commitment, &mut verifier_transcript)
-            .unwrap();
-    }
-}

+ 0 - 49
zk-sdk/src/sigma_proofs/errors.rs

@@ -1,49 +0,0 @@
-//! Errors related to proving and verifying sigma proofs.
-use {crate::errors::TranscriptError, thiserror::Error};
-
-#[derive(Error, Clone, Debug, Eq, PartialEq)]
-pub enum SigmaProofVerificationError {
-    #[error("required algebraic relation does not hold")]
-    AlgebraicRelation,
-    #[error("malformed proof")]
-    Deserialization,
-    #[error("multiscalar multiplication failed")]
-    MultiscalarMul,
-    #[error("transcript failed to produce a challenge")]
-    Transcript(#[from] TranscriptError),
-}
-
-macro_rules! impl_from_transcript_error {
-    ($sigma_error_type:ty) => {
-        impl From<TranscriptError> for $sigma_error_type {
-            fn from(err: TranscriptError) -> Self {
-                SigmaProofVerificationError::Transcript(err).into()
-            }
-        }
-    };
-}
-
-#[derive(Error, Clone, Debug, Eq, PartialEq)]
-#[error("equality proof verification failed: {0}")]
-pub struct EqualityProofVerificationError(#[from] pub(crate) SigmaProofVerificationError);
-impl_from_transcript_error!(EqualityProofVerificationError);
-
-#[derive(Error, Clone, Debug, Eq, PartialEq)]
-#[error("validity proof verification failed: {0}")]
-pub struct ValidityProofVerificationError(#[from] pub(crate) SigmaProofVerificationError);
-impl_from_transcript_error!(ValidityProofVerificationError);
-
-#[derive(Error, Clone, Debug, Eq, PartialEq)]
-#[error("zero-ciphertext proof verification failed: {0}")]
-pub struct ZeroCiphertextProofVerificationError(#[from] pub(crate) SigmaProofVerificationError);
-impl_from_transcript_error!(ZeroCiphertextProofVerificationError);
-
-#[derive(Error, Clone, Debug, Eq, PartialEq)]
-#[error("percentage-with-cap proof verification failed: {0}")]
-pub struct PercentageWithCapProofVerificationError(#[from] pub(crate) SigmaProofVerificationError);
-impl_from_transcript_error!(PercentageWithCapProofVerificationError);
-
-#[derive(Error, Clone, Debug, Eq, PartialEq)]
-#[error("public key validity proof verification failed: {0}")]
-pub struct PubkeyValidityProofVerificationError(#[from] pub(crate) SigmaProofVerificationError);
-impl_from_transcript_error!(PubkeyValidityProofVerificationError);

+ 0 - 445
zk-sdk/src/sigma_proofs/grouped_ciphertext_validity/handles_2.rs

@@ -1,445 +0,0 @@
-//! The ciphertext validity sigma proof system.
-//!
-//! The ciphertext validity proof is defined with respect to a Pedersen commitment and two
-//! decryption handles. The proof certifies that a given Pedersen commitment can be decrypted using
-//! ElGamal private keys that are associated with each of the two decryption handles. To generate
-//! the proof, a prover must provide the Pedersen opening associated with the commitment.
-//!
-//! The protocol guarantees computational soundness (by the hardness of discrete log) and perfect
-//! zero-knowledge in the random oracle model.
-
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::{
-            elgamal::{DecryptHandle, ElGamalPubkey},
-            pedersen::{PedersenCommitment, PedersenOpening, G, H},
-        },
-        sigma_proofs::{canonical_scalar_from_optional_slice, ristretto_point_from_optional_slice},
-        UNIT_LEN,
-    },
-    curve25519_dalek::traits::MultiscalarMul,
-    rand::rngs::OsRng,
-    zeroize::Zeroize,
-};
-use {
-    crate::{
-        sigma_proofs::errors::{SigmaProofVerificationError, ValidityProofVerificationError},
-        transcript::TranscriptProtocol,
-    },
-    curve25519_dalek::{
-        ristretto::{CompressedRistretto, RistrettoPoint},
-        scalar::Scalar,
-        traits::{IsIdentity, VartimeMultiscalarMul},
-    },
-    merlin::Transcript,
-};
-
-/// Byte length of a grouped ciphertext validity proof for 2 handles
-const GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY_PROOF_LEN: usize = UNIT_LEN * 5;
-
-/// The grouped ciphertext validity proof for 2 handles.
-///
-/// Contains all the elliptic curve and scalar components that make up the sigma protocol.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[allow(non_snake_case)]
-#[derive(Clone)]
-pub struct GroupedCiphertext2HandlesValidityProof {
-    Y_0: CompressedRistretto,
-    Y_1: CompressedRistretto,
-    Y_2: CompressedRistretto,
-    z_r: Scalar,
-    z_x: Scalar,
-}
-
-#[allow(non_snake_case)]
-#[cfg(not(target_os = "solana"))]
-impl GroupedCiphertext2HandlesValidityProof {
-    /// Creates a grouped ciphertext validity proof for 2 handles.
-    ///
-    /// The function does *not* hash the public keys, commitment, or decryption handles into the
-    /// transcript. For security, the caller (the main protocol) should hash these public
-    /// components prior to invoking this constructor.
-    ///
-    /// This function is randomized. It uses `OsRng` internally to generate random scalars.
-    ///
-    /// Note that the proof constructor does not take the actual Pedersen commitment or decryption
-    /// handles as input; it only takes the associated Pedersen opening instead.
-    ///
-    /// * `first_pubkey` - The first ElGamal public key
-    /// * `second_pubkey` - The second ElGamal public key
-    /// * `amount` - The committed message in the commitment
-    /// * `opening` - The opening associated with the Pedersen commitment
-    /// * `transcript` - The transcript that does the bookkeeping for the Fiat-Shamir heuristic
-    pub fn new<T: Into<Scalar>>(
-        first_pubkey: &ElGamalPubkey,
-        second_pubkey: &ElGamalPubkey,
-        amount: T,
-        opening: &PedersenOpening,
-        transcript: &mut Transcript,
-    ) -> Self {
-        transcript.grouped_ciphertext_validity_proof_domain_separator(2);
-
-        // extract the relevant scalar and Ristretto points from the inputs
-        let P_first = first_pubkey.get_point();
-        let P_second = second_pubkey.get_point();
-
-        let x = amount.into();
-        let r = opening.get_scalar();
-
-        // generate random masking factors that also serves as nonces
-        let mut y_r = Scalar::random(&mut OsRng);
-        let mut y_x = Scalar::random(&mut OsRng);
-
-        let Y_0 = RistrettoPoint::multiscalar_mul(vec![&y_r, &y_x], vec![&(*H), &G]).compress();
-        let Y_1 = (&y_r * P_first).compress();
-        let Y_2 = (&y_r * P_second).compress();
-
-        // record masking factors in transcript and get challenges
-        transcript.append_point(b"Y_0", &Y_0);
-        transcript.append_point(b"Y_1", &Y_1);
-        transcript.append_point(b"Y_2", &Y_2);
-
-        let c = transcript.challenge_scalar(b"c");
-        transcript.challenge_scalar(b"w");
-
-        // compute masked message and opening
-        let z_r = &(&c * r) + &y_r;
-        let z_x = &(&c * &x) + &y_x;
-
-        y_r.zeroize();
-        y_x.zeroize();
-
-        Self {
-            Y_0,
-            Y_1,
-            Y_2,
-            z_r,
-            z_x,
-        }
-    }
-
-    /// Verifies a grouped ciphertext validity proof for 2 handles.
-    ///
-    /// * `commitment` - The Pedersen commitment
-    /// * `first_pubkey` - The first ElGamal public key
-    /// * `second_pubkey` - The second ElGamal public key
-    /// * `first_handle` - The first decryption handle
-    /// * `second_handle` - The second decryption handle
-    /// * `transcript` - The transcript that does the bookkeeping for the Fiat-Shamir heuristic
-    pub fn verify(
-        self,
-        commitment: &PedersenCommitment,
-        first_pubkey: &ElGamalPubkey,
-        second_pubkey: &ElGamalPubkey,
-        first_handle: &DecryptHandle,
-        second_handle: &DecryptHandle,
-        transcript: &mut Transcript,
-    ) -> Result<(), ValidityProofVerificationError> {
-        transcript.grouped_ciphertext_validity_proof_domain_separator(2);
-
-        // include Y_0, Y_1, Y_2 to transcript and extract challenges
-        transcript.validate_and_append_point(b"Y_0", &self.Y_0)?;
-        transcript.validate_and_append_point(b"Y_1", &self.Y_1)?;
-        // Y_2 can be an all zero point if the second public key is all zero
-        transcript.append_point(b"Y_2", &self.Y_2);
-
-        let c = transcript.challenge_scalar(b"c");
-
-        transcript.append_scalar(b"z_r", &self.z_r);
-        transcript.append_scalar(b"z_x", &self.z_x);
-        let w = transcript.challenge_scalar(b"w");
-        let ww = &w * &w;
-
-        let w_negated = -&w;
-        let ww_negated = -&ww;
-
-        // check the required algebraic conditions
-        let Y_0 = self
-            .Y_0
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-        let Y_1 = self
-            .Y_1
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-        let Y_2 = self
-            .Y_2
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-
-        let P_first = first_pubkey.get_point();
-        let P_second = second_pubkey.get_point();
-
-        let C = commitment.get_point();
-        let D_first = first_handle.get_point();
-        let D_second = second_handle.get_point();
-
-        let check = RistrettoPoint::vartime_multiscalar_mul(
-            vec![
-                &self.z_r,           // z_r
-                &self.z_x,           // z_x
-                &(-&c),              // -c
-                &-(&Scalar::ONE),    // -identity
-                &(&w * &self.z_r),   // w * z_r
-                &(&w_negated * &c),  // -w * c
-                &w_negated,          // -w
-                &(&ww * &self.z_r),  // ww * z_r
-                &(&ww_negated * &c), // -ww * c
-                &ww_negated,         // -ww
-            ],
-            vec![
-                &(*H),    // H
-                &G,       // G
-                C,        // C
-                &Y_0,     // Y_0
-                P_first,  // P_first
-                D_first,  // D_first
-                &Y_1,     // Y_1
-                P_second, // P_second
-                D_second, // D_second
-                &Y_2,     // Y_2
-            ],
-        );
-
-        if check.is_identity() {
-            Ok(())
-        } else {
-            Err(SigmaProofVerificationError::AlgebraicRelation.into())
-        }
-    }
-
-    pub fn to_bytes(&self) -> [u8; GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY_PROOF_LEN] {
-        let mut buf = [0_u8; GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY_PROOF_LEN];
-        let mut chunks = buf.chunks_mut(UNIT_LEN);
-        chunks.next().unwrap().copy_from_slice(self.Y_0.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.Y_1.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.Y_2.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.z_r.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.z_x.as_bytes());
-        buf
-    }
-
-    pub fn from_bytes(bytes: &[u8]) -> Result<Self, ValidityProofVerificationError> {
-        let mut chunks = bytes.chunks(UNIT_LEN);
-        let Y_0 = ristretto_point_from_optional_slice(chunks.next())?;
-        let Y_1 = ristretto_point_from_optional_slice(chunks.next())?;
-        let Y_2 = ristretto_point_from_optional_slice(chunks.next())?;
-        let z_r = canonical_scalar_from_optional_slice(chunks.next())?;
-        let z_x = canonical_scalar_from_optional_slice(chunks.next())?;
-
-        Ok(GroupedCiphertext2HandlesValidityProof {
-            Y_0,
-            Y_1,
-            Y_2,
-            z_r,
-            z_x,
-        })
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use {
-        super::*,
-        crate::{
-            encryption::{
-                elgamal::ElGamalKeypair,
-                pedersen::Pedersen,
-                pod::{
-                    elgamal::{PodDecryptHandle, PodElGamalPubkey},
-                    pedersen::PodPedersenCommitment,
-                },
-            },
-            sigma_proofs::pod::PodGroupedCiphertext2HandlesValidityProof,
-        },
-        std::str::FromStr,
-    };
-
-    #[test]
-    fn test_grouped_ciphertext_validity_proof_correctness() {
-        let first_keypair = ElGamalKeypair::new_rand();
-        let first_pubkey = first_keypair.pubkey();
-
-        let second_keypair = ElGamalKeypair::new_rand();
-        let second_pubkey = second_keypair.pubkey();
-
-        let amount: u64 = 55;
-        let (commitment, opening) = Pedersen::new(amount);
-
-        let first_handle = first_pubkey.decrypt_handle(&opening);
-        let second_handle = second_pubkey.decrypt_handle(&opening);
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = GroupedCiphertext2HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            amount,
-            &opening,
-            &mut prover_transcript,
-        );
-
-        proof
-            .verify(
-                &commitment,
-                first_pubkey,
-                second_pubkey,
-                &first_handle,
-                &second_handle,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-    }
-
-    #[test]
-    fn test_grouped_ciphertext_validity_proof_edge_cases() {
-        // if the first public key zeroed, then the proof should always reject
-        let first_pubkey = ElGamalPubkey::try_from([0u8; 32].as_slice()).unwrap();
-
-        let second_keypair = ElGamalKeypair::new_rand();
-        let second_pubkey = second_keypair.pubkey();
-
-        let amount: u64 = 55;
-        let (commitment, opening) = Pedersen::new(amount);
-
-        let first_handle = first_pubkey.decrypt_handle(&opening);
-        let second_handle = second_pubkey.decrypt_handle(&opening);
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = GroupedCiphertext2HandlesValidityProof::new(
-            &first_pubkey,
-            second_pubkey,
-            amount,
-            &opening,
-            &mut prover_transcript,
-        );
-
-        assert!(proof
-            .verify(
-                &commitment,
-                &first_pubkey,
-                second_pubkey,
-                &first_handle,
-                &second_handle,
-                &mut verifier_transcript,
-            )
-            .is_err());
-
-        // all zeroed ciphertext should still be valid
-        let first_keypair = ElGamalKeypair::new_rand();
-        let first_pubkey = first_keypair.pubkey();
-
-        let second_keypair = ElGamalKeypair::new_rand();
-        let second_pubkey = second_keypair.pubkey();
-
-        let amount: u64 = 0;
-        let commitment = PedersenCommitment::from_bytes(&[0u8; 32]).unwrap();
-        let opening = PedersenOpening::from_bytes(&[0u8; 32]).unwrap();
-
-        let first_handle = first_pubkey.decrypt_handle(&opening);
-        let second_handle = second_pubkey.decrypt_handle(&opening);
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = GroupedCiphertext2HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            amount,
-            &opening,
-            &mut prover_transcript,
-        );
-
-        proof
-            .verify(
-                &commitment,
-                first_pubkey,
-                second_pubkey,
-                &first_handle,
-                &second_handle,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-
-        // decryption handles can be zero as long as the Pedersen commitment is valid
-        let first_keypair = ElGamalKeypair::new_rand();
-        let first_pubkey = first_keypair.pubkey();
-
-        let second_keypair = ElGamalKeypair::new_rand();
-        let second_pubkey = second_keypair.pubkey();
-
-        let amount: u64 = 55;
-        let (commitment, opening) = Pedersen::new(amount);
-
-        let first_handle = first_pubkey.decrypt_handle(&opening);
-        let second_handle = second_pubkey.decrypt_handle(&opening);
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = GroupedCiphertext2HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            amount,
-            &opening,
-            &mut prover_transcript,
-        );
-
-        proof
-            .verify(
-                &commitment,
-                first_pubkey,
-                second_pubkey,
-                &first_handle,
-                &second_handle,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-    }
-
-    #[test]
-    fn test_grouped_ciphertext_validity_proof_string() {
-        let commitment_str = "VjdpJcofkU/Lhd6RRvwsCoqaZ8XSbhiizI7jsxZNKSU=";
-        let pod_commitment = PodPedersenCommitment::from_str(commitment_str).unwrap();
-        let commitment: PedersenCommitment = pod_commitment.try_into().unwrap();
-
-        let first_pubkey_str = "YllcTvlVBp9nv+bi8d0Z9UOujPfMsgH3ZcCqQSwXfic=";
-        let pod_first_pubkey = PodElGamalPubkey::from_str(first_pubkey_str).unwrap();
-        let first_pubkey: ElGamalPubkey = pod_first_pubkey.try_into().unwrap();
-
-        let second_pubkey_str = "CCq+4oKGWlh3pkSbZpEsj6vfimhC/c3TxTVAghXq5Xo=";
-        let pod_second_pubkey = PodElGamalPubkey::from_str(second_pubkey_str).unwrap();
-        let second_pubkey: ElGamalPubkey = pod_second_pubkey.try_into().unwrap();
-
-        let first_handle_str = "EE1qdL/QLMGXvsWIjw2c07Vg/DgUsaexxQECKtjEwWE=";
-        let pod_first_handle_str = PodDecryptHandle::from_str(first_handle_str).unwrap();
-        let first_handle: DecryptHandle = pod_first_handle_str.try_into().unwrap();
-
-        let second_handle_str = "2Jn0+IVwpI5O/5pBU/nizS759k6dNn6UyUzxc1bt3RM=";
-        let pod_second_handle_str = PodDecryptHandle::from_str(second_handle_str).unwrap();
-        let second_handle: DecryptHandle = pod_second_handle_str.try_into().unwrap();
-
-        let proof_str = "/GITIw3LjQSphEG1GWYpKGjKUrYnC1n4yGFDvBwcE2V6XdSM8FKgc3AjQYJWGVkUMsciv/vMRv3lyDuW4VJJclQk9STY7Pd2F4r6Lz1P3fBmODbDp++k3Ni759FrV141Oy4puCzHV8+LHg6ePh3WlZ8yL+Ri6VDTyLc+3pblSQ0VIno0QoxyavznU6faQhuCXuy3bD+E87ZlRNtk9jPKDg==";
-        let pod_proof = PodGroupedCiphertext2HandlesValidityProof::from_str(proof_str).unwrap();
-        let proof: GroupedCiphertext2HandlesValidityProof = pod_proof.try_into().unwrap();
-
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        proof
-            .verify(
-                &commitment,
-                &first_pubkey,
-                &second_pubkey,
-                &first_handle,
-                &second_handle,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-    }
-}

+ 0 - 513
zk-sdk/src/sigma_proofs/grouped_ciphertext_validity/handles_3.rs

@@ -1,513 +0,0 @@
-//! The grouped ciphertext with 3 handles validity sigma proof system.
-//!
-//! This ciphertext validity proof is defined with respect to a Pedersen commitment and three
-//! decryption handles. The proof certifies that a given Pedersen commitment can be decrypted using
-//! ElGamal private keys that are associated with each of the three decryption handles. To generate
-//! the proof, a prover must provide the Pedersen opening associated with the commitment.
-//!
-//! The protocol guarantees computational soundness (by the hardness of discrete log) and perfect
-//! zero-knowledge in the random oracle model.
-
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::{
-            elgamal::{DecryptHandle, ElGamalPubkey},
-            pedersen::{PedersenCommitment, PedersenOpening, G, H},
-        },
-        sigma_proofs::{canonical_scalar_from_optional_slice, ristretto_point_from_optional_slice},
-        UNIT_LEN,
-    },
-    curve25519_dalek::traits::MultiscalarMul,
-    rand::rngs::OsRng,
-    zeroize::Zeroize,
-};
-use {
-    crate::{
-        sigma_proofs::errors::{SigmaProofVerificationError, ValidityProofVerificationError},
-        transcript::TranscriptProtocol,
-    },
-    curve25519_dalek::{
-        ristretto::{CompressedRistretto, RistrettoPoint},
-        scalar::Scalar,
-        traits::{IsIdentity, VartimeMultiscalarMul},
-    },
-    merlin::Transcript,
-};
-
-/// Byte length of a grouped ciphertext validity proof for 3 handles
-const GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_LEN: usize = UNIT_LEN * 6;
-
-/// The grouped ciphertext validity proof for 3 handles.
-///
-/// Contains all the elliptic curve and scalar components that make up the sigma protocol.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[allow(non_snake_case)]
-#[derive(Clone)]
-pub struct GroupedCiphertext3HandlesValidityProof {
-    Y_0: CompressedRistretto,
-    Y_1: CompressedRistretto,
-    Y_2: CompressedRistretto,
-    Y_3: CompressedRistretto,
-    z_r: Scalar,
-    z_x: Scalar,
-}
-
-#[allow(non_snake_case)]
-#[cfg(not(target_os = "solana"))]
-impl GroupedCiphertext3HandlesValidityProof {
-    /// Creates a grouped ciphertext with 3 handles validity proof.
-    ///
-    /// The function does *not* hash the public keys, commitment, or decryption handles into the
-    /// transcript. For security, the caller (the main protocol) should hash these public
-    /// components prior to invoking this constructor.
-    ///
-    /// This function is randomized. It uses `OsRng` internally to generate random scalars.
-    ///
-    /// Note that the proof constructor does not take the actual Pedersen commitment or decryption
-    /// handles as input; it only takes the associated Pedersen opening instead.
-    ///
-    /// * `first_pubkey` - The first ElGamal public key
-    /// * `second_pubkey` - The second ElGamal public key
-    /// * `third_pubkey` - The third ElGamal public key
-    /// * `amount` - The committed message in the commitment
-    /// * `opening` - The opening associated with the Pedersen commitment
-    /// * `transcript` - The transcript that does the bookkeeping for the Fiat-Shamir heuristic
-    pub fn new<T: Into<Scalar>>(
-        first_pubkey: &ElGamalPubkey,
-        second_pubkey: &ElGamalPubkey,
-        third_pubkey: &ElGamalPubkey,
-        amount: T,
-        opening: &PedersenOpening,
-        transcript: &mut Transcript,
-    ) -> Self {
-        transcript.grouped_ciphertext_validity_proof_domain_separator(3);
-
-        // extract the relevant scalar and Ristretto points from the inputs
-        let P_first = first_pubkey.get_point();
-        let P_second = second_pubkey.get_point();
-        let P_third = third_pubkey.get_point();
-
-        let x = amount.into();
-        let r = opening.get_scalar();
-
-        // generate random masking factors that also serves as nonces
-        let mut y_r = Scalar::random(&mut OsRng);
-        let mut y_x = Scalar::random(&mut OsRng);
-
-        let Y_0 = RistrettoPoint::multiscalar_mul(vec![&y_r, &y_x], vec![&(*H), &G]).compress();
-        let Y_1 = (&y_r * P_first).compress();
-        let Y_2 = (&y_r * P_second).compress();
-        let Y_3 = (&y_r * P_third).compress();
-
-        // record masking factors in transcript and get challenges
-        transcript.append_point(b"Y_0", &Y_0);
-        transcript.append_point(b"Y_1", &Y_1);
-        transcript.append_point(b"Y_2", &Y_2);
-        transcript.append_point(b"Y_3", &Y_3);
-
-        let c = transcript.challenge_scalar(b"c");
-        transcript.challenge_scalar(b"w");
-
-        // compute masked message and opening
-        let z_r = &(&c * r) + &y_r;
-        let z_x = &(&c * &x) + &y_x;
-
-        y_r.zeroize();
-        y_x.zeroize();
-
-        Self {
-            Y_0,
-            Y_1,
-            Y_2,
-            Y_3,
-            z_r,
-            z_x,
-        }
-    }
-
-    /// Verifies a grouped ciphertext with 3 handles validity proof.
-    ///
-    /// * `commitment` - The Pedersen commitment
-    /// * `first_pubkey` - The first ElGamal public key
-    /// * `second_pubkey` - The second ElGamal public key
-    /// * `third_pubkey` - The third ElGamal public key
-    /// * `first_handle` - The first decryption handle
-    /// * `second_handle` - The second decryption handle
-    /// * `third_handle` - The third decryption handle
-    /// * `transcript` - The transcript that does the bookkeeping for the Fiat-Shamir heuristic
-    pub fn verify(
-        self,
-        commitment: &PedersenCommitment,
-        first_pubkey: &ElGamalPubkey,
-        second_pubkey: &ElGamalPubkey,
-        third_pubkey: &ElGamalPubkey,
-        first_handle: &DecryptHandle,
-        second_handle: &DecryptHandle,
-        third_handle: &DecryptHandle,
-        transcript: &mut Transcript,
-    ) -> Result<(), ValidityProofVerificationError> {
-        transcript.grouped_ciphertext_validity_proof_domain_separator(3);
-
-        // include `Y_0`, `Y_1`, `Y_2` to transcript and extract challenges
-        transcript.validate_and_append_point(b"Y_0", &self.Y_0)?;
-        transcript.validate_and_append_point(b"Y_1", &self.Y_1)?;
-        transcript.validate_and_append_point(b"Y_2", &self.Y_2)?;
-        // the point `Y_3` is defined with respect to the third public key and can be zero if the
-        // third public key is zero
-        transcript.append_point(b"Y_3", &self.Y_3);
-
-        let c = transcript.challenge_scalar(b"c");
-
-        transcript.append_scalar(b"z_r", &self.z_r);
-        transcript.append_scalar(b"z_x", &self.z_x);
-        let w = transcript.challenge_scalar(b"w");
-        let ww = &w * &w;
-        let www = &w * &ww;
-
-        let w_negated = -&w;
-        let ww_negated = -&ww;
-        let www_negated = -&www;
-
-        // check the required algebraic conditions
-        let Y_0 = self
-            .Y_0
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-        let Y_1 = self
-            .Y_1
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-        let Y_2 = self
-            .Y_2
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-        let Y_3 = self
-            .Y_3
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-
-        let P_first = first_pubkey.get_point();
-        let P_second = second_pubkey.get_point();
-        let P_third = third_pubkey.get_point();
-
-        let C = commitment.get_point();
-        let D_first = first_handle.get_point();
-        let D_second = second_handle.get_point();
-        let D_third = third_handle.get_point();
-
-        let check = RistrettoPoint::vartime_multiscalar_mul(
-            vec![
-                &self.z_r,            // z_r
-                &self.z_x,            // z_x
-                &(-&c),               // -c
-                &-(&Scalar::ONE),     // -identity
-                &(&w * &self.z_r),    // w * z_r
-                &(&w_negated * &c),   // -w * c
-                &w_negated,           // -w
-                &(&ww * &self.z_r),   // ww * z_r
-                &(&ww_negated * &c),  // -ww * c
-                &ww_negated,          // -ww
-                &(&www * &self.z_r),  // www * z_r
-                &(&www_negated * &c), // -www * c
-                &www_negated,         // -www
-            ],
-            vec![
-                &(*H),    // H
-                &G,       // G
-                C,        // C
-                &Y_0,     // Y_0
-                P_first,  // P_first
-                D_first,  // D_first
-                &Y_1,     // Y_1
-                P_second, // P_second
-                D_second, // D_second
-                &Y_2,     // Y_2
-                P_third,  // P_third
-                D_third,  // D_third
-                &Y_3,     // Y_3
-            ],
-        );
-
-        if check.is_identity() {
-            Ok(())
-        } else {
-            Err(SigmaProofVerificationError::AlgebraicRelation.into())
-        }
-    }
-
-    pub fn to_bytes(&self) -> [u8; GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_LEN] {
-        let mut buf = [0_u8; GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_LEN];
-        let mut chunks = buf.chunks_mut(UNIT_LEN);
-        chunks.next().unwrap().copy_from_slice(self.Y_0.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.Y_1.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.Y_2.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.Y_3.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.z_r.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.z_x.as_bytes());
-        buf
-    }
-
-    pub fn from_bytes(bytes: &[u8]) -> Result<Self, ValidityProofVerificationError> {
-        let mut chunks = bytes.chunks(UNIT_LEN);
-        let Y_0 = ristretto_point_from_optional_slice(chunks.next())?;
-        let Y_1 = ristretto_point_from_optional_slice(chunks.next())?;
-        let Y_2 = ristretto_point_from_optional_slice(chunks.next())?;
-        let Y_3 = ristretto_point_from_optional_slice(chunks.next())?;
-        let z_r = canonical_scalar_from_optional_slice(chunks.next())?;
-        let z_x = canonical_scalar_from_optional_slice(chunks.next())?;
-
-        Ok(GroupedCiphertext3HandlesValidityProof {
-            Y_0,
-            Y_1,
-            Y_2,
-            Y_3,
-            z_r,
-            z_x,
-        })
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use {
-        super::*,
-        crate::{
-            encryption::{
-                elgamal::ElGamalKeypair,
-                pedersen::Pedersen,
-                pod::{
-                    elgamal::{PodDecryptHandle, PodElGamalCiphertext, PodElGamalPubkey},
-                    pedersen::PodPedersenCommitment,
-                },
-            },
-            sigma_proofs::pod::PodGroupedCiphertext3HandlesValidityProof,
-        },
-        std::str::FromStr,
-    };
-
-    #[test]
-    fn test_grouped_ciphertext_3_handles_validity_proof_correctness() {
-        let first_keypair = ElGamalKeypair::new_rand();
-        let first_pubkey = first_keypair.pubkey();
-
-        let second_keypair = ElGamalKeypair::new_rand();
-        let second_pubkey = second_keypair.pubkey();
-
-        let third_keypair = ElGamalKeypair::new_rand();
-        let third_pubkey = third_keypair.pubkey();
-
-        let amount: u64 = 55;
-        let (commitment, opening) = Pedersen::new(amount);
-
-        let first_handle = first_pubkey.decrypt_handle(&opening);
-        let second_handle = second_pubkey.decrypt_handle(&opening);
-        let third_handle = third_pubkey.decrypt_handle(&opening);
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = GroupedCiphertext3HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            third_pubkey,
-            amount,
-            &opening,
-            &mut prover_transcript,
-        );
-
-        proof
-            .verify(
-                &commitment,
-                first_pubkey,
-                second_pubkey,
-                third_pubkey,
-                &first_handle,
-                &second_handle,
-                &third_handle,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-    }
-
-    #[test]
-    fn test_grouped_ciphertext_3_handles_validity_proof_edge_cases() {
-        // if first or second public key zeroed, then the proof should always reject
-        let first_pubkey = ElGamalPubkey::try_from([0u8; 32].as_slice()).unwrap();
-        let second_pubkey = ElGamalPubkey::try_from([0u8; 32].as_slice()).unwrap();
-
-        let third_keypair = ElGamalKeypair::new_rand();
-        let third_pubkey = third_keypair.pubkey();
-
-        let amount: u64 = 55;
-        let (commitment, opening) = Pedersen::new(amount);
-
-        let first_handle = second_pubkey.decrypt_handle(&opening);
-        let second_handle = second_pubkey.decrypt_handle(&opening);
-        let third_handle = third_pubkey.decrypt_handle(&opening);
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = GroupedCiphertext3HandlesValidityProof::new(
-            &first_pubkey,
-            &second_pubkey,
-            third_pubkey,
-            amount,
-            &opening,
-            &mut prover_transcript,
-        );
-
-        assert!(proof
-            .verify(
-                &commitment,
-                &first_pubkey,
-                &second_pubkey,
-                third_pubkey,
-                &first_handle,
-                &second_handle,
-                &third_handle,
-                &mut verifier_transcript,
-            )
-            .is_err());
-
-        // all zeroed ciphertext should still be valid
-        let first_keypair = ElGamalKeypair::new_rand();
-        let first_pubkey = first_keypair.pubkey();
-
-        let second_keypair = ElGamalKeypair::new_rand();
-        let second_pubkey = second_keypair.pubkey();
-
-        let third_keypair = ElGamalKeypair::new_rand();
-        let third_pubkey = third_keypair.pubkey();
-
-        let amount: u64 = 0;
-        let commitment = PedersenCommitment::from_bytes(&[0u8; 32]).unwrap();
-        let opening = PedersenOpening::from_bytes(&[0u8; 32]).unwrap();
-
-        let first_handle = first_pubkey.decrypt_handle(&opening);
-        let second_handle = second_pubkey.decrypt_handle(&opening);
-        let third_handle = third_pubkey.decrypt_handle(&opening);
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = GroupedCiphertext3HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            third_pubkey,
-            amount,
-            &opening,
-            &mut prover_transcript,
-        );
-
-        proof
-            .verify(
-                &commitment,
-                first_pubkey,
-                second_pubkey,
-                third_pubkey,
-                &first_handle,
-                &second_handle,
-                &third_handle,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-
-        // decryption handles can be zero as long as the Pedersen commitment is valid
-        let first_keypair = ElGamalKeypair::new_rand();
-        let first_pubkey = first_keypair.pubkey();
-
-        let second_keypair = ElGamalKeypair::new_rand();
-        let second_pubkey = second_keypair.pubkey();
-
-        let third_keypair = ElGamalKeypair::new_rand();
-        let third_pubkey = third_keypair.pubkey();
-
-        let amount: u64 = 55;
-        let zeroed_opening = PedersenOpening::default();
-
-        let commitment = Pedersen::with(amount, &zeroed_opening);
-
-        let first_handle = first_pubkey.decrypt_handle(&zeroed_opening);
-        let second_handle = second_pubkey.decrypt_handle(&zeroed_opening);
-        let third_handle = third_pubkey.decrypt_handle(&zeroed_opening);
-
-        let mut prover_transcript = Transcript::new(b"Test");
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        let proof = GroupedCiphertext3HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            third_pubkey,
-            amount,
-            &opening,
-            &mut prover_transcript,
-        );
-
-        proof
-            .verify(
-                &commitment,
-                first_pubkey,
-                second_pubkey,
-                third_pubkey,
-                &first_handle,
-                &second_handle,
-                &third_handle,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-    }
-
-    #[test]
-    fn test_grouped_ciphertext_3_handles_validity_proof_string() {
-        let commitment_str = "DDSCVZLH+eqC9gX+ZeP3HQQxigojAOgda3YwVChR5W4=";
-        let pod_commitment = PodPedersenCommitment::from_str(commitment_str).unwrap();
-        let commitment: PedersenCommitment = pod_commitment.try_into().unwrap();
-
-        let first_pubkey_str = "yGGJnLUs8B744So/Ua3n2wNm+8u9ey/6KrDdHx4ySwk=";
-        let pod_first_pubkey = PodElGamalPubkey::from_str(first_pubkey_str).unwrap();
-        let first_pubkey: ElGamalPubkey = pod_first_pubkey.try_into().unwrap();
-
-        let second_pubkey_str = "ZFETe85sZdWpxLAo177kwiOxZCpsXGeyZEnzern7tAk=";
-        let pod_second_pubkey = PodElGamalPubkey::from_str(second_pubkey_str).unwrap();
-        let second_pubkey: ElGamalPubkey = pod_second_pubkey.try_into().unwrap();
-
-        let third_pubkey_str = "duUYiBx0l0jRRPsTLCoCD8PIKFczPdrxl+2f4eCflhQ=";
-        let pod_third_pubkey = PodElGamalPubkey::from_str(third_pubkey_str).unwrap();
-        let third_pubkey: ElGamalPubkey = pod_third_pubkey.try_into().unwrap();
-
-        let first_handle_str = "Asor2klomf847EmJZmXn3qoi0SGE3cBXCkKttbJa+lE=";
-        let pod_first_handle_str = PodDecryptHandle::from_str(first_handle_str).unwrap();
-        let first_handle: DecryptHandle = pod_first_handle_str.try_into().unwrap();
-
-        let second_handle_str = "kJ0GYHDVeB1Kgvqp+MY/my3BYZvqsC5Mv0gQLJHnNBQ=";
-        let pod_second_handle_str = PodDecryptHandle::from_str(second_handle_str).unwrap();
-        let second_handle: DecryptHandle = pod_second_handle_str.try_into().unwrap();
-
-        let third_handle_str = "Jnd5jZLNDOMMt+kbgQWCQqTytbwHx3Bz5vwtfDLhRn0=";
-        let pod_third_handle_str = PodDecryptHandle::from_str(third_handle_str).unwrap();
-        let third_handle: DecryptHandle = pod_third_handle_str.try_into().unwrap();
-
-        let proof_str = "8NoqOM40+fvPY2aHzO0SdWZM6lvSoaqI7KpaFuE4wQUaqewILtQV8IMHeHmpevxt/GTErJsdcV8kY3HDZ1GHbMoDujYpstUhyubX1voJh/DstYAL1SQqlRpNLG+kWEUZYvCudTur7i5R+zqZQY3sRMEAxW458V+1GmyCWbWP3FZEz5gX/Pa28/ZNLBvmSPpJBZapXRI5Ra0dKPskFmQ0CH0gBWo6pxj/PH9sgNEkLrbVZB7jpVtdmNzivwgFeb4M";
-        let pod_proof = PodGroupedCiphertext3HandlesValidityProof::from_str(proof_str).unwrap();
-        let proof: GroupedCiphertext3HandlesValidityProof = pod_proof.try_into().unwrap();
-
-        let mut verifier_transcript = Transcript::new(b"Test");
-
-        proof
-            .verify(
-                &commitment,
-                &first_pubkey,
-                &second_pubkey,
-                &third_pubkey,
-                &first_handle,
-                &second_handle,
-                &third_handle,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-    }
-}

+ 0 - 7
zk-sdk/src/sigma_proofs/grouped_ciphertext_validity/mod.rs

@@ -1,7 +0,0 @@
-mod handles_2;
-mod handles_3;
-
-pub use {
-    handles_2::GroupedCiphertext2HandlesValidityProof,
-    handles_3::GroupedCiphertext3HandlesValidityProof,
-};

+ 0 - 93
zk-sdk/src/sigma_proofs/mod.rs

@@ -1,93 +0,0 @@
-//! Collection of sigma proofs that are used in the ZK Token proof program.
-//!
-//! Formal documentation and security proofs for the sigma proofs in this module can be found in
-//! [`ZK Token proof`] program documentation.
-//!
-//! [`ZK Token proof`]: https://docs.solanalabs.com/runtime/zk-token-proof
-
-#![allow(dead_code, unused_imports)]
-
-pub mod errors;
-pub mod pod;
-
-#[cfg(not(target_os = "solana"))]
-pub mod batched_grouped_ciphertext_validity;
-#[cfg(not(target_os = "solana"))]
-pub mod ciphertext_ciphertext_equality;
-#[cfg(not(target_os = "solana"))]
-pub mod ciphertext_commitment_equality;
-#[cfg(not(target_os = "solana"))]
-pub mod grouped_ciphertext_validity;
-#[cfg(not(target_os = "solana"))]
-pub mod percentage_with_cap;
-#[cfg(not(target_os = "solana"))]
-pub mod pubkey_validity;
-#[cfg(not(target_os = "solana"))]
-pub mod zero_ciphertext;
-
-/// Byte length of a ciphertext-commitment equality proof
-pub const CIPHERTEXT_COMMITMENT_EQUALITY_PROOF_LEN: usize = 192;
-
-/// Byte length of a ciphertext-ciphertext equality proof
-pub const CIPHERTEXT_CIPHERTEXT_EQUALITY_PROOF_LEN: usize = 224;
-
-/// Byte length of a grouped ciphertext for 2 handles validity proof
-pub const GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY_PROOF_LEN: usize = 160;
-
-/// Byte length of a grouped ciphertext for 3 handles validity proof
-pub const GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_LEN: usize = 192;
-
-/// Byte length of a batched grouped ciphertext for 2 handles validity proof
-pub const BATCHED_GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY_PROOF_LEN: usize = 160;
-
-/// Byte length of a batched grouped ciphertext for 3 handles validity proof
-pub const BATCHED_GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_LEN: usize = 192;
-
-/// Byte length of a zero-ciphertext proof
-pub const ZERO_CIPHERTEXT_PROOF_LEN: usize = 96;
-
-/// Byte length of a percentage with cap proof
-pub const PERCENTAGE_WITH_CAP_PROOF_LEN: usize = 256;
-
-/// Byte length of a public key validity proof
-pub const PUBKEY_VALIDITY_PROOF_LEN: usize = 64;
-
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{sigma_proofs::errors::SigmaProofVerificationError, RISTRETTO_POINT_LEN, SCALAR_LEN},
-    curve25519_dalek::{ristretto::CompressedRistretto, scalar::Scalar},
-};
-
-/// Deserializes an optional slice of bytes to a compressed Ristretto point.
-///
-/// This is a helper function for deserializing byte encodings of sigma proofs. It is designed to
-/// be used with `std::slice::Chunks`.
-#[cfg(not(target_os = "solana"))]
-fn ristretto_point_from_optional_slice(
-    optional_slice: Option<&[u8]>,
-) -> Result<CompressedRistretto, SigmaProofVerificationError> {
-    let Some(slice) = optional_slice else {
-        return Err(SigmaProofVerificationError::Deserialization);
-    };
-
-    if slice.len() != RISTRETTO_POINT_LEN {
-        return Err(SigmaProofVerificationError::Deserialization);
-    }
-
-    CompressedRistretto::from_slice(slice).map_err(|_| SigmaProofVerificationError::Deserialization)
-}
-
-/// Deserializes an optional slice of bytes to a scalar.
-///
-/// This is a helper function for deserializing byte encodings of sigma proofs. It is designed to
-/// be used with `std::slice::Chunks`.
-#[cfg(not(target_os = "solana"))]
-fn canonical_scalar_from_optional_slice(
-    optional_slice: Option<&[u8]>,
-) -> Result<Scalar, SigmaProofVerificationError> {
-    optional_slice
-        .and_then(|slice| (slice.len() == SCALAR_LEN).then_some(slice)) // if chunk is the wrong length, convert to None
-        .and_then(|slice| slice.try_into().ok()) // convert to array
-        .and_then(|slice| Scalar::from_canonical_bytes(slice).into_option())
-        .ok_or(SigmaProofVerificationError::Deserialization)
-}

+ 0 - 751
zk-sdk/src/sigma_proofs/percentage_with_cap.rs

@@ -1,751 +0,0 @@
-//! The percentage-with-cap sigma proof.
-//!
-//! The proof is defined with respect to three Pedersen commitments that encodes values referred to
-//! as a `percentage`, `delta`, and `claimed` amounts. The proof certifies that either
-//! - the `percentage` amount is equal to a constant (referred to as the `max_value`)
-//! - the `delta` and `claimed` amounts are equal
-//!
-//! This type of proof is useful as a building block to prove that, given two Pedersen commitments,
-//! one encodes a percentage value of the number encoded by the other commitment with a specified
-//! max cap value.
-//!
-//! A more detailed description of the context and how the proof is computed is provided in the
-//! [`ZK Token proof program`] documentation.
-//!
-//! The protocol guarantees computational soundness (by the hardness of discrete log) and perfect
-//! zero-knowledge in the random oracle model.
-//!
-//! [`ZK Token proof program`]: https://docs.solanalabs.com/runtime/zk-token-proof
-
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::pedersen::{PedersenCommitment, PedersenOpening, G, H},
-        sigma_proofs::{canonical_scalar_from_optional_slice, ristretto_point_from_optional_slice},
-        UNIT_LEN,
-    },
-    rand::rngs::OsRng,
-};
-use {
-    crate::{
-        sigma_proofs::errors::{
-            PercentageWithCapProofVerificationError, SigmaProofVerificationError,
-        },
-        transcript::TranscriptProtocol,
-    },
-    curve25519_dalek::{
-        ristretto::{CompressedRistretto, RistrettoPoint},
-        scalar::Scalar,
-        traits::{IsIdentity, MultiscalarMul, VartimeMultiscalarMul},
-    },
-    merlin::Transcript,
-    subtle::{Choice, ConditionallySelectable, ConstantTimeGreater},
-};
-
-/// Byte length of a percentage-with-cap proof.
-const PERCENTAGE_WITH_CAP_PROOF_LEN: usize = UNIT_LEN * 8;
-
-/// Percentage-with-cap proof.
-///
-/// The proof consists of two main components: `percentage_max_proof` and
-/// `percentage_equality_proof`. If the committed amount is greater than the maximum cap value,
-/// then the `percentage_max_proof` is properly generated and `percentage_equality_proof` is
-/// simulated. If the committed amount is smaller than the maximum cap bound, the
-/// `percentage_equality_proof` is properly generated and `percentage_max_proof` is simulated.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone)]
-pub struct PercentageWithCapProof {
-    /// Proof that the committed amount equals the maximum cap bound
-    percentage_max_proof: PercentageMaxProof,
-
-    /// Proof that the `delta` value is equal to the `claimed` value
-    percentage_equality_proof: PercentageEqualityProof,
-}
-
-#[allow(non_snake_case, dead_code)]
-#[cfg(not(target_os = "solana"))]
-impl PercentageWithCapProof {
-    /// Creates a percentage-with-cap sigma proof.
-    ///
-    /// A typical percentage-with-cap application is defined with respect to the following values:
-    /// - a commitment encoding a `base_amount` and a commitment encoding a `percentage_amount`
-    /// - two constants `percentage_rate_basis_point`, which defines the percentage rate in units
-    ///   of 0.01% and `max_value`, which defines the max cap amount.
-    ///
-    /// This setting requires that the `percentage_amount` is either a certain percentage of the
-    /// `base_amount` (determined by the `percentage_rate_basis_point`) or is equal to the max cap
-    /// amount (determined by `max_value`).
-    ///
-    /// If `percentage_amount < max_value`, then assuming that there is no division rounding, the
-    /// `percentage_amount` must satisfy the relation `transfer_amount *
-    /// (percentage_rate_basis_point / 10_000) = percentage_amount` or equivalently, `(base_amount
-    /// * percentage_rate_basis_point) - (10_000 * percentage_amount) = 0`. More generally, let
-    /// `delta_amount = (base_amount * percentage_rate_basis_point) - (10_000 * percentage_amount)`.
-    /// Then assuming that a division rounding could occur, the `delta_amount` must satisfy the
-    /// bound `0 <= delta_amount < 10_000`.
-    ///
-    /// If `percentage_amount >= max_amount`, then `percentage_amount = max_value` and therefore,
-    /// the prover can generate a proof certifying that a percentage commitment exactly encodes
-    /// `max_value`. If `percentage_amount < max_value`, then the prover can create a commitment
-    /// (referred to as the `claimed_amount`) to `delta_amount` and create a range proof certifying
-    /// that the committed value satisfies the bound `0 <= delta_amount < 10_000`.
-    ///
-    /// Since the type of proof that a prover generates reveals information about the base and
-    /// percentage amounts, the prover must generate and include both types of proofs. If
-    /// `percentage_amount >= max_value`, then the prover generates a valid `percentage_max_proof`,
-    /// but commits to 0 as the `claimed_amount` and simulates ("fakes") a proof
-    /// (`percentage_equality_proof`) that this is valid. If `percentage_amount > max_value`, then
-    /// the prover simulates a `percentage_max_proof`, and creates a valid
-    /// `percentage_equality_proof` certifying that the claimed delta value is equal to the "real"
-    /// delta value.
-    ///
-    /// Note: In the implementation, the proof is generated twice via `create_proof_above_max`
-    /// and `create_proof_below_max` to enforce that the function executes in constant time.
-    ///
-    /// * `percentage_commitment` - The Pedersen commitment to a percentage amount
-    /// * `percentage_opening` - The Pedersen opening of a percentage amount
-    /// * `percentage_amount` - The percentage amount
-    /// * `delta_commitment` - The Pedersen commitment to a delta amount
-    /// * `delta_opening` - The Pedersen opening of a delta amount
-    /// * `delta_amount` - The delta amount
-    /// * `claimed_commitment` - The Pedersen commitment to a claimed amount
-    /// * `claimed_opening` - The Pedersen opening of a claimed amount
-    /// * `max_value` - The maximum cap bound
-    /// * `transcript` - The transcript that does the bookkeeping for the Fiat-Shamir heuristic
-    #[allow(clippy::too_many_arguments)]
-    pub fn new(
-        percentage_commitment: &PedersenCommitment,
-        percentage_opening: &PedersenOpening,
-        percentage_amount: u64,
-        delta_commitment: &PedersenCommitment,
-        delta_opening: &PedersenOpening,
-        delta_amount: u64,
-        claimed_commitment: &PedersenCommitment,
-        claimed_opening: &PedersenOpening,
-        max_value: u64,
-        transcript: &mut Transcript,
-    ) -> Self {
-        transcript.percentage_with_cap_proof_domain_separator();
-        let mut transcript_percentage_above_max = transcript.clone();
-        let mut transcript_percentage_below_max = transcript.clone();
-
-        // compute proof for both cases `percentage_amount' >= `max_value` and
-        // `percentage_amount` < `max_value`
-        let proof_above_max = Self::create_proof_percentage_above_max(
-            percentage_opening,
-            delta_commitment,
-            claimed_commitment,
-            &mut transcript_percentage_above_max,
-        );
-
-        let proof_below_max = Self::create_proof_percentage_below_max(
-            percentage_commitment,
-            delta_opening,
-            delta_amount,
-            claimed_opening,
-            max_value,
-            &mut transcript_percentage_below_max,
-        );
-
-        let below_max = u64::ct_gt(&max_value, &percentage_amount);
-
-        // choose one of `proof_above_max` or `proof_below_max` according to whether the
-        // percentage amount is greater than `max_value` or not
-        let percentage_max_proof = PercentageMaxProof::conditional_select(
-            &proof_above_max.percentage_max_proof,
-            &proof_below_max.percentage_max_proof,
-            below_max,
-        );
-
-        let percentage_equality_proof = PercentageEqualityProof::conditional_select(
-            &proof_above_max.percentage_equality_proof,
-            &proof_below_max.percentage_equality_proof,
-            below_max,
-        );
-
-        transcript.append_point(b"Y_max_proof", &percentage_max_proof.Y_max_proof);
-        transcript.append_point(b"Y_delta", &percentage_equality_proof.Y_delta);
-        transcript.append_point(b"Y_claimed", &percentage_equality_proof.Y_claimed);
-        transcript.challenge_scalar(b"c");
-        transcript.challenge_scalar(b"w");
-
-        Self {
-            percentage_max_proof,
-            percentage_equality_proof,
-        }
-    }
-
-    /// Creates a percentage-with-cap proof assuming that the committed percentage is greater than
-    /// the maximum cap bound.
-    ///
-    /// * `percentage_opening` - The Pedersen opening of a percentage amount
-    /// * `delta_commitment` - The Pedersen commitment to a delta amount
-    /// * `claimed_commitment` - The Pedersen commitment to a claimed amount
-    /// * `transcript` - The transcript that does the bookkeeping for the Fiat-Shamir heuristic
-    fn create_proof_percentage_above_max(
-        percentage_opening: &PedersenOpening,
-        delta_commitment: &PedersenCommitment,
-        claimed_commitment: &PedersenCommitment,
-        transcript: &mut Transcript,
-    ) -> Self {
-        // simulate equality proof
-        let C_delta = delta_commitment.get_point();
-        let C_claimed = claimed_commitment.get_point();
-
-        let z_x = Scalar::random(&mut OsRng);
-        let z_delta = Scalar::random(&mut OsRng);
-        let z_claimed = Scalar::random(&mut OsRng);
-        let c_equality = Scalar::random(&mut OsRng);
-
-        let Y_delta = RistrettoPoint::multiscalar_mul(
-            vec![z_x, z_delta, -c_equality],
-            vec![&G, &(*H), C_delta],
-        )
-        .compress();
-
-        let Y_claimed = RistrettoPoint::multiscalar_mul(
-            vec![z_x, z_claimed, -c_equality],
-            vec![&G, &(*H), C_claimed],
-        )
-        .compress();
-
-        let percentage_equality_proof = PercentageEqualityProof {
-            Y_delta,
-            Y_claimed,
-            z_x,
-            z_delta,
-            z_claimed,
-        };
-
-        // generate max proof
-        let r_percentage = percentage_opening.get_scalar();
-
-        let y_max_proof = Scalar::random(&mut OsRng);
-        let Y_max_proof = (y_max_proof * &(*H)).compress();
-
-        transcript.append_point(b"Y_max_proof", &Y_max_proof);
-        transcript.append_point(b"Y_delta", &Y_delta);
-        transcript.append_point(b"Y_claimed", &Y_claimed);
-
-        let c = transcript.challenge_scalar(b"c");
-        let c_max_proof = c - c_equality;
-
-        transcript.challenge_scalar(b"w");
-
-        let z_max_proof = c_max_proof * r_percentage + y_max_proof;
-
-        let percentage_max_proof = PercentageMaxProof {
-            Y_max_proof,
-            z_max_proof,
-            c_max_proof,
-        };
-
-        Self {
-            percentage_max_proof,
-            percentage_equality_proof,
-        }
-    }
-
-    /// Creates a percentage-with-cap proof assuming that the committed amount is less than the
-    /// maximum cap bound.
-    ///
-    /// * `percentage_commitment` - The Pedersen commitment to a percentage amount
-    /// * `delta_opening` - The Pedersen opening of a delta amount
-    /// * `delta_amount` - The delta amount
-    /// * `claimed_opening` - The Pedersen opening of a claimed amount
-    /// * `max_value` - The maximum cap bound
-    /// * `transcript` - The transcript that does the bookkeeping for the Fiat-Shamir heuristic
-    fn create_proof_percentage_below_max(
-        percentage_commitment: &PedersenCommitment,
-        delta_opening: &PedersenOpening,
-        delta_amount: u64,
-        claimed_opening: &PedersenOpening,
-        max_value: u64,
-        transcript: &mut Transcript,
-    ) -> Self {
-        // simulate max proof
-        let m = Scalar::from(max_value);
-        let C_percentage = percentage_commitment.get_point();
-
-        let z_max_proof = Scalar::random(&mut OsRng);
-        let c_max_proof = Scalar::random(&mut OsRng); // random challenge
-
-        // solve for Y_max in the verification algebraic relation
-        let Y_max_proof = RistrettoPoint::multiscalar_mul(
-            vec![z_max_proof, -c_max_proof, c_max_proof * m],
-            vec![&(*H), C_percentage, &G],
-        )
-        .compress();
-
-        let percentage_max_proof = PercentageMaxProof {
-            Y_max_proof,
-            z_max_proof,
-            c_max_proof,
-        };
-
-        // generate equality proof
-        let x = Scalar::from(delta_amount);
-
-        let r_delta = delta_opening.get_scalar();
-        let r_claimed = claimed_opening.get_scalar();
-
-        let y_x = Scalar::random(&mut OsRng);
-        let y_delta = Scalar::random(&mut OsRng);
-        let y_claimed = Scalar::random(&mut OsRng);
-
-        let Y_delta =
-            RistrettoPoint::multiscalar_mul(vec![y_x, y_delta], vec![&G, &(*H)]).compress();
-        let Y_claimed =
-            RistrettoPoint::multiscalar_mul(vec![y_x, y_claimed], vec![&G, &(*H)]).compress();
-
-        transcript.append_point(b"Y_max_proof", &Y_max_proof);
-        transcript.append_point(b"Y_delta", &Y_delta);
-        transcript.append_point(b"Y_claimed", &Y_claimed);
-
-        let c = transcript.challenge_scalar(b"c");
-        let c_equality = c - c_max_proof;
-
-        transcript.challenge_scalar(b"w");
-
-        let z_x = c_equality * x + y_x;
-        let z_delta = c_equality * r_delta + y_delta;
-        let z_claimed = c_equality * r_claimed + y_claimed;
-
-        let percentage_equality_proof = PercentageEqualityProof {
-            Y_delta,
-            Y_claimed,
-            z_x,
-            z_delta,
-            z_claimed,
-        };
-
-        Self {
-            percentage_max_proof,
-            percentage_equality_proof,
-        }
-    }
-
-    /// Verifies a percentage-with-cap proof.
-    ///
-    /// * `percentage_commitment` - The Pedersen commitment of the value being proved
-    /// * `delta_commitment` - The Pedersen commitment of the "real" delta value
-    /// * `claimed_commitment` - The Pedersen commitment of the "claimed" delta value
-    /// * `max_value` - The maximum cap bound
-    /// * `transcript` - The transcript that does the bookkeeping for the Fiat-Shamir heuristic
-    pub fn verify(
-        self,
-        percentage_commitment: &PedersenCommitment,
-        delta_commitment: &PedersenCommitment,
-        claimed_commitment: &PedersenCommitment,
-        max_value: u64,
-        transcript: &mut Transcript,
-    ) -> Result<(), PercentageWithCapProofVerificationError> {
-        transcript.percentage_with_cap_proof_domain_separator();
-
-        // extract the relevant scalar and Ristretto points from the input
-        let m = Scalar::from(max_value);
-
-        let C_max = percentage_commitment.get_point();
-        let C_delta = delta_commitment.get_point();
-        let C_claimed = claimed_commitment.get_point();
-
-        transcript
-            .validate_and_append_point(b"Y_max_proof", &self.percentage_max_proof.Y_max_proof)?;
-        transcript
-            .validate_and_append_point(b"Y_delta", &self.percentage_equality_proof.Y_delta)?;
-        transcript
-            .validate_and_append_point(b"Y_claimed", &self.percentage_equality_proof.Y_claimed)?;
-
-        let Y_max = self
-            .percentage_max_proof
-            .Y_max_proof
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-        let z_max = self.percentage_max_proof.z_max_proof;
-
-        let Y_delta_real = self
-            .percentage_equality_proof
-            .Y_delta
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-        let Y_claimed = self
-            .percentage_equality_proof
-            .Y_claimed
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-        let z_x = self.percentage_equality_proof.z_x;
-        let z_delta_real = self.percentage_equality_proof.z_delta;
-        let z_claimed = self.percentage_equality_proof.z_claimed;
-
-        let c = transcript.challenge_scalar(b"c");
-        let c_max_proof = self.percentage_max_proof.c_max_proof;
-        let c_equality = c - c_max_proof;
-
-        transcript.append_scalar(b"z_max", &z_max);
-        transcript.append_scalar(b"z_x", &z_x);
-        transcript.append_scalar(b"z_delta_real", &z_delta_real);
-        transcript.append_scalar(b"z_claimed", &z_claimed);
-        let w = transcript.challenge_scalar(b"w");
-        let ww = w * w;
-
-        let check = RistrettoPoint::vartime_multiscalar_mul(
-            vec![
-                c_max_proof,
-                -c_max_proof * m,
-                -z_max,
-                Scalar::ONE,
-                w * z_x,
-                w * z_delta_real,
-                -w * c_equality,
-                -w,
-                ww * z_x,
-                ww * z_claimed,
-                -ww * c_equality,
-                -ww,
-            ],
-            vec![
-                C_max,
-                &G,
-                &(*H),
-                &Y_max,
-                &G,
-                &(*H),
-                C_delta,
-                &Y_delta_real,
-                &G,
-                &(*H),
-                C_claimed,
-                &Y_claimed,
-            ],
-        );
-
-        if check.is_identity() {
-            Ok(())
-        } else {
-            Err(SigmaProofVerificationError::AlgebraicRelation.into())
-        }
-    }
-
-    pub fn to_bytes(&self) -> [u8; PERCENTAGE_WITH_CAP_PROOF_LEN] {
-        let mut buf = [0_u8; PERCENTAGE_WITH_CAP_PROOF_LEN];
-        let mut chunks = buf.chunks_mut(UNIT_LEN);
-        chunks
-            .next()
-            .unwrap()
-            .copy_from_slice(self.percentage_max_proof.Y_max_proof.as_bytes());
-        chunks
-            .next()
-            .unwrap()
-            .copy_from_slice(self.percentage_max_proof.z_max_proof.as_bytes());
-        chunks
-            .next()
-            .unwrap()
-            .copy_from_slice(self.percentage_max_proof.c_max_proof.as_bytes());
-        chunks
-            .next()
-            .unwrap()
-            .copy_from_slice(self.percentage_equality_proof.Y_delta.as_bytes());
-        chunks
-            .next()
-            .unwrap()
-            .copy_from_slice(self.percentage_equality_proof.Y_claimed.as_bytes());
-        chunks
-            .next()
-            .unwrap()
-            .copy_from_slice(self.percentage_equality_proof.z_x.as_bytes());
-        chunks
-            .next()
-            .unwrap()
-            .copy_from_slice(self.percentage_equality_proof.z_delta.as_bytes());
-        chunks
-            .next()
-            .unwrap()
-            .copy_from_slice(self.percentage_equality_proof.z_claimed.as_bytes());
-        buf
-    }
-
-    pub fn from_bytes(bytes: &[u8]) -> Result<Self, PercentageWithCapProofVerificationError> {
-        let mut chunks = bytes.chunks(UNIT_LEN);
-        let Y_max_proof = ristretto_point_from_optional_slice(chunks.next())?;
-        let z_max_proof = canonical_scalar_from_optional_slice(chunks.next())?;
-        let c_max_proof = canonical_scalar_from_optional_slice(chunks.next())?;
-
-        let Y_delta = ristretto_point_from_optional_slice(chunks.next())?;
-        let Y_claimed = ristretto_point_from_optional_slice(chunks.next())?;
-        let z_x = canonical_scalar_from_optional_slice(chunks.next())?;
-        let z_delta = canonical_scalar_from_optional_slice(chunks.next())?;
-        let z_claimed = canonical_scalar_from_optional_slice(chunks.next())?;
-
-        Ok(Self {
-            percentage_max_proof: PercentageMaxProof {
-                Y_max_proof,
-                z_max_proof,
-                c_max_proof,
-            },
-            percentage_equality_proof: PercentageEqualityProof {
-                Y_delta,
-                Y_claimed,
-                z_x,
-                z_delta,
-                z_claimed,
-            },
-        })
-    }
-}
-
-/// The percentage max proof.
-///
-/// The proof certifies that a Pedersen commitment encodes the maximum cap bound.
-#[allow(non_snake_case)]
-#[derive(Clone, Copy)]
-pub struct PercentageMaxProof {
-    Y_max_proof: CompressedRistretto,
-    z_max_proof: Scalar,
-    c_max_proof: Scalar,
-}
-
-impl ConditionallySelectable for PercentageMaxProof {
-    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
-        Self {
-            Y_max_proof: conditional_select_ristretto(&a.Y_max_proof, &b.Y_max_proof, choice),
-            z_max_proof: Scalar::conditional_select(&a.z_max_proof, &b.z_max_proof, choice),
-            c_max_proof: Scalar::conditional_select(&a.c_max_proof, &b.c_max_proof, choice),
-        }
-    }
-}
-
-/// The percentage equality proof.
-///
-/// The proof certifies that the "real" delta value commitment and the "claimed" delta value
-/// commitment encode the same message.
-#[allow(non_snake_case)]
-#[derive(Clone, Copy)]
-pub struct PercentageEqualityProof {
-    Y_delta: CompressedRistretto,
-    Y_claimed: CompressedRistretto,
-    z_x: Scalar,
-    z_delta: Scalar,
-    z_claimed: Scalar,
-}
-
-impl ConditionallySelectable for PercentageEqualityProof {
-    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
-        Self {
-            Y_delta: conditional_select_ristretto(&a.Y_delta, &b.Y_delta, choice),
-            Y_claimed: conditional_select_ristretto(&a.Y_claimed, &b.Y_claimed, choice),
-            z_x: Scalar::conditional_select(&a.z_x, &b.z_x, choice),
-            z_delta: Scalar::conditional_select(&a.z_delta, &b.z_delta, choice),
-            z_claimed: Scalar::conditional_select(&a.z_claimed, &b.z_claimed, choice),
-        }
-    }
-}
-
-/// Selects one of two Ristretto points in constant time.
-#[allow(clippy::needless_range_loop)]
-fn conditional_select_ristretto(
-    a: &CompressedRistretto,
-    b: &CompressedRistretto,
-    choice: Choice,
-) -> CompressedRistretto {
-    let mut bytes = [0u8; 32];
-    for i in 0..32 {
-        bytes[i] = u8::conditional_select(&a.as_bytes()[i], &b.as_bytes()[i], choice);
-    }
-    CompressedRistretto(bytes)
-}
-
-#[cfg(test)]
-mod test {
-    use {
-        super::*,
-        crate::{
-            encryption::{pedersen::Pedersen, pod::pedersen::PodPedersenCommitment},
-            sigma_proofs::pod::PodPercentageWithCapProof,
-        },
-        std::str::FromStr,
-    };
-
-    #[test]
-    fn test_proof_above_max_proof() {
-        let transfer_amount: u64 = 55;
-        let max_value: u64 = 3;
-
-        let percentage_rate: u16 = 555; // 5.55%
-        let percentage_amount: u64 = 4;
-        let delta: u64 = 9475; // 4*10000 - 55*555
-
-        let (transfer_commitment, transfer_opening) = Pedersen::new(transfer_amount);
-        let (percentage_commitment, percentage_opening) = Pedersen::new(max_value);
-
-        let scalar_rate = Scalar::from(percentage_rate);
-        let delta_commitment =
-            &percentage_commitment * &Scalar::from(10000_u64) - &transfer_commitment * &scalar_rate;
-        let delta_opening =
-            &percentage_opening * &Scalar::from(10000_u64) - &transfer_opening * &scalar_rate;
-
-        let (claimed_commitment, claimed_opening) = Pedersen::new(0_u64);
-
-        let mut prover_transcript = Transcript::new(b"test");
-        let mut verifier_transcript = Transcript::new(b"test");
-
-        let proof = PercentageWithCapProof::new(
-            &percentage_commitment,
-            &percentage_opening,
-            percentage_amount,
-            &delta_commitment,
-            &delta_opening,
-            delta,
-            &claimed_commitment,
-            &claimed_opening,
-            max_value,
-            &mut prover_transcript,
-        );
-
-        proof
-            .verify(
-                &percentage_commitment,
-                &delta_commitment,
-                &claimed_commitment,
-                max_value,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-    }
-
-    #[test]
-    fn test_proof_below_max_proof() {
-        let transfer_amount: u64 = 1;
-        let max_value: u64 = 3;
-
-        let percentage_rate: u16 = 400; // 4.00%
-        let percentage_amount: u64 = 1;
-        let delta: u64 = 9600; // 1*10000 - 1*400
-
-        let (transfer_commitment, transfer_opening) = Pedersen::new(transfer_amount);
-        let (percentage_commitment, percentage_opening) = Pedersen::new(percentage_amount);
-
-        let scalar_rate = Scalar::from(percentage_rate);
-        let delta_commitment =
-            &percentage_commitment * &Scalar::from(10000_u64) - &transfer_commitment * &scalar_rate;
-        let delta_opening =
-            &percentage_opening * &Scalar::from(10000_u64) - &transfer_opening * &scalar_rate;
-
-        let (claimed_commitment, claimed_opening) = Pedersen::new(delta);
-
-        assert_eq!(
-            delta_commitment.get_point() - delta_opening.get_scalar() * &(*H),
-            claimed_commitment.get_point() - claimed_opening.get_scalar() * &(*H)
-        );
-
-        let mut prover_transcript = Transcript::new(b"test");
-        let mut verifier_transcript = Transcript::new(b"test");
-
-        let proof = PercentageWithCapProof::new(
-            &percentage_commitment,
-            &percentage_opening,
-            percentage_amount,
-            &delta_commitment,
-            &delta_opening,
-            delta,
-            &claimed_commitment,
-            &claimed_opening,
-            max_value,
-            &mut prover_transcript,
-        );
-
-        proof
-            .verify(
-                &percentage_commitment,
-                &delta_commitment,
-                &claimed_commitment,
-                max_value,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-    }
-
-    #[test]
-    fn test_proof_delta_is_zero() {
-        let transfer_amount: u64 = 100;
-        let max_value: u64 = 3;
-
-        let percentage_rate: u16 = 100; // 1.00%
-        let percentage_amount: u64 = 1;
-        let delta: u64 = 0; // 1*10000 - 100*100
-
-        let (transfer_commitment, transfer_opening) = Pedersen::new(transfer_amount);
-        let (percentage_commitment, percentage_opening) = Pedersen::new(percentage_amount);
-
-        let scalar_rate = Scalar::from(percentage_rate);
-        let delta_commitment = &(&percentage_commitment * &Scalar::from(10000_u64))
-            - &(&transfer_commitment * &scalar_rate);
-        let delta_opening =
-            &(&percentage_opening * &Scalar::from(10000_u64)) - &(&transfer_opening * &scalar_rate);
-
-        let (claimed_commitment, claimed_opening) = Pedersen::new(delta);
-
-        let mut prover_transcript = Transcript::new(b"test");
-        let mut verifier_transcript = Transcript::new(b"test");
-
-        let proof = PercentageWithCapProof::new(
-            &percentage_commitment,
-            &percentage_opening,
-            percentage_amount,
-            &delta_commitment,
-            &delta_opening,
-            delta,
-            &claimed_commitment,
-            &claimed_opening,
-            max_value,
-            &mut prover_transcript,
-        );
-
-        proof
-            .verify(
-                &percentage_commitment,
-                &delta_commitment,
-                &claimed_commitment,
-                max_value,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-    }
-
-    #[test]
-    fn test_percentage_with_cap_proof_string() {
-        let max_value: u64 = 3;
-
-        let percentage_commitment_str = "JGuzRjhmp3d8PWshbrN3Q7kg027OdPn7IU26ISTiz3c=";
-        let pod_percentage_commitment =
-            PodPedersenCommitment::from_str(percentage_commitment_str).unwrap();
-        let percentage_commitment: PedersenCommitment =
-            pod_percentage_commitment.try_into().unwrap();
-
-        let delta_commitment_str = "3mwfK4u0J0UqCVznbxyCjlGEgMrI+XHdW7g00YVjSVA=";
-        let pod_delta_commitment = PodPedersenCommitment::from_str(delta_commitment_str).unwrap();
-        let delta_commitment: PedersenCommitment = pod_delta_commitment.try_into().unwrap();
-
-        let claimed_commitment_str = "/t9n3yJa7p9wJV5P2cclnUiirKU5oNUv/gQMe27WMT4=";
-        let pod_claimed_commitment =
-            PodPedersenCommitment::from_str(claimed_commitment_str).unwrap();
-        let claimed_commitment: PedersenCommitment = pod_claimed_commitment.try_into().unwrap();
-
-        let proof_str = "SpmzL7hrLLp7P/Cz+2kBh22QKq3mWb0v28Er6lO9aRfBer77VY03i9VSEd4uHYMXdaf/MBPUsDVjUxNjoauwBmw6OrAcq6tq9o1Z+NS8lkukVh6sqSrSh9dy9ipq6JcIePAVmGwDNk07ACgPE/ynrenwSPJ7ZHDGZszGkw95h25gTKPyoaMbvZoXGLtkuHmvXJ7KBBJmK2eTzELb6UF2HOUg9cGFgomL8Xa3l14LBDMwLAokJK4n2d6eTkk1O0ECddmTDwoG6lmt0fHXYm37Z+k4yrQkhUgKwph2nLWG3Q7zvRM2qVFxFUGfLWJq5Sm7l7segOm+hQpRaH+q7OHNBg==";
-        let pod_proof = PodPercentageWithCapProof::from_str(proof_str).unwrap();
-        let proof: PercentageWithCapProof = pod_proof.try_into().unwrap();
-
-        let mut verifier_transcript = Transcript::new(b"test");
-
-        proof
-            .verify(
-                &percentage_commitment,
-                &delta_commitment,
-                &claimed_commitment,
-                max_value,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-    }
-}

+ 0 - 445
zk-sdk/src/sigma_proofs/pod.rs

@@ -1,445 +0,0 @@
-//! Plain Old Data types for sigma proofs.
-
-#[cfg(not(target_os = "solana"))]
-use crate::sigma_proofs::{
-    batched_grouped_ciphertext_validity::{
-        BatchedGroupedCiphertext2HandlesValidityProof,
-        BatchedGroupedCiphertext3HandlesValidityProof,
-    },
-    ciphertext_ciphertext_equality::CiphertextCiphertextEqualityProof,
-    ciphertext_commitment_equality::CiphertextCommitmentEqualityProof,
-    grouped_ciphertext_validity::{
-        GroupedCiphertext2HandlesValidityProof, GroupedCiphertext3HandlesValidityProof,
-    },
-    percentage_with_cap::PercentageWithCapProof,
-    pubkey_validity::PubkeyValidityProof,
-    zero_ciphertext::ZeroCiphertextProof,
-};
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-use {
-    crate::{
-        pod::{impl_from_bytes, impl_from_str},
-        sigma_proofs::{errors::*, *},
-    },
-    base64::{prelude::BASE64_STANDARD, Engine},
-    bytemuck::{Pod, Zeroable},
-    std::fmt,
-};
-
-/// The `CiphertextCommitmentEqualityProof` type as a `Pod`.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy)]
-#[repr(transparent)]
-pub struct PodCiphertextCommitmentEqualityProof(
-    pub(crate) [u8; CIPHERTEXT_COMMITMENT_EQUALITY_PROOF_LEN],
-);
-
-#[cfg(not(target_os = "solana"))]
-impl From<CiphertextCommitmentEqualityProof> for PodCiphertextCommitmentEqualityProof {
-    fn from(decoded_proof: CiphertextCommitmentEqualityProof) -> Self {
-        Self(decoded_proof.to_bytes())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodCiphertextCommitmentEqualityProof> for CiphertextCommitmentEqualityProof {
-    type Error = EqualityProofVerificationError;
-
-    fn try_from(pod_proof: PodCiphertextCommitmentEqualityProof) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_proof.0)
-    }
-}
-
-const CIPHERTEXT_COMMITMENT_EQUALITY_PROOF_MAX_BASE64_LEN: usize = 256;
-
-impl fmt::Display for PodCiphertextCommitmentEqualityProof {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodCiphertextCommitmentEqualityProof,
-    BYTES_LEN = CIPHERTEXT_COMMITMENT_EQUALITY_PROOF_LEN,
-    BASE64_LEN = CIPHERTEXT_COMMITMENT_EQUALITY_PROOF_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(
-    TYPE = PodCiphertextCommitmentEqualityProof,
-    BYTES_LEN = CIPHERTEXT_COMMITMENT_EQUALITY_PROOF_LEN
-);
-
-/// The `CiphertextCiphertextEqualityProof` type as a `Pod`.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy)]
-#[repr(transparent)]
-pub struct PodCiphertextCiphertextEqualityProof(
-    pub(crate) [u8; CIPHERTEXT_CIPHERTEXT_EQUALITY_PROOF_LEN],
-);
-
-#[cfg(not(target_os = "solana"))]
-impl From<CiphertextCiphertextEqualityProof> for PodCiphertextCiphertextEqualityProof {
-    fn from(decoded_proof: CiphertextCiphertextEqualityProof) -> Self {
-        Self(decoded_proof.to_bytes())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodCiphertextCiphertextEqualityProof> for CiphertextCiphertextEqualityProof {
-    type Error = EqualityProofVerificationError;
-
-    fn try_from(pod_proof: PodCiphertextCiphertextEqualityProof) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_proof.0)
-    }
-}
-
-const CIPHERTEXT_CIPHERTEXT_EQUALITY_PROOF_MAX_BASE64_LEN: usize = 300;
-
-impl fmt::Display for PodCiphertextCiphertextEqualityProof {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodCiphertextCiphertextEqualityProof,
-    BYTES_LEN = CIPHERTEXT_CIPHERTEXT_EQUALITY_PROOF_LEN,
-    BASE64_LEN = CIPHERTEXT_CIPHERTEXT_EQUALITY_PROOF_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(
-    TYPE = PodCiphertextCiphertextEqualityProof,
-    BYTES_LEN = CIPHERTEXT_CIPHERTEXT_EQUALITY_PROOF_LEN
-);
-
-/// The `GroupedCiphertext2HandlesValidityProof` type as a `Pod`.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy)]
-#[repr(transparent)]
-pub struct PodGroupedCiphertext2HandlesValidityProof(
-    pub(crate) [u8; GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY_PROOF_LEN],
-);
-
-#[cfg(not(target_os = "solana"))]
-impl From<GroupedCiphertext2HandlesValidityProof> for PodGroupedCiphertext2HandlesValidityProof {
-    fn from(decoded_proof: GroupedCiphertext2HandlesValidityProof) -> Self {
-        Self(decoded_proof.to_bytes())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodGroupedCiphertext2HandlesValidityProof> for GroupedCiphertext2HandlesValidityProof {
-    type Error = ValidityProofVerificationError;
-
-    fn try_from(pod_proof: PodGroupedCiphertext2HandlesValidityProof) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_proof.0)
-    }
-}
-
-const GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY_PROOF_MAX_BASE64_LEN: usize = 216;
-
-impl fmt::Display for PodGroupedCiphertext2HandlesValidityProof {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodGroupedCiphertext2HandlesValidityProof,
-    BYTES_LEN = GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY_PROOF_LEN,
-    BASE64_LEN = GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY_PROOF_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(
-    TYPE = PodGroupedCiphertext2HandlesValidityProof,
-    BYTES_LEN = GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY_PROOF_LEN
-);
-
-/// The `GroupedCiphertext3HandlesValidityProof` type as a `Pod`.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy)]
-#[repr(transparent)]
-pub struct PodGroupedCiphertext3HandlesValidityProof(
-    pub(crate) [u8; GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_LEN],
-);
-
-#[cfg(not(target_os = "solana"))]
-impl From<GroupedCiphertext3HandlesValidityProof> for PodGroupedCiphertext3HandlesValidityProof {
-    fn from(decoded_proof: GroupedCiphertext3HandlesValidityProof) -> Self {
-        Self(decoded_proof.to_bytes())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodGroupedCiphertext3HandlesValidityProof> for GroupedCiphertext3HandlesValidityProof {
-    type Error = ValidityProofVerificationError;
-
-    fn try_from(pod_proof: PodGroupedCiphertext3HandlesValidityProof) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_proof.0)
-    }
-}
-
-const GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_MAX_BASE64_LEN: usize = 256;
-
-impl fmt::Display for PodGroupedCiphertext3HandlesValidityProof {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodGroupedCiphertext3HandlesValidityProof,
-    BYTES_LEN = GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_LEN,
-    BASE64_LEN = GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(
-    TYPE = PodGroupedCiphertext3HandlesValidityProof,
-    BYTES_LEN = GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_LEN
-);
-
-/// The `BatchedGroupedCiphertext2HandlesValidityProof` type as a `Pod`.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy)]
-#[repr(transparent)]
-pub struct PodBatchedGroupedCiphertext2HandlesValidityProof(
-    pub(crate) [u8; BATCHED_GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY_PROOF_LEN],
-);
-
-#[cfg(not(target_os = "solana"))]
-impl From<BatchedGroupedCiphertext2HandlesValidityProof>
-    for PodBatchedGroupedCiphertext2HandlesValidityProof
-{
-    fn from(decoded_proof: BatchedGroupedCiphertext2HandlesValidityProof) -> Self {
-        Self(decoded_proof.to_bytes())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodBatchedGroupedCiphertext2HandlesValidityProof>
-    for BatchedGroupedCiphertext2HandlesValidityProof
-{
-    type Error = ValidityProofVerificationError;
-
-    fn try_from(
-        pod_proof: PodBatchedGroupedCiphertext2HandlesValidityProof,
-    ) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_proof.0)
-    }
-}
-
-const BATCHED_GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY_PROOF_MAX_BASE64_LEN: usize = 216;
-
-impl fmt::Display for PodBatchedGroupedCiphertext2HandlesValidityProof {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodBatchedGroupedCiphertext2HandlesValidityProof,
-    BYTES_LEN = BATCHED_GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY_PROOF_LEN,
-    BASE64_LEN = BATCHED_GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY_PROOF_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(
-    TYPE = PodBatchedGroupedCiphertext2HandlesValidityProof,
-    BYTES_LEN = BATCHED_GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY_PROOF_LEN
-);
-
-/// The `BatchedGroupedCiphertext3HandlesValidityProof` type as a `Pod`.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy)]
-#[repr(transparent)]
-pub struct PodBatchedGroupedCiphertext3HandlesValidityProof(
-    pub(crate) [u8; BATCHED_GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_LEN],
-);
-
-#[cfg(not(target_os = "solana"))]
-impl From<BatchedGroupedCiphertext3HandlesValidityProof>
-    for PodBatchedGroupedCiphertext3HandlesValidityProof
-{
-    fn from(decoded_proof: BatchedGroupedCiphertext3HandlesValidityProof) -> Self {
-        Self(decoded_proof.to_bytes())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodBatchedGroupedCiphertext3HandlesValidityProof>
-    for BatchedGroupedCiphertext3HandlesValidityProof
-{
-    type Error = ValidityProofVerificationError;
-
-    fn try_from(
-        pod_proof: PodBatchedGroupedCiphertext3HandlesValidityProof,
-    ) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_proof.0)
-    }
-}
-
-const BATCHED_GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_MAX_BASE64_LEN: usize = 256;
-
-impl fmt::Display for PodBatchedGroupedCiphertext3HandlesValidityProof {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodBatchedGroupedCiphertext3HandlesValidityProof,
-    BYTES_LEN = BATCHED_GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_LEN,
-    BASE64_LEN = BATCHED_GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(
-    TYPE = PodBatchedGroupedCiphertext3HandlesValidityProof,
-    BYTES_LEN = BATCHED_GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_LEN
-);
-
-/// The `ZeroCiphertextProof` type as a `Pod`.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy)]
-#[repr(transparent)]
-pub struct PodZeroCiphertextProof(pub(crate) [u8; ZERO_CIPHERTEXT_PROOF_LEN]);
-
-#[cfg(not(target_os = "solana"))]
-impl From<ZeroCiphertextProof> for PodZeroCiphertextProof {
-    fn from(decoded_proof: ZeroCiphertextProof) -> Self {
-        Self(decoded_proof.to_bytes())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodZeroCiphertextProof> for ZeroCiphertextProof {
-    type Error = ZeroCiphertextProofVerificationError;
-
-    fn try_from(pod_proof: PodZeroCiphertextProof) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_proof.0)
-    }
-}
-
-const ZERO_CIPHERTEXT_PROOF_MAX_BASE64_LEN: usize = 128;
-
-impl fmt::Display for PodZeroCiphertextProof {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodZeroCiphertextProof,
-    BYTES_LEN = ZERO_CIPHERTEXT_PROOF_LEN,
-    BASE64_LEN = ZERO_CIPHERTEXT_PROOF_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(
-    TYPE = PodZeroCiphertextProof,
-    BYTES_LEN = ZERO_CIPHERTEXT_PROOF_LEN
-);
-
-/// The `PercentageWithCapProof` type as a `Pod`.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, bytemuck_derive::Pod, bytemuck_derive::Zeroable)]
-#[repr(transparent)]
-pub struct PodPercentageWithCapProof(pub(crate) [u8; PERCENTAGE_WITH_CAP_PROOF_LEN]);
-
-#[cfg(not(target_os = "solana"))]
-impl From<PercentageWithCapProof> for PodPercentageWithCapProof {
-    fn from(decoded_proof: PercentageWithCapProof) -> Self {
-        Self(decoded_proof.to_bytes())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodPercentageWithCapProof> for PercentageWithCapProof {
-    type Error = PercentageWithCapProofVerificationError;
-
-    fn try_from(pod_proof: PodPercentageWithCapProof) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_proof.0)
-    }
-}
-
-const PERCENTAGE_WITH_CAP_PROOF_MAX_BASE64_LEN: usize = 344;
-
-impl fmt::Display for PodPercentageWithCapProof {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodPercentageWithCapProof,
-    BYTES_LEN = PERCENTAGE_WITH_CAP_PROOF_LEN,
-    BASE64_LEN = PERCENTAGE_WITH_CAP_PROOF_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(
-    TYPE = PodPercentageWithCapProof,
-    BYTES_LEN = PERCENTAGE_WITH_CAP_PROOF_LEN
-);
-
-/// The `PubkeyValidityProof` type as a `Pod`.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, bytemuck_derive::Pod, bytemuck_derive::Zeroable)]
-#[repr(transparent)]
-pub struct PodPubkeyValidityProof(pub(crate) [u8; PUBKEY_VALIDITY_PROOF_LEN]);
-
-#[cfg(not(target_os = "solana"))]
-impl From<PubkeyValidityProof> for PodPubkeyValidityProof {
-    fn from(decoded_proof: PubkeyValidityProof) -> Self {
-        Self(decoded_proof.to_bytes())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryFrom<PodPubkeyValidityProof> for PubkeyValidityProof {
-    type Error = PubkeyValidityProofVerificationError;
-
-    fn try_from(pod_proof: PodPubkeyValidityProof) -> Result<Self, Self::Error> {
-        Self::from_bytes(&pod_proof.0)
-    }
-}
-
-const PUBKEY_VALIDITY_PROOF_MAX_BASE64_LEN: usize = 88;
-
-impl fmt::Display for PodPubkeyValidityProof {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", BASE64_STANDARD.encode(self.0))
-    }
-}
-
-impl_from_str!(
-    TYPE = PodPubkeyValidityProof,
-    BYTES_LEN = PUBKEY_VALIDITY_PROOF_LEN,
-    BASE64_LEN = PUBKEY_VALIDITY_PROOF_MAX_BASE64_LEN
-);
-
-impl_from_bytes!(
-    TYPE = PodPubkeyValidityProof,
-    BYTES_LEN = PUBKEY_VALIDITY_PROOF_LEN
-);
-
-// The sigma proof pod types are wrappers for byte arrays, which are both `Pod` and `Zeroable`. However,
-// the marker traits `bytemuck::Pod` and `bytemuck::Zeroable` can only be derived for power-of-two
-// length byte arrays. Directly implement these traits for the sigma proof pod types.
-unsafe impl Zeroable for PodCiphertextCommitmentEqualityProof {}
-unsafe impl Pod for PodCiphertextCommitmentEqualityProof {}
-
-unsafe impl Zeroable for PodCiphertextCiphertextEqualityProof {}
-unsafe impl Pod for PodCiphertextCiphertextEqualityProof {}
-
-unsafe impl Zeroable for PodGroupedCiphertext2HandlesValidityProof {}
-unsafe impl Pod for PodGroupedCiphertext2HandlesValidityProof {}
-
-unsafe impl Zeroable for PodGroupedCiphertext3HandlesValidityProof {}
-unsafe impl Pod for PodGroupedCiphertext3HandlesValidityProof {}
-
-unsafe impl Zeroable for PodBatchedGroupedCiphertext2HandlesValidityProof {}
-unsafe impl Pod for PodBatchedGroupedCiphertext2HandlesValidityProof {}
-
-unsafe impl Zeroable for PodBatchedGroupedCiphertext3HandlesValidityProof {}
-unsafe impl Pod for PodBatchedGroupedCiphertext3HandlesValidityProof {}
-
-unsafe impl Zeroable for PodZeroCiphertextProof {}
-unsafe impl Pod for PodZeroCiphertextProof {}

+ 0 - 194
zk-sdk/src/sigma_proofs/pubkey_validity.rs

@@ -1,194 +0,0 @@
-//! The public-key (validity) proof system.
-//!
-//! The protocol guarantees computational soundness (by the hardness of discrete log) and perfect
-//! zero-knowledge in the random oracle model.
-
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::{
-            elgamal::{ElGamalKeypair, ElGamalPubkey},
-            pedersen::H,
-        },
-        sigma_proofs::{canonical_scalar_from_optional_slice, ristretto_point_from_optional_slice},
-        UNIT_LEN,
-    },
-    rand::rngs::OsRng,
-    zeroize::Zeroize,
-};
-use {
-    crate::{
-        sigma_proofs::errors::{PubkeyValidityProofVerificationError, SigmaProofVerificationError},
-        transcript::TranscriptProtocol,
-    },
-    curve25519_dalek::{
-        ristretto::{CompressedRistretto, RistrettoPoint},
-        scalar::Scalar,
-        traits::{IsIdentity, VartimeMultiscalarMul},
-    },
-    merlin::Transcript,
-};
-
-/// Byte length of a public key validity proof.
-const PUBKEY_VALIDITY_PROOF_LEN: usize = UNIT_LEN * 2;
-
-/// Public-key proof.
-///
-/// Contains all the elliptic curve and scalar components that make up the sigma protocol.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[allow(non_snake_case)]
-#[derive(Clone)]
-pub struct PubkeyValidityProof {
-    Y: CompressedRistretto,
-    z: Scalar,
-}
-
-#[allow(non_snake_case)]
-#[cfg(not(target_os = "solana"))]
-impl PubkeyValidityProof {
-    /// Creates a public key validity proof.
-    ///
-    /// The function does *not* hash the public key into the transcript. For
-    /// security, the caller (the main protocol) should hash these public key components prior to
-    /// invoking this constructor.
-    ///
-    /// This function is randomized. It uses `OsRng` internally to generate random scalars.
-    ///
-    /// This function panics if the provided keypair is not valid (i.e. secret key is not
-    /// invertible).
-    ///
-    /// * `elgamal_keypair` = The ElGamal keypair that pertains to the ElGamal public key to be
-    ///   proved
-    /// * `transcript` - The transcript that does the bookkeeping for the Fiat-Shamir heuristic
-    pub fn new(elgamal_keypair: &ElGamalKeypair, transcript: &mut Transcript) -> Self {
-        transcript.pubkey_proof_domain_separator();
-
-        // extract the relevant scalar and Ristretto points from the input
-        let s = elgamal_keypair.secret().get_scalar();
-
-        assert!(s != &Scalar::ZERO);
-        let s_inv = s.invert();
-
-        // generate a random masking factor that also serves as a nonce
-        let mut y = Scalar::random(&mut OsRng);
-        let Y = (&y * &(*H)).compress();
-
-        // record masking factors in transcript and get challenges
-        transcript.append_point(b"Y", &Y);
-        let c = transcript.challenge_scalar(b"c");
-
-        // compute masked secret key
-        let z = &(&c * s_inv) + &y;
-
-        y.zeroize();
-
-        Self { Y, z }
-    }
-
-    /// Verifies a public key validity proof.
-    ///
-    /// * `elgamal_pubkey` - The ElGamal public key to be proved
-    /// * `transcript` - The transcript that does the bookkeeping for the Fiat-Shamir heuristic
-    pub fn verify(
-        self,
-        elgamal_pubkey: &ElGamalPubkey,
-        transcript: &mut Transcript,
-    ) -> Result<(), PubkeyValidityProofVerificationError> {
-        transcript.pubkey_proof_domain_separator();
-
-        // extract the relevant scalar and Ristretto points from the input
-        let P = elgamal_pubkey.get_point();
-
-        // include Y to transcript and extract challenge
-        transcript.validate_and_append_point(b"Y", &self.Y)?;
-        let c = transcript.challenge_scalar(b"c");
-
-        // check that the required algebraic condition holds
-        let Y = self
-            .Y
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-
-        let check = RistrettoPoint::vartime_multiscalar_mul(
-            vec![&self.z, &(-&c), &(-&Scalar::ONE)],
-            vec![&(*H), P, &Y],
-        );
-
-        if check.is_identity() {
-            Ok(())
-        } else {
-            Err(SigmaProofVerificationError::AlgebraicRelation.into())
-        }
-    }
-
-    pub fn to_bytes(&self) -> [u8; PUBKEY_VALIDITY_PROOF_LEN] {
-        let mut buf = [0_u8; PUBKEY_VALIDITY_PROOF_LEN];
-        let mut chunks = buf.chunks_mut(UNIT_LEN);
-        chunks.next().unwrap().copy_from_slice(self.Y.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.z.as_bytes());
-        buf
-    }
-
-    pub fn from_bytes(bytes: &[u8]) -> Result<Self, PubkeyValidityProofVerificationError> {
-        let mut chunks = bytes.chunks(UNIT_LEN);
-        let Y = ristretto_point_from_optional_slice(chunks.next())?;
-        let z = canonical_scalar_from_optional_slice(chunks.next())?;
-        Ok(PubkeyValidityProof { Y, z })
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use {
-        super::*,
-        crate::{
-            encryption::pod::elgamal::PodElGamalPubkey, sigma_proofs::pod::PodPubkeyValidityProof,
-        },
-        solana_keypair::Keypair,
-        solana_pubkey::Pubkey,
-        std::str::FromStr,
-    };
-
-    #[test]
-    fn test_pubkey_proof_correctness() {
-        // random ElGamal keypair
-        let keypair = ElGamalKeypair::new_rand();
-
-        let mut prover_transcript = Transcript::new(b"test");
-        let mut verifier_transcript = Transcript::new(b"test");
-
-        let proof = PubkeyValidityProof::new(&keypair, &mut prover_transcript);
-        proof
-            .verify(keypair.pubkey(), &mut verifier_transcript)
-            .unwrap();
-
-        // derived ElGamal keypair
-        let keypair =
-            ElGamalKeypair::new_from_signer(&Keypair::new(), Pubkey::default().as_ref()).unwrap();
-
-        let mut prover_transcript = Transcript::new(b"test");
-        let mut verifier_transcript = Transcript::new(b"test");
-
-        let proof = PubkeyValidityProof::new(&keypair, &mut prover_transcript);
-        proof
-            .verify(keypair.pubkey(), &mut verifier_transcript)
-            .unwrap();
-    }
-
-    #[test]
-    fn test_pubkey_proof_str() {
-        let pubkey_str = "XKF3GnFDX4HBoBEj04yDTr6Lqx+0qp9pQyPzFjyVmXY=";
-        let pod_pubkey = PodElGamalPubkey::from_str(pubkey_str).unwrap();
-        let pubkey: ElGamalPubkey = pod_pubkey.try_into().unwrap();
-
-        let proof_str = "5hmM4uVtfJ2JfCcjWpo2dEbg22n4CdzHYQF4oBgWSGeYAh5d91z4emkjeXq9ihtmqAR+7BYCv44TqQWoMQrECA==";
-        let pod_proof = PodPubkeyValidityProof::from_str(proof_str).unwrap();
-        let proof: PubkeyValidityProof = pod_proof.try_into().unwrap();
-
-        let mut verifier_transcript = Transcript::new(b"test");
-
-        proof.verify(&pubkey, &mut verifier_transcript).unwrap();
-    }
-}

+ 0 - 315
zk-sdk/src/sigma_proofs/zero_ciphertext.rs

@@ -1,315 +0,0 @@
-//! The zero-ciphertext sigma proof system.
-//!
-//! The protocol guarantees computational soundness (by the hardness of discrete log) and perfect
-//! zero-knowledge in the random oracle model.
-
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::{
-            elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey},
-            pedersen::H,
-        },
-        sigma_proofs::{canonical_scalar_from_optional_slice, ristretto_point_from_optional_slice},
-        UNIT_LEN,
-    },
-    curve25519_dalek::traits::MultiscalarMul,
-    rand::rngs::OsRng,
-    zeroize::Zeroize,
-};
-use {
-    crate::{
-        sigma_proofs::errors::{SigmaProofVerificationError, ZeroCiphertextProofVerificationError},
-        transcript::TranscriptProtocol,
-    },
-    curve25519_dalek::{
-        ristretto::{CompressedRistretto, RistrettoPoint},
-        scalar::Scalar,
-        traits::IsIdentity,
-    },
-    merlin::Transcript,
-};
-
-/// Byte length of a zero-ciphertext proof.
-const ZERO_CIPHERTEXT_PROOF_LEN: usize = UNIT_LEN * 3;
-
-/// Zero-ciphertext proof.
-///
-/// Contains all the elliptic curve and scalar components that make up the sigma protocol.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[allow(non_snake_case)]
-#[derive(Clone)]
-pub struct ZeroCiphertextProof {
-    Y_P: CompressedRistretto,
-    Y_D: CompressedRistretto,
-    z: Scalar,
-}
-
-#[allow(non_snake_case)]
-#[cfg(not(target_os = "solana"))]
-impl ZeroCiphertextProof {
-    /// Creates a zero-ciphertext proof.
-    ///
-    /// The function does *not* hash the public key and ciphertext into the transcript. For
-    /// security, the caller (the main protocol) should hash these public components prior to
-    /// invoking this constructor.
-    ///
-    /// This function is randomized. It uses `OsRng` internally to generate random scalars.
-    ///
-    /// Note that the proof constructor does not take the actual ElGamal ciphertext as input; it
-    /// uses the ElGamal private key instead to generate the proof.
-    ///
-    /// * `elgamal_keypair` - The ElGamal keypair associated with the ciphertext to be proved
-    /// * `ciphertext` - The main ElGamal ciphertext to be proved
-    /// * `transcript` - The transcript that does the bookkeeping for the Fiat-Shamir heuristic
-    pub fn new(
-        elgamal_keypair: &ElGamalKeypair,
-        ciphertext: &ElGamalCiphertext,
-        transcript: &mut Transcript,
-    ) -> Self {
-        transcript.zero_ciphertext_proof_domain_separator();
-
-        // extract the relevant scalar and Ristretto points from the input
-        let P = elgamal_keypair.pubkey().get_point();
-        let s = elgamal_keypair.secret().get_scalar();
-        let D = ciphertext.handle.get_point();
-
-        // generate a random masking factor that also serves as a nonce
-        let mut y = Scalar::random(&mut OsRng);
-        let Y_P = (&y * P).compress();
-        let Y_D = (&y * D).compress();
-
-        // record Y in the transcript and receive a challenge scalar
-        transcript.append_point(b"Y_P", &Y_P);
-        transcript.append_point(b"Y_D", &Y_D);
-
-        let c = transcript.challenge_scalar(b"c");
-        transcript.challenge_scalar(b"w");
-
-        // compute the masked secret key
-        let z = &(&c * s) + &y;
-
-        // zeroize random scalar
-        y.zeroize();
-
-        Self { Y_P, Y_D, z }
-    }
-
-    /// Verifies a zero-ciphertext proof.
-    ///
-    /// * `elgamal_pubkey` - The ElGamal pubkey associated with the ciphertext to be proved
-    /// * `ciphertext` - The main ElGamal ciphertext to be proved
-    /// * `transcript` - The transcript that does the bookkeeping for the Fiat-Shamir heuristic
-    pub fn verify(
-        self,
-        elgamal_pubkey: &ElGamalPubkey,
-        ciphertext: &ElGamalCiphertext,
-        transcript: &mut Transcript,
-    ) -> Result<(), ZeroCiphertextProofVerificationError> {
-        transcript.zero_ciphertext_proof_domain_separator();
-
-        // extract the relevant scalar and Ristretto points from the input
-        let P = elgamal_pubkey.get_point();
-        let C = ciphertext.commitment.get_point();
-        let D = ciphertext.handle.get_point();
-
-        // record Y in transcript and receive challenge scalars
-        transcript.validate_and_append_point(b"Y_P", &self.Y_P)?;
-        transcript.append_point(b"Y_D", &self.Y_D);
-
-        let c = transcript.challenge_scalar(b"c");
-
-        transcript.append_scalar(b"z", &self.z);
-        let w = transcript.challenge_scalar(b"w"); // w used for batch verification
-
-        let w_negated = -&w;
-
-        // decompress Y or return verification error
-        let Y_P = self
-            .Y_P
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-        let Y_D = self
-            .Y_D
-            .decompress()
-            .ok_or(SigmaProofVerificationError::Deserialization)?;
-
-        // check the required algebraic relation
-        let check = RistrettoPoint::multiscalar_mul(
-            vec![
-                &self.z,            // z
-                &(-&c),             // -c
-                &(-&Scalar::ONE),   // -identity
-                &(&w * &self.z),    // w * z
-                &(&w_negated * &c), // -w * c
-                &w_negated,         // -w
-            ],
-            vec![
-                P,     // P
-                &(*H), // H
-                &Y_P,  // Y_P
-                D,     // D
-                C,     // C
-                &Y_D,  // Y_D
-            ],
-        );
-
-        if check.is_identity() {
-            Ok(())
-        } else {
-            Err(SigmaProofVerificationError::AlgebraicRelation.into())
-        }
-    }
-
-    pub fn to_bytes(&self) -> [u8; ZERO_CIPHERTEXT_PROOF_LEN] {
-        let mut buf = [0_u8; ZERO_CIPHERTEXT_PROOF_LEN];
-        let mut chunks = buf.chunks_mut(UNIT_LEN);
-        chunks.next().unwrap().copy_from_slice(self.Y_P.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.Y_D.as_bytes());
-        chunks.next().unwrap().copy_from_slice(self.z.as_bytes());
-        buf
-    }
-
-    pub fn from_bytes(bytes: &[u8]) -> Result<Self, ZeroCiphertextProofVerificationError> {
-        let mut chunks = bytes.chunks(UNIT_LEN);
-        let Y_P = ristretto_point_from_optional_slice(chunks.next())?;
-        let Y_D = ristretto_point_from_optional_slice(chunks.next())?;
-        let z = canonical_scalar_from_optional_slice(chunks.next())?;
-        Ok(ZeroCiphertextProof { Y_P, Y_D, z })
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use {
-        super::*,
-        crate::{
-            encryption::{
-                elgamal::{DecryptHandle, ElGamalKeypair},
-                pedersen::{Pedersen, PedersenCommitment, PedersenOpening},
-                pod::elgamal::{PodElGamalCiphertext, PodElGamalPubkey},
-            },
-            sigma_proofs::pod::PodZeroCiphertextProof,
-        },
-        std::str::FromStr,
-    };
-
-    #[test]
-    fn test_zero_ciphertext_proof_correctness() {
-        let keypair = ElGamalKeypair::new_rand();
-
-        let mut prover_transcript = Transcript::new(b"test");
-        let mut verifier_transcript = Transcript::new(b"test");
-
-        // general case: encryption of 0
-        let elgamal_ciphertext = keypair.pubkey().encrypt(0_u64);
-        let proof = ZeroCiphertextProof::new(&keypair, &elgamal_ciphertext, &mut prover_transcript);
-        proof
-            .verify(
-                keypair.pubkey(),
-                &elgamal_ciphertext,
-                &mut verifier_transcript,
-            )
-            .unwrap();
-
-        // general case: encryption of > 0
-        let elgamal_ciphertext = keypair.pubkey().encrypt(1_u64);
-        let proof = ZeroCiphertextProof::new(&keypair, &elgamal_ciphertext, &mut prover_transcript);
-        assert!(proof
-            .verify(
-                keypair.pubkey(),
-                &elgamal_ciphertext,
-                &mut verifier_transcript
-            )
-            .is_err());
-    }
-
-    #[test]
-    fn test_zero_ciphertext_proof_edge_cases() {
-        let keypair = ElGamalKeypair::new_rand();
-
-        let mut prover_transcript = Transcript::new(b"test");
-        let mut verifier_transcript = Transcript::new(b"test");
-
-        // all zero ciphertext should always be a valid encryption of 0
-        let ciphertext = ElGamalCiphertext::from_bytes(&[0u8; 64]).unwrap();
-
-        let proof = ZeroCiphertextProof::new(&keypair, &ciphertext, &mut prover_transcript);
-
-        proof
-            .verify(keypair.pubkey(), &ciphertext, &mut verifier_transcript)
-            .unwrap();
-
-        // if only either commitment or handle is zero, the ciphertext is always invalid and proof
-        // verification should always reject
-        let mut prover_transcript = Transcript::new(b"test");
-        let mut verifier_transcript = Transcript::new(b"test");
-
-        let zeroed_commitment = PedersenCommitment::from_bytes(&[0u8; 32]).unwrap();
-        let handle = keypair
-            .pubkey()
-            .decrypt_handle(&PedersenOpening::new_rand());
-
-        let ciphertext = ElGamalCiphertext {
-            commitment: zeroed_commitment,
-            handle,
-        };
-
-        let proof = ZeroCiphertextProof::new(&keypair, &ciphertext, &mut prover_transcript);
-
-        assert!(proof
-            .verify(keypair.pubkey(), &ciphertext, &mut verifier_transcript)
-            .is_err());
-
-        let mut prover_transcript = Transcript::new(b"test");
-        let mut verifier_transcript = Transcript::new(b"test");
-
-        let (zeroed_commitment, _) = Pedersen::new(0_u64);
-        let ciphertext = ElGamalCiphertext {
-            commitment: zeroed_commitment,
-            handle: DecryptHandle::from_bytes(&[0u8; 32]).unwrap(),
-        };
-
-        let proof = ZeroCiphertextProof::new(&keypair, &ciphertext, &mut prover_transcript);
-
-        assert!(proof
-            .verify(keypair.pubkey(), &ciphertext, &mut verifier_transcript)
-            .is_err());
-
-        // if public key is always zero, then the proof should always reject
-        let mut prover_transcript = Transcript::new(b"test");
-        let mut verifier_transcript = Transcript::new(b"test");
-
-        let public = ElGamalPubkey::try_from([0u8; 32].as_slice()).unwrap();
-        let ciphertext = public.encrypt(0_u64);
-
-        let proof = ZeroCiphertextProof::new(&keypair, &ciphertext, &mut prover_transcript);
-
-        assert!(proof
-            .verify(keypair.pubkey(), &ciphertext, &mut verifier_transcript)
-            .is_err());
-    }
-
-    #[test]
-    fn test_zero_ciphertext_proof_string() {
-        let pubkey_str = "Vlx+Fr61KnreO27JDg5MsBN8NgbICGa3fIech8oZ4hQ=";
-        let pod_pubkey = PodElGamalPubkey::from_str(pubkey_str).unwrap();
-        let pubkey: ElGamalPubkey = pod_pubkey.try_into().unwrap();
-
-        let ciphertext_str = "wps5X1mou5PUdPD+llxiJ+aoX4YWrR/S6/U2MUC2LjLS7wDu6S9nOG92VMnlngQaP4irBY0OqlsGdXS4j8DROg==";
-        let pod_ciphertext = PodElGamalCiphertext::from_str(ciphertext_str).unwrap();
-        let ciphertext: ElGamalCiphertext = pod_ciphertext.try_into().unwrap();
-
-        let proof_str = "qMDiQ5zPcTYFhchYBZzRS81UGIt2QRNce2/ULEqDBXBQEnGRI0u0G1HzRJfpIbOWCHBwMaNgsT1jTZwTOTWyMBE/2UjHI4x9IFpAM6ccGuexo/HjSECPDgL+85zrfA8L";
-        let pod_proof = PodZeroCiphertextProof::from_str(proof_str).unwrap();
-        let proof: ZeroCiphertextProof = pod_proof.try_into().unwrap();
-
-        let mut verifier_transcript = Transcript::new(b"test");
-
-        proof
-            .verify(&pubkey, &ciphertext, &mut verifier_transcript)
-            .unwrap();
-    }
-}

+ 0 - 129
zk-sdk/src/transcript.rs

@@ -1,129 +0,0 @@
-use {
-    crate::errors::TranscriptError,
-    curve25519_dalek::{ristretto::CompressedRistretto, scalar::Scalar, traits::IsIdentity},
-    merlin::Transcript,
-};
-
-pub trait TranscriptProtocol {
-    /// Append a `scalar` with the given `label`.
-    #[cfg(not(target_os = "solana"))]
-    fn append_scalar(&mut self, label: &'static [u8], scalar: &Scalar);
-
-    /// Append a `point` with the given `label`.
-    #[cfg(not(target_os = "solana"))]
-    fn append_point(&mut self, label: &'static [u8], point: &CompressedRistretto);
-
-    /// Check that a point is not the identity, then append it to the
-    /// transcript.  Otherwise, return an error.
-    #[cfg(not(target_os = "solana"))]
-    fn validate_and_append_point(
-        &mut self,
-        label: &'static [u8],
-        point: &CompressedRistretto,
-    ) -> Result<(), TranscriptError>;
-
-    /// Append a domain separator for an `n`-bit range proof
-    fn range_proof_domain_separator(&mut self, n: u64);
-
-    /// Append a domain separator for a length-`n` inner product proof.
-    fn inner_product_proof_domain_separator(&mut self, n: u64);
-
-    /// Append a domain separator for ciphertext-ciphertext equality proof.
-    fn ciphertext_ciphertext_equality_proof_domain_separator(&mut self);
-
-    /// Append a domain separator for ciphertext-commitment equality proof.
-    fn ciphertext_commitment_equality_proof_domain_separator(&mut self);
-
-    /// Append a domain separator for zero-ciphertext proof.
-    fn zero_ciphertext_proof_domain_separator(&mut self);
-
-    /// Append a domain separator for grouped ciphertext validity proof.
-    fn grouped_ciphertext_validity_proof_domain_separator(&mut self, handles: u64);
-
-    /// Append a domain separator for batched grouped ciphertext validity proof.
-    fn batched_grouped_ciphertext_validity_proof_domain_separator(&mut self, handles: u64);
-
-    /// Append a domain separator for percentage with cap proof.
-    fn percentage_with_cap_proof_domain_separator(&mut self);
-
-    /// Append a domain separator for public-key proof.
-    fn pubkey_proof_domain_separator(&mut self);
-
-    /// Compute a `label`ed challenge variable.
-    #[cfg(not(target_os = "solana"))]
-    fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar;
-}
-
-impl TranscriptProtocol for Transcript {
-    #[cfg(not(target_os = "solana"))]
-    fn append_scalar(&mut self, label: &'static [u8], scalar: &Scalar) {
-        self.append_message(label, scalar.as_bytes());
-    }
-
-    #[cfg(not(target_os = "solana"))]
-    fn append_point(&mut self, label: &'static [u8], point: &CompressedRistretto) {
-        self.append_message(label, point.as_bytes());
-    }
-
-    #[cfg(not(target_os = "solana"))]
-    fn validate_and_append_point(
-        &mut self,
-        label: &'static [u8],
-        point: &CompressedRistretto,
-    ) -> Result<(), TranscriptError> {
-        if point.is_identity() {
-            Err(TranscriptError::ValidationError)
-        } else {
-            self.append_message(label, point.as_bytes());
-            Ok(())
-        }
-    }
-
-    fn range_proof_domain_separator(&mut self, n: u64) {
-        self.append_message(b"dom-sep", b"range-proof");
-        self.append_u64(b"n", n);
-    }
-
-    fn inner_product_proof_domain_separator(&mut self, n: u64) {
-        self.append_message(b"dom-sep", b"inner-product");
-        self.append_u64(b"n", n);
-    }
-
-    fn ciphertext_ciphertext_equality_proof_domain_separator(&mut self) {
-        self.append_message(b"dom-sep", b"ciphertext-ciphertext-equality-proof")
-    }
-
-    fn ciphertext_commitment_equality_proof_domain_separator(&mut self) {
-        self.append_message(b"dom-sep", b"ciphertext-commitment-equality-proof")
-    }
-
-    fn zero_ciphertext_proof_domain_separator(&mut self) {
-        self.append_message(b"dom-sep", b"zero-ciphertext-proof")
-    }
-
-    fn grouped_ciphertext_validity_proof_domain_separator(&mut self, handles: u64) {
-        self.append_message(b"dom-sep", b"validity-proof");
-        self.append_u64(b"handles", handles);
-    }
-
-    fn batched_grouped_ciphertext_validity_proof_domain_separator(&mut self, handles: u64) {
-        self.append_message(b"dom-sep", b"batched-validity-proof");
-        self.append_u64(b"handles", handles);
-    }
-
-    fn percentage_with_cap_proof_domain_separator(&mut self) {
-        self.append_message(b"dom-sep", b"percentage-with-cap-proof")
-    }
-
-    fn pubkey_proof_domain_separator(&mut self) {
-        self.append_message(b"dom-sep", b"pubkey-proof")
-    }
-
-    #[cfg(not(target_os = "solana"))]
-    fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar {
-        let mut buf = [0u8; 64];
-        self.challenge_bytes(label, &mut buf);
-
-        Scalar::from_bytes_mod_order_wide(&buf)
-    }
-}

+ 0 - 88
zk-sdk/src/zk_elgamal_proof_program/errors.rs

@@ -1,88 +0,0 @@
-#[cfg(not(target_os = "solana"))]
-use crate::range_proof::errors::RangeProofGenerationError;
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-use {
-    crate::{
-        errors::ElGamalError, range_proof::errors::RangeProofVerificationError,
-        sigma_proofs::errors::*,
-    },
-    thiserror::Error,
-};
-
-#[cfg(not(target_os = "solana"))]
-#[derive(Error, Clone, Debug, Eq, PartialEq)]
-pub enum ProofGenerationError {
-    #[error("illegal number of commitments")]
-    IllegalCommitmentLength,
-    #[error("illegal amount bit length")]
-    IllegalAmountBitLength,
-    #[error("invalid commitment")]
-    InvalidCommitment,
-    #[error("range proof generation failed")]
-    RangeProof(#[from] RangeProofGenerationError),
-    #[error("unexpected proof length")]
-    ProofLength,
-}
-
-#[derive(Error, Clone, Debug, Eq, PartialEq)]
-pub enum ProofVerificationError {
-    #[error("range proof verification failed")]
-    RangeProof(#[from] RangeProofVerificationError),
-    #[error("sigma proof verification failed")]
-    SigmaProof(SigmaProofType, SigmaProofVerificationError),
-    #[error("ElGamal ciphertext or public key error")]
-    ElGamal(#[from] ElGamalError),
-    #[error("Invalid proof context")]
-    ProofContext,
-    #[error("illegal commitment length")]
-    IllegalCommitmentLength,
-    #[error("illegal amount bit length")]
-    IllegalAmountBitLength,
-}
-
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub enum SigmaProofType {
-    ZeroCiphertext,
-    Equality,
-    PubkeyValidity,
-    PercentageWithCap,
-    ValidityProof,
-}
-
-impl From<ZeroCiphertextProofVerificationError> for ProofVerificationError {
-    fn from(err: ZeroCiphertextProofVerificationError) -> Self {
-        Self::SigmaProof(SigmaProofType::ZeroCiphertext, err.0)
-    }
-}
-
-impl From<EqualityProofVerificationError> for ProofVerificationError {
-    fn from(err: EqualityProofVerificationError) -> Self {
-        Self::SigmaProof(SigmaProofType::Equality, err.0)
-    }
-}
-
-impl From<PubkeyValidityProofVerificationError> for ProofVerificationError {
-    fn from(err: PubkeyValidityProofVerificationError) -> Self {
-        Self::SigmaProof(SigmaProofType::PubkeyValidity, err.0)
-    }
-}
-
-impl From<PercentageWithCapProofVerificationError> for ProofVerificationError {
-    fn from(err: PercentageWithCapProofVerificationError) -> Self {
-        Self::SigmaProof(SigmaProofType::PercentageWithCap, err.0)
-    }
-}
-
-impl From<ValidityProofVerificationError> for ProofVerificationError {
-    fn from(err: ValidityProofVerificationError) -> Self {
-        Self::SigmaProof(SigmaProofType::ValidityProof, err.0)
-    }
-}
-
-#[cfg(target_arch = "wasm32")]
-impl From<ProofGenerationError> for JsValue {
-    fn from(err: ProofGenerationError) -> Self {
-        js_sys::Error::new(&err.to_string()).into()
-    }
-}

+ 0 - 383
zk-sdk/src/zk_elgamal_proof_program/instruction.rs

@@ -1,383 +0,0 @@
-//! Instructions provided by the [`ZK ElGamal proof`] program.
-//!
-//! There are two types of instructions in the proof program: proof verification instructions and
-//! the `CloseContextState` instruction.
-//!
-//! Each proof verification instruction verifies a certain type of zero-knowledge proof. These
-//! instructions are processed by the program in two steps:
-//!   1. The program verifies the zero-knowledge proof.
-//!   2. The program optionally stores the context component of the zero-knowledge proof to a
-//!      dedicated [`context-state`] account.
-//!
-//! In step 1, the zero-knowledge proof can either be included directly as the instruction data or
-//! pre-written to an account. The program determines whether the proof is provided as instruction
-//! data or pre-written to an account by inspecting the length of the data. If the instruction data
-//! is exactly 5 bytes (instruction discriminator + unsigned 32-bit integer), then the program
-//! assumes that the first account provided with the instruction contains the zero-knowledge proof
-//! and verifies the account data at the offset specified in the instruction data. Otherwise, the
-//! program assumes that the zero-knowledge proof is provided as part of the instruction data.
-//!
-//! In step 2, the program determines whether to create a context-state account by inspecting the
-//! number of accounts provided with the instruction. If two additional accounts are provided with
-//! the instruction after verifying the zero-knowledge proof, then the program writes the context
-//! data to the specified context-state account.
-//!
-//! NOTE: A context-state account must be pre-allocated to the exact size of the context data that
-//! is expected for a proof type before it is included as part of a proof verification instruction.
-//!
-//! The `CloseContextState` instruction closes a context state account. A transaction containing
-//! this instruction must be signed by the context account's owner. This instruction can be used by
-//! the account owner to reclaim lamports for storage.
-//!
-//! [`ZK ElGamal proof`]: https://docs.solanalabs.com/runtime/zk-token-proof
-//! [`context-state`]: https://docs.solanalabs.com/runtime/zk-token-proof#context-data
-
-use {
-    crate::zk_elgamal_proof_program::proof_data::ZkProofData,
-    bytemuck::{bytes_of, Pod},
-    num_derive::{FromPrimitive, ToPrimitive},
-    num_traits::{FromPrimitive, ToPrimitive},
-    solana_instruction::{AccountMeta, Instruction},
-    solana_pubkey::Pubkey,
-};
-
-#[derive(Clone, Copy, Debug, FromPrimitive, ToPrimitive, PartialEq, Eq)]
-#[repr(u8)]
-pub enum ProofInstruction {
-    /// Close a zero-knowledge proof context state.
-    ///
-    /// Accounts expected by this instruction:
-    ///   0. `[writable]` The proof context account to close
-    ///   1. `[writable]` The destination account for lamports
-    ///   2. `[signer]` The context account's owner
-    ///
-    /// Data expected by this instruction:
-    ///   None
-    ///
-    CloseContextState,
-
-    /// Verify a zero-ciphertext proof.
-    ///
-    /// A zero-ciphertext proof certifies that an ElGamal ciphertext encrypts the value zero.
-    ///
-    /// Accounts expected by this instruction:
-    ///
-    ///   0. `[]` (Optional) Account to read the proof from
-    ///   1. `[writable]` (Optional) The proof context account
-    ///   2. `[]` (Optional) The proof context account owner
-    ///
-    /// The instruction expects either:
-    ///   i. `ZeroCiphertextProofData` if proof is provided as instruction data
-    ///   ii. `u32` byte offset if proof is provided as an account
-    ///
-    VerifyZeroCiphertext,
-
-    /// Verify a ciphertext-ciphertext equality proof.
-    ///
-    /// A ciphertext-ciphertext equality proof certifies that two ElGamal ciphertexts encrypt the
-    /// same message.
-    ///
-    /// Accounts expected by this instruction:
-    ///
-    ///   0. `[]` (Optional) Account to read the proof from
-    ///   1. `[writable]` (Optional) The proof context account
-    ///   2. `[]` (Optional) The proof context account owner
-    ///
-    /// The instruction expects either:
-    ///   i. `CiphertextCiphertextEqualityProofData` if proof is provided as instruction data
-    ///   ii. `u32` byte offset if proof is provided as an account
-    ///
-    VerifyCiphertextCiphertextEquality,
-
-    /// Verify a ciphertext-commitment equality proof.
-    ///
-    /// A ciphertext-commitment equality proof certifies that an ElGamal ciphertext and a Pedersen
-    /// commitment encrypt/encode the same message.
-    ///
-    /// Accounts expected by this instruction:
-    ///
-    ///   0. `[]` (Optional) Account to read the proof from
-    ///   1. `[writable]` (Optional) The proof context account
-    ///   2. `[]` (Optional) The proof context account owner
-    ///
-    /// The instruction expects either:
-    ///   i. `CiphertextCommitmentEqualityProofData` if proof is provided as instruction data
-    ///   ii. `u32` byte offset if proof is provided as an account
-    ///
-    VerifyCiphertextCommitmentEquality,
-
-    /// Verify a public key validity zero-knowledge proof.
-    ///
-    /// A public key validity proof certifies that an ElGamal public key is well-formed and the
-    /// prover knows the corresponding secret key.
-    ///
-    /// Accounts expected by this instruction:
-    ///
-    ///   0. `[]` (Optional) Account to read the proof from
-    ///   1. `[writable]` (Optional) The proof context account
-    ///   2. `[]` (Optional) The proof context account owner
-    ///
-    /// The instruction expects either:
-    ///   i. `PubkeyValidityData` if proof is provided as instruction data
-    ///   ii. `u32` byte offset if proof is provided as an account
-    ///
-    VerifyPubkeyValidity,
-
-    /// Verify a percentage-with-cap proof.
-    ///
-    /// A percentage-with-cap proof certifies that a tuple of Pedersen commitments satisfy a
-    /// percentage relation.
-    ///
-    /// Accounts expected by this instruction:
-    ///
-    ///   0. `[]` (Optional) Account to read the proof from
-    ///   1. `[writable]` (Optional) The proof context account
-    ///   2. `[]` (Optional) The proof context account owner
-    ///
-    /// The instruction expects either:
-    ///   i. `PercentageWithCapProofData` if proof is provided as instruction data
-    ///   ii. `u32` byte offset if proof is provided as an account
-    ///
-    VerifyPercentageWithCap,
-
-    /// Verify a 64-bit batched range proof.
-    ///
-    /// A batched range proof is defined with respect to a sequence of Pedersen commitments `[C_1,
-    /// ..., C_N]` and bit-lengths `[n_1, ..., n_N]`. It certifies that each commitment `C_i` is a
-    /// commitment to a positive number of bit-length `n_i`. Batch verifying range proofs is more
-    /// efficient than verifying independent range proofs on commitments `C_1, ..., C_N`
-    /// separately.
-    ///
-    /// The bit-length of a batched range proof specifies the sum of the individual bit-lengths
-    /// `n_1, ..., n_N`. For example, this instruction can be used to certify that two commitments
-    /// `C_1` and `C_2` each hold positive 32-bit numbers.
-    ///
-    /// Accounts expected by this instruction:
-    ///
-    ///   0. `[]` (Optional) Account to read the proof from
-    ///   1. `[writable]` (Optional) The proof context account
-    ///   2. `[]` (Optional) The proof context account owner
-    ///
-    /// The instruction expects either:
-    ///   i. `BatchedRangeProofU64Data` if proof is provided as instruction data
-    ///   ii. `u32` byte offset if proof is provided as an account
-    ///
-    VerifyBatchedRangeProofU64,
-
-    /// Verify 128-bit batched range proof.
-    ///
-    /// The bit-length of a batched range proof specifies the sum of the individual bit-lengths
-    /// `n_1, ..., n_N`. For example, this instruction can be used to certify that two commitments
-    /// `C_1` and `C_2` each hold positive 64-bit numbers.
-    ///
-    /// Accounts expected by this instruction:
-    ///
-    ///   0. `[]` (Optional) Account to read the proof from
-    ///   1. `[writable]` (Optional) The proof context account
-    ///   2. `[]` (Optional) The proof context account owner
-    ///
-    /// The instruction expects either:
-    ///   i. `BatchedRangeProofU128Data` if proof is provided as instruction data
-    ///   ii. `u32` byte offset if proof is provided as an account
-    ///
-    VerifyBatchedRangeProofU128,
-
-    /// Verify 256-bit batched range proof.
-    ///
-    /// The bit-length of a batched range proof specifies the sum of the individual bit-lengths
-    /// `n_1, ..., n_N`. For example, this instruction can be used to certify that four commitments
-    /// `[C_1, C_2, C_3, C_4]` each hold positive 64-bit numbers.
-    ///
-    /// Accounts expected by this instruction:
-    ///
-    ///   0. `[]` (Optional) Account to read the proof from
-    ///   1. `[writable]` (Optional) The proof context account
-    ///   2. `[]` (Optional) The proof context account owner
-    ///
-    /// The instruction expects either:
-    ///   i. `BatchedRangeProofU256Data` if proof is provided as instruction data
-    ///   ii. `u32` byte offset if proof is provided as an account
-    ///
-    VerifyBatchedRangeProofU256,
-
-    /// Verify a grouped-ciphertext with 2 handles validity proof.
-    ///
-    /// A grouped-ciphertext validity proof certifies that a grouped ElGamal ciphertext is
-    /// well-defined, i.e. the ciphertext can be decrypted by private keys associated with its
-    /// decryption handles.
-    ///
-    /// Accounts expected by this instruction:
-    ///
-    ///   0. `[]` (Optional) Account to read the proof from
-    ///   1. `[writable]` (Optional) The proof context account
-    ///   2. `[]` (Optional) The proof context account owner
-    ///
-    /// The instruction expects either:
-    ///   i. `GroupedCiphertext2HandlesValidityProofData` if proof is provided as instruction data
-    ///   ii. `u32` byte offset if proof is provided as an account
-    ///
-    VerifyGroupedCiphertext2HandlesValidity,
-
-    /// Verify a batched grouped-ciphertext with 2 handles validity proof.
-    ///
-    /// A batched grouped-ciphertext validity proof certifies the validity of two grouped ElGamal
-    /// ciphertext that are encrypted using the same set of ElGamal public keys. A batched
-    /// grouped-ciphertext validity proof is shorter and more efficient than two individual
-    /// grouped-ciphertext validity proofs.
-    ///
-    /// Accounts expected by this instruction:
-    ///
-    ///   0. `[]` (Optional) Account to read the proof from
-    ///   1. `[writable]` (Optional) The proof context account
-    ///   2. `[]` (Optional) The proof context account owner
-    ///
-    /// The instruction expects either:
-    ///   i. `BatchedGroupedCiphertext2HandlesValidityProofData` if proof is provided as instruction data
-    ///   ii. `u32` byte offset if proof is provided as an account
-    ///
-    VerifyBatchedGroupedCiphertext2HandlesValidity,
-
-    /// Verify a grouped-ciphertext with 3 handles validity proof.
-    ///
-    /// A grouped-ciphertext validity proof certifies that a grouped ElGamal ciphertext is
-    /// well-defined, i.e. the ciphertext can be decrypted by private keys associated with its
-    /// decryption handles.
-    ///
-    /// Accounts expected by this instruction:
-    ///
-    ///   * Creating a proof context account
-    ///   0. `[]` (Optional) Account to read the proof from
-    ///   1. `[writable]` The proof context account
-    ///   2. `[]` The proof context account owner
-    ///
-    ///   * Otherwise
-    ///     None
-    ///
-    /// The instruction expects either:
-    ///   i. `GroupedCiphertext3HandlesValidityProofData` if proof is provided as instruction data
-    ///   ii. `u32` byte offset if proof is provided as an account
-    ///
-    VerifyGroupedCiphertext3HandlesValidity,
-
-    /// Verify a batched grouped-ciphertext with 3 handles validity proof.
-    ///
-    /// A batched grouped-ciphertext validity proof certifies the validity of two grouped ElGamal
-    /// ciphertext that are encrypted using the same set of ElGamal public keys. A batched
-    /// grouped-ciphertext validity proof is shorter and more efficient than two individual
-    /// grouped-ciphertext validity proofs.
-    ///
-    /// Accounts expected by this instruction:
-    ///
-    ///   * Creating a proof context account
-    ///   0. `[]` (Optional) Account to read the proof from
-    ///   1. `[writable]` The proof context account
-    ///   2. `[]` The proof context account owner
-    ///
-    ///   * Otherwise
-    ///     None
-    ///
-    /// The instruction expects either:
-    ///   i. `BatchedGroupedCiphertext3HandlesValidityProofData` if proof is provided as instruction data
-    ///   ii. `u32` byte offset if proof is provided as an account
-    ///
-    VerifyBatchedGroupedCiphertext3HandlesValidity,
-}
-
-/// Pubkeys associated with a context state account to be used as parameters to functions.
-#[derive(Clone, Copy, Debug, PartialEq)]
-pub struct ContextStateInfo<'a> {
-    pub context_state_account: &'a Pubkey,
-    pub context_state_authority: &'a Pubkey,
-}
-
-/// Create a `CloseContextState` instruction.
-pub fn close_context_state(
-    context_state_info: ContextStateInfo,
-    destination_account: &Pubkey,
-) -> Instruction {
-    let accounts = vec![
-        AccountMeta::new(*context_state_info.context_state_account, false),
-        AccountMeta::new(*destination_account, false),
-        AccountMeta::new_readonly(*context_state_info.context_state_authority, true),
-    ];
-
-    let data = vec![ToPrimitive::to_u8(&ProofInstruction::CloseContextState).unwrap()];
-
-    Instruction {
-        program_id: crate::zk_elgamal_proof_program::id(),
-        accounts,
-        data,
-    }
-}
-
-impl ProofInstruction {
-    pub fn encode_verify_proof<T, U>(
-        &self,
-        context_state_info: Option<ContextStateInfo>,
-        proof_data: &T,
-    ) -> Instruction
-    where
-        T: Pod + ZkProofData<U>,
-        U: Pod,
-    {
-        let accounts = if let Some(context_state_info) = context_state_info {
-            vec![
-                AccountMeta::new(*context_state_info.context_state_account, false),
-                AccountMeta::new_readonly(*context_state_info.context_state_authority, false),
-            ]
-        } else {
-            vec![]
-        };
-
-        let mut data = vec![ToPrimitive::to_u8(self).unwrap()];
-        data.extend_from_slice(bytes_of(proof_data));
-
-        Instruction {
-            program_id: crate::zk_elgamal_proof_program::id(),
-            accounts,
-            data,
-        }
-    }
-
-    pub fn encode_verify_proof_from_account(
-        &self,
-        context_state_info: Option<ContextStateInfo>,
-        proof_account: &Pubkey,
-        offset: u32,
-    ) -> Instruction {
-        let accounts = if let Some(context_state_info) = context_state_info {
-            vec![
-                AccountMeta::new(*proof_account, false),
-                AccountMeta::new(*context_state_info.context_state_account, false),
-                AccountMeta::new_readonly(*context_state_info.context_state_authority, false),
-            ]
-        } else {
-            vec![AccountMeta::new(*proof_account, false)]
-        };
-
-        let mut data = vec![ToPrimitive::to_u8(self).unwrap()];
-        data.extend_from_slice(&offset.to_le_bytes());
-
-        Instruction {
-            program_id: crate::zk_elgamal_proof_program::id(),
-            accounts,
-            data,
-        }
-    }
-
-    pub fn instruction_type(input: &[u8]) -> Option<Self> {
-        input
-            .first()
-            .and_then(|instruction| FromPrimitive::from_u8(*instruction))
-    }
-
-    pub fn proof_data<T, U>(input: &[u8]) -> Option<&T>
-    where
-        T: Pod + ZkProofData<U>,
-        U: Pod,
-    {
-        input
-            .get(1..)
-            .and_then(|data| bytemuck::try_from_bytes(data).ok())
-    }
-}

+ 0 - 16
zk-sdk/src/zk_elgamal_proof_program/mod.rs

@@ -1,16 +0,0 @@
-//! The native ZK ElGamal proof program.
-//!
-//! The program verifies a number of zero-knowledge proofs that are tailored to work with Pedersen
-//! commitments and ElGamal encryption over the elliptic curve curve25519. A general overview of
-//! the program as well as the technical details of some of the proof instructions can be found in
-//! the [`ZK ElGamal proof`] documentation.
-//!
-//! [`ZK ElGamal proof`]: https://docs.solanalabs.com/runtime/zk-token-proof
-
-pub mod errors;
-pub mod instruction;
-pub mod proof_data;
-pub mod state;
-
-// Program Id of the ZK ElGamal Proof program
-pub use solana_sdk_ids::zk_elgamal_proof_program::{check_id, id, ID};

+ 0 - 263
zk-sdk/src/zk_elgamal_proof_program/proof_data/batched_grouped_ciphertext_validity/handles_2.rs

@@ -1,263 +0,0 @@
-//! The batched grouped-ciphertext validity proof instruction.
-//!
-//! A batched grouped-ciphertext validity proof certifies the validity of two grouped ElGamal
-//! ciphertext that are encrypted using the same set of ElGamal public keys. A batched
-//! grouped-ciphertext validity proof is shorter and more efficient than two individual
-//! grouped-ciphertext validity proofs.
-
-#[cfg(target_arch = "wasm32")]
-use {
-    crate::encryption::grouped_elgamal::GroupedElGamalCiphertext2Handles, wasm_bindgen::prelude::*,
-};
-use {
-    crate::{
-        encryption::pod::{
-            elgamal::PodElGamalPubkey, grouped_elgamal::PodGroupedElGamalCiphertext2Handles,
-        },
-        sigma_proofs::pod::PodBatchedGroupedCiphertext2HandlesValidityProof,
-        zk_elgamal_proof_program::proof_data::{pod::impl_wasm_to_bytes, ProofType, ZkProofData},
-    },
-    bytemuck_derive::{Pod, Zeroable},
-};
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::{
-            elgamal::ElGamalPubkey, grouped_elgamal::GroupedElGamalCiphertext,
-            pedersen::PedersenOpening,
-        },
-        sigma_proofs::batched_grouped_ciphertext_validity::BatchedGroupedCiphertext2HandlesValidityProof,
-        zk_elgamal_proof_program::{
-            errors::{ProofGenerationError, ProofVerificationError},
-            proof_data::errors::ProofDataError,
-        },
-    },
-    bytemuck::bytes_of,
-    merlin::Transcript,
-};
-
-/// The instruction data that is needed for the
-/// `ProofInstruction::VerifyBatchedGroupedCiphertextValidity` instruction.
-///
-/// It includes the cryptographic proof as well as the context data information needed to verify
-/// the proof.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct BatchedGroupedCiphertext2HandlesValidityProofData {
-    pub context: BatchedGroupedCiphertext2HandlesValidityProofContext,
-
-    pub proof: PodBatchedGroupedCiphertext2HandlesValidityProof,
-}
-
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct BatchedGroupedCiphertext2HandlesValidityProofContext {
-    pub first_pubkey: PodElGamalPubkey, // 32 bytes
-
-    pub second_pubkey: PodElGamalPubkey, // 32 bytes
-
-    pub grouped_ciphertext_lo: PodGroupedElGamalCiphertext2Handles, // 96 bytes
-
-    pub grouped_ciphertext_hi: PodGroupedElGamalCiphertext2Handles, // 96 bytes
-}
-
-#[cfg(not(target_os = "solana"))]
-#[cfg(not(target_arch = "wasm32"))]
-impl BatchedGroupedCiphertext2HandlesValidityProofData {
-    pub fn new(
-        first_pubkey: &ElGamalPubkey,
-        second_pubkey: &ElGamalPubkey,
-        grouped_ciphertext_lo: &GroupedElGamalCiphertext<2>,
-        grouped_ciphertext_hi: &GroupedElGamalCiphertext<2>,
-        amount_lo: u64,
-        amount_hi: u64,
-        opening_lo: &PedersenOpening,
-        opening_hi: &PedersenOpening,
-    ) -> Result<Self, ProofGenerationError> {
-        let pod_first_pubkey = PodElGamalPubkey(first_pubkey.into());
-        let pod_second_pubkey = PodElGamalPubkey(second_pubkey.into());
-        let pod_grouped_ciphertext_lo = (*grouped_ciphertext_lo).into();
-        let pod_grouped_ciphertext_hi = (*grouped_ciphertext_hi).into();
-
-        let context = BatchedGroupedCiphertext2HandlesValidityProofContext {
-            first_pubkey: pod_first_pubkey,
-            second_pubkey: pod_second_pubkey,
-            grouped_ciphertext_lo: pod_grouped_ciphertext_lo,
-            grouped_ciphertext_hi: pod_grouped_ciphertext_hi,
-        };
-
-        let mut transcript = context.new_transcript();
-
-        let proof = BatchedGroupedCiphertext2HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            amount_lo,
-            amount_hi,
-            opening_lo,
-            opening_hi,
-            &mut transcript,
-        )
-        .into();
-
-        Ok(Self { context, proof })
-    }
-}
-
-// Define a separate constructor for `wasm32` target since `wasm_bindgen` does
-// not yet support parameters with generic constants (i.e.
-// `GroupedElGamalCiphertext<2>`).
-#[cfg(target_arch = "wasm32")]
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-impl BatchedGroupedCiphertext2HandlesValidityProofData {
-    pub fn new(
-        first_pubkey: &ElGamalPubkey,
-        second_pubkey: &ElGamalPubkey,
-        grouped_ciphertext_lo: &GroupedElGamalCiphertext2Handles,
-        grouped_ciphertext_hi: &GroupedElGamalCiphertext2Handles,
-        amount_lo: u64,
-        amount_hi: u64,
-        opening_lo: &PedersenOpening,
-        opening_hi: &PedersenOpening,
-    ) -> Result<Self, ProofGenerationError> {
-        let pod_first_pubkey = PodElGamalPubkey(first_pubkey.into());
-        let pod_second_pubkey = PodElGamalPubkey(second_pubkey.into());
-        let pod_grouped_ciphertext_lo = grouped_ciphertext_lo.0.into();
-        let pod_grouped_ciphertext_hi = grouped_ciphertext_hi.0.into();
-
-        let context = BatchedGroupedCiphertext2HandlesValidityProofContext {
-            first_pubkey: pod_first_pubkey,
-            second_pubkey: pod_second_pubkey,
-            grouped_ciphertext_lo: pod_grouped_ciphertext_lo,
-            grouped_ciphertext_hi: pod_grouped_ciphertext_hi,
-        };
-
-        let mut transcript = context.new_transcript();
-
-        let proof = BatchedGroupedCiphertext2HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            amount_lo,
-            amount_hi,
-            opening_lo,
-            opening_hi,
-            &mut transcript,
-        )
-        .into();
-
-        Ok(Self { context, proof })
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = BatchedGroupedCiphertext2HandlesValidityProofData);
-
-impl ZkProofData<BatchedGroupedCiphertext2HandlesValidityProofContext>
-    for BatchedGroupedCiphertext2HandlesValidityProofData
-{
-    const PROOF_TYPE: ProofType = ProofType::BatchedGroupedCiphertext2HandlesValidity;
-
-    fn context_data(&self) -> &BatchedGroupedCiphertext2HandlesValidityProofContext {
-        &self.context
-    }
-
-    #[cfg(not(target_os = "solana"))]
-    fn verify_proof(&self) -> Result<(), ProofVerificationError> {
-        let mut transcript = self.context.new_transcript();
-
-        let first_pubkey = self.context.first_pubkey.try_into()?;
-        let second_pubkey = self.context.second_pubkey.try_into()?;
-        let grouped_ciphertext_lo: GroupedElGamalCiphertext<2> =
-            self.context.grouped_ciphertext_lo.try_into()?;
-        let grouped_ciphertext_hi: GroupedElGamalCiphertext<2> =
-            self.context.grouped_ciphertext_hi.try_into()?;
-
-        let first_handle_lo = grouped_ciphertext_lo.handles.first().unwrap();
-        let second_handle_lo = grouped_ciphertext_lo.handles.get(1).unwrap();
-
-        let first_handle_hi = grouped_ciphertext_hi.handles.first().unwrap();
-        let second_handle_hi = grouped_ciphertext_hi.handles.get(1).unwrap();
-
-        let proof: BatchedGroupedCiphertext2HandlesValidityProof = self.proof.try_into()?;
-
-        proof
-            .verify(
-                &first_pubkey,
-                &second_pubkey,
-                &grouped_ciphertext_lo.commitment,
-                &grouped_ciphertext_hi.commitment,
-                first_handle_lo,
-                first_handle_hi,
-                second_handle_lo,
-                second_handle_hi,
-                &mut transcript,
-            )
-            .map_err(|e| e.into())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl BatchedGroupedCiphertext2HandlesValidityProofContext {
-    fn new_transcript(&self) -> Transcript {
-        let mut transcript =
-            Transcript::new(b"batched-grouped-ciphertext-validity-2-handles-instruction");
-
-        transcript.append_message(b"first-pubkey", bytes_of(&self.first_pubkey));
-        transcript.append_message(b"second-pubkey", bytes_of(&self.second_pubkey));
-        transcript.append_message(
-            b"grouped-ciphertext-lo",
-            bytes_of(&self.grouped_ciphertext_lo),
-        );
-        transcript.append_message(
-            b"grouped-ciphertext-hi",
-            bytes_of(&self.grouped_ciphertext_hi),
-        );
-
-        transcript
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = BatchedGroupedCiphertext2HandlesValidityProofContext);
-
-#[cfg(test)]
-mod test {
-    use {
-        super::*,
-        crate::encryption::{elgamal::ElGamalKeypair, grouped_elgamal::GroupedElGamal},
-    };
-
-    #[test]
-    fn test_ciphertext_validity_proof_instruction_correctness() {
-        let first_keypair = ElGamalKeypair::new_rand();
-        let first_pubkey = first_keypair.pubkey();
-
-        let second_keypair = ElGamalKeypair::new_rand();
-        let second_pubkey = second_keypair.pubkey();
-
-        let amount_lo: u64 = 11;
-        let amount_hi: u64 = 22;
-
-        let opening_lo = PedersenOpening::new_rand();
-        let opening_hi = PedersenOpening::new_rand();
-
-        let grouped_ciphertext_lo =
-            GroupedElGamal::encrypt_with([first_pubkey, second_pubkey], amount_lo, &opening_lo);
-
-        let grouped_ciphertext_hi =
-            GroupedElGamal::encrypt_with([first_pubkey, second_pubkey], amount_hi, &opening_hi);
-
-        let proof_data = BatchedGroupedCiphertext2HandlesValidityProofData::new(
-            first_pubkey,
-            second_pubkey,
-            &grouped_ciphertext_lo,
-            &grouped_ciphertext_hi,
-            amount_lo,
-            amount_hi,
-            &opening_lo,
-            &opening_hi,
-        )
-        .unwrap();
-
-        assert!(proof_data.verify_proof().is_ok());
-    }
-}

+ 0 - 290
zk-sdk/src/zk_elgamal_proof_program/proof_data/batched_grouped_ciphertext_validity/handles_3.rs

@@ -1,290 +0,0 @@
-//! The batched grouped-ciphertext with 3 handles validity proof instruction.
-//!
-//! A batched grouped-ciphertext validity proof certifies the validity of two grouped ElGamal
-//! ciphertext that are encrypted using the same set of ElGamal public keys. A batched
-//! grouped-ciphertext validity proof is shorter and more efficient than two individual
-//! grouped-ciphertext validity proofs.
-
-#[cfg(target_arch = "wasm32")]
-use {
-    crate::encryption::grouped_elgamal::GroupedElGamalCiphertext3Handles, wasm_bindgen::prelude::*,
-};
-use {
-    crate::{
-        encryption::pod::{
-            elgamal::PodElGamalPubkey, grouped_elgamal::PodGroupedElGamalCiphertext3Handles,
-        },
-        sigma_proofs::pod::PodBatchedGroupedCiphertext3HandlesValidityProof,
-        zk_elgamal_proof_program::proof_data::{pod::impl_wasm_to_bytes, ProofType, ZkProofData},
-    },
-    bytemuck_derive::{Pod, Zeroable},
-};
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::{
-            elgamal::ElGamalPubkey, grouped_elgamal::GroupedElGamalCiphertext,
-            pedersen::PedersenOpening,
-        },
-        sigma_proofs::batched_grouped_ciphertext_validity::BatchedGroupedCiphertext3HandlesValidityProof,
-        zk_elgamal_proof_program::{
-            errors::{ProofGenerationError, ProofVerificationError},
-            proof_data::errors::ProofDataError,
-        },
-    },
-    bytemuck::bytes_of,
-    merlin::Transcript,
-};
-
-/// The instruction data that is needed for the
-/// `ProofInstruction::VerifyBatchedGroupedCiphertext3HandlesValidity` instruction.
-///
-/// It includes the cryptographic proof as well as the context data information needed to verify
-/// the proof.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct BatchedGroupedCiphertext3HandlesValidityProofData {
-    pub context: BatchedGroupedCiphertext3HandlesValidityProofContext,
-
-    pub proof: PodBatchedGroupedCiphertext3HandlesValidityProof,
-}
-
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct BatchedGroupedCiphertext3HandlesValidityProofContext {
-    pub first_pubkey: PodElGamalPubkey, // 32 bytes
-
-    pub second_pubkey: PodElGamalPubkey, // 32 bytes
-
-    pub third_pubkey: PodElGamalPubkey, // 32 bytes
-
-    pub grouped_ciphertext_lo: PodGroupedElGamalCiphertext3Handles, // 128 bytes
-
-    pub grouped_ciphertext_hi: PodGroupedElGamalCiphertext3Handles, // 128 bytes
-}
-
-#[cfg(not(target_os = "solana"))]
-#[cfg(not(target_arch = "wasm32"))]
-impl BatchedGroupedCiphertext3HandlesValidityProofData {
-    pub fn new(
-        first_pubkey: &ElGamalPubkey,
-        second_pubkey: &ElGamalPubkey,
-        third_pubkey: &ElGamalPubkey,
-        grouped_ciphertext_lo: &GroupedElGamalCiphertext<3>,
-        grouped_ciphertext_hi: &GroupedElGamalCiphertext<3>,
-        amount_lo: u64,
-        amount_hi: u64,
-        opening_lo: &PedersenOpening,
-        opening_hi: &PedersenOpening,
-    ) -> Result<Self, ProofGenerationError> {
-        let pod_first_pubkey = PodElGamalPubkey(first_pubkey.into());
-        let pod_second_pubkey = PodElGamalPubkey(second_pubkey.into());
-        let pod_third_pubkey = PodElGamalPubkey(third_pubkey.into());
-        let pod_grouped_ciphertext_lo = (*grouped_ciphertext_lo).into();
-        let pod_grouped_ciphertext_hi = (*grouped_ciphertext_hi).into();
-
-        let context = BatchedGroupedCiphertext3HandlesValidityProofContext {
-            first_pubkey: pod_first_pubkey,
-            second_pubkey: pod_second_pubkey,
-            third_pubkey: pod_third_pubkey,
-            grouped_ciphertext_lo: pod_grouped_ciphertext_lo,
-            grouped_ciphertext_hi: pod_grouped_ciphertext_hi,
-        };
-
-        let mut transcript = context.new_transcript();
-
-        let proof = BatchedGroupedCiphertext3HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            third_pubkey,
-            amount_lo,
-            amount_hi,
-            opening_lo,
-            opening_hi,
-            &mut transcript,
-        )
-        .into();
-
-        Ok(Self { context, proof })
-    }
-}
-
-// Define a separate constructor for `wasm32` target since `wasm_bindgen` does
-// not yet support parameters with generic constants (i.e.
-// `GroupedElGamalCiphertext<3>`).
-#[cfg(target_arch = "wasm32")]
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-impl BatchedGroupedCiphertext3HandlesValidityProofData {
-    pub fn new(
-        first_pubkey: &ElGamalPubkey,
-        second_pubkey: &ElGamalPubkey,
-        third_pubkey: &ElGamalPubkey,
-        grouped_ciphertext_lo: &GroupedElGamalCiphertext3Handles,
-        grouped_ciphertext_hi: &GroupedElGamalCiphertext3Handles,
-        amount_lo: u64,
-        amount_hi: u64,
-        opening_lo: &PedersenOpening,
-        opening_hi: &PedersenOpening,
-    ) -> Result<Self, ProofGenerationError> {
-        let pod_first_pubkey = PodElGamalPubkey(first_pubkey.into());
-        let pod_second_pubkey = PodElGamalPubkey(second_pubkey.into());
-        let pod_third_pubkey = PodElGamalPubkey(third_pubkey.into());
-        let pod_grouped_ciphertext_lo = grouped_ciphertext_lo.0.into();
-        let pod_grouped_ciphertext_hi = grouped_ciphertext_hi.0.into();
-
-        let context = BatchedGroupedCiphertext3HandlesValidityProofContext {
-            first_pubkey: pod_first_pubkey,
-            second_pubkey: pod_second_pubkey,
-            third_pubkey: pod_third_pubkey,
-            grouped_ciphertext_lo: pod_grouped_ciphertext_lo,
-            grouped_ciphertext_hi: pod_grouped_ciphertext_hi,
-        };
-
-        let mut transcript = context.new_transcript();
-
-        let proof = BatchedGroupedCiphertext3HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            third_pubkey,
-            amount_lo,
-            amount_hi,
-            opening_lo,
-            opening_hi,
-            &mut transcript,
-        )
-        .into();
-
-        Ok(Self { context, proof })
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = BatchedGroupedCiphertext3HandlesValidityProofData);
-
-impl ZkProofData<BatchedGroupedCiphertext3HandlesValidityProofContext>
-    for BatchedGroupedCiphertext3HandlesValidityProofData
-{
-    const PROOF_TYPE: ProofType = ProofType::BatchedGroupedCiphertext3HandlesValidity;
-
-    fn context_data(&self) -> &BatchedGroupedCiphertext3HandlesValidityProofContext {
-        &self.context
-    }
-
-    #[cfg(not(target_os = "solana"))]
-    fn verify_proof(&self) -> Result<(), ProofVerificationError> {
-        let mut transcript = self.context.new_transcript();
-
-        let first_pubkey = self.context.first_pubkey.try_into()?;
-        let second_pubkey = self.context.second_pubkey.try_into()?;
-        let third_pubkey = self.context.third_pubkey.try_into()?;
-        let grouped_ciphertext_lo: GroupedElGamalCiphertext<3> =
-            self.context.grouped_ciphertext_lo.try_into()?;
-        let grouped_ciphertext_hi: GroupedElGamalCiphertext<3> =
-            self.context.grouped_ciphertext_hi.try_into()?;
-
-        let first_handle_lo = grouped_ciphertext_lo.handles.first().unwrap();
-        let second_handle_lo = grouped_ciphertext_lo.handles.get(1).unwrap();
-        let third_handle_lo = grouped_ciphertext_lo.handles.get(2).unwrap();
-
-        let first_handle_hi = grouped_ciphertext_hi.handles.first().unwrap();
-        let second_handle_hi = grouped_ciphertext_hi.handles.get(1).unwrap();
-        let third_handle_hi = grouped_ciphertext_hi.handles.get(2).unwrap();
-
-        let proof: BatchedGroupedCiphertext3HandlesValidityProof = self.proof.try_into()?;
-
-        proof
-            .verify(
-                &first_pubkey,
-                &second_pubkey,
-                &third_pubkey,
-                &grouped_ciphertext_lo.commitment,
-                &grouped_ciphertext_hi.commitment,
-                first_handle_lo,
-                first_handle_hi,
-                second_handle_lo,
-                second_handle_hi,
-                third_handle_lo,
-                third_handle_hi,
-                &mut transcript,
-            )
-            .map_err(|e| e.into())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl BatchedGroupedCiphertext3HandlesValidityProofContext {
-    fn new_transcript(&self) -> Transcript {
-        let mut transcript =
-            Transcript::new(b"batched-grouped-ciphertext-validity-3-handles-instruction");
-
-        transcript.append_message(b"first-pubkey", bytes_of(&self.first_pubkey));
-        transcript.append_message(b"second-pubkey", bytes_of(&self.second_pubkey));
-        transcript.append_message(b"third-pubkey", bytes_of(&self.third_pubkey));
-        transcript.append_message(
-            b"grouped-ciphertext-lo",
-            bytes_of(&self.grouped_ciphertext_lo),
-        );
-        transcript.append_message(
-            b"grouped-ciphertext-hi",
-            bytes_of(&self.grouped_ciphertext_hi),
-        );
-
-        transcript
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = BatchedGroupedCiphertext3HandlesValidityProofContext);
-
-#[cfg(test)]
-mod test {
-    use {
-        super::*,
-        crate::encryption::{elgamal::ElGamalKeypair, grouped_elgamal::GroupedElGamal},
-    };
-
-    #[test]
-    fn test_ciphertext_validity_proof_instruction_correctness() {
-        let first_keypair = ElGamalKeypair::new_rand();
-        let first_pubkey = first_keypair.pubkey();
-
-        let second_keypair = ElGamalKeypair::new_rand();
-        let second_pubkey = second_keypair.pubkey();
-
-        let third_keypair = ElGamalKeypair::new_rand();
-        let third_pubkey = third_keypair.pubkey();
-
-        let amount_lo: u64 = 11;
-        let amount_hi: u64 = 22;
-
-        let opening_lo = PedersenOpening::new_rand();
-        let opening_hi = PedersenOpening::new_rand();
-
-        let grouped_ciphertext_lo = GroupedElGamal::encrypt_with(
-            [first_pubkey, second_pubkey, third_pubkey],
-            amount_lo,
-            &opening_lo,
-        );
-
-        let grouped_ciphertext_hi = GroupedElGamal::encrypt_with(
-            [first_pubkey, second_pubkey, third_pubkey],
-            amount_hi,
-            &opening_hi,
-        );
-
-        let proof_data = BatchedGroupedCiphertext3HandlesValidityProofData::new(
-            first_pubkey,
-            second_pubkey,
-            third_pubkey,
-            &grouped_ciphertext_lo,
-            &grouped_ciphertext_hi,
-            amount_lo,
-            amount_hi,
-            &opening_lo,
-            &opening_hi,
-        )
-        .unwrap();
-
-        assert!(proof_data.verify_proof().is_ok());
-    }
-}

+ 0 - 13
zk-sdk/src/zk_elgamal_proof_program/proof_data/batched_grouped_ciphertext_validity/mod.rs

@@ -1,13 +0,0 @@
-mod handles_2;
-mod handles_3;
-
-pub use {
-    handles_2::{
-        BatchedGroupedCiphertext2HandlesValidityProofContext,
-        BatchedGroupedCiphertext2HandlesValidityProofData,
-    },
-    handles_3::{
-        BatchedGroupedCiphertext3HandlesValidityProofContext,
-        BatchedGroupedCiphertext3HandlesValidityProofData,
-    },
-};

+ 0 - 199
zk-sdk/src/zk_elgamal_proof_program/proof_data/batched_range_proof/batched_range_proof_u128.rs

@@ -1,199 +0,0 @@
-//! The 128-bit batched range proof instruction.
-
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::pedersen::{PedersenCommitment, PedersenOpening},
-        range_proof::RangeProof,
-        zk_elgamal_proof_program::{
-            errors::{ProofGenerationError, ProofVerificationError},
-            proof_data::batched_range_proof::MAX_COMMITMENTS,
-        },
-    },
-    std::convert::TryInto,
-};
-use {
-    crate::{
-        range_proof::pod::PodRangeProofU128,
-        zk_elgamal_proof_program::proof_data::{
-            batched_range_proof::BatchedRangeProofContext, ProofType, ZkProofData,
-        },
-    },
-    bytemuck_derive::{Pod, Zeroable},
-};
-
-/// The instruction data that is needed for the
-/// `ProofInstruction::VerifyBatchedRangeProofU128` instruction.
-///
-/// It includes the cryptographic proof as well as the context data information needed to verify
-/// the proof.
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct BatchedRangeProofU128Data {
-    /// The context data for a batched range proof
-    pub context: BatchedRangeProofContext,
-
-    /// The batched range proof
-    pub proof: PodRangeProofU128,
-}
-
-#[cfg(not(target_os = "solana"))]
-impl BatchedRangeProofU128Data {
-    pub fn new(
-        commitments: Vec<&PedersenCommitment>,
-        amounts: Vec<u64>,
-        bit_lengths: Vec<usize>,
-        openings: Vec<&PedersenOpening>,
-    ) -> Result<Self, ProofGenerationError> {
-        // the sum of the bit lengths must be 128
-        let batched_bit_length = bit_lengths
-            .iter()
-            .try_fold(0_usize, |acc, &x| acc.checked_add(x))
-            .ok_or(ProofGenerationError::IllegalAmountBitLength)?;
-
-        // `u128::BITS` is 128, which fits in a single byte and should not overflow to `usize` for
-        // an overwhelming number of platforms. However, to be extra cautious, use `try_from` and
-        // `unwrap` here. A simple case `u128::BITS as usize` can silently overflow.
-        let expected_bit_length = usize::try_from(u128::BITS).unwrap();
-        if batched_bit_length != expected_bit_length {
-            return Err(ProofGenerationError::IllegalAmountBitLength);
-        }
-
-        let context =
-            BatchedRangeProofContext::new(&commitments, &amounts, &bit_lengths, &openings)?;
-
-        let mut transcript = context.new_transcript();
-        let proof: PodRangeProofU128 =
-            RangeProof::new(amounts, bit_lengths, openings, &mut transcript)?
-                .try_into()
-                .map_err(|_| ProofGenerationError::ProofLength)?;
-
-        Ok(Self { context, proof })
-    }
-}
-
-impl ZkProofData<BatchedRangeProofContext> for BatchedRangeProofU128Data {
-    const PROOF_TYPE: ProofType = ProofType::BatchedRangeProofU128;
-
-    fn context_data(&self) -> &BatchedRangeProofContext {
-        &self.context
-    }
-
-    #[cfg(not(target_os = "solana"))]
-    fn verify_proof(&self) -> Result<(), ProofVerificationError> {
-        let (commitments, bit_lengths) = self.context.try_into()?;
-        let num_commitments = commitments.len();
-
-        if num_commitments > MAX_COMMITMENTS || num_commitments != bit_lengths.len() {
-            return Err(ProofVerificationError::IllegalCommitmentLength);
-        }
-
-        let mut transcript = self.context_data().new_transcript();
-        let proof: RangeProof = self.proof.try_into()?;
-
-        proof
-            .verify(commitments.iter().collect(), bit_lengths, &mut transcript)
-            .map_err(|e| e.into())
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use {
-        super::*,
-        crate::{
-            encryption::pedersen::Pedersen, range_proof::errors::RangeProofVerificationError,
-            zk_elgamal_proof_program::errors::ProofVerificationError,
-        },
-    };
-
-    #[test]
-    fn test_batched_range_proof_u128_instruction_correctness() {
-        let amount_1 = 65535_u64;
-        let amount_2 = 77_u64;
-        let amount_3 = 99_u64;
-        let amount_4 = 99_u64;
-        let amount_5 = 11_u64;
-        let amount_6 = 33_u64;
-        let amount_7 = 99_u64;
-        let amount_8 = 99_u64;
-
-        let (commitment_1, opening_1) = Pedersen::new(amount_1);
-        let (commitment_2, opening_2) = Pedersen::new(amount_2);
-        let (commitment_3, opening_3) = Pedersen::new(amount_3);
-        let (commitment_4, opening_4) = Pedersen::new(amount_4);
-        let (commitment_5, opening_5) = Pedersen::new(amount_5);
-        let (commitment_6, opening_6) = Pedersen::new(amount_6);
-        let (commitment_7, opening_7) = Pedersen::new(amount_7);
-        let (commitment_8, opening_8) = Pedersen::new(amount_8);
-
-        let proof_data = BatchedRangeProofU128Data::new(
-            vec![
-                &commitment_1,
-                &commitment_2,
-                &commitment_3,
-                &commitment_4,
-                &commitment_5,
-                &commitment_6,
-                &commitment_7,
-                &commitment_8,
-            ],
-            vec![
-                amount_1, amount_2, amount_3, amount_4, amount_5, amount_6, amount_7, amount_8,
-            ],
-            vec![16, 16, 16, 16, 16, 16, 16, 16],
-            vec![
-                &opening_1, &opening_2, &opening_3, &opening_4, &opening_5, &opening_6, &opening_7,
-                &opening_8,
-            ],
-        )
-        .unwrap();
-
-        assert!(proof_data.verify_proof().is_ok());
-
-        let amount_1 = 65536_u64; // not representable as a 16-bit number
-        let amount_2 = 77_u64;
-        let amount_3 = 99_u64;
-        let amount_4 = 99_u64;
-        let amount_5 = 11_u64;
-        let amount_6 = 33_u64;
-        let amount_7 = 99_u64;
-        let amount_8 = 99_u64;
-
-        let (commitment_1, opening_1) = Pedersen::new(amount_1);
-        let (commitment_2, opening_2) = Pedersen::new(amount_2);
-        let (commitment_3, opening_3) = Pedersen::new(amount_3);
-        let (commitment_4, opening_4) = Pedersen::new(amount_4);
-        let (commitment_5, opening_5) = Pedersen::new(amount_5);
-        let (commitment_6, opening_6) = Pedersen::new(amount_6);
-        let (commitment_7, opening_7) = Pedersen::new(amount_7);
-        let (commitment_8, opening_8) = Pedersen::new(amount_8);
-
-        let proof_data = BatchedRangeProofU128Data::new(
-            vec![
-                &commitment_1,
-                &commitment_2,
-                &commitment_3,
-                &commitment_4,
-                &commitment_5,
-                &commitment_6,
-                &commitment_7,
-                &commitment_8,
-            ],
-            vec![
-                amount_1, amount_2, amount_3, amount_4, amount_5, amount_6, amount_7, amount_8,
-            ],
-            vec![16, 16, 16, 16, 16, 16, 16, 16],
-            vec![
-                &opening_1, &opening_2, &opening_3, &opening_4, &opening_5, &opening_6, &opening_7,
-                &opening_8,
-            ],
-        )
-        .unwrap();
-
-        assert_eq!(
-            proof_data.verify_proof().unwrap_err(),
-            ProofVerificationError::RangeProof(RangeProofVerificationError::AlgebraicRelation),
-        );
-    }
-}

+ 0 - 213
zk-sdk/src/zk_elgamal_proof_program/proof_data/batched_range_proof/batched_range_proof_u256.rs

@@ -1,213 +0,0 @@
-//! The 256-bit batched range proof instruction.
-
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::pedersen::{PedersenCommitment, PedersenOpening},
-        range_proof::RangeProof,
-        zk_elgamal_proof_program::{
-            errors::{ProofGenerationError, ProofVerificationError},
-            proof_data::batched_range_proof::{MAX_COMMITMENTS, MAX_SINGLE_BIT_LENGTH},
-        },
-    },
-    std::convert::TryInto,
-};
-use {
-    crate::{
-        range_proof::pod::PodRangeProofU256,
-        zk_elgamal_proof_program::proof_data::{
-            batched_range_proof::BatchedRangeProofContext, ProofType, ZkProofData,
-        },
-    },
-    bytemuck_derive::{Pod, Zeroable},
-};
-
-#[cfg(not(target_os = "solana"))]
-const BATCHED_RANGE_PROOF_U256_BIT_LENGTH: usize = 256;
-
-/// The instruction data that is needed for the
-/// `ProofInstruction::BatchedRangeProofU256Data` instruction.
-///
-/// It includes the cryptographic proof as well as the context data information needed to verify
-/// the proof.
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct BatchedRangeProofU256Data {
-    /// The context data for a batched range proof
-    pub context: BatchedRangeProofContext,
-
-    /// The batched range proof
-    pub proof: PodRangeProofU256,
-}
-
-#[cfg(not(target_os = "solana"))]
-impl BatchedRangeProofU256Data {
-    pub fn new(
-        commitments: Vec<&PedersenCommitment>,
-        amounts: Vec<u64>,
-        bit_lengths: Vec<usize>,
-        openings: Vec<&PedersenOpening>,
-    ) -> Result<Self, ProofGenerationError> {
-        // Range proof on 256 bit length could potentially result in an unexpected behavior and
-        // therefore, restrict the bit length to be at most 128. This check is not needed for the
-        // `BatchedRangeProofU64` or `BatchedRangeProofU128`.
-        if bit_lengths
-            .iter()
-            .any(|length| *length > MAX_SINGLE_BIT_LENGTH)
-        {
-            return Err(ProofGenerationError::IllegalCommitmentLength);
-        }
-
-        // the sum of the bit lengths must be 256
-        let batched_bit_length = bit_lengths
-            .iter()
-            .try_fold(0_usize, |acc, &x| acc.checked_add(x))
-            .ok_or(ProofGenerationError::IllegalAmountBitLength)?;
-        if batched_bit_length != BATCHED_RANGE_PROOF_U256_BIT_LENGTH {
-            return Err(ProofGenerationError::IllegalAmountBitLength);
-        }
-
-        let context =
-            BatchedRangeProofContext::new(&commitments, &amounts, &bit_lengths, &openings)?;
-
-        let mut transcript = context.new_transcript();
-        let proof = RangeProof::new(amounts, bit_lengths, openings, &mut transcript)?
-            .try_into()
-            .map_err(|_| ProofGenerationError::ProofLength)?;
-
-        Ok(Self { context, proof })
-    }
-}
-
-impl ZkProofData<BatchedRangeProofContext> for BatchedRangeProofU256Data {
-    const PROOF_TYPE: ProofType = ProofType::BatchedRangeProofU256;
-
-    fn context_data(&self) -> &BatchedRangeProofContext {
-        &self.context
-    }
-
-    #[cfg(not(target_os = "solana"))]
-    fn verify_proof(&self) -> Result<(), ProofVerificationError> {
-        let (commitments, bit_lengths) = self.context.try_into()?;
-        let num_commitments = commitments.len();
-
-        if bit_lengths
-            .iter()
-            .any(|length| *length > MAX_SINGLE_BIT_LENGTH)
-        {
-            return Err(ProofVerificationError::IllegalCommitmentLength);
-        }
-
-        if num_commitments > MAX_COMMITMENTS || num_commitments != bit_lengths.len() {
-            return Err(ProofVerificationError::IllegalCommitmentLength);
-        }
-
-        let mut transcript = self.context_data().new_transcript();
-        let proof: RangeProof = self.proof.try_into()?;
-
-        proof
-            .verify(commitments.iter().collect(), bit_lengths, &mut transcript)
-            .map_err(|e| e.into())
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use {
-        super::*,
-        crate::{
-            encryption::pedersen::Pedersen, range_proof::errors::RangeProofVerificationError,
-            zk_elgamal_proof_program::errors::ProofVerificationError,
-        },
-    };
-
-    #[test]
-    fn test_batched_range_proof_256_instruction_correctness() {
-        let amount_1 = 4294967295_u64;
-        let amount_2 = 77_u64;
-        let amount_3 = 99_u64;
-        let amount_4 = 99_u64;
-        let amount_5 = 11_u64;
-        let amount_6 = 33_u64;
-        let amount_7 = 99_u64;
-        let amount_8 = 99_u64;
-
-        let (commitment_1, opening_1) = Pedersen::new(amount_1);
-        let (commitment_2, opening_2) = Pedersen::new(amount_2);
-        let (commitment_3, opening_3) = Pedersen::new(amount_3);
-        let (commitment_4, opening_4) = Pedersen::new(amount_4);
-        let (commitment_5, opening_5) = Pedersen::new(amount_5);
-        let (commitment_6, opening_6) = Pedersen::new(amount_6);
-        let (commitment_7, opening_7) = Pedersen::new(amount_7);
-        let (commitment_8, opening_8) = Pedersen::new(amount_8);
-
-        let proof_data = BatchedRangeProofU256Data::new(
-            vec![
-                &commitment_1,
-                &commitment_2,
-                &commitment_3,
-                &commitment_4,
-                &commitment_5,
-                &commitment_6,
-                &commitment_7,
-                &commitment_8,
-            ],
-            vec![
-                amount_1, amount_2, amount_3, amount_4, amount_5, amount_6, amount_7, amount_8,
-            ],
-            vec![32, 32, 32, 32, 32, 32, 32, 32],
-            vec![
-                &opening_1, &opening_2, &opening_3, &opening_4, &opening_5, &opening_6, &opening_7,
-                &opening_8,
-            ],
-        )
-        .unwrap();
-
-        assert!(proof_data.verify_proof().is_ok());
-
-        let amount_1 = 4294967296_u64; // not representable as a 32-bit number
-        let amount_2 = 77_u64;
-        let amount_3 = 99_u64;
-        let amount_4 = 99_u64;
-        let amount_5 = 11_u64;
-        let amount_6 = 33_u64;
-        let amount_7 = 99_u64;
-        let amount_8 = 99_u64;
-
-        let (commitment_1, opening_1) = Pedersen::new(amount_1);
-        let (commitment_2, opening_2) = Pedersen::new(amount_2);
-        let (commitment_3, opening_3) = Pedersen::new(amount_3);
-        let (commitment_4, opening_4) = Pedersen::new(amount_4);
-        let (commitment_5, opening_5) = Pedersen::new(amount_5);
-        let (commitment_6, opening_6) = Pedersen::new(amount_6);
-        let (commitment_7, opening_7) = Pedersen::new(amount_7);
-        let (commitment_8, opening_8) = Pedersen::new(amount_8);
-
-        let proof_data = BatchedRangeProofU256Data::new(
-            vec![
-                &commitment_1,
-                &commitment_2,
-                &commitment_3,
-                &commitment_4,
-                &commitment_5,
-                &commitment_6,
-                &commitment_7,
-                &commitment_8,
-            ],
-            vec![
-                amount_1, amount_2, amount_3, amount_4, amount_5, amount_6, amount_7, amount_8,
-            ],
-            vec![32, 32, 32, 32, 32, 32, 32, 32],
-            vec![
-                &opening_1, &opening_2, &opening_3, &opening_4, &opening_5, &opening_6, &opening_7,
-                &opening_8,
-            ],
-        )
-        .unwrap();
-
-        assert_eq!(
-            proof_data.verify_proof().unwrap_err(),
-            ProofVerificationError::RangeProof(RangeProofVerificationError::AlgebraicRelation),
-        );
-    }
-}

+ 0 - 198
zk-sdk/src/zk_elgamal_proof_program/proof_data/batched_range_proof/batched_range_proof_u64.rs

@@ -1,198 +0,0 @@
-//! The 64-bit batched range proof instruction.
-
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::pedersen::{PedersenCommitment, PedersenOpening},
-        range_proof::RangeProof,
-        zk_elgamal_proof_program::{
-            errors::{ProofGenerationError, ProofVerificationError},
-            proof_data::batched_range_proof::MAX_COMMITMENTS,
-        },
-    },
-    std::convert::TryInto,
-};
-use {
-    crate::{
-        range_proof::pod::PodRangeProofU64,
-        zk_elgamal_proof_program::proof_data::{
-            batched_range_proof::BatchedRangeProofContext, ProofType, ZkProofData,
-        },
-    },
-    bytemuck_derive::{Pod, Zeroable},
-};
-
-/// The instruction data that is needed for the
-/// `ProofInstruction::VerifyBatchedRangeProofU64` instruction.
-///
-/// It includes the cryptographic proof as well as the context data information needed to verify
-/// the proof.
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct BatchedRangeProofU64Data {
-    /// The context data for a batched range proof
-    pub context: BatchedRangeProofContext,
-
-    /// The batched range proof
-    pub proof: PodRangeProofU64,
-}
-
-#[cfg(not(target_os = "solana"))]
-impl BatchedRangeProofU64Data {
-    pub fn new(
-        commitments: Vec<&PedersenCommitment>,
-        amounts: Vec<u64>,
-        bit_lengths: Vec<usize>,
-        openings: Vec<&PedersenOpening>,
-    ) -> Result<Self, ProofGenerationError> {
-        // the sum of the bit lengths must be 64
-        let batched_bit_length = bit_lengths
-            .iter()
-            .try_fold(0_usize, |acc, &x| acc.checked_add(x))
-            .ok_or(ProofGenerationError::IllegalAmountBitLength)?;
-
-        // `u64::BITS` is 64, which fits in a single byte and should not overflow to `usize` for an
-        // overwhelming number of platforms. However, to be extra cautious, use `try_from` and
-        // `unwrap` here. A simple case `u64::BITS as usize` can silently overflow.
-        let expected_bit_length = usize::try_from(u64::BITS).unwrap();
-        if batched_bit_length != expected_bit_length {
-            return Err(ProofGenerationError::IllegalAmountBitLength);
-        }
-
-        let context =
-            BatchedRangeProofContext::new(&commitments, &amounts, &bit_lengths, &openings)?;
-
-        let mut transcript = context.new_transcript();
-        let proof = RangeProof::new(amounts, bit_lengths, openings, &mut transcript)?
-            .try_into()
-            .map_err(|_| ProofGenerationError::ProofLength)?;
-
-        Ok(Self { context, proof })
-    }
-}
-
-impl ZkProofData<BatchedRangeProofContext> for BatchedRangeProofU64Data {
-    const PROOF_TYPE: ProofType = ProofType::BatchedRangeProofU64;
-
-    fn context_data(&self) -> &BatchedRangeProofContext {
-        &self.context
-    }
-
-    #[cfg(not(target_os = "solana"))]
-    fn verify_proof(&self) -> Result<(), ProofVerificationError> {
-        let (commitments, bit_lengths) = self.context.try_into()?;
-        let num_commitments = commitments.len();
-
-        if num_commitments > MAX_COMMITMENTS || num_commitments != bit_lengths.len() {
-            return Err(ProofVerificationError::IllegalCommitmentLength);
-        }
-
-        let mut transcript = self.context_data().new_transcript();
-        let proof: RangeProof = self.proof.try_into()?;
-
-        proof
-            .verify(commitments.iter().collect(), bit_lengths, &mut transcript)
-            .map_err(|e| e.into())
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use {
-        super::*,
-        crate::{
-            encryption::pedersen::Pedersen, range_proof::errors::RangeProofVerificationError,
-            zk_elgamal_proof_program::errors::ProofVerificationError,
-        },
-    };
-
-    #[test]
-    fn test_batched_range_proof_u64_instruction_correctness() {
-        let amount_1 = 255_u64;
-        let amount_2 = 77_u64;
-        let amount_3 = 99_u64;
-        let amount_4 = 99_u64;
-        let amount_5 = 11_u64;
-        let amount_6 = 33_u64;
-        let amount_7 = 99_u64;
-        let amount_8 = 99_u64;
-
-        let (commitment_1, opening_1) = Pedersen::new(amount_1);
-        let (commitment_2, opening_2) = Pedersen::new(amount_2);
-        let (commitment_3, opening_3) = Pedersen::new(amount_3);
-        let (commitment_4, opening_4) = Pedersen::new(amount_4);
-        let (commitment_5, opening_5) = Pedersen::new(amount_5);
-        let (commitment_6, opening_6) = Pedersen::new(amount_6);
-        let (commitment_7, opening_7) = Pedersen::new(amount_7);
-        let (commitment_8, opening_8) = Pedersen::new(amount_8);
-
-        let proof_data = BatchedRangeProofU64Data::new(
-            vec![
-                &commitment_1,
-                &commitment_2,
-                &commitment_3,
-                &commitment_4,
-                &commitment_5,
-                &commitment_6,
-                &commitment_7,
-                &commitment_8,
-            ],
-            vec![
-                amount_1, amount_2, amount_3, amount_4, amount_5, amount_6, amount_7, amount_8,
-            ],
-            vec![8, 8, 8, 8, 8, 8, 8, 8],
-            vec![
-                &opening_1, &opening_2, &opening_3, &opening_4, &opening_5, &opening_6, &opening_7,
-                &opening_8,
-            ],
-        )
-        .unwrap();
-
-        assert!(proof_data.verify_proof().is_ok());
-
-        let amount_1 = 256_u64; // not representable as an 8-bit number
-        let amount_2 = 77_u64;
-        let amount_3 = 99_u64;
-        let amount_4 = 99_u64;
-        let amount_5 = 11_u64;
-        let amount_6 = 33_u64;
-        let amount_7 = 99_u64;
-        let amount_8 = 99_u64;
-
-        let (commitment_1, opening_1) = Pedersen::new(amount_1);
-        let (commitment_2, opening_2) = Pedersen::new(amount_2);
-        let (commitment_3, opening_3) = Pedersen::new(amount_3);
-        let (commitment_4, opening_4) = Pedersen::new(amount_4);
-        let (commitment_5, opening_5) = Pedersen::new(amount_5);
-        let (commitment_6, opening_6) = Pedersen::new(amount_6);
-        let (commitment_7, opening_7) = Pedersen::new(amount_7);
-        let (commitment_8, opening_8) = Pedersen::new(amount_8);
-
-        let proof_data = BatchedRangeProofU64Data::new(
-            vec![
-                &commitment_1,
-                &commitment_2,
-                &commitment_3,
-                &commitment_4,
-                &commitment_5,
-                &commitment_6,
-                &commitment_7,
-                &commitment_8,
-            ],
-            vec![
-                amount_1, amount_2, amount_3, amount_4, amount_5, amount_6, amount_7, amount_8,
-            ],
-            vec![8, 8, 8, 8, 8, 8, 8, 8],
-            vec![
-                &opening_1, &opening_2, &opening_3, &opening_4, &opening_5, &opening_6, &opening_7,
-                &opening_8,
-            ],
-        )
-        .unwrap();
-
-        assert_eq!(
-            proof_data.verify_proof().unwrap_err(),
-            ProofVerificationError::RangeProof(RangeProofVerificationError::AlgebraicRelation),
-        );
-    }
-}

+ 0 - 126
zk-sdk/src/zk_elgamal_proof_program/proof_data/batched_range_proof/mod.rs

@@ -1,126 +0,0 @@
-//! The batched range proof instructions.
-//!
-//! A batched range proof is defined with respect to a sequence of commitments `[C_1, ..., C_N]`
-//! and bit-lengths `[n_1, ..., n_N]`. It certifies that each `C_i` is a commitment to a number of
-//! bit-length `n_i`.
-//!
-//! There are three batched range proof instructions: `VerifyBatchedRangeProof64`,
-//! `VerifyBatchedRangeProof128`, and `VerifyBatchedRangeProof256`. The value `N` in
-//! `VerifyBatchedRangeProof{N}` specifies the sum of the bit-lengths that the proof is certifying
-//! for a sequence of commitments.
-//!
-//! For example to generate a batched range proof on a sequence of commitments `[C_1, C_2, C_3]` on
-//! a sequence of bit-lengths `[32, 32, 64]`, one must use `VerifyBatchedRangeProof128` as 128 is
-//! the sum of all bit-lengths.
-//!
-//! The maximum number of commitments is fixed at 8. Each bit-length in `[n_1, ..., n_N]` must be a
-//! power-of-two positive integer less than or equal to 128.
-
-pub mod batched_range_proof_u128;
-pub mod batched_range_proof_u256;
-pub mod batched_range_proof_u64;
-
-use crate::encryption::pod::pedersen::PodPedersenCommitment;
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::pedersen::{PedersenCommitment, PedersenOpening},
-        zk_elgamal_proof_program::errors::{ProofGenerationError, ProofVerificationError},
-    },
-    bytemuck::{bytes_of, Zeroable},
-    curve25519_dalek::traits::IsIdentity,
-    merlin::Transcript,
-    std::convert::TryInto,
-};
-
-const MAX_COMMITMENTS: usize = 8;
-
-/// A bit length in a batched range proof must be at most 128.
-///
-/// A 256-bit range proof on a single Pedersen commitment is meaningless and hence enforce an upper
-/// bound as the largest power-of-two number less than 256.
-#[cfg(not(target_os = "solana"))]
-const MAX_SINGLE_BIT_LENGTH: usize = 128;
-
-/// The context data needed to verify a range-proof for a Pedersen committed value.
-///
-/// The context data is shared by all `VerifyBatchedRangeProof{N}` instructions.
-#[derive(Clone, Copy, bytemuck_derive::Pod, bytemuck_derive::Zeroable)]
-#[repr(C)]
-pub struct BatchedRangeProofContext {
-    pub commitments: [PodPedersenCommitment; MAX_COMMITMENTS],
-    pub bit_lengths: [u8; MAX_COMMITMENTS],
-}
-
-#[allow(non_snake_case)]
-#[cfg(not(target_os = "solana"))]
-impl BatchedRangeProofContext {
-    fn new_transcript(&self) -> Transcript {
-        let mut transcript = Transcript::new(b"batched-range-proof-instruction");
-        transcript.append_message(b"commitments", bytes_of(&self.commitments));
-        transcript.append_message(b"bit-lengths", bytes_of(&self.bit_lengths));
-        transcript
-    }
-
-    fn new(
-        commitments: &[&PedersenCommitment],
-        amounts: &[u64],
-        bit_lengths: &[usize],
-        openings: &[&PedersenOpening],
-    ) -> Result<Self, ProofGenerationError> {
-        // the number of commitments is capped at 8
-        let num_commitments = commitments.len();
-        if num_commitments > MAX_COMMITMENTS
-            || num_commitments != amounts.len()
-            || num_commitments != bit_lengths.len()
-            || num_commitments != openings.len()
-        {
-            return Err(ProofGenerationError::IllegalCommitmentLength);
-        }
-
-        let mut pod_commitments = [PodPedersenCommitment::zeroed(); MAX_COMMITMENTS];
-        for (i, commitment) in commitments.iter().enumerate() {
-            // all-zero commitment is invalid
-            if commitment.get_point().is_identity() {
-                return Err(ProofGenerationError::InvalidCommitment);
-            }
-            pod_commitments[i] = PodPedersenCommitment(commitment.to_bytes());
-        }
-
-        let mut pod_bit_lengths = [0; MAX_COMMITMENTS];
-        for (i, bit_length) in bit_lengths.iter().enumerate() {
-            pod_bit_lengths[i] = (*bit_length)
-                .try_into()
-                .map_err(|_| ProofGenerationError::IllegalAmountBitLength)?;
-        }
-
-        Ok(BatchedRangeProofContext {
-            commitments: pod_commitments,
-            bit_lengths: pod_bit_lengths,
-        })
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl TryInto<(Vec<PedersenCommitment>, Vec<usize>)> for BatchedRangeProofContext {
-    type Error = ProofVerificationError;
-
-    fn try_into(self) -> Result<(Vec<PedersenCommitment>, Vec<usize>), Self::Error> {
-        let commitments = self
-            .commitments
-            .into_iter()
-            .take_while(|commitment| *commitment != PodPedersenCommitment::zeroed())
-            .map(|commitment| commitment.try_into())
-            .collect::<Result<Vec<PedersenCommitment>, _>>()
-            .map_err(|_| ProofVerificationError::ProofContext)?;
-
-        let bit_lengths: Vec<_> = self
-            .bit_lengths
-            .into_iter()
-            .take(commitments.len())
-            .map(|bit_length| bit_length as usize)
-            .collect();
-
-        Ok((commitments, bit_lengths))
-    }
-}

+ 0 - 222
zk-sdk/src/zk_elgamal_proof_program/proof_data/ciphertext_ciphertext_equality.rs

@@ -1,222 +0,0 @@
-//! The ciphertext-ciphertext equality proof instruction.
-//!
-//! A ciphertext-ciphertext equality proof is defined with respect to two twisted ElGamal
-//! ciphertexts. The proof certifies that the two ciphertexts encrypt the same message. To generate
-//! the proof, a prover must provide the decryption key for the first ciphertext and the randomness
-//! used to generate the second ciphertext.
-
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-use {
-    crate::{
-        encryption::pod::elgamal::{PodElGamalCiphertext, PodElGamalPubkey},
-        sigma_proofs::pod::PodCiphertextCiphertextEqualityProof,
-        zk_elgamal_proof_program::proof_data::{pod::impl_wasm_to_bytes, ProofType, ZkProofData},
-    },
-    bytemuck_derive::{Pod, Zeroable},
-};
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::{
-            elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey},
-            pedersen::PedersenOpening,
-        },
-        sigma_proofs::ciphertext_ciphertext_equality::CiphertextCiphertextEqualityProof,
-        zk_elgamal_proof_program::{
-            errors::{ProofGenerationError, ProofVerificationError},
-            proof_data::errors::ProofDataError,
-        },
-    },
-    bytemuck::bytes_of,
-    merlin::Transcript,
-    std::convert::TryInto,
-};
-
-/// The instruction data that is needed for the
-/// `ProofInstruction::VerifyCiphertextCiphertextEquality` instruction.
-///
-/// It includes the cryptographic proof as well as the context data information needed to verify
-/// the proof.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct CiphertextCiphertextEqualityProofData {
-    pub context: CiphertextCiphertextEqualityProofContext,
-
-    pub proof: PodCiphertextCiphertextEqualityProof,
-}
-
-/// The context data needed to verify a ciphertext-ciphertext equality proof.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct CiphertextCiphertextEqualityProofContext {
-    pub first_pubkey: PodElGamalPubkey, // 32 bytes
-
-    pub second_pubkey: PodElGamalPubkey, // 32 bytes
-
-    pub first_ciphertext: PodElGamalCiphertext, // 64 bytes
-
-    pub second_ciphertext: PodElGamalCiphertext, // 64 bytes
-}
-
-#[cfg(not(target_os = "solana"))]
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-impl CiphertextCiphertextEqualityProofData {
-    pub fn new(
-        first_keypair: &ElGamalKeypair,
-        second_pubkey: &ElGamalPubkey,
-        first_ciphertext: &ElGamalCiphertext,
-        second_ciphertext: &ElGamalCiphertext,
-        second_opening: &PedersenOpening,
-        amount: u64,
-    ) -> Result<Self, ProofGenerationError> {
-        let pod_first_pubkey = PodElGamalPubkey(first_keypair.pubkey().into());
-        let pod_second_pubkey = PodElGamalPubkey(second_pubkey.into());
-        let pod_first_ciphertext = PodElGamalCiphertext(first_ciphertext.to_bytes());
-        let pod_second_ciphertext = PodElGamalCiphertext(second_ciphertext.to_bytes());
-
-        let context = CiphertextCiphertextEqualityProofContext {
-            first_pubkey: pod_first_pubkey,
-            second_pubkey: pod_second_pubkey,
-            first_ciphertext: pod_first_ciphertext,
-            second_ciphertext: pod_second_ciphertext,
-        };
-
-        let mut transcript = context.new_transcript();
-
-        let proof = CiphertextCiphertextEqualityProof::new(
-            first_keypair,
-            second_pubkey,
-            first_ciphertext,
-            second_opening,
-            amount,
-            &mut transcript,
-        )
-        .into();
-
-        Ok(Self { context, proof })
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = CiphertextCiphertextEqualityProofData);
-
-impl ZkProofData<CiphertextCiphertextEqualityProofContext>
-    for CiphertextCiphertextEqualityProofData
-{
-    const PROOF_TYPE: ProofType = ProofType::CiphertextCiphertextEquality;
-
-    fn context_data(&self) -> &CiphertextCiphertextEqualityProofContext {
-        &self.context
-    }
-
-    #[cfg(not(target_os = "solana"))]
-    fn verify_proof(&self) -> Result<(), ProofVerificationError> {
-        let mut transcript = self.context.new_transcript();
-
-        let first_pubkey = self.context.first_pubkey.try_into()?;
-        let second_pubkey = self.context.second_pubkey.try_into()?;
-        let first_ciphertext = self.context.first_ciphertext.try_into()?;
-        let second_ciphertext = self.context.second_ciphertext.try_into()?;
-        let proof: CiphertextCiphertextEqualityProof = self.proof.try_into()?;
-
-        proof
-            .verify(
-                &first_pubkey,
-                &second_pubkey,
-                &first_ciphertext,
-                &second_ciphertext,
-                &mut transcript,
-            )
-            .map_err(|e| e.into())
-    }
-}
-
-#[allow(non_snake_case)]
-#[cfg(not(target_os = "solana"))]
-impl CiphertextCiphertextEqualityProofContext {
-    fn new_transcript(&self) -> Transcript {
-        let mut transcript = Transcript::new(b"ciphertext-ciphertext-equality-instruction");
-
-        transcript.append_message(b"first-pubkey", bytes_of(&self.first_pubkey));
-        transcript.append_message(b"second-pubkey", bytes_of(&self.second_pubkey));
-        transcript.append_message(b"first-ciphertext", bytes_of(&self.first_ciphertext));
-        transcript.append_message(b"second-ciphertext", bytes_of(&self.second_ciphertext));
-
-        transcript
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = CiphertextCiphertextEqualityProofContext);
-
-#[cfg(test)]
-mod test {
-    use super::*;
-
-    #[test]
-    fn test_ciphertext_ciphertext_instruction_correctness() {
-        let first_keypair = ElGamalKeypair::new_rand();
-        let second_keypair = ElGamalKeypair::new_rand();
-
-        let amount: u64 = 0;
-        let first_ciphertext = first_keypair.pubkey().encrypt(amount);
-
-        let second_opening = PedersenOpening::new_rand();
-        let second_ciphertext = second_keypair
-            .pubkey()
-            .encrypt_with(amount, &second_opening);
-
-        let proof_data = CiphertextCiphertextEqualityProofData::new(
-            &first_keypair,
-            second_keypair.pubkey(),
-            &first_ciphertext,
-            &second_ciphertext,
-            &second_opening,
-            amount,
-        )
-        .unwrap();
-
-        assert!(proof_data.verify_proof().is_ok());
-
-        let amount: u64 = 55;
-        let first_ciphertext = first_keypair.pubkey().encrypt(amount);
-
-        let second_opening = PedersenOpening::new_rand();
-        let second_ciphertext = second_keypair
-            .pubkey()
-            .encrypt_with(amount, &second_opening);
-
-        let proof_data = CiphertextCiphertextEqualityProofData::new(
-            &first_keypair,
-            second_keypair.pubkey(),
-            &first_ciphertext,
-            &second_ciphertext,
-            &second_opening,
-            amount,
-        )
-        .unwrap();
-
-        assert!(proof_data.verify_proof().is_ok());
-
-        let amount = u64::MAX;
-        let first_ciphertext = first_keypair.pubkey().encrypt(amount);
-
-        let second_opening = PedersenOpening::new_rand();
-        let second_ciphertext = second_keypair
-            .pubkey()
-            .encrypt_with(amount, &second_opening);
-
-        let proof_data = CiphertextCiphertextEqualityProofData::new(
-            &first_keypair,
-            second_keypair.pubkey(),
-            &first_ciphertext,
-            &second_ciphertext,
-            &second_opening,
-            amount,
-        )
-        .unwrap();
-
-        assert!(proof_data.verify_proof().is_ok());
-    }
-}

+ 0 - 161
zk-sdk/src/zk_elgamal_proof_program/proof_data/ciphertext_commitment_equality.rs

@@ -1,161 +0,0 @@
-//! The ciphertext-commitment equality proof instruction.
-//!
-//! A ciphertext-commitment equality proof is defined with respect to a twisted ElGamal ciphertext
-//! and a Pedersen commitment. The proof certifies that a given ciphertext and a commitment pair
-//! encrypts/encodes the same message. To generate the proof, a prover must provide the decryption
-//! key for the first ciphertext and the Pedersen opening for the commitment.
-
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-use {
-    crate::{
-        encryption::pod::{
-            elgamal::{PodElGamalCiphertext, PodElGamalPubkey},
-            pedersen::PodPedersenCommitment,
-        },
-        sigma_proofs::pod::PodCiphertextCommitmentEqualityProof,
-        zk_elgamal_proof_program::proof_data::{pod::impl_wasm_to_bytes, ProofType, ZkProofData},
-    },
-    bytemuck_derive::{Pod, Zeroable},
-};
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::{
-            elgamal::{ElGamalCiphertext, ElGamalKeypair},
-            pedersen::{PedersenCommitment, PedersenOpening},
-        },
-        sigma_proofs::ciphertext_commitment_equality::CiphertextCommitmentEqualityProof,
-        zk_elgamal_proof_program::{
-            errors::{ProofGenerationError, ProofVerificationError},
-            proof_data::errors::ProofDataError,
-        },
-    },
-    bytemuck::bytes_of,
-    merlin::Transcript,
-    std::convert::TryInto,
-};
-/// The instruction data that is needed for the
-/// `ProofInstruction::VerifyCiphertextCommitmentEquality` instruction.
-///
-/// It includes the cryptographic proof as well as the context data information needed to verify
-/// the proof.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct CiphertextCommitmentEqualityProofData {
-    pub context: CiphertextCommitmentEqualityProofContext,
-    pub proof: PodCiphertextCommitmentEqualityProof,
-}
-
-/// The context data needed to verify a ciphertext-commitment equality proof.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct CiphertextCommitmentEqualityProofContext {
-    /// The ElGamal pubkey
-    pub pubkey: PodElGamalPubkey, // 32 bytes
-
-    /// The ciphertext encrypted under the ElGamal pubkey
-    pub ciphertext: PodElGamalCiphertext, // 64 bytes
-
-    /// The Pedersen commitment
-    pub commitment: PodPedersenCommitment, // 32 bytes
-}
-
-#[cfg(not(target_os = "solana"))]
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-impl CiphertextCommitmentEqualityProofData {
-    pub fn new(
-        keypair: &ElGamalKeypair,
-        ciphertext: &ElGamalCiphertext,
-        commitment: &PedersenCommitment,
-        opening: &PedersenOpening,
-        amount: u64,
-    ) -> Result<Self, ProofGenerationError> {
-        let context = CiphertextCommitmentEqualityProofContext {
-            pubkey: PodElGamalPubkey(keypair.pubkey().into()),
-            ciphertext: PodElGamalCiphertext(ciphertext.to_bytes()),
-            commitment: PodPedersenCommitment(commitment.to_bytes()),
-        };
-        let mut transcript = context.new_transcript();
-        let proof = CiphertextCommitmentEqualityProof::new(
-            keypair,
-            ciphertext,
-            opening,
-            amount,
-            &mut transcript,
-        );
-        Ok(CiphertextCommitmentEqualityProofData {
-            context,
-            proof: proof.into(),
-        })
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = CiphertextCommitmentEqualityProofData);
-
-impl ZkProofData<CiphertextCommitmentEqualityProofContext>
-    for CiphertextCommitmentEqualityProofData
-{
-    const PROOF_TYPE: ProofType = ProofType::CiphertextCommitmentEquality;
-
-    fn context_data(&self) -> &CiphertextCommitmentEqualityProofContext {
-        &self.context
-    }
-
-    #[cfg(not(target_os = "solana"))]
-    fn verify_proof(&self) -> Result<(), ProofVerificationError> {
-        let mut transcript = self.context.new_transcript();
-
-        let pubkey = self.context.pubkey.try_into()?;
-        let ciphertext = self.context.ciphertext.try_into()?;
-        let commitment = self.context.commitment.try_into()?;
-        let proof: CiphertextCommitmentEqualityProof = self.proof.try_into()?;
-
-        proof
-            .verify(&pubkey, &ciphertext, &commitment, &mut transcript)
-            .map_err(|e| e.into())
-    }
-}
-
-#[allow(non_snake_case)]
-#[cfg(not(target_os = "solana"))]
-impl CiphertextCommitmentEqualityProofContext {
-    fn new_transcript(&self) -> Transcript {
-        let mut transcript = Transcript::new(b"ciphertext-commitment-equality-instruction");
-        transcript.append_message(b"pubkey", bytes_of(&self.pubkey));
-        transcript.append_message(b"ciphertext", bytes_of(&self.ciphertext));
-        transcript.append_message(b"commitment", bytes_of(&self.commitment));
-        transcript
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = CiphertextCommitmentEqualityProofContext);
-
-#[cfg(test)]
-mod test {
-    use {
-        super::*,
-        crate::encryption::{elgamal::ElGamalKeypair, pedersen::Pedersen},
-    };
-
-    #[test]
-    fn test_ctxt_comm_equality_proof_correctness() {
-        let keypair = ElGamalKeypair::new_rand();
-        let amount: u64 = 55;
-        let ciphertext = keypair.pubkey().encrypt(amount);
-        let (commitment, opening) = Pedersen::new(amount);
-
-        let proof_data = CiphertextCommitmentEqualityProofData::new(
-            &keypair,
-            &ciphertext,
-            &commitment,
-            &opening,
-            amount,
-        )
-        .unwrap();
-
-        assert!(proof_data.verify_proof().is_ok());
-    }
-}

+ 0 - 26
zk-sdk/src/zk_elgamal_proof_program/proof_data/errors.rs

@@ -1,26 +0,0 @@
-use thiserror::Error;
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-
-#[derive(Error, Clone, Debug, Eq, PartialEq)]
-pub enum ProofDataError {
-    #[error("decryption error")]
-    Decryption,
-    #[error("missing ciphertext")]
-    MissingCiphertext,
-    #[error("illegal amount bit length")]
-    IllegalAmountBitLength,
-    #[error("arithmetic overflow")]
-    Overflow,
-    #[error("invalid proof type")]
-    InvalidProofType,
-    #[error("deserialization failed")]
-    Deserialization,
-}
-
-#[cfg(target_arch = "wasm32")]
-impl From<ProofDataError> for JsValue {
-    fn from(err: ProofDataError) -> Self {
-        js_sys::Error::new(&err.to_string()).into()
-    }
-}

+ 0 - 221
zk-sdk/src/zk_elgamal_proof_program/proof_data/grouped_ciphertext_validity/handles_2.rs

@@ -1,221 +0,0 @@
-//! The grouped-ciphertext validity proof instruction.
-//!
-//! A grouped-ciphertext validity proof certifies that a grouped ElGamal ciphertext is
-//! well-defined, i.e. the ciphertext can be decrypted by private keys associated with its
-//! decryption handles. To generate the proof, a prover must provide the Pedersen opening
-//! associated with the grouped ciphertext's commitment.
-
-#[cfg(target_arch = "wasm32")]
-use {
-    crate::encryption::grouped_elgamal::GroupedElGamalCiphertext2Handles, wasm_bindgen::prelude::*,
-};
-use {
-    crate::{
-        encryption::pod::{
-            elgamal::PodElGamalPubkey, grouped_elgamal::PodGroupedElGamalCiphertext2Handles,
-        },
-        sigma_proofs::pod::PodGroupedCiphertext2HandlesValidityProof,
-        zk_elgamal_proof_program::proof_data::{pod::impl_wasm_to_bytes, ProofType, ZkProofData},
-    },
-    bytemuck_derive::{Pod, Zeroable},
-};
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::{
-            elgamal::ElGamalPubkey, grouped_elgamal::GroupedElGamalCiphertext,
-            pedersen::PedersenOpening,
-        },
-        sigma_proofs::grouped_ciphertext_validity::GroupedCiphertext2HandlesValidityProof,
-        zk_elgamal_proof_program::{
-            errors::{ProofGenerationError, ProofVerificationError},
-            proof_data::errors::ProofDataError,
-        },
-    },
-    bytemuck::bytes_of,
-    merlin::Transcript,
-};
-
-/// The instruction data that is needed for the `ProofInstruction::VerifyGroupedCiphertextValidity`
-/// instruction.
-///
-/// It includes the cryptographic proof as well as the context data information needed to verify
-/// the proof.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct GroupedCiphertext2HandlesValidityProofData {
-    pub context: GroupedCiphertext2HandlesValidityProofContext,
-
-    pub proof: PodGroupedCiphertext2HandlesValidityProof,
-}
-
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct GroupedCiphertext2HandlesValidityProofContext {
-    pub first_pubkey: PodElGamalPubkey, // 32 bytes
-
-    pub second_pubkey: PodElGamalPubkey, // 32 bytes
-
-    pub grouped_ciphertext: PodGroupedElGamalCiphertext2Handles, // 96 bytes
-}
-
-#[cfg(not(target_os = "solana"))]
-#[cfg(not(target_arch = "wasm32"))]
-impl GroupedCiphertext2HandlesValidityProofData {
-    pub fn new(
-        first_pubkey: &ElGamalPubkey,
-        second_pubkey: &ElGamalPubkey,
-        grouped_ciphertext: &GroupedElGamalCiphertext<2>,
-        amount: u64,
-        opening: &PedersenOpening,
-    ) -> Result<Self, ProofGenerationError> {
-        let pod_first_pubkey = PodElGamalPubkey(first_pubkey.into());
-        let pod_second_pubkey = PodElGamalPubkey(second_pubkey.into());
-        let pod_grouped_ciphertext = (*grouped_ciphertext).into();
-
-        let context = GroupedCiphertext2HandlesValidityProofContext {
-            first_pubkey: pod_first_pubkey,
-            second_pubkey: pod_second_pubkey,
-            grouped_ciphertext: pod_grouped_ciphertext,
-        };
-
-        let mut transcript = context.new_transcript();
-
-        let proof = GroupedCiphertext2HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            amount,
-            opening,
-            &mut transcript,
-        )
-        .into();
-
-        Ok(Self { context, proof })
-    }
-}
-
-// Define a separate constructor for `wasm32` target since `wasm_bindgen` does
-// not yet support parameters with generic constants (i.e.
-// `GroupedElGamalCiphertext<2>`).
-#[cfg(target_arch = "wasm32")]
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-impl GroupedCiphertext2HandlesValidityProofData {
-    pub fn new(
-        first_pubkey: &ElGamalPubkey,
-        second_pubkey: &ElGamalPubkey,
-        grouped_ciphertext: &GroupedElGamalCiphertext2Handles,
-        amount: u64,
-        opening: &PedersenOpening,
-    ) -> Result<Self, ProofGenerationError> {
-        let pod_first_pubkey = PodElGamalPubkey(first_pubkey.into());
-        let pod_second_pubkey = PodElGamalPubkey(second_pubkey.into());
-        let pod_grouped_ciphertext = grouped_ciphertext.0.into();
-
-        let context = GroupedCiphertext2HandlesValidityProofContext {
-            first_pubkey: pod_first_pubkey,
-            second_pubkey: pod_second_pubkey,
-            grouped_ciphertext: pod_grouped_ciphertext,
-        };
-
-        let mut transcript = context.new_transcript();
-
-        let proof = GroupedCiphertext2HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            amount,
-            opening,
-            &mut transcript,
-        )
-        .into();
-
-        Ok(Self { context, proof })
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = GroupedCiphertext2HandlesValidityProofData);
-
-impl ZkProofData<GroupedCiphertext2HandlesValidityProofContext>
-    for GroupedCiphertext2HandlesValidityProofData
-{
-    const PROOF_TYPE: ProofType = ProofType::GroupedCiphertext2HandlesValidity;
-
-    fn context_data(&self) -> &GroupedCiphertext2HandlesValidityProofContext {
-        &self.context
-    }
-
-    #[cfg(not(target_os = "solana"))]
-    fn verify_proof(&self) -> Result<(), ProofVerificationError> {
-        let mut transcript = self.context.new_transcript();
-
-        let first_pubkey = self.context.first_pubkey.try_into()?;
-        let second_pubkey = self.context.second_pubkey.try_into()?;
-        let grouped_ciphertext: GroupedElGamalCiphertext<2> =
-            self.context.grouped_ciphertext.try_into()?;
-
-        let first_handle = grouped_ciphertext.handles.first().unwrap();
-        let second_handle = grouped_ciphertext.handles.get(1).unwrap();
-
-        let proof: GroupedCiphertext2HandlesValidityProof = self.proof.try_into()?;
-
-        proof
-            .verify(
-                &grouped_ciphertext.commitment,
-                &first_pubkey,
-                &second_pubkey,
-                first_handle,
-                second_handle,
-                &mut transcript,
-            )
-            .map_err(|e| e.into())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl GroupedCiphertext2HandlesValidityProofContext {
-    fn new_transcript(&self) -> Transcript {
-        let mut transcript = Transcript::new(b"grouped-ciphertext-validity-2-handles-instruction");
-
-        transcript.append_message(b"first-pubkey", bytes_of(&self.first_pubkey));
-        transcript.append_message(b"second-pubkey", bytes_of(&self.second_pubkey));
-        transcript.append_message(b"grouped-ciphertext", bytes_of(&self.grouped_ciphertext));
-
-        transcript
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = GroupedCiphertext2HandlesValidityProofContext);
-
-#[cfg(test)]
-mod test {
-    use {
-        super::*,
-        crate::encryption::{elgamal::ElGamalKeypair, grouped_elgamal::GroupedElGamal},
-    };
-
-    #[test]
-    fn test_ciphertext_validity_proof_instruction_correctness() {
-        let first_keypair = ElGamalKeypair::new_rand();
-        let first_pubkey = first_keypair.pubkey();
-
-        let second_keypair = ElGamalKeypair::new_rand();
-        let second_pubkey = second_keypair.pubkey();
-
-        let amount: u64 = 55;
-        let opening = PedersenOpening::new_rand();
-        let grouped_ciphertext =
-            GroupedElGamal::encrypt_with([first_pubkey, second_pubkey], amount, &opening);
-
-        let proof_data = GroupedCiphertext2HandlesValidityProofData::new(
-            first_pubkey,
-            second_pubkey,
-            &grouped_ciphertext,
-            amount,
-            &opening,
-        )
-        .unwrap();
-
-        assert!(proof_data.verify_proof().is_ok());
-    }
-}

+ 0 - 243
zk-sdk/src/zk_elgamal_proof_program/proof_data/grouped_ciphertext_validity/handles_3.rs

@@ -1,243 +0,0 @@
-//! The grouped-ciphertext with 3 decryption handles validity proof instruction.
-//!
-//! A grouped-ciphertext validity proof certifies that a grouped ElGamal ciphertext is
-//! well-defined, i.e. the ciphertext can be decrypted by private keys associated with its
-//! decryption handles. To generate the proof, a prover must provide the Pedersen opening
-//! associated with the grouped ciphertext's commitment.
-
-#[cfg(target_arch = "wasm32")]
-use {
-    crate::encryption::grouped_elgamal::GroupedElGamalCiphertext3Handles, wasm_bindgen::prelude::*,
-};
-use {
-    crate::{
-        encryption::pod::{
-            elgamal::PodElGamalPubkey, grouped_elgamal::PodGroupedElGamalCiphertext3Handles,
-        },
-        sigma_proofs::pod::PodGroupedCiphertext3HandlesValidityProof,
-        zk_elgamal_proof_program::proof_data::{pod::impl_wasm_to_bytes, ProofType, ZkProofData},
-    },
-    bytemuck_derive::{Pod, Zeroable},
-};
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::{
-            elgamal::ElGamalPubkey, grouped_elgamal::GroupedElGamalCiphertext,
-            pedersen::PedersenOpening,
-        },
-        sigma_proofs::grouped_ciphertext_validity::GroupedCiphertext3HandlesValidityProof,
-        zk_elgamal_proof_program::{
-            errors::{ProofGenerationError, ProofVerificationError},
-            proof_data::errors::ProofDataError,
-        },
-    },
-    bytemuck::bytes_of,
-    merlin::Transcript,
-};
-
-/// The instruction data that is needed for the
-/// `ProofInstruction::VerifyGroupedCiphertext3HandlesValidity` instruction.
-///
-/// It includes the cryptographic proof as well as the context data information needed to verify
-/// the proof.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct GroupedCiphertext3HandlesValidityProofData {
-    pub context: GroupedCiphertext3HandlesValidityProofContext,
-
-    pub proof: PodGroupedCiphertext3HandlesValidityProof,
-}
-
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct GroupedCiphertext3HandlesValidityProofContext {
-    pub first_pubkey: PodElGamalPubkey, // 32 bytes
-
-    pub second_pubkey: PodElGamalPubkey, // 32 bytes
-
-    pub third_pubkey: PodElGamalPubkey, // 32 bytes
-
-    pub grouped_ciphertext: PodGroupedElGamalCiphertext3Handles, // 128 bytes
-}
-
-#[cfg(not(target_os = "solana"))]
-#[cfg(not(target_arch = "wasm32"))]
-impl GroupedCiphertext3HandlesValidityProofData {
-    pub fn new(
-        first_pubkey: &ElGamalPubkey,
-        second_pubkey: &ElGamalPubkey,
-        third_pubkey: &ElGamalPubkey,
-        grouped_ciphertext: &GroupedElGamalCiphertext<3>,
-        amount: u64,
-        opening: &PedersenOpening,
-    ) -> Result<Self, ProofGenerationError> {
-        let pod_first_pubkey = PodElGamalPubkey(first_pubkey.into());
-        let pod_second_pubkey = PodElGamalPubkey(second_pubkey.into());
-        let pod_third_pubkey = PodElGamalPubkey(third_pubkey.into());
-        let pod_grouped_ciphertext = (*grouped_ciphertext).into();
-
-        let context = GroupedCiphertext3HandlesValidityProofContext {
-            first_pubkey: pod_first_pubkey,
-            second_pubkey: pod_second_pubkey,
-            third_pubkey: pod_third_pubkey,
-            grouped_ciphertext: pod_grouped_ciphertext,
-        };
-
-        let mut transcript = context.new_transcript();
-
-        let proof = GroupedCiphertext3HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            third_pubkey,
-            amount,
-            opening,
-            &mut transcript,
-        )
-        .into();
-
-        Ok(Self { context, proof })
-    }
-}
-
-// Define a separate constructor for `wasm32` target since `wasm_bindgen` does
-// not yet support parameters with generic constants (i.e.
-// `GroupedElGamalCiphertext<3>`).
-#[cfg(target_arch = "wasm32")]
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-impl GroupedCiphertext3HandlesValidityProofData {
-    pub fn new(
-        first_pubkey: &ElGamalPubkey,
-        second_pubkey: &ElGamalPubkey,
-        third_pubkey: &ElGamalPubkey,
-        grouped_ciphertext: &GroupedElGamalCiphertext3Handles,
-        amount: u64,
-        opening: &PedersenOpening,
-    ) -> Result<Self, ProofGenerationError> {
-        let pod_first_pubkey = PodElGamalPubkey(first_pubkey.into());
-        let pod_second_pubkey = PodElGamalPubkey(second_pubkey.into());
-        let pod_third_pubkey = PodElGamalPubkey(third_pubkey.into());
-        let pod_grouped_ciphertext = grouped_ciphertext.0.into();
-
-        let context = GroupedCiphertext3HandlesValidityProofContext {
-            first_pubkey: pod_first_pubkey,
-            second_pubkey: pod_second_pubkey,
-            third_pubkey: pod_third_pubkey,
-            grouped_ciphertext: pod_grouped_ciphertext,
-        };
-
-        let mut transcript = context.new_transcript();
-
-        let proof = GroupedCiphertext3HandlesValidityProof::new(
-            first_pubkey,
-            second_pubkey,
-            third_pubkey,
-            amount,
-            opening,
-            &mut transcript,
-        )
-        .into();
-
-        Ok(Self { context, proof })
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = GroupedCiphertext3HandlesValidityProofData);
-
-impl ZkProofData<GroupedCiphertext3HandlesValidityProofContext>
-    for GroupedCiphertext3HandlesValidityProofData
-{
-    const PROOF_TYPE: ProofType = ProofType::GroupedCiphertext3HandlesValidity;
-
-    fn context_data(&self) -> &GroupedCiphertext3HandlesValidityProofContext {
-        &self.context
-    }
-
-    #[cfg(not(target_os = "solana"))]
-    fn verify_proof(&self) -> Result<(), ProofVerificationError> {
-        let mut transcript = self.context.new_transcript();
-
-        let first_pubkey = self.context.first_pubkey.try_into()?;
-        let second_pubkey = self.context.second_pubkey.try_into()?;
-        let third_pubkey = self.context.third_pubkey.try_into()?;
-        let grouped_ciphertext: GroupedElGamalCiphertext<3> =
-            self.context.grouped_ciphertext.try_into()?;
-
-        let first_handle = grouped_ciphertext.handles.first().unwrap();
-        let second_handle = grouped_ciphertext.handles.get(1).unwrap();
-        let third_handle = grouped_ciphertext.handles.get(2).unwrap();
-
-        let proof: GroupedCiphertext3HandlesValidityProof = self.proof.try_into()?;
-
-        proof
-            .verify(
-                &grouped_ciphertext.commitment,
-                &first_pubkey,
-                &second_pubkey,
-                &third_pubkey,
-                first_handle,
-                second_handle,
-                third_handle,
-                &mut transcript,
-            )
-            .map_err(|e| e.into())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl GroupedCiphertext3HandlesValidityProofContext {
-    fn new_transcript(&self) -> Transcript {
-        let mut transcript = Transcript::new(b"grouped-ciphertext-validity-3-handles-instruction");
-
-        transcript.append_message(b"first-pubkey", bytes_of(&self.first_pubkey));
-        transcript.append_message(b"second-pubkey", bytes_of(&self.second_pubkey));
-        transcript.append_message(b"third-pubkey", bytes_of(&self.third_pubkey));
-        transcript.append_message(b"grouped-ciphertext", bytes_of(&self.grouped_ciphertext));
-
-        transcript
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = GroupedCiphertext3HandlesValidityProofContext);
-
-#[cfg(test)]
-mod test {
-    use {
-        super::*,
-        crate::encryption::{elgamal::ElGamalKeypair, grouped_elgamal::GroupedElGamal},
-    };
-
-    #[test]
-    fn test_ciphertext_validity_proof_instruction_correctness() {
-        let first_keypair = ElGamalKeypair::new_rand();
-        let first_pubkey = first_keypair.pubkey();
-
-        let second_keypair = ElGamalKeypair::new_rand();
-        let second_pubkey = second_keypair.pubkey();
-
-        let third_keypair = ElGamalKeypair::new_rand();
-        let third_pubkey = third_keypair.pubkey();
-
-        let amount: u64 = 55;
-        let opening = PedersenOpening::new_rand();
-        let grouped_ciphertext = GroupedElGamal::encrypt_with(
-            [first_pubkey, second_pubkey, third_pubkey],
-            amount,
-            &opening,
-        );
-
-        let proof_data = GroupedCiphertext3HandlesValidityProofData::new(
-            first_pubkey,
-            second_pubkey,
-            third_pubkey,
-            &grouped_ciphertext,
-            amount,
-            &opening,
-        )
-        .unwrap();
-
-        assert!(proof_data.verify_proof().is_ok());
-    }
-}

+ 0 - 11
zk-sdk/src/zk_elgamal_proof_program/proof_data/grouped_ciphertext_validity/mod.rs

@@ -1,11 +0,0 @@
-mod handles_2;
-mod handles_3;
-
-pub use {
-    handles_2::{
-        GroupedCiphertext2HandlesValidityProofContext, GroupedCiphertext2HandlesValidityProofData,
-    },
-    handles_3::{
-        GroupedCiphertext3HandlesValidityProofContext, GroupedCiphertext3HandlesValidityProofData,
-    },
-};

+ 0 - 72
zk-sdk/src/zk_elgamal_proof_program/proof_data/mod.rs

@@ -1,72 +0,0 @@
-#[cfg(not(target_os = "solana"))]
-use crate::zk_elgamal_proof_program::errors::ProofVerificationError;
-use {
-    bytemuck::Pod,
-    num_derive::{FromPrimitive, ToPrimitive},
-};
-
-pub mod batched_grouped_ciphertext_validity;
-pub mod batched_range_proof;
-pub mod ciphertext_ciphertext_equality;
-pub mod ciphertext_commitment_equality;
-pub mod errors;
-pub mod grouped_ciphertext_validity;
-pub mod percentage_with_cap;
-pub mod pod;
-pub mod pubkey_validity;
-pub mod zero_ciphertext;
-
-pub use {
-    batched_grouped_ciphertext_validity::{
-        BatchedGroupedCiphertext2HandlesValidityProofContext,
-        BatchedGroupedCiphertext2HandlesValidityProofData,
-        BatchedGroupedCiphertext3HandlesValidityProofContext,
-        BatchedGroupedCiphertext3HandlesValidityProofData,
-    },
-    batched_range_proof::{
-        batched_range_proof_u128::BatchedRangeProofU128Data,
-        batched_range_proof_u256::BatchedRangeProofU256Data,
-        batched_range_proof_u64::BatchedRangeProofU64Data, BatchedRangeProofContext,
-    },
-    ciphertext_ciphertext_equality::{
-        CiphertextCiphertextEqualityProofContext, CiphertextCiphertextEqualityProofData,
-    },
-    ciphertext_commitment_equality::{
-        CiphertextCommitmentEqualityProofContext, CiphertextCommitmentEqualityProofData,
-    },
-    grouped_ciphertext_validity::{
-        GroupedCiphertext2HandlesValidityProofContext, GroupedCiphertext2HandlesValidityProofData,
-        GroupedCiphertext3HandlesValidityProofContext, GroupedCiphertext3HandlesValidityProofData,
-    },
-    percentage_with_cap::{PercentageWithCapProofContext, PercentageWithCapProofData},
-    pubkey_validity::{PubkeyValidityProofContext, PubkeyValidityProofData},
-    zero_ciphertext::{ZeroCiphertextProofContext, ZeroCiphertextProofData},
-};
-
-#[derive(Clone, Copy, Debug, FromPrimitive, ToPrimitive, PartialEq, Eq)]
-#[repr(u8)]
-pub enum ProofType {
-    /// Empty proof type used to distinguish if a proof context account is initialized
-    Uninitialized,
-    ZeroCiphertext,
-    CiphertextCiphertextEquality,
-    CiphertextCommitmentEquality,
-    PubkeyValidity,
-    PercentageWithCap,
-    BatchedRangeProofU64,
-    BatchedRangeProofU128,
-    BatchedRangeProofU256,
-    GroupedCiphertext2HandlesValidity,
-    BatchedGroupedCiphertext2HandlesValidity,
-    GroupedCiphertext3HandlesValidity,
-    BatchedGroupedCiphertext3HandlesValidity,
-}
-
-pub trait ZkProofData<T: Pod> {
-    const PROOF_TYPE: ProofType;
-
-    fn context_data(&self) -> &T;
-
-    #[cfg(not(target_os = "solana"))]
-    fn verify_proof(&self) -> Result<(), ProofVerificationError>;
-}

+ 0 - 239
zk-sdk/src/zk_elgamal_proof_program/proof_data/percentage_with_cap.rs

@@ -1,239 +0,0 @@
-//! The percentage-with-cap proof instruction.
-//!
-//! The percentage-with-cap proof is defined with respect to three Pedersen commitments that
-//! encodes values referred to as a `percentage`, `delta`, and `claimed` amounts. The proof
-//! certifies that either
-//! - the `percentage` amount is equal to a constant (referred to as the `max_value`)
-//! - the `delta` and `claimed` amounts are equal
-
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::pedersen::{PedersenCommitment, PedersenOpening},
-        sigma_proofs::percentage_with_cap::PercentageWithCapProof,
-        zk_elgamal_proof_program::{
-            errors::{ProofGenerationError, ProofVerificationError},
-            proof_data::errors::ProofDataError,
-        },
-    },
-    bytemuck::bytes_of,
-    merlin::Transcript,
-    std::convert::TryInto,
-};
-use {
-    crate::{
-        encryption::pod::pedersen::PodPedersenCommitment,
-        pod::PodU64,
-        sigma_proofs::pod::PodPercentageWithCapProof,
-        zk_elgamal_proof_program::proof_data::{pod::impl_wasm_to_bytes, ProofType, ZkProofData},
-    },
-    bytemuck_derive::{Pod, Zeroable},
-};
-
-/// The instruction data that is needed for the `ProofInstruction::VerifyPercentageWithCap`
-/// instruction.
-///
-/// It includes the cryptographic proof as well as the context data information needed to verify
-/// the proof.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct PercentageWithCapProofData {
-    pub context: PercentageWithCapProofContext,
-
-    pub proof: PodPercentageWithCapProof,
-}
-
-/// The context data needed to verify a percentage-with-cap proof.
-///
-/// We refer to [`ZK ElGamal proof`] for the formal details on how the percentage-with-cap proof is
-/// computed.
-///
-/// [`ZK ElGamal proof`]: https://docs.solanalabs.com/runtime/zk-token-proof
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct PercentageWithCapProofContext {
-    /// The Pedersen commitment to the percentage amount.
-    pub percentage_commitment: PodPedersenCommitment,
-
-    /// The Pedersen commitment to the delta amount.
-    pub delta_commitment: PodPedersenCommitment,
-
-    /// The Pedersen commitment to the claimed amount.
-    pub claimed_commitment: PodPedersenCommitment,
-
-    /// The maximum cap bound.
-    pub max_value: PodU64,
-}
-
-#[cfg(not(target_os = "solana"))]
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-impl PercentageWithCapProofData {
-    pub fn new(
-        percentage_commitment: &PedersenCommitment,
-        percentage_opening: &PedersenOpening,
-        percentage_amount: u64,
-        delta_commitment: &PedersenCommitment,
-        delta_opening: &PedersenOpening,
-        delta_amount: u64,
-        claimed_commitment: &PedersenCommitment,
-        claimed_opening: &PedersenOpening,
-        max_value: u64,
-    ) -> Result<Self, ProofGenerationError> {
-        let pod_percentage_commitment = PodPedersenCommitment(percentage_commitment.to_bytes());
-        let pod_delta_commitment = PodPedersenCommitment(delta_commitment.to_bytes());
-        let pod_claimed_commitment = PodPedersenCommitment(claimed_commitment.to_bytes());
-        let pod_max_value = max_value.into();
-
-        let context = PercentageWithCapProofContext {
-            percentage_commitment: pod_percentage_commitment,
-            delta_commitment: pod_delta_commitment,
-            claimed_commitment: pod_claimed_commitment,
-            max_value: pod_max_value,
-        };
-
-        let mut transcript = context.new_transcript();
-
-        let proof = PercentageWithCapProof::new(
-            percentage_commitment,
-            percentage_opening,
-            percentage_amount,
-            delta_commitment,
-            delta_opening,
-            delta_amount,
-            claimed_commitment,
-            claimed_opening,
-            max_value,
-            &mut transcript,
-        )
-        .into();
-
-        Ok(Self { context, proof })
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = PercentageWithCapProofData);
-
-impl ZkProofData<PercentageWithCapProofContext> for PercentageWithCapProofData {
-    const PROOF_TYPE: ProofType = ProofType::PercentageWithCap;
-
-    fn context_data(&self) -> &PercentageWithCapProofContext {
-        &self.context
-    }
-
-    #[cfg(not(target_os = "solana"))]
-    fn verify_proof(&self) -> Result<(), ProofVerificationError> {
-        let mut transcript = self.context.new_transcript();
-
-        let percentage_commitment = self.context.percentage_commitment.try_into()?;
-        let delta_commitment = self.context.delta_commitment.try_into()?;
-        let claimed_commitment = self.context.claimed_commitment.try_into()?;
-        let max_value = self.context.max_value.into();
-        let proof: PercentageWithCapProof = self.proof.try_into()?;
-
-        proof
-            .verify(
-                &percentage_commitment,
-                &delta_commitment,
-                &claimed_commitment,
-                max_value,
-                &mut transcript,
-            )
-            .map_err(|e| e.into())
-    }
-}
-
-#[cfg(not(target_os = "solana"))]
-impl PercentageWithCapProofContext {
-    fn new_transcript(&self) -> Transcript {
-        let mut transcript = Transcript::new(b"percentage-with-cap-instruction");
-        transcript.append_message(
-            b"percentage-commitment",
-            bytes_of(&self.percentage_commitment),
-        );
-        transcript.append_message(b"delta-commitment", bytes_of(&self.delta_commitment));
-        transcript.append_message(b"claimed-commitment", bytes_of(&self.claimed_commitment));
-        transcript.append_u64(b"max-value", self.max_value.into());
-        transcript
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = PercentageWithCapProofContext);
-
-#[cfg(test)]
-mod test {
-    use {super::*, crate::encryption::pedersen::Pedersen, curve25519_dalek::scalar::Scalar};
-
-    #[test]
-    fn test_percentage_with_cap_instruction_correctness() {
-        // base amount is below max value
-        let base_amount: u64 = 1;
-        let max_value: u64 = 3;
-
-        let percentage_rate: u16 = 400;
-        let percentage_amount: u64 = 1;
-        let delta_amount: u64 = 9600;
-
-        let (base_commitment, base_opening) = Pedersen::new(base_amount);
-        let (percentage_commitment, percentage_opening) = Pedersen::new(percentage_amount);
-
-        let scalar_rate = Scalar::from(percentage_rate);
-        let delta_commitment =
-            &percentage_commitment * Scalar::from(10_000_u64) - &base_commitment * &scalar_rate;
-        let delta_opening =
-            &percentage_opening * &Scalar::from(10_000_u64) - &base_opening * &scalar_rate;
-
-        let (claimed_commitment, claimed_opening) = Pedersen::new(delta_amount);
-
-        let proof_data = PercentageWithCapProofData::new(
-            &percentage_commitment,
-            &percentage_opening,
-            percentage_amount,
-            &delta_commitment,
-            &delta_opening,
-            delta_amount,
-            &claimed_commitment,
-            &claimed_opening,
-            max_value,
-        )
-        .unwrap();
-
-        assert!(proof_data.verify_proof().is_ok());
-
-        // base amount is equal to max value
-        let base_amount: u64 = 55;
-        let max_value: u64 = 3;
-
-        let percentage_rate: u16 = 555;
-        let percentage_amount: u64 = 4;
-
-        let (transfer_commitment, transfer_opening) = Pedersen::new(base_amount);
-        let (percentage_commitment, percentage_opening) = Pedersen::new(max_value);
-
-        let scalar_rate = Scalar::from(percentage_rate);
-        let delta_commitment =
-            &percentage_commitment * &Scalar::from(10000_u64) - &transfer_commitment * &scalar_rate;
-        let delta_opening =
-            &percentage_opening * &Scalar::from(10000_u64) - &transfer_opening * &scalar_rate;
-
-        let (claimed_commitment, claimed_opening) = Pedersen::new(0_u64);
-
-        let proof_data = PercentageWithCapProofData::new(
-            &percentage_commitment,
-            &percentage_opening,
-            percentage_amount,
-            &delta_commitment,
-            &delta_opening,
-            delta_amount,
-            &claimed_commitment,
-            &claimed_opening,
-            max_value,
-        )
-        .unwrap();
-
-        assert!(proof_data.verify_proof().is_ok());
-    }
-}

+ 0 - 42
zk-sdk/src/zk_elgamal_proof_program/proof_data/pod.rs

@@ -1,42 +0,0 @@
-use {
-    crate::zk_elgamal_proof_program::proof_data::{errors::ProofDataError, ProofType},
-    bytemuck_derive::{Pod, Zeroable},
-    num_traits::{FromPrimitive, ToPrimitive},
-};
-
-#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Pod, Zeroable)]
-#[repr(transparent)]
-pub struct PodProofType(u8);
-impl From<ProofType> for PodProofType {
-    fn from(proof_type: ProofType) -> Self {
-        Self(ToPrimitive::to_u8(&proof_type).unwrap())
-    }
-}
-impl TryFrom<PodProofType> for ProofType {
-    type Error = ProofDataError;
-
-    fn try_from(pod: PodProofType) -> Result<Self, Self::Error> {
-        FromPrimitive::from_u8(pod.0).ok_or(Self::Error::InvalidProofType)
-    }
-}
-
-macro_rules! impl_wasm_to_bytes {
-    (TYPE = $type:ident) => {
-        #[cfg(not(target_os = "solana"))]
-        #[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-        impl $type {
-            #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = toBytes))]
-            pub fn to_bytes(&self) -> Box<[u8]> {
-                bytes_of(self).into()
-            }
-
-            #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = fromBytes))]
-            pub fn from_bytes(bytes: &[u8]) -> Result<Self, ProofDataError> {
-                bytemuck::try_from_bytes(bytes)
-                    .copied()
-                    .map_err(|_| ProofDataError::Deserialization)
-            }
-        }
-    };
-}
-pub(crate) use impl_wasm_to_bytes;

+ 0 - 114
zk-sdk/src/zk_elgamal_proof_program/proof_data/pubkey_validity.rs

@@ -1,114 +0,0 @@
-//! The public-key validity proof instruction.
-//!
-//! A public-key validity proof system is defined with respect to an ElGamal public key. The proof
-//! certifies that a given public key is a valid ElGamal public key (i.e. the prover knows a
-//! corresponding secret key). To generate the proof, a prover must provide the secret key for the
-//! public key.
-
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::elgamal::ElGamalKeypair,
-        sigma_proofs::pubkey_validity::PubkeyValidityProof,
-        zk_elgamal_proof_program::{
-            errors::{ProofGenerationError, ProofVerificationError},
-            proof_data::errors::ProofDataError,
-        },
-    },
-    bytemuck::bytes_of,
-    merlin::Transcript,
-    std::convert::TryInto,
-};
-use {
-    crate::{
-        encryption::pod::elgamal::PodElGamalPubkey,
-        sigma_proofs::pod::PodPubkeyValidityProof,
-        zk_elgamal_proof_program::proof_data::{pod::impl_wasm_to_bytes, ProofType, ZkProofData},
-    },
-    bytemuck_derive::{Pod, Zeroable},
-};
-
-/// The instruction data that is needed for the `ProofInstruction::VerifyPubkeyValidity`
-/// instruction.
-///
-/// It includes the cryptographic proof as well as the context data information needed to verify
-/// the proof.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct PubkeyValidityProofData {
-    /// The context data for the public key validity proof
-    pub context: PubkeyValidityProofContext, // 32 bytes
-
-    /// Proof that the public key is well-formed
-    pub proof: PodPubkeyValidityProof, // 64 bytes
-}
-
-/// The context data needed to verify a pubkey validity proof.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct PubkeyValidityProofContext {
-    /// The public key to be proved
-    pub pubkey: PodElGamalPubkey, // 32 bytes
-}
-
-#[cfg(not(target_os = "solana"))]
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-impl PubkeyValidityProofData {
-    pub fn new(keypair: &ElGamalKeypair) -> Result<Self, ProofGenerationError> {
-        let pod_pubkey = PodElGamalPubkey(keypair.pubkey().into());
-
-        let context = PubkeyValidityProofContext { pubkey: pod_pubkey };
-
-        let mut transcript = context.new_transcript();
-        let proof = PubkeyValidityProof::new(keypair, &mut transcript).into();
-
-        Ok(PubkeyValidityProofData { context, proof })
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = PubkeyValidityProofData);
-
-impl ZkProofData<PubkeyValidityProofContext> for PubkeyValidityProofData {
-    const PROOF_TYPE: ProofType = ProofType::PubkeyValidity;
-
-    fn context_data(&self) -> &PubkeyValidityProofContext {
-        &self.context
-    }
-
-    #[cfg(not(target_os = "solana"))]
-    fn verify_proof(&self) -> Result<(), ProofVerificationError> {
-        let mut transcript = self.context.new_transcript();
-        let pubkey = self.context.pubkey.try_into()?;
-        let proof: PubkeyValidityProof = self.proof.try_into()?;
-        proof.verify(&pubkey, &mut transcript).map_err(|e| e.into())
-    }
-}
-
-#[allow(non_snake_case)]
-#[cfg(not(target_os = "solana"))]
-impl PubkeyValidityProofContext {
-    fn new_transcript(&self) -> Transcript {
-        let mut transcript = Transcript::new(b"pubkey-validity-instruction");
-        transcript.append_message(b"pubkey", bytes_of(&self.pubkey));
-        transcript
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = PubkeyValidityProofContext);
-
-#[cfg(test)]
-mod test {
-    use super::*;
-
-    #[test]
-    fn test_pubkey_validity_instruction_correctness() {
-        let keypair = ElGamalKeypair::new_rand();
-
-        let pubkey_validity_data = PubkeyValidityProofData::new(&keypair).unwrap();
-        assert!(pubkey_validity_data.verify_proof().is_ok());
-    }
-}

+ 0 - 137
zk-sdk/src/zk_elgamal_proof_program/proof_data/zero_ciphertext.rs

@@ -1,137 +0,0 @@
-//! The zero-ciphertext proof instruction.
-//!
-//! A zero-ciphertext proof is defined with respect to a twisted ElGamal ciphertext. The proof
-//! certifies that a given ciphertext encrypts the message 0 in the field (`Scalar::zero()`). To
-//! generate the proof, a prover must provide the decryption key for the ciphertext.
-
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::prelude::*;
-#[cfg(not(target_os = "solana"))]
-use {
-    crate::{
-        encryption::elgamal::{ElGamalCiphertext, ElGamalKeypair},
-        sigma_proofs::zero_ciphertext::ZeroCiphertextProof,
-        zk_elgamal_proof_program::{
-            errors::{ProofGenerationError, ProofVerificationError},
-            proof_data::errors::ProofDataError,
-        },
-    },
-    bytemuck::bytes_of,
-    merlin::Transcript,
-    std::convert::TryInto,
-};
-use {
-    crate::{
-        encryption::pod::elgamal::{PodElGamalCiphertext, PodElGamalPubkey},
-        sigma_proofs::pod::PodZeroCiphertextProof,
-        zk_elgamal_proof_program::proof_data::{pod::impl_wasm_to_bytes, ProofType, ZkProofData},
-    },
-    bytemuck_derive::{Pod, Zeroable},
-};
-
-/// The instruction data that is needed for the `ProofInstruction::ZeroCiphertext` instruction.
-///
-/// It includes the cryptographic proof as well as the context data information needed to verify
-/// the proof.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct ZeroCiphertextProofData {
-    /// The context data for the zero-ciphertext proof
-    pub context: ZeroCiphertextProofContext, // 96 bytes
-
-    /// Proof that the ciphertext is zero
-    pub proof: PodZeroCiphertextProof, // 96 bytes
-}
-
-/// The context data needed to verify a zero-ciphertext proof.
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-#[derive(Clone, Copy, Pod, Zeroable)]
-#[repr(C)]
-pub struct ZeroCiphertextProofContext {
-    /// The ElGamal pubkey associated with the ElGamal ciphertext
-    pub pubkey: PodElGamalPubkey, // 32 bytes
-
-    /// The ElGamal ciphertext that encrypts zero
-    pub ciphertext: PodElGamalCiphertext, // 64 bytes
-}
-
-#[cfg(not(target_os = "solana"))]
-#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
-impl ZeroCiphertextProofData {
-    pub fn new(
-        keypair: &ElGamalKeypair,
-        ciphertext: &ElGamalCiphertext,
-    ) -> Result<Self, ProofGenerationError> {
-        let pod_pubkey = PodElGamalPubkey(keypair.pubkey().into());
-        let pod_ciphertext = PodElGamalCiphertext(ciphertext.to_bytes());
-
-        let context = ZeroCiphertextProofContext {
-            pubkey: pod_pubkey,
-            ciphertext: pod_ciphertext,
-        };
-
-        let mut transcript = context.new_transcript();
-        let proof = ZeroCiphertextProof::new(keypair, ciphertext, &mut transcript).into();
-
-        Ok(ZeroCiphertextProofData { context, proof })
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = ZeroCiphertextProofData);
-
-impl ZkProofData<ZeroCiphertextProofContext> for ZeroCiphertextProofData {
-    const PROOF_TYPE: ProofType = ProofType::ZeroCiphertext;
-
-    fn context_data(&self) -> &ZeroCiphertextProofContext {
-        &self.context
-    }
-
-    #[cfg(not(target_os = "solana"))]
-    fn verify_proof(&self) -> Result<(), ProofVerificationError> {
-        let mut transcript = self.context.new_transcript();
-        let pubkey = self.context.pubkey.try_into()?;
-        let ciphertext = self.context.ciphertext.try_into()?;
-        let proof: ZeroCiphertextProof = self.proof.try_into()?;
-        proof
-            .verify(&pubkey, &ciphertext, &mut transcript)
-            .map_err(|e| e.into())
-    }
-}
-
-#[allow(non_snake_case)]
-#[cfg(not(target_os = "solana"))]
-impl ZeroCiphertextProofContext {
-    fn new_transcript(&self) -> Transcript {
-        let mut transcript = Transcript::new(b"zero-ciphertext-instruction");
-
-        transcript.append_message(b"pubkey", bytes_of(&self.pubkey));
-        transcript.append_message(b"ciphertext", bytes_of(&self.ciphertext));
-
-        transcript
-    }
-}
-
-impl_wasm_to_bytes!(TYPE = ZeroCiphertextProofContext);
-
-#[cfg(test)]
-mod test {
-    use super::*;
-
-    #[test]
-    fn test_zero_ciphertext_proof_instruction_correctness() {
-        let keypair = ElGamalKeypair::new_rand();
-
-        // general case: encryption of 0
-        let ciphertext = keypair.pubkey().encrypt(0_u64);
-        let zero_ciphertext_proof_data =
-            ZeroCiphertextProofData::new(&keypair, &ciphertext).unwrap();
-        assert!(zero_ciphertext_proof_data.verify_proof().is_ok());
-
-        // general case: encryption of > 0
-        let ciphertext = keypair.pubkey().encrypt(1_u64);
-        let zero_ciphertext_proof_data =
-            ZeroCiphertextProofData::new(&keypair, &ciphertext).unwrap();
-        assert!(zero_ciphertext_proof_data.verify_proof().is_err());
-    }
-}

+ 0 - 70
zk-sdk/src/zk_elgamal_proof_program/state.rs

@@ -1,70 +0,0 @@
-use {
-    crate::zk_elgamal_proof_program::proof_data::{pod::PodProofType, ProofType},
-    bytemuck::{bytes_of, Pod, Zeroable},
-    num_traits::ToPrimitive,
-    solana_instruction::error::{InstructionError, InstructionError::InvalidAccountData},
-    solana_pubkey::Pubkey,
-    std::mem::size_of,
-};
-
-/// The proof context account state
-#[derive(Clone, Copy, Debug, PartialEq)]
-#[repr(C)]
-pub struct ProofContextState<T: Pod> {
-    /// The proof context authority that can close the account
-    pub context_state_authority: Pubkey,
-    /// The proof type for the context data
-    pub proof_type: PodProofType,
-    /// The proof context data
-    pub proof_context: T,
-}
-
-// `bytemuck::Pod` cannot be derived for generic structs unless the struct is marked
-// `repr(packed)`, which may cause unnecessary complications when referencing its fields. Directly
-// mark `ProofContextState` as `Zeroable` and `Pod` since since none of its fields has an alignment
-// requirement greater than 1 and therefore, guaranteed to be `packed`.
-unsafe impl<T: Pod> Zeroable for ProofContextState<T> {}
-unsafe impl<T: Pod> Pod for ProofContextState<T> {}
-
-impl<T: Pod> ProofContextState<T> {
-    pub fn encode(
-        context_state_authority: &Pubkey,
-        proof_type: ProofType,
-        proof_context: &T,
-    ) -> Vec<u8> {
-        let mut buf = Vec::with_capacity(size_of::<Self>());
-        buf.extend_from_slice(context_state_authority.as_ref());
-        buf.push(ToPrimitive::to_u8(&proof_type).unwrap());
-        buf.extend_from_slice(bytes_of(proof_context));
-        buf
-    }
-
-    /// Interpret a slice as a `ProofContextState`.
-    ///
-    /// This function requires a generic parameter. To access only the generic-independent fields
-    /// in `ProofContextState` without a generic parameter, use
-    /// `ProofContextStateMeta::try_from_bytes` instead.
-    pub fn try_from_bytes(input: &[u8]) -> Result<&Self, InstructionError> {
-        bytemuck::try_from_bytes(input).map_err(|_| InvalidAccountData)
-    }
-}
-
-/// The `ProofContextState` without the proof context itself. This struct exists to facilitate the
-/// decoding of generic-independent fields in `ProofContextState`.
-#[derive(Clone, Copy, Debug, PartialEq, bytemuck_derive::Pod, bytemuck_derive::Zeroable)]
-#[repr(C)]
-pub struct ProofContextStateMeta {
-    /// The proof context authority that can close the account
-    pub context_state_authority: Pubkey,
-    /// The proof type for the context data
-    pub proof_type: PodProofType,
-}
-
-impl ProofContextStateMeta {
-    pub fn try_from_bytes(input: &[u8]) -> Result<&Self, InstructionError> {
-        input
-            .get(..size_of::<ProofContextStateMeta>())
-            .and_then(|data| bytemuck::try_from_bytes(data).ok())
-            .ok_or(InvalidAccountData)
-    }
-}