@rolly-dev/wasm-signer 0.12.0 → 1.0.0

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.
package/README.md CHANGED
@@ -23,7 +23,6 @@ const {
23
23
  poseidon2_hash,
24
24
  derive_session_key,
25
25
  session_public_key,
26
- create_bet_auth,
27
26
  } = require('@rolly-dev/wasm-signer');
28
27
 
29
28
  const hash = poseidon2_hash(BigUint64Array.from([1n, 2n, 3n]));
@@ -36,10 +35,11 @@ const hash = poseidon2_hash(BigUint64Array.from([1n, 2n, 3n]));
36
35
  import {
37
36
  poseidon2_hash,
38
37
  derive_session_key,
39
- create_bet_auth,
38
+ session_public_key,
40
39
  } from '@rolly-dev/wasm-signer';
41
40
 
42
- const hash = poseidon2_hash(BigUint64Array.from([1n, 2n, 3n]));
41
+ const sessionKey = derive_session_key(metamaskSignatureBytes);
42
+ const pkHash = session_public_key(sessionKey, BigInt(expiryTimestamp));
43
43
  ```
44
44
 
45
45
  ### React
@@ -47,17 +47,15 @@ const hash = poseidon2_hash(BigUint64Array.from([1n, 2n, 3n]));
47
47
  ```jsx
48
48
  import { useRollyWasm } from '@rolly-dev/wasm-signer/react';
49
49
 
50
- function BetButton({ sessionKey, amount, nonce }) {
51
- const { ready, create_bet_auth } = useRollyWasm();
50
+ function SessionInfo({ sessionKey, expiry }) {
51
+ const { ready, session_public_key } = useRollyWasm();
52
52
 
53
53
  if (!ready) return <span>Loading...</span>;
54
54
 
55
- const handleBet = () => {
56
- const auth = create_bet_auth(sessionKey, BigInt(amount), BigInt(nonce));
57
- // send auth to server...
58
- };
55
+ const pkHash = session_public_key(sessionKey, BigInt(expiry));
56
+ // register pkHash on-chain via key_register tx...
59
57
 
60
- return <button onClick={handleBet}>Place Bet</button>;
58
+ return <div>Session active until {new Date(Number(expiry) * 1000).toLocaleString()}</div>;
61
59
  }
62
60
  ```
63
61
 
@@ -89,10 +87,9 @@ poseidon2_hash(BigUint64Array.from([1n]));
89
87
  | `poseidon2_hash` | `BigUint64Array` | `BigUint64Array(4)` | Hash N field elements |
90
88
  | `poseidon2_two_to_one` | `BigUint64Array(4)` × 2 | `BigUint64Array(4)` | Merkle hash: H(left‖right) |
91
89
  | `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) |
90
+ | `session_public_key` | `(BigUint64Array(4), bigint)` | `BigUint64Array(4)` | pk_hash = Poseidon2(session_key, expiry) |
94
91
  | `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) |
92
+ | `seed_hash_truncated` | `BigUint64Array(8)` | `BigUint64Array(3)` | First 3 elements (circuit leaf format, 192-bit commitment) |
96
93
  | `goldilocks_modulus` | — | `bigint` | Returns p = 2^64 - 2^32 + 1 |
97
94
  | `goldilocks_reduce` | `bigint` | `bigint` | Reduce mod p |
98
95
 
@@ -23,7 +23,6 @@ const {
23
23
  poseidon2_hash,
24
24
  derive_session_key,
25
25
  session_public_key,
26
- create_bet_auth,
27
26
  } = require('@rolly-dev/wasm-signer');
28
27
 
29
28
  const hash = poseidon2_hash(BigUint64Array.from([1n, 2n, 3n]));
@@ -36,10 +35,11 @@ const hash = poseidon2_hash(BigUint64Array.from([1n, 2n, 3n]));
36
35
  import {
37
36
  poseidon2_hash,
38
37
  derive_session_key,
39
- create_bet_auth,
38
+ session_public_key,
40
39
  } from '@rolly-dev/wasm-signer';
41
40
 
42
- const hash = poseidon2_hash(BigUint64Array.from([1n, 2n, 3n]));
41
+ const sessionKey = derive_session_key(metamaskSignatureBytes);
42
+ const pkHash = session_public_key(sessionKey, BigInt(expiryTimestamp));
43
43
  ```
44
44
 
45
45
  ### React
