Expand description
§curvy-wasm
wasm-bindgen exports for curvy-core: Poseidon, seed-backed and direct-scalar
BabyJubjub signing, note encryption and commitments, Merkle trees, witness-input
builders, and stealth addressing.
This crate is the JavaScript binding for core cryptography and tree operations.
Groth16 proving is emitted as a separate WASM module by curvy-prover, allowing
applications to ship only the functionality they use.
§Build
Use the workspace scripts rather than invoking wasm-bindgen manually:
scripts/build.sh wasm-nodejs
scripts/build.sh wasm-web
scripts/build.sh wasm-bundler
scripts/build.sh wasm-web-threadsPortable builds are single-threaded. The threaded browser build exports
initThreadPool(n), requires cross-origin isolation, and uses n as this
module’s worker-pool size.
The generated TypeScript declarations are the JavaScript API reference for each concrete output package. Rust item documentation on docs.rs/curvy-wasm describes the underlying wasm-bindgen exports and boundary validation.
Both signing profiles are supported:
| JavaScript API | Profile |
|---|---|
pubFromPrivateKey, sign | Seed-backed BLAKE-512/prune derivation |
pubFromScalar, signWithScalar, verifyScalarSignature | Checked direct-scalar derivation |
See the workspace guide for exact output directories, per-target requirements, and worker-budget configuration.
§Boundary conventions
Seed-backed and direct-scalar signing are both supported. Scalar crypto
operations cross the boundary as decimal strings (and Vec<String> for
points / signatures), matching every existing TS wire shape.
Bulk Merkle operations instead use concatenated canonical 32-byte field
elements so thousands of nodes stay inside wasm.
Field-element inputs reduce mod the field (fr_from_dec); raw 256-bit inputs
(cipher key material, EdDSA message, sha256BigInt) are parsed without
reduction (dec_to_biguint) - see the core crate for why.
Structs§
- Scan
Match - One
scancandidate:indexinto the input arrays + the derived keys. - Viewer
Match - One
viewer_scancandidate:index+ the derived spending PUBLIC key. - Wasm
Completed Shard - Wasm
Frontier Append - Wasm
Inclusion Proof - Wasm
Merkle Tree - Generic incremental Merkle tree with a reverse leaf index.
- Wasm
Notes Frontier - Constant-space append frontier. It retains no leaves or witnesses and emits a shard descriptor only at an exact boundary.
- Wasm
Ordered Merkle Tree - Position-addressed tree for public vectors whose values may repeat.
- Wasm
Owned Note Witness - Wasm
Sharded Notes Tree - Rust-owned sharded notes tree. Field elements cross this bulk boundary as canonical packed 32-byte big-endian values, avoiding one JS↔wasm call and one decimal-string allocation per Poseidon node.
Functions§
- dbg_
is_ valid_ bn254_ point - dbg_
is_ valid_ secp256k1_ point - decrypt_
amount_ token_ wasm - Decrypt
(encryptedAmount, encryptedToken)->[amount, token]. - encrypt_
amount_ token_ wasm - Encrypt
(amount, token)->[encryptedAmount, encryptedToken]. - ephemeral_
pub_ key_ wasm - Ephemeral public key
R = scalar · Base8as[x, y](ephemeralPubKey). - get_
meta - Public meta-keys
[k, v, K, V]for the given private spend (k) / view (v) keys. Throws on degenerate keys (zero reduction). - new_
meta - Fresh random meta-keys
[k, v, K, V]= spend priv, view priv, spend pub, view pub. - note_id
id = Poseidon([ownerHash, amount, token]).- notes_
shard_ height - notes_
shard_ size - notes_
tree_ depth - Protocol notes-tree parameters, exported so JavaScript consumers read them from the core rather than hardcoding a second copy.
- notes_
tree_ version - nullifier
nullifier = Poseidon([sharedSecret, pub.x, pub.y]).- owner_
hash ownerHash = Poseidon([pub.x, pub.y, sharedSecret]).- poseidon
- Poseidon hash of
1..=16decimal field elements. - pub_
from_ private_ key - BabyJubjub public key
[x, y]from a hex private key (pubFromPrivateKey). - pub_
from_ scalar - BabyJubJub public key
[x, y] = scalar * Base8from a canonical subgroup scalar. This path performs no seed hashing, pruning, or clamping. - scan
- Recipient scan → the SPARSE list of tag-matching announcements, in input
order: each match carries its
indexinto the input arrays plus the derived one-time keys. Matches are CANDIDATES (1-byte viewTag ⇒ ~1/256 false positives) - the caller’s note-commitment recompute confirms ownership. Malformed / off-curve announcements are non-matches (skipped), never fatal; throws only on the caller’s own inputs (keys, mismatched array lengths). - send
- Announce a payment to recipient
(K, V)→[r, R, viewTag, spendingPubKey]. Throws on malformed / off-curve recipient keys (an unspendable announcement must never be produced). - sha256_
bigint sha256BigInt: raw 256-bit decimal inputs -> decimal digest (no field reduction).- sign
- EdDSA-Poseidon signature
[R8.x, R8.y, S](sign). - sign_
with_ scalar - Curvy-compatible direct-scalar signature
[R8.x, R8.y, S]from a canonical BabyJubjub subgroup scalar and canonical BN254 field message. - verify_
merkle_ proof - Verify a packed conventional inclusion proof without reimplementing Poseidon/path ordering in JavaScript.
- verify_
scalar_ signature - Verify a scalar-native Curvy signature. Malformed or non-canonical boundary
values throw; a well-formed but invalid signature returns
false. - version
- viewer_
scan - Viewer scan (view key
v+ recipient spend pubK, no spend key): the same sparse candidate list, spending PUBLIC keys only.