Răsfoiți Sursa

[zk-sdk] Expose sigma proof types for wasm target (#4315)

* expose ElGamal encryption, grouped ElGamal encryption, and Pedersen types for wasm target

* expose sigma proof types for wasm target

* simplify `[wasm_bindgen]` for `grouped_elgamal_wasm` module

* add clarifying comments on separate ciphertext validity proof constructors
samkim-crypto 10 luni în urmă
părinte
comite
b39a976400
26 a modificat fișierele cu 409 adăugiri și 4 ștergeri
  1. 14 0
      zk-sdk/src/encryption/elgamal.rs
  2. 49 0
      zk-sdk/src/encryption/grouped_elgamal.rs
  3. 19 4
      zk-sdk/src/encryption/pedersen.rs
  4. 4 0
      zk-sdk/src/encryption/pod/grouped_elgamal.rs
  5. 3 0
      zk-sdk/src/encryption/pod/pedersen.rs
  6. 1 0
      zk-sdk/src/pod.rs
  7. 3 0
      zk-sdk/src/sigma_proofs/batched_grouped_ciphertext_validity/handles_2.rs
  8. 3 0
      zk-sdk/src/sigma_proofs/batched_grouped_ciphertext_validity/handles_3.rs
  9. 3 0
      zk-sdk/src/sigma_proofs/ciphertext_ciphertext_equality.rs
  10. 3 0
      zk-sdk/src/sigma_proofs/ciphertext_commitment_equality.rs
  11. 3 0
      zk-sdk/src/sigma_proofs/grouped_ciphertext_validity/handles_2.rs
  12. 3 0
      zk-sdk/src/sigma_proofs/grouped_ciphertext_validity/handles_3.rs
  13. 3 0
      zk-sdk/src/sigma_proofs/percentage_with_cap.rs
  14. 11 0
      zk-sdk/src/sigma_proofs/pod.rs
  15. 3 0
      zk-sdk/src/sigma_proofs/pubkey_validity.rs
  16. 3 0
      zk-sdk/src/sigma_proofs/zero_ciphertext.rs
  17. 9 0
      zk-sdk/src/zk_elgamal_proof_program/errors.rs
  18. 57 0
      zk-sdk/src/zk_elgamal_proof_program/proof_data/batched_grouped_ciphertext_validity/handles_2.rs
  19. 61 0
      zk-sdk/src/zk_elgamal_proof_program/proof_data/batched_grouped_ciphertext_validity/handles_3.rs
  20. 10 0
      zk-sdk/src/zk_elgamal_proof_program/proof_data/ciphertext_ciphertext_equality.rs
  21. 10 0
      zk-sdk/src/zk_elgamal_proof_program/proof_data/ciphertext_commitment_equality.rs
  22. 50 0
      zk-sdk/src/zk_elgamal_proof_program/proof_data/grouped_ciphertext_validity/handles_2.rs
  23. 54 0
      zk-sdk/src/zk_elgamal_proof_program/proof_data/grouped_ciphertext_validity/handles_3.rs
  24. 10 0
      zk-sdk/src/zk_elgamal_proof_program/proof_data/percentage_with_cap.rs
  25. 10 0
      zk-sdk/src/zk_elgamal_proof_program/proof_data/pubkey_validity.rs
  26. 10 0
      zk-sdk/src/zk_elgamal_proof_program/proof_data/zero_ciphertext.rs

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

@@ -163,6 +163,7 @@ impl ElGamalKeypair {
         ElGamal::keygen()
     }
 
+    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = pubkeyOwned))]
     pub fn pubkey_owned(&self) -> ElGamalPubkey {
         self.public
     }
@@ -371,6 +372,19 @@ impl ElGamalPubkey {
     }
 }
 
+#[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>> {

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

@@ -14,6 +14,10 @@
 
 #[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::{
@@ -216,6 +220,51 @@ impl<const N: usize> GroupedElGamalCiphertext<N> {
     }
 }
 
+// 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]
+    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,
+            ))
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use {super::*, crate::encryption::elgamal::ElGamalKeypair};