@@ -47,17 +47,15 @@ const hash = poseidon2_hash(BigUint64Array.from([1n, 2n, 3n]));
47
47
  ```jsx
48
48
  import { useRollyWasm } from '@rolly-dev/wasm-signer/react';
49
49
 
50
- function BetButton({ sessionKey, amount, nonce }) {
51
- const { ready, create_bet_auth } = useRollyWasm();
50
+ function SessionInfo({ sessionKey, expiry }) {
51
+ const { ready, session_public_key } = useRollyWasm();
52
52
 
53
53
  if (!ready) return <span>Loading...</span>;
54
54
 
55
- const handleBet = () => {
56
- const auth = create_bet_auth(sessionKey, BigInt(amount), BigInt(nonce));
57
- // send auth to server...
58
- };
55
+ const pkHash = session_public_key(sessionKey, BigInt(expiry));
56
+ // register pkHash on-chain via key_register tx...
59
57
 
60
- return <button onClick={handleBet}>Place Bet</button>;
58
+ return <div>Session active until {new Date(Number(expiry) * 1000).toLocaleString()}</div>;
61
59
  }
62
60
  ```
63
61
 
@@ -89,10 +87,9 @@ poseidon2_hash(BigUint64Array.from([1n]));
89
87
  | `poseidon2_hash` | `BigUint64Array` | `BigUint64Array(4)` | Hash N field elements |
90
88
  | `poseidon2_two_to_one` | `BigUint64Array(4)` × 2 | `BigUint64Array(4)` | Merkle hash: H(left‖right) |
91
89
  | `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) |
90
+ | `session_public_key` | `(BigUint64Array(4), bigint)` | `BigUint64Array(4)` | pk_hash = Poseidon2(session_key, expiry) |
94
91
  | `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) |
92
+ | `seed_hash_truncated` | `BigUint64Array(8)` | `BigUint64Array(3)` | First 3 elements (circuit leaf format, 192-bit commitment) |
96
93
  | `goldilocks_modulus` | — | `bigint` | Returns p = 2^64 - 2^32 + 1 |
97
94
  | `goldilocks_reduce` | `bigint` | `bigint` | Reduce mod p |
98
95
 
@@ -22,7 +22,7 @@ export function compute_address_hash(address_hex: string): BigUint64Array;
22
22
  * Full Poseidon2 hash of an 8-element server seed.
23
23
  *
24
24
  * Returns all 4 hash elements. Note: the circuit stores only the
25
- * **first 2 elements** as the leaf commitment (see `seed_hash_truncated`).
25
+ * **first 3 elements** as the leaf commitment (see `seed_hash_truncated`).
26
26
  * This full variant is useful for client-side verification where all
27
27
  * 4 elements may be needed.
28
28
  *
@@ -30,45 +30,6 @@ export function compute_address_hash(address_hex: string): BigUint64Array;
30
30
  */
31
31
  export function compute_server_seed_hash(server_seed: BigUint64Array): BigUint64Array;
32
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
33
  /**
73
34
  * Derive a session key from 32 bytes of entropy (e.g. MetaMask signature).
74
35
  *
@@ -126,151 +87,89 @@ export function goldilocks_modulus(): bigint;
126
87
  export function goldilocks_reduce(value: bigint): bigint;
127
88
 
128
89
  /**
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).
90
+ * Hash a raw 7-element balance leaf 4-element Merkle node.
168
91
  *
169
- * Returns `BigUint64Array` of length 5.
92
+ * Raw layout: `[balance_lo, balance_hi, seed_hash_0, seed_hash_1, seed_hash_2, credit_lo, credit_hi]`
170
93
  *
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.
94
+ * Identical to `hash_balance_leaf` in `prover/circuit/src/helpers/leaf_ops.rs`.
203
95
  *
204
- * Returns hex-encoded w-encoding of the ECgFp5 point (80 chars = 40 bytes).
96
+ * **Input** : `BigUint64Array` of exactly 7 elements (each < `GOLDILOCKS_P`).
97
+ * **Output**: `BigUint64Array` of length 4 (one `HashOut`).
205
98
  *
206
99
  * ```js
207
- * const pkHex = schnorr_pubkey(skHex);
100
+ * const raw = BigUint64Array.from([balLo, balHi, seed0, seed1, seed2, credLo, credHi]);
101
+ * const balanceHash = hash_balance_leaf(raw); // length 4
208
102
  * ```
209
103
  */
210
- export function schnorr_pubkey(sk_hex: string): string;
104
+ export function hash_balance_leaf(raw: BigUint64Array): BigUint64Array;
211
105
 
212
106
  /**
213
- * Sign a ChangePubKey (tx_type=9) transaction in (s, e) format.
107
+ * Build a main Merkle tree leaf from balance_hash, pk_hash, and address_hash.
214
108
  *
215
- * msg_hash = Poseidon2(9, user_id, new_pk_hash[0..4])
109
+ * `main_leaf = Poseidon2(balance_hash[4] || pk_hash[0..2] || address_hash[0..2])`
216
110
  *
217
- * The old key signs this message to authorize key rotation.
111
+ * Uses truncated (128-bit) pk/address hashes to keep the preimage at 8 elements
112
+ * (single Poseidon2 permutation round). Identical to `make_main_leaf` in
113
+ * `prover/circuit/src/helpers/leaf_ops.rs`.
218
114
  *
219
- * Returns a JS object: `{ pubkey: "hex", sig_s: "hex", sig_e: "hex" }`
115
+ * All three inputs must be exactly 4 elements.
116
+ * **Output**: `BigUint64Array` of length 4 (the Merkle leaf hash).
220
117
  *
221
118
  * ```js
222
- * const sig = schnorr_sign_cpk(oldSkHex, userId, newPkHashArray);
119
+ * const leaf = make_main_leaf(balanceHash, pkHash, addressHash);
223
120
  * ```
224
121
  */
