@rolly-dev/wasm-signer 0.9.1 → 0.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,115 @@
1
+ # @rolly-dev/wasm-signer
2
+
3
+ Client-side Poseidon2 hashing and bet authentication for the Rolly ZK-Rollup casino.
4
+
5
+ Built with Rust → WebAssembly (via `wasm-pack`), using the same Poseidon2 hasher
6
+ and Goldilocks field as the plonky2 proving circuit.
7
+
8
+ ## Build
9
+
10
+ ```bash
11
+ # requires: cargo, wasm-pack
12
+ npm run build
13
+ # → dist/node/ (Node.js, CJS, sync init)
14
+ # → dist/web/ (Browser, ESM, async init)
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ### Node.js (CommonJS)
20
+
21
+ ```javascript
22
+ const {
23
+ poseidon2_hash,
24
+ derive_session_key,
25
+ session_public_key,
26
+ create_bet_auth,
27
+ } = require('@rolly-dev/wasm-signer');
28
+
29
+ const hash = poseidon2_hash(BigUint64Array.from([1n, 2n, 3n]));
30
+ // → BigUint64Array(4)
31
+ ```
32
+
33
+ ### Node.js (ESM)
34
+
35
+ ```javascript
36
+ import {
37
+ poseidon2_hash,
38
+ derive_session_key,
39
+ create_bet_auth,
40
+ } from '@rolly-dev/wasm-signer';
41
+
42
+ const hash = poseidon2_hash(BigUint64Array.from([1n, 2n, 3n]));
43
+ ```
44
+
45
+ ### React
46
+
47
+ ```jsx
48
+ import { useRollyWasm } from '@rolly-dev/wasm-signer/react';
49
+
50
+ function BetButton({ sessionKey, amount, nonce }) {
51
+ const { ready, create_bet_auth } = useRollyWasm();
52
+
53
+ if (!ready) return <span>Loading...</span>;
54
+
55
+ const handleBet = () => {
56
+ const auth = create_bet_auth(sessionKey, BigInt(amount), BigInt(nonce));
57
+ // send auth to server...
58
+ };
59
+
60
+ return <button onClick={handleBet}>Place Bet</button>;
61
+ }
62
+ ```
63
+
64
+ ### Browser (vanilla ESM)
65
+
66
+ ```html
67
+ <script type="module">
68
+ import { init, poseidon2_hash } from '@rolly-dev/wasm-signer';
69
+
70
+ await init(); // loads .wasm, must be called once
71
+ const h = poseidon2_hash(BigUint64Array.from([1n, 2n]));
72
+ </script>
73
+ ```
74
+
75
+ ### Manual init (advanced)
76
+
77
+ ```javascript
78
+ import init, { poseidon2_hash } from '@rolly-dev/wasm-signer/init';
79
+
80
+ // custom wasm URL or ArrayBuffer
81
+ await init('/assets/rolly_wasm_signer_bg.wasm');
82
+ poseidon2_hash(BigUint64Array.from([1n]));
83
+ ```
84
+
85
+ ## API
86
+
87
+ | Function | Input | Output | Description |
88
+ |----------------------------|--------------------------------|-------------------|------------------------------------------------|
89
+ | `poseidon2_hash` | `BigUint64Array` | `BigUint64Array(4)` | Hash N field elements |
90
+ | `poseidon2_two_to_one` | `BigUint64Array(4)` × 2 | `BigUint64Array(4)` | Merkle hash: H(left‖right) |
91
+ | `derive_session_key` | `Uint8Array(32)` | `BigUint64Array(4)` | MetaMask sig → session key |
92
+ | `session_public_key` | `BigUint64Array(4)` | `BigUint64Array(4)` | session_pk = H(session_key) |
93
+ | `create_bet_auth` | `(BigUint64Array(4), bigint, bigint)` | `BigUint64Array(4)` | MAC = H(sk‖amount_lo‖amount_hi‖nonce) |
94
+ | `compute_server_seed_hash` | `BigUint64Array(8)` | `BigUint64Array(4)` | Full hash of server seed |
95
+ | `seed_hash_truncated` | `BigUint64Array(8)` | `BigUint64Array(2)` | First 2 elements (circuit leaf format) |
96
+ | `goldilocks_modulus` | — | `bigint` | Returns p = 2^64 - 2^32 + 1 |
97
+ | `goldilocks_reduce` | `bigint` | `bigint` | Reduce mod p |
98
+
99
+ ## Bundler notes
100
+
101
+ **Vite** — add to `optimizeDeps.exclude`:
102
+ ```js
103
+ optimizeDeps: { exclude: ['@rolly-dev/wasm-signer'] }
104
+ ```
105
+
106
+ **Webpack 5** — enable WASM experiments:
107
+ ```js
108
+ module.exports = { experiments: { asyncWebAssembly: true } };
109
+ ```
110
+
111
+ **Next.js** — conditional exports auto-resolve: Node.js entry on server, browser entry on client.
112
+
113
+ ## License
114
+
115
+ MIT
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,302 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * Split a u64 amount into (lo, hi) u32 pair matching the circuit representation.
6
+ *
7
+ * Returns `[amount_lo, amount_hi]` as a `Uint32Array` of length 2.
8
+ *
9
+ * ```js
10
+ * const [lo, hi] = amount_split(123456789n);
11
+ * ```
12
+ */
13
+ export function amount_split(amount: bigint): Uint32Array;
14
+
15
+ /**
16
+ * Compute address_hash = Poseidon2(addr_byte_0, ..., addr_byte_19).
17
+ * Takes a hex address string (with or without 0x prefix), returns [u64; 4].
18
+ */
19
+ export function compute_address_hash(address_hex: string): BigUint64Array;
20
+
21
+ /**
22
+ * Full Poseidon2 hash of an 8-element server seed.
23
+ *
24
+ * Returns all 4 hash elements. Note: the circuit stores only the
25
+ * **first 2 elements** as the leaf commitment (see `seed_hash_truncated`).
26
+ * This full variant is useful for client-side verification where all
27
+ * 4 elements may be needed.
28
+ *
29
+ * `server_seed` must be exactly 8 elements.
30
+ */
31
+ export function compute_server_seed_hash(server_seed: BigUint64Array): BigUint64Array;
32
+
33
+ /**
34
+ * Compute the transaction message hash (for debugging / verification).
35
+ *
36
+ * Returns `BigUint64Array` of length 4 — the same hash the circuit computes.
37
+ *
38
+ * ```js
39
+ * const hash = compute_tx_msg_hash(5, userId, 0, amountLo, amountHi);
40
+ * ```
41
+ */
42
+ export function compute_tx_msg_hash(tx_type: number, user_id: number, currency_id: number, amount_lo: number, amount_hi: number, session_expiry: bigint): BigUint64Array;
43
+
44
+ /**
45
+ * Create a `bet_auth` MAC that proves the user authorized this specific bet.
46
+ *
47
+ * ```text
48
+ * bet_auth = Poseidon2(
49
+ * session_key[0..4], // 4 field elements (private)
50
+ * amount_lo, // lower 32 bits of bet_amount
51
+ * amount_hi, // upper 32 bits of bet_amount
52
+ * nonce, // monotonic counter, prevents replay
53
+ * )
54
+ * ```
55
+ *
56
+ * The circuit verifies two things:
57
+ * 1. `session_pk == Poseidon2(session_key)` — knowledge of key
58
+ * 2. `bet_auth == Poseidon2(session_key ‖ amount_lo ‖ amount_hi ‖ nonce)`
59
+ *
60
+ * The lo/hi split matches `src/circuit/main_circuit.rs` witness assignment:
61
+ * `amount as u32` / `(amount >> 32) as u32`, both via `from_canonical_u32`.
62
+ *
63
+ * **Parameters**
64
+ * - `session_key` : 4 × u64 (private, from `derive_session_key`)
65
+ * - `bet_amount` : u64 (in smallest currency units)
66
+ * - `nonce` : u64 (incrementing per-session counter)
67
+ *
68
+ * **Returns**: 4 × u64 (`bet_auth` hash)
69
+ */
70
+ export function create_bet_auth(session_key: BigUint64Array, bet_amount: bigint, nonce: bigint): BigUint64Array;
71
+
72
+ /**
73
+ * Derive a session key from 32 bytes of entropy (e.g. MetaMask signature).
74
+ *
75
+ * **Algorithm**: split 32 bytes into 4 × 8 bytes, interpret each chunk as
76
+ * little-endian u64, reduce mod p, then hash:
77
+ * `session_key = Poseidon2(reduced_chunks)`
78
+ *
79
+ * The reduction via `from_noncanonical_u64` is necessary because raw
80
+ * signature bytes can produce values >= p.
81
+ *
82
+ * ```js
83
+ * const sig = ethers.getBytes(metaMaskSignature).slice(0, 32);
84
+ * const sk = derive_session_key(new Uint8Array(sig));
85
+ * // sk.length === 4
86
+ * ```
87
+ */
88
+ export function derive_session_key(sig_bytes: Uint8Array): BigUint64Array;
89
+
90
+ /**
91
+ * Generate a random user seed — 10 alphanumeric characters.
92
+ *
93
+ * Uses `getrandom` (backed by `crypto.getRandomValues` in the browser
94
+ * and OS entropy on Node.js) for cryptographically secure randomness.
95
+ *
96
+ * ```js
97
+ * const seed = generate_user_seed();
98
+ * // e.g. "k7Qm2xW9aB"
99
+ * ```
100
+ */
101
+ export function generate_user_seed(): string;
102
+
103
+ /**
104
+ * Convert any Goldilocks field elements to a hex string.
105
+ *
106
+ * Each u64 is encoded as 8 little-endian bytes → 16 hex chars.
107
+ * For 4 elements: 64 hex chars (32 bytes).
108
+ *
109
+ * ```js
110
+ * const hex = goldilocks_fields_to_hex(BigUint64Array.from([1n, 2n, 3n, 4n]));
111
+ * ```
112
+ */
113
+ export function goldilocks_fields_to_hex(fields: BigUint64Array): string;
114
+
115
+ /**
116
+ * Returns the Goldilocks prime: p = 2^64 - 2^32 + 1.
117
+ */
118
+ export function goldilocks_modulus(): bigint;
119
+
120
+ /**
121
+ * Reduce an arbitrary u64 to its canonical representative mod p.
122
+ *
123
+ * Values already < p are returned unchanged. Values >= p are reduced.
124
+ * This uses `from_noncanonical_u64` internally (no panic on large values).
125
+ */
126
+ export function goldilocks_reduce(value: bigint): bigint;
127
+
128
+ /**
129
+ * Poseidon2 hash of an arbitrary number of Goldilocks field elements.
130
+ *
131
+ * Mirrors `builder.hash_n_to_hash_no_pad::<Poseidon2Hash>(...)` inside
132
+ * the circuit and `Poseidon2Hash::hash_no_pad` in `src/block_builder`.
133
+ *
134
+ * **Input** : `BigUint64Array` — each element must be < `GOLDILOCKS_P`.
135
+ * **Output**: `BigUint64Array` of length 4 (one `HashOut`).
136
+ *
137
+ * ```js
138
+ * const h = poseidon2_hash(BigUint64Array.from([1n, 2n, 3n]));
139
+ * // h.length === 4
140
+ * ```
141
+ */
142
+ export function poseidon2_hash(input: BigUint64Array): BigUint64Array;
143
+
144
+ /**
145
+ * Merkle-tree hash: Poseidon2(left[4] ‖ right[4]).
146
+ *
147
+ * Identical to `poseidon_hash(left, right)` in `src/merkletree/hash.rs`.
148
+ * Input ordering is critical — `left` concatenated before `right`.
149
+ *
150
+ * Both arrays **must** have exactly 4 elements (one `HashOut` each).
151
+ */
152
+ export function poseidon2_two_to_one(left: BigUint64Array, right: BigUint64Array): BigUint64Array;
153
+
154
+ /**
155
+ * Derive a Schnorr secret key from entropy bytes (e.g. MetaMask signature).
156
+ *
157
+ * Takes at least 32 bytes, uses `Scalar::decode_reduce` to map them into
158
+ * the ECgFp5 scalar field. Returns hex-encoded secret key (80 chars = 40 bytes).
159
+ *
160
+ * ```js
161
+ * const skHex = schnorr_keygen(sigBytes.slice(0, 32));
162
+ * ```
163
+ */
164
+ export function schnorr_keygen(entropy: Uint8Array): string;
165
+
166
+ /**
167
+ * Get the w-encoding of a public key as 5 Goldilocks field elements (for circuit witness).
168
+ *
169
+ * Returns `BigUint64Array` of length 5.
170
+ *
171
+ * ```js
172
+ * const encode = schnorr_pk_encode(pkHex);
173
+ * // encode.length === 5
174
+ * ```
175
+ */
176
+ export function schnorr_pk_encode(pk_hex: string): BigUint64Array;
177
+
178
+ /**
179
+ * Compute pk_hash = Poseidon2(w_encoding[5]) from a hex-encoded public key.
180
+ *
181
+ * The w-encoding is the 40-byte (80 hex) representation returned by `schnorr_pubkey`.
182
+ * pk_hash is stored in the Merkle tree to bind the Schnorr key to an account.
183
+ *
184
+ * Returns `BigUint64Array` of length 4.
185
+ *
186
+ * ```js
187
+ * const pkHash = schnorr_pk_hash(pkHex);
188
+ * ```
189
+ */
190
+ export function schnorr_pk_hash(pk_hex: string): BigUint64Array;
191
+
192
+ /**
193
+ * Compute pk_hash as a hex string (for convenience).
194
+ *
195
+ * ```js
196
+ * const pkHashHex = schnorr_pk_hash_hex(pkHex);
197
+ * ```
198
+ */
199
+ export function schnorr_pk_hash_hex(pk_hex: string): string;
200
+
201
+ /**
202
+ * Compute the Schnorr public key from a hex-encoded secret key.
203
+ *
204
+ * Returns hex-encoded w-encoding of the ECgFp5 point (80 chars = 40 bytes).
205
+ *
206
+ * ```js
207
+ * const pkHex = schnorr_pubkey(skHex);
208
+ * ```
209
+ */
210
+ export function schnorr_pubkey(sk_hex: string): string;
211
+
212
+ /**
213
+ * Sign a ChangePubKey (tx_type=9) transaction in (s, e) format.
214
+ *
215
+ * msg_hash = Poseidon2(9, user_id, new_pk_hash[0..4])
216
+ *
217
+ * The old key signs this message to authorize key rotation.
218
+ *
219
+ * Returns a JS object: `{ pubkey: "hex", sig_s: "hex", sig_e: "hex" }`
220
+ *
221
+ * ```js
222
+ * const sig = schnorr_sign_cpk(oldSkHex, userId, newPkHashArray);
223
+ * ```
224
+ */
225
+ export function schnorr_sign_cpk(old_sk_hex: string, user_id: number, new_pk_hash: BigUint64Array): any;
226
+
227
+ /**
228
+ * Sign a transaction with Schnorr (ECgFp5) in (s, e) format.
229
+ *
230
+ * msg_hash = Poseidon2(tx_type, user_id, currency_id, amount_lo, amount_hi)
231
+ *
232
+ * Returns a JS object: `{ pubkey: "hex", sig_s: "hex", sig_e: "hex" }`
233
+ *
234
+ * ```js
235
+ * const sig = schnorr_sign_tx(skHex, 5, userId, 0, amountLo, amountHi);
236
+ * // sig.pubkey (80 hex), sig.sig_s (80 hex), sig.sig_e (80 hex)
237
+ * ```
238
+ */
239
+ export function schnorr_sign_tx(sk_hex: string, tx_type: number, user_id: number, currency_id: number, amount_lo: number, amount_hi: number, session_expiry: bigint): any;
240
+
241
+ /**
242
+ * Verify a Schnorr signature (s, e) for a transaction.
243
+ *
244
+ * Algorithm: R_v = s·G + e·pk, e_v = H(R_v‖pk‖msg), check e == e_v.
245
+ *
246
+ * Returns `true` if signature is valid, `false` otherwise.
247
+ *
248
+ * ```js
249
+ * const ok = schnorr_verify_tx(pubkeyHex, sigSHex, sigEHex, 5, userId, 0, amountLo, amountHi);
250
+ * ```
251
+ */
252
+ export function schnorr_verify_tx(pk_hex: string, sig_s_hex: string, sig_e_hex: string, tx_type: number, user_id: number, currency_id: number, amount_lo: number, amount_hi: number, session_expiry: bigint): boolean;
253
+
254
+ /**
255
+ * Truncated seed hash — first 2 elements of `Poseidon2(server_seed)`.
256
+ *
257
+ * This is the exact format stored in the Merkle-tree leaf and verified
258
+ * by the circuit. Matches `seed_hash_truncated` in
259
+ * `src/block_builder/builder.rs` and `src/circuit/main_circuit.rs`.
260
+ *
261
+ * Returns `BigUint64Array` of length 2: `[h[0], h[1]]`.
262
+ */
263
+ export function seed_hash_truncated(server_seed: BigUint64Array): BigUint64Array;
264
+
265
+ /**
266
+ * Compute the public key for a session: `session_pk = Poseidon2(session_key)`.
267
+ *
268
+ * The public key is stored in the user-asset Merkle leaf and verified
269
+ * inside the circuit (the prover must know the preimage `session_key`).
270
+ *
271
+ * `session_key` must be exactly 4 elements (output of `derive_session_key`).
272
+ */
273
+ export function session_public_key(session_key: BigUint64Array): BigUint64Array;
274
+
275
+ /**
276
+ * Convert a user seed string to 4 Goldilocks field elements.
277
+ *
278
+ * `SHA-256(str)` → split into 4 × 8 LE bytes → reduce each mod p.
279
+ *
280
+ * This matches the backend's `stringToUserSeed` and produces the exact
281
+ * field elements used in the provably-fair random computation:
282
+ * `random = Poseidon2(server_seed ‖ user_seed)`
283
+ *
284
+ * ```js
285
+ * const fields = string_to_user_seed("my-seed-123");
286
+ * // fields.length === 4, each < GOLDILOCKS_P
287
+ * ```
288
+ */
289
+ export function string_to_user_seed(input: string): BigUint64Array;
290
+
291
+ /**
292
+ * Convert a user seed string directly to a hex representation.
293
+ *
294
+ * Equivalent to `goldiLocksFieldsToHex(stringToUserSeed(str))`.
295
+ * Returns a 64-character lowercase hex string (32 bytes).
296
+ *
297
+ * ```js
298
+ * const hex = string_to_user_seed_hex("my-seed-123");
299
+ * // hex === "a1b2c3..." (64 chars)
300
+ * ```
301
+ */
302
+ export function string_to_user_seed_hex(input: string): string;