+ 19 - 4
zk-sdk/src/encryption/pedersen.rs

@@ -28,6 +28,7 @@ lazy_static::lazy_static! {
 }
 
 /// 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
@@ -62,12 +63,30 @@ impl Pedersen {
     }
 }
 
+#[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)
@@ -77,10 +96,6 @@ impl PedersenOpening {
         &self.0
     }
 
-    pub fn new_rand() -> Self {
-        PedersenOpening(Scalar::random(&mut OsRng))
-    }
-
     pub fn as_bytes(&self) -> &[u8; PEDERSEN_OPENING_LEN] {
         self.0.as_bytes()
     }

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

@@ -2,6 +2,8 @@
 
 #[cfg(not(target_os = "solana"))]
 use crate::encryption::grouped_elgamal::GroupedElGamalCiphertext;
+#[cfg(target_arch = "wasm32")]
+use wasm_bindgen::prelude::*;
 use {
     crate::{
         encryption::{
@@ -69,6 +71,7 @@ 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(
@@ -123,6 +126,7 @@ impl TryFrom<PodGroupedElGamalCiphertext2Handles> for GroupedElGamalCiphertext<2
 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(

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

@@ -1,5 +1,7 @@
 //! 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},
@@ -19,6 +21,7 @@ use {
 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]);

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

@@ -14,6 +14,7 @@ impl From<PodU16> for u16 {
     }
 }
 
+#[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]);

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

@@ -13,6 +13,8 @@ use crate::encryption::{
     elgamal::{DecryptHandle, ElGamalPubkey},
     pedersen::{PedersenCommitment, PedersenOpening},
 };
+#[cfg(target_arch = "wasm32")]
+use wasm_bindgen::prelude::*;
 use {
     crate::{
         sigma_proofs::{
@@ -34,6 +36,7 @@ use {
 /// 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);

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

@@ -17,6 +17,8 @@ use crate::encryption::{
     elgamal::{DecryptHandle, ElGamalPubkey},
     pedersen::{PedersenCommitment, PedersenOpening},
 };
+#[cfg(target_arch = "wasm32")]
+use wasm_bindgen::prelude::*;
 use {
     crate::{
         sigma_proofs::{
@@ -35,6 +37,7 @@ use {
 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);

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

@@ -3,6 +3,8 @@
 //! 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::{
@@ -36,6 +38,7 @@ 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 {

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

@@ -8,6 +8,8 @@
 //! The protocol guarantees computationally 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::{
@@ -41,6 +43,7 @@ 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 {

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

@@ -8,6 +8,8 @@
 //! 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::{
@@ -41,6 +43,7 @@ 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 {

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

@@ -8,6 +8,8 @@
 //! 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::{
@@ -41,6 +43,7 @@ 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 {

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

@@ -17,6 +17,8 @@
 //!
 //! [`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::{
@@ -52,6 +54,7 @@ const PERCENTAGE_WITH_CAP_PROOF_LEN: usize = UNIT_LEN * 8;
 /// then the `percentage_max_proof` is properly generated and `percentage_equality_proof` is
 /// simulated. If the encrypted 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

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

@@ -15,6 +15,8 @@ use crate::sigma_proofs::{
     pubkey_validity::PubkeyValidityProof,
     zero_ciphertext::ZeroCiphertextProof,
 };
+#[cfg(target_arch = "wasm32")]
+use wasm_bindgen::prelude::*;
 use {
     crate::{
         pod::{impl_from_bytes, impl_from_str},
@@ -26,6 +28,7 @@ use {
 };
 
 /// The `CiphertextCommitmentEqualityProof` type as a `Pod`.
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
 #[derive(Clone, Copy)]
 #[repr(transparent)]
 pub struct PodCiphertextCommitmentEqualityProof(
@@ -68,6 +71,7 @@ impl_from_bytes!(
 );
 
 /// The `CiphertextCiphertextEqualityProof` type as a `Pod`.
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
 #[derive(Clone, Copy)]
 #[repr(transparent)]
 pub struct PodCiphertextCiphertextEqualityProof(
@@ -110,6 +114,7 @@ impl_from_bytes!(
 );
 
 /// The `GroupedCiphertext2HandlesValidityProof` type as a `Pod`.
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
 #[derive(Clone, Copy)]
 #[repr(transparent)]
 pub struct PodGroupedCiphertext2HandlesValidityProof(
@@ -152,6 +157,7 @@ impl_from_bytes!(
 );
 
 /// The `GroupedCiphertext3HandlesValidityProof` type as a `Pod`.
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
 #[derive(Clone, Copy)]
 #[repr(transparent)]
 pub struct PodGroupedCiphertext3HandlesValidityProof(
@@ -194,6 +200,7 @@ impl_from_bytes!(
 );
 
 /// The `BatchedGroupedCiphertext2HandlesValidityProof` type as a `Pod`.
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
 #[derive(Clone, Copy)]
 #[repr(transparent)]
 pub struct PodBatchedGroupedCiphertext2HandlesValidityProof(
@@ -242,6 +249,7 @@ impl_from_bytes!(
 );
 
 /// The `BatchedGroupedCiphertext3HandlesValidityProof` type as a `Pod`.
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
 #[derive(Clone, Copy)]
 #[repr(transparent)]
 pub struct PodBatchedGroupedCiphertext3HandlesValidityProof(
@@ -290,6 +298,7 @@ impl_from_bytes!(
 );
 
 /// 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]);
@@ -330,6 +339,7 @@ impl_from_bytes!(
 );
 
 /// 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]);
@@ -370,6 +380,7 @@ impl_from_bytes!(
 );
 
 /// 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]);

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

@@ -3,6 +3,8 @@
 //! 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::{
@@ -35,6 +37,7 @@ 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 {

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

@@ -3,6 +3,8 @@
 //! The protocol guarantees computationally 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::{
@@ -36,6 +38,7 @@ 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 {

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

@@ -1,5 +1,7 @@
 #[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,
@@ -77,3 +79,10 @@ impl From<ValidityProofVerificationError> for ProofVerificationError {
         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()
+    }
+}

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

@@ -5,6 +5,10 @@
 //! 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::{
@@ -34,6 +38,7 @@ use {
 ///
 /// 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 {
@@ -42,6 +47,7 @@ pub struct BatchedGroupedCiphertext2HandlesValidityProofData {
     pub proof: PodBatchedGroupedCiphertext2HandlesValidityProof,
 }
 
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
 #[derive(Clone, Copy, Pod, Zeroable)]
 #[repr(C)]
 pub struct BatchedGroupedCiphertext2HandlesValidityProofContext {
@@ -55,6 +61,7 @@ pub struct BatchedGroupedCiphertext2HandlesValidityProofContext {
 }
 
 #[cfg(not(target_os = "solana"))]
+#[cfg(not(target_arch = "wasm32"))]
 impl BatchedGroupedCiphertext2HandlesValidityProofData {
     pub fn new(
         first_pubkey: &ElGamalPubkey,
@@ -95,6 +102,56 @@ impl BatchedGroupedCiphertext2HandlesValidityProofData {
     }
 }
 
+// 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 })
+    }
+
+    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = toBytes))]
+    pub fn to_bytes(&self) -> Box<[u8]> {
+        bytes_of(self).into()
+    }
+}
+
 impl ZkProofData<BatchedGroupedCiphertext2HandlesValidityProofContext>
     for BatchedGroupedCiphertext2HandlesValidityProofData
 {

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

@@ -5,6 +5,10 @@
 //! 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::{
@@ -34,6 +38,7 @@ use {
 ///
 /// 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 {
@@ -42,6 +47,7 @@ pub struct BatchedGroupedCiphertext3HandlesValidityProofData {
     pub proof: PodBatchedGroupedCiphertext3HandlesValidityProof,
 }
 
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
 #[derive(Clone, Copy, Pod, Zeroable)]
 #[repr(C)]
 pub struct BatchedGroupedCiphertext3HandlesValidityProofContext {
@@ -57,6 +63,7 @@ pub struct BatchedGroupedCiphertext3HandlesValidityProofContext {
 }
 
 #[cfg(not(target_os = "solana"))]
+#[cfg(not(target_arch = "wasm32"))]
 impl BatchedGroupedCiphertext3HandlesValidityProofData {
     pub fn new(
         first_pubkey: &ElGamalPubkey,
@@ -101,6 +108,60 @@ impl BatchedGroupedCiphertext3HandlesValidityProofData {
     }
 }
 
+// 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 })
+    }
+
+    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = toBytes))]
+    pub fn to_bytes(&self) -> Box<[u8]> {
+        bytes_of(self).into()
+    }
+}
+
 impl ZkProofData<BatchedGroupedCiphertext3HandlesValidityProofContext>
     for BatchedGroupedCiphertext3HandlesValidityProofData
 {

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

@@ -5,6 +5,8 @@
 //! 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},
@@ -33,6 +35,7 @@ use {
 ///
 /// 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 {
@@ -42,6 +45,7 @@ pub struct CiphertextCiphertextEqualityProofData {
 }
 
 /// 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 {
@@ -55,6 +59,7 @@ pub struct CiphertextCiphertextEqualityProofContext {
 }
 
 #[cfg(not(target_os = "solana"))]
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
 impl CiphertextCiphertextEqualityProofData {
     pub fn new(
         first_keypair: &ElGamalKeypair,
@@ -90,6 +95,11 @@ impl CiphertextCiphertextEqualityProofData {
 
         Ok(Self { context, proof })
     }
+
+    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = toBytes))]
+    pub fn to_bytes(&self) -> Box<[u8]> {
+        bytes_of(self).into()
+    }
 }
 
 impl ZkProofData<CiphertextCiphertextEqualityProofContext>

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

@@ -5,6 +5,8 @@
 //! 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::{
@@ -35,6 +37,7 @@ use {
 ///
 /// 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 {
@@ -43,6 +46,7 @@ pub struct CiphertextCommitmentEqualityProofData {
 }
 
 /// 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 {
@@ -57,6 +61,7 @@ pub struct CiphertextCommitmentEqualityProofContext {
 }
 
 #[cfg(not(target_os = "solana"))]
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
 impl CiphertextCommitmentEqualityProofData {
     pub fn new(
         keypair: &ElGamalKeypair,
@@ -83,6 +88,11 @@ impl CiphertextCommitmentEqualityProofData {
             proof: proof.into(),
         })
     }
+
+    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = toBytes))]
+    pub fn to_bytes(&self) -> Box<[u8]> {
+        bytes_of(self).into()
+    }
 }
 
 impl ZkProofData<CiphertextCommitmentEqualityProofContext>

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

@@ -5,6 +5,10 @@
 //! 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::{
@@ -34,6 +38,7 @@ use {
 ///
 /// 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 {
@@ -42,6 +47,7 @@ pub struct GroupedCiphertext2HandlesValidityProofData {
     pub proof: PodGroupedCiphertext2HandlesValidityProof,
 }
 
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
 #[derive(Clone, Copy, Pod, Zeroable)]
 #[repr(C)]
 pub struct GroupedCiphertext2HandlesValidityProofContext {
@@ -53,6 +59,7 @@ pub struct GroupedCiphertext2HandlesValidityProofContext {
 }
 
 #[cfg(not(target_os = "solana"))]
+#[cfg(not(target_arch = "wasm32"))]
 impl GroupedCiphertext2HandlesValidityProofData {
     pub fn new(
         first_pubkey: &ElGamalPubkey,
@@ -86,6 +93,49 @@ impl GroupedCiphertext2HandlesValidityProofData {
     }
 }
 
+// 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 })
+    }
+
+    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = toBytes))]
+    pub fn to_bytes(&self) -> Box<[u8]> {
+        bytes_of(self).into()
+    }
+}
+
 impl ZkProofData<GroupedCiphertext2HandlesValidityProofContext>
     for GroupedCiphertext2HandlesValidityProofData
 {

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

@@ -5,6 +5,10 @@
 //! 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::{
@@ -34,6 +38,7 @@ use {
 ///
 /// 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 {
@@ -42,6 +47,7 @@ pub struct GroupedCiphertext3HandlesValidityProofData {
     pub proof: PodGroupedCiphertext3HandlesValidityProof,
 }
 
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
 #[derive(Clone, Copy, Pod, Zeroable)]
 #[repr(C)]
 pub struct GroupedCiphertext3HandlesValidityProofContext {
@@ -55,6 +61,7 @@ pub struct GroupedCiphertext3HandlesValidityProofContext {
 }
 
 #[cfg(not(target_os = "solana"))]
+#[cfg(not(target_arch = "wasm32"))]
 impl GroupedCiphertext3HandlesValidityProofData {
     pub fn new(
         first_pubkey: &ElGamalPubkey,
@@ -92,6 +99,53 @@ impl GroupedCiphertext3HandlesValidityProofData {
     }
 }
 
+// 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 })
+    }
+
+    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = toBytes))]
+    pub fn to_bytes(&self) -> Box<[u8]> {
+        bytes_of(self).into()
+    }
+}
+
 impl ZkProofData<GroupedCiphertext3HandlesValidityProofContext>
     for GroupedCiphertext3HandlesValidityProofData
 {

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

@@ -6,6 +6,8 @@
 //! - 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::{
@@ -32,6 +34,7 @@ use {
 ///
 /// 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 {
@@ -46,6 +49,7 @@ pub struct PercentageWithCapProofData {
 /// 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 {
@@ -63,6 +67,7 @@ pub struct PercentageWithCapProofContext {
 }
 
 #[cfg(not(target_os = "solana"))]
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
 impl PercentageWithCapProofData {
     pub fn new(
         percentage_commitment: &PedersenCommitment,
@@ -105,6 +110,11 @@ impl PercentageWithCapProofData {
 
         Ok(Self { context, proof })
     }
+
+    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = toBytes))]
+    pub fn to_bytes(&self) -> Box<[u8]> {
+        bytes_of(self).into()
+    }
 }
 
 impl ZkProofData<PercentageWithCapProofContext> for PercentageWithCapProofData {

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

@@ -5,6 +5,8 @@
 //! 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::{
@@ -30,6 +32,7 @@ use {
 ///
 /// 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 {
@@ -41,6 +44,7 @@ pub struct PubkeyValidityProofData {
 }
 
 /// 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 {
@@ -49,6 +53,7 @@ pub struct PubkeyValidityProofContext {
 }
 
 #[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());
@@ -60,6 +65,11 @@ impl PubkeyValidityProofData {
 
         Ok(PubkeyValidityProofData { context, proof })
     }
+
+    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = toBytes))]
+    pub fn to_bytes(&self) -> Box<[u8]> {
+        bytes_of(self).into()
+    }
 }
 
 impl ZkProofData<PubkeyValidityProofContext> for PubkeyValidityProofData {

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

@@ -4,6 +4,8 @@
 //! 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::{
@@ -28,6 +30,7 @@ use {
 ///
 /// 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 {
@@ -39,6 +42,7 @@ pub struct ZeroCiphertextProofData {
 }
 
 /// 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 {
@@ -50,6 +54,7 @@ pub struct ZeroCiphertextProofContext {
 }
 
 #[cfg(not(target_os = "solana"))]
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
 impl ZeroCiphertextProofData {
     pub fn new(
         keypair: &ElGamalKeypair,
@@ -68,6 +73,11 @@ impl ZeroCiphertextProofData {
 
         Ok(ZeroCiphertextProofData { context, proof })
     }
+
+    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = toBytes))]
+    pub fn to_bytes(&self) -> Box<[u8]> {
+        bytes_of(self).into()
+    }
 }
 
 impl ZkProofData<ZeroCiphertextProofContext> for ZeroCiphertextProofData {