Skip to content

Commit b39a976

Browse files
[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
1 parent 9e831dc commit b39a976

26 files changed

+409
-4
lines changed

zk-sdk/src/encryption/elgamal.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ impl ElGamalKeypair {
163163
ElGamal::keygen()
164164
}
165165

166+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = pubkeyOwned))]
166167
pub fn pubkey_owned(&self) -> ElGamalPubkey {
167168
self.public
168169
}
@@ -371,6 +372,19 @@ impl ElGamalPubkey {
371372
}
372373
}
373374

375+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
376+
impl ElGamalPubkey {
377+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = encryptU64))]
378+
pub fn encrypt_u64(&self, amount: u64) -> ElGamalCiphertext {
379+
ElGamal::encrypt(self, amount)
380+
}
381+
382+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = encryptWithU64))]
383+
pub fn encrypt_with_u64(&self, amount: u64, opening: &PedersenOpening) -> ElGamalCiphertext {
384+
ElGamal::encrypt_with(amount, self, opening)
385+
}
386+
}
387+
374388
#[cfg(not(target_arch = "wasm32"))]
375389
impl EncodableKey for ElGamalPubkey {
376390
fn read<R: Read>(reader: &mut R) -> Result<Self, Box<dyn error::Error>> {

zk-sdk/src/encryption/grouped_elgamal.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
1515
#[cfg(not(target_arch = "wasm32"))]
1616
use crate::encryption::{discrete_log::DiscreteLog, elgamal::ElGamalSecretKey};
17+
#[cfg(target_arch = "wasm32")]
18+
pub use grouped_elgamal_wasm::*;
19+
#[cfg(target_arch = "wasm32")]
20+
use wasm_bindgen::prelude::*;
1721
use {
1822
crate::{
1923
encryption::{
@@ -216,6 +220,51 @@ impl<const N: usize> GroupedElGamalCiphertext<N> {
216220
}
217221
}
218222

223+
// Define specific grouped ElGamal ciphertext types for 2 and 3 handles since
224+
// `wasm_bindgen` do not yet support the export of types that take on generic
225+
// type parameters.
226+
#[cfg(target_arch = "wasm32")]
227+
mod grouped_elgamal_wasm {
228+
use super::*;
229+
230+
#[wasm_bindgen]
231+
pub struct GroupedElGamalCiphertext2Handles(pub(crate) GroupedElGamalCiphertext<2>);
232+
233+
#[wasm_bindgen]
234+
impl GroupedElGamalCiphertext2Handles {
235+
#[wasm_bindgen(js_name = encryptU64)]
236+
pub fn encrypt_u64(
237+
first_pubkey: &ElGamalPubkey,
238+
second_pubkey: &ElGamalPubkey,
239+
amount: u64,
240+
) -> Self {
241+
Self(GroupedElGamal::<2>::encrypt(
242+
[first_pubkey, second_pubkey],
243+
amount,
244+
))
245+
}
246+
}
247+
248+
#[wasm_bindgen]
249+
pub struct GroupedElGamalCiphertext3Handles(pub(crate) GroupedElGamalCiphertext<3>);
250+
251+
#[wasm_bindgen]
252+
impl GroupedElGamalCiphertext3Handles {
253+
#[wasm_bindgen(js_name = encryptU64)]
254+
pub fn encrypt_u64(
255+
first_pubkey: &ElGamalPubkey,
256+
second_pubkey: &ElGamalPubkey,
257+
third_pubkey: &ElGamalPubkey,
258+
amount: u64,
259+
) -> Self {
260+
Self(GroupedElGamal::<3>::encrypt(
261+
[first_pubkey, second_pubkey, third_pubkey],
262+
amount,
263+
))
264+
}
265+
}
266+
}
267+
219268
#[cfg(test)]
220269
mod tests {
221270
use {super::*, crate::encryption::elgamal::ElGamalKeypair};

zk-sdk/src/encryption/pedersen.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ lazy_static::lazy_static! {
2828
}
2929

3030
/// Algorithm handle for the Pedersen commitment scheme.
31+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
3132
pub struct Pedersen;
3233
impl Pedersen {
3334
/// On input a message (numeric amount), the function returns a Pedersen commitment of the
@@ -62,12 +63,30 @@ impl Pedersen {
6263
}
6364
}
6465

66+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
67+
impl Pedersen {
68+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = withU64))]
69+
pub fn with_u64(amount: u64, opening: &PedersenOpening) -> PedersenCommitment {
70+
Pedersen::with(amount, opening)
71+
}
72+
}
73+
6574
/// Pedersen opening type.
6675
///
6776
/// Instances of Pedersen openings are zeroized on drop.
77+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
6878
#[derive(Clone, Debug, Default, Serialize, Deserialize, Zeroize)]
6979
#[zeroize(drop)]
7080
pub struct PedersenOpening(Scalar);
81+
82+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
83+
impl PedersenOpening {
84+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen(js_name = newRand))]
85+
pub fn new_rand() -> Self {
86+
PedersenOpening(Scalar::random(&mut OsRng))
87+
}
88+
}
89+
7190
impl PedersenOpening {
7291
pub fn new(scalar: Scalar) -> Self {
7392
Self(scalar)
@@ -77,10 +96,6 @@ impl PedersenOpening {
7796
&self.0
7897
}
7998

80-
pub fn new_rand() -> Self {
81-
PedersenOpening(Scalar::random(&mut OsRng))
82-
}
83-
8499
pub fn as_bytes(&self) -> &[u8; PEDERSEN_OPENING_LEN] {
85100
self.0.as_bytes()
86101
}

zk-sdk/src/encryption/pod/grouped_elgamal.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
33
#[cfg(not(target_os = "solana"))]
44
use crate::encryption::grouped_elgamal::GroupedElGamalCiphertext;
5+
#[cfg(target_arch = "wasm32")]
6+
use wasm_bindgen::prelude::*;
57
use {
68
crate::{
79
encryption::{
@@ -69,6 +71,7 @@ const GROUPED_ELGAMAL_CIPHERTEXT_3_HANDLES: usize =
6971
PEDERSEN_COMMITMENT_LEN + DECRYPT_HANDLE_LEN + DECRYPT_HANDLE_LEN + DECRYPT_HANDLE_LEN;
7072

7173
/// The `GroupedElGamalCiphertext` type with two decryption handles as a `Pod`
74+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
7275
#[derive(Clone, Copy, bytemuck_derive::Pod, bytemuck_derive::Zeroable, PartialEq, Eq)]
7376
#[repr(transparent)]
7477
pub struct PodGroupedElGamalCiphertext2Handles(
@@ -123,6 +126,7 @@ impl TryFrom<PodGroupedElGamalCiphertext2Handles> for GroupedElGamalCiphertext<2
123126
impl_extract!(TYPE = PodGroupedElGamalCiphertext2Handles);
124127

125128
/// The `GroupedElGamalCiphertext` type with three decryption handles as a `Pod`
129+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
126130
#[derive(Clone, Copy, bytemuck_derive::Pod, bytemuck_derive::Zeroable, PartialEq, Eq)]
127131
#[repr(transparent)]
128132
pub struct PodGroupedElGamalCiphertext3Handles(

zk-sdk/src/encryption/pod/pedersen.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Plain Old Data type for the Pedersen commitment scheme.
22
3+
#[cfg(target_arch = "wasm32")]
4+
use wasm_bindgen::prelude::*;
35
#[cfg(not(target_os = "solana"))]
46
use {
57
crate::{encryption::pedersen::PedersenCommitment, errors::ElGamalError},
@@ -19,6 +21,7 @@ use {
1921
const PEDERSEN_COMMITMENT_MAX_BASE64_LEN: usize = 44;
2022

2123
/// The `PedersenCommitment` type as a `Pod`.
24+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
2225
#[derive(Clone, Copy, Default, Pod, Zeroable, PartialEq, Eq)]
2326
#[repr(transparent)]
2427
pub struct PodPedersenCommitment(pub(crate) [u8; PEDERSEN_COMMITMENT_LEN]);

zk-sdk/src/pod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ impl From<PodU16> for u16 {
1414
}
1515
}
1616

17+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)]
1718
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Pod, Zeroable)]
1819
#[repr(transparent)]
1920
pub struct PodU64([u8; 8]);

zk-sdk/src/sigma_proofs/batched_grouped_ciphertext_validity/handles_2.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use crate::encryption::{
1313
elgamal::{DecryptHandle, ElGamalPubkey},
1414
pedersen::{PedersenCommitment, PedersenOpening},
1515
};
16+
#[cfg(target_arch = "wasm32")]
17+
use wasm_bindgen::prelude::*;
1618
use {
1719
crate::{
1820
sigma_proofs::{
@@ -34,6 +36,7 @@ use {
3436
/// first_handle_0, second_handle_0)` and `(commitment_1, first_handle_1,
3537
/// second_handle_1)`. The proof certifies the analogous decryptable properties for each one of
3638
/// these pairs of commitment and decryption handles.
39+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
3740
#[allow(non_snake_case)]
3841
#[derive(Clone)]
3942
pub struct BatchedGroupedCiphertext2HandlesValidityProof(GroupedCiphertext2HandlesValidityProof);

zk-sdk/src/sigma_proofs/batched_grouped_ciphertext_validity/handles_3.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ use crate::encryption::{
1717
elgamal::{DecryptHandle, ElGamalPubkey},
1818
pedersen::{PedersenCommitment, PedersenOpening},
1919
};
20+
#[cfg(target_arch = "wasm32")]
21+
use wasm_bindgen::prelude::*;
2022
use {
2123
crate::{
2224
sigma_proofs::{
@@ -35,6 +37,7 @@ use {
3537
const BATCHED_GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_LEN: usize = UNIT_LEN * 6;
3638

3739
/// Batched grouped ciphertext validity proof with two handles.
40+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
3841
#[allow(non_snake_case)]
3942
#[derive(Clone)]
4043
pub struct BatchedGroupedCiphertext3HandlesValidityProof(GroupedCiphertext3HandlesValidityProof);

zk-sdk/src/sigma_proofs/ciphertext_ciphertext_equality.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
//! The protocol guarantees computational soundness (by the hardness of discrete log) and perfect
44
//! zero-knowledge in the random oracle model.
55
6+
#[cfg(target_arch = "wasm32")]
7+
use wasm_bindgen::prelude::*;
68
#[cfg(not(target_os = "solana"))]
79
use {
810
crate::{
@@ -36,6 +38,7 @@ const CIPHERTEXT_CIPHERTEXT_EQUALITY_PROOF_LEN: usize = UNIT_LEN * 7;
3638
/// The ciphertext-ciphertext equality proof.
3739
///
3840
/// Contains all the elliptic curve and scalar components that make up the sigma protocol.
41+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
3942
#[allow(non_snake_case)]
4043
#[derive(Clone)]
4144
pub struct CiphertextCiphertextEqualityProof {

zk-sdk/src/sigma_proofs/ciphertext_commitment_equality.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
//! The protocol guarantees computationally soundness (by the hardness of discrete log) and perfect
99
//! zero-knowledge in the random oracle model.
1010
11+
#[cfg(target_arch = "wasm32")]
12+
use wasm_bindgen::prelude::*;
1113
#[cfg(not(target_os = "solana"))]
1214
use {
1315
crate::{
@@ -41,6 +43,7 @@ const CIPHERTEXT_COMMITMENT_EQUALITY_PROOF_LEN: usize = UNIT_LEN * 6;
4143
/// Equality proof.
4244
///
4345
/// Contains all the elliptic curve and scalar components that make up the sigma protocol.
46+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
4447
#[allow(non_snake_case)]
4548
#[derive(Clone)]
4649
pub struct CiphertextCommitmentEqualityProof {

zk-sdk/src/sigma_proofs/grouped_ciphertext_validity/handles_2.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
//! The protocol guarantees computational soundness (by the hardness of discrete log) and perfect
99
//! zero-knowledge in the random oracle model.
1010
11+
#[cfg(target_arch = "wasm32")]
12+
use wasm_bindgen::prelude::*;
1113
#[cfg(not(target_os = "solana"))]
1214
use {
1315
crate::{
@@ -41,6 +43,7 @@ const GROUPED_CIPHERTEXT_2_HANDLES_VALIDITY_PROOF_LEN: usize = UNIT_LEN * 5;
4143
/// The grouped ciphertext validity proof for 2 handles.
4244
///
4345
/// Contains all the elliptic curve and scalar components that make up the sigma protocol.
46+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
4447
#[allow(non_snake_case)]
4548
#[derive(Clone)]
4649
pub struct GroupedCiphertext2HandlesValidityProof {

zk-sdk/src/sigma_proofs/grouped_ciphertext_validity/handles_3.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
//! The protocol guarantees computational soundness (by the hardness of discrete log) and perfect
99
//! zero-knowledge in the random oracle model.
1010
11+
#[cfg(target_arch = "wasm32")]
12+
use wasm_bindgen::prelude::*;
1113
#[cfg(not(target_os = "solana"))]
1214
use {
1315
crate::{
@@ -41,6 +43,7 @@ const GROUPED_CIPHERTEXT_3_HANDLES_VALIDITY_PROOF_LEN: usize = UNIT_LEN * 6;
4143
/// The grouped ciphertext validity proof for 3 handles.
4244
///
4345
/// Contains all the elliptic curve and scalar components that make up the sigma protocol.
46+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
4447
#[allow(non_snake_case)]
4548
#[derive(Clone)]
4649
pub struct GroupedCiphertext3HandlesValidityProof {

zk-sdk/src/sigma_proofs/percentage_with_cap.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
//!
1818
//! [`ZK Token proof program`]: https://docs.solanalabs.com/runtime/zk-token-proof
1919
20+
#[cfg(target_arch = "wasm32")]
21+
use wasm_bindgen::prelude::*;
2022
#[cfg(not(target_os = "solana"))]
2123
use {
2224
crate::{
@@ -52,6 +54,7 @@ const PERCENTAGE_WITH_CAP_PROOF_LEN: usize = UNIT_LEN * 8;
5254
/// then the `percentage_max_proof` is properly generated and `percentage_equality_proof` is
5355
/// simulated. If the encrypted amount is smaller than the maximum cap bound, the
5456
/// `percentage_equality_proof` is properly generated and `percentage_max_proof` is simulated.
57+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
5558
#[derive(Clone)]
5659
pub struct PercentageWithCapProof {
5760
/// Proof that the committed amount equals the maximum cap bound

zk-sdk/src/sigma_proofs/pod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use crate::sigma_proofs::{
1515
pubkey_validity::PubkeyValidityProof,
1616
zero_ciphertext::ZeroCiphertextProof,
1717
};
18+
#[cfg(target_arch = "wasm32")]
19+
use wasm_bindgen::prelude::*;
1820
use {
1921
crate::{
2022
pod::{impl_from_bytes, impl_from_str},
@@ -26,6 +28,7 @@ use {
2628
};
2729

2830
/// The `CiphertextCommitmentEqualityProof` type as a `Pod`.
31+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
2932
#[derive(Clone, Copy)]
3033
#[repr(transparent)]
3134
pub struct PodCiphertextCommitmentEqualityProof(
@@ -68,6 +71,7 @@ impl_from_bytes!(
6871
);
6972

7073
/// The `CiphertextCiphertextEqualityProof` type as a `Pod`.
74+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
7175
#[derive(Clone, Copy)]
7276
#[repr(transparent)]
7377
pub struct PodCiphertextCiphertextEqualityProof(
@@ -110,6 +114,7 @@ impl_from_bytes!(
110114
);
111115

112116
/// The `GroupedCiphertext2HandlesValidityProof` type as a `Pod`.
117+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
113118
#[derive(Clone, Copy)]
114119
#[repr(transparent)]
115120
pub struct PodGroupedCiphertext2HandlesValidityProof(
@@ -152,6 +157,7 @@ impl_from_bytes!(
152157
);
153158

154159
/// The `GroupedCiphertext3HandlesValidityProof` type as a `Pod`.
160+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
155161
#[derive(Clone, Copy)]
156162
#[repr(transparent)]
157163
pub struct PodGroupedCiphertext3HandlesValidityProof(
@@ -194,6 +200,7 @@ impl_from_bytes!(
194200
);
195201

196202
/// The `BatchedGroupedCiphertext2HandlesValidityProof` type as a `Pod`.
203+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
197204
#[derive(Clone, Copy)]
198205
#[repr(transparent)]
199206
pub struct PodBatchedGroupedCiphertext2HandlesValidityProof(
@@ -242,6 +249,7 @@ impl_from_bytes!(
242249
);
243250

244251
/// The `BatchedGroupedCiphertext3HandlesValidityProof` type as a `Pod`.
252+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
245253
#[derive(Clone, Copy)]
246254
#[repr(transparent)]
247255
pub struct PodBatchedGroupedCiphertext3HandlesValidityProof(
@@ -290,6 +298,7 @@ impl_from_bytes!(
290298
);
291299

292300
/// The `ZeroCiphertextProof` type as a `Pod`.
301+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
293302
#[derive(Clone, Copy)]
294303
#[repr(transparent)]
295304
pub struct PodZeroCiphertextProof(pub(crate) [u8; ZERO_CIPHERTEXT_PROOF_LEN]);
@@ -330,6 +339,7 @@ impl_from_bytes!(
330339
);
331340

332341
/// The `PercentageWithCapProof` type as a `Pod`.
342+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
333343
#[derive(Clone, Copy, bytemuck_derive::Pod, bytemuck_derive::Zeroable)]
334344
#[repr(transparent)]
335345
pub struct PodPercentageWithCapProof(pub(crate) [u8; PERCENTAGE_WITH_CAP_PROOF_LEN]);
@@ -370,6 +380,7 @@ impl_from_bytes!(
370380
);
371381

372382
/// The `PubkeyValidityProof` type as a `Pod`.
383+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
373384
#[derive(Clone, Copy, bytemuck_derive::Pod, bytemuck_derive::Zeroable)]
374385
#[repr(transparent)]
375386
pub struct PodPubkeyValidityProof(pub(crate) [u8; PUBKEY_VALIDITY_PROOF_LEN]);

0 commit comments

Comments
 (0)