225
- export function schnorr_sign_cpk(old_sk_hex: string, user_id: number, new_pk_hash: BigUint64Array): any;
122
+ export function make_main_leaf(balance_hash: BigUint64Array, pk_hash: BigUint64Array, address_hash: BigUint64Array): BigUint64Array;
226
123
 
227
124
  /**
228
- * Sign a transaction with Schnorr (ECgFp5) in (s, e) format.
125
+ * Poseidon2 hash of an arbitrary number of Goldilocks field elements.
229
126
  *
230
- * msg_hash = Poseidon2(tx_type, user_id, currency_id, amount_lo, amount_hi)
127
+ * Mirrors `builder.hash_n_to_hash_no_pad::<Poseidon2Hash>(...)` inside
128
+ * the circuit and `Poseidon2Hash::hash_no_pad` in `src/block_builder`.
231
129
  *
232
- * Returns a JS object: `{ pubkey: "hex", sig_s: "hex", sig_e: "hex" }`
130
+ * **Input** : `BigUint64Array` each element must be < `GOLDILOCKS_P`.
131
+ * **Output**: `BigUint64Array` of length 4 (one `HashOut`).
233
132
  *
234
133
  * ```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)
134
+ * const h = poseidon2_hash(BigUint64Array.from([1n, 2n, 3n]));
135
+ * // h.length === 4
237
136
  * ```
238
137
  */
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;
138
+ export function poseidon2_hash(input: BigUint64Array): BigUint64Array;
240
139
 
241
140
  /**
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.
141
+ * Merkle-tree hash: Poseidon2(left[4] right[4]).
245
142
  *
246
- * Returns `true` if signature is valid, `false` otherwise.
143
+ * Identical to `poseidon_hash(left, right)` in `src/merkletree/hash.rs`.
144
+ * Input ordering is critical — `left` concatenated before `right`.
247
145
  *
248
- * ```js
249
- * const ok = schnorr_verify_tx(pubkeyHex, sigSHex, sigEHex, 5, userId, 0, amountLo, amountHi);
250
- * ```
146
+ * Both arrays **must** have exactly 4 elements (one `HashOut` each).
251
147
  */
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;
148
+ export function poseidon2_two_to_one(left: BigUint64Array, right: BigUint64Array): BigUint64Array;
253
149
 
254
150
  /**
255
- * Truncated seed hash — first 2 elements of `Poseidon2(server_seed)`.
151
+ * Truncated seed hash — first 3 elements of `Poseidon2(server_seed)`.
256
152
  *
153
+ * 192 bits of commitment → ~96-bit collision resistance, which closes the
154
+ * multi-preimage grinding vector that an earlier 128-bit truncation left open.
257
155
  * This is the exact format stored in the Merkle-tree leaf and verified
258
156
  * by the circuit. Matches `seed_hash_truncated` in
259
- * `src/block_builder/builder.rs` and `src/circuit/main_circuit.rs`.
157
+ * `src/block_builder/builder.rs` and `src/circuit/slot/fairness.rs`.
260
158
  *
261
- * Returns `BigUint64Array` of length 2: `[h[0], h[1]]`.
159
+ * Returns `BigUint64Array` of length 3: `[h[0], h[1], h[2]]`.
262
160
  */
263
161
  export function seed_hash_truncated(server_seed: BigUint64Array): BigUint64Array;
264
162
 
265
163
  /**
266
- * Compute the public key for a session: `session_pk = Poseidon2(session_key)`.
164
+ * Compute the public key for a session: `pk_hash = Poseidon2(session_key[4], expiry)`.
267
165
  *
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`).
166
+ * The public key hash is stored in the user-asset Merkle leaf and verified
167
+ * inside the circuit (the prover must know the preimage `session_key` + `expiry`).
270
168
  *
271
169
  * `session_key` must be exactly 4 elements (output of `derive_session_key`).
170
+ * `session_expiry` is the Unix timestamp after which the session is invalid.
272
171
  */
273
- export function session_public_key(session_key: BigUint64Array): BigUint64Array;
172
+ export function session_public_key(session_key: BigUint64Array, session_expiry: bigint): BigUint64Array;
274
173
 
275
174
  /**
276
175
  * Convert a user seed string to 4 Goldilocks field elements.