@rolly-dev/wasm-signer 0.1.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 +115 -0
- package/dist/node/README.md +115 -0
- package/dist/node/package.json +1 -0
- package/dist/node/rolly_wasm_signer.d.ts +120 -0
- package/dist/node/rolly_wasm_signer.js +328 -0
- package/dist/node/rolly_wasm_signer_bg.wasm +0 -0
- package/dist/node/rolly_wasm_signer_bg.wasm.d.ts +15 -0
- package/dist/web/README.md +115 -0
- package/dist/web/rolly_wasm_signer.d.ts +160 -0
- package/dist/web/rolly_wasm_signer.js +415 -0
- package/dist/web/rolly_wasm_signer_bg.wasm +0 -0
- package/dist/web/rolly_wasm_signer_bg.wasm.d.ts +15 -0
- package/js/browser.mjs +13 -0
- package/js/node.cjs +15 -0
- package/js/node.mjs +16 -0
- package/js/react.mjs +57 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# @rolly/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/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/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/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/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/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/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,115 @@
|
|
|
1
|
+
# @rolly/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/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/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/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/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/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/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,120 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Full Poseidon2 hash of an 8-element server seed.
|
|
6
|
+
*
|
|
7
|
+
* Returns all 4 hash elements. Note: the circuit stores only the
|
|
8
|
+
* **first 2 elements** as the leaf commitment (see `seed_hash_truncated`).
|
|
9
|
+
* This full variant is useful for client-side verification where all
|
|
10
|
+
* 4 elements may be needed.
|
|
11
|
+
*
|
|
12
|
+
* `server_seed` must be exactly 8 elements.
|
|
13
|
+
*/
|
|
14
|
+
export function compute_server_seed_hash(server_seed: BigUint64Array): BigUint64Array;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create a `bet_auth` MAC that proves the user authorized this specific bet.
|
|
18
|
+
*
|
|
19
|
+
* ```text
|
|
20
|
+
* bet_auth = Poseidon2(
|
|
21
|
+
* session_key[0..4], // 4 field elements (private)
|
|
22
|
+
* amount_lo, // lower 32 bits of bet_amount
|
|
23
|
+
* amount_hi, // upper 32 bits of bet_amount
|
|
24
|
+
* nonce, // monotonic counter, prevents replay
|
|
25
|
+
* )
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* The circuit verifies two things:
|
|
29
|
+
* 1. `session_pk == Poseidon2(session_key)` — knowledge of key
|
|
30
|
+
* 2. `bet_auth == Poseidon2(session_key ‖ amount_lo ‖ amount_hi ‖ nonce)`
|
|
31
|
+
*
|
|
32
|
+
* The lo/hi split matches `src/circuit/main_circuit.rs` witness assignment:
|
|
33
|
+
* `amount as u32` / `(amount >> 32) as u32`, both via `from_canonical_u32`.
|
|
34
|
+
*
|
|
35
|
+
* **Parameters**
|
|
36
|
+
* - `session_key` : 4 × u64 (private, from `derive_session_key`)
|
|
37
|
+
* - `bet_amount` : u64 (in smallest currency units)
|
|
38
|
+
* - `nonce` : u64 (incrementing per-session counter)
|
|
39
|
+
*
|
|
40
|
+
* **Returns**: 4 × u64 (`bet_auth` hash)
|
|
41
|
+
*/
|
|
42
|
+
export function create_bet_auth(session_key: BigUint64Array, bet_amount: bigint, nonce: bigint): BigUint64Array;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Derive a session key from 32 bytes of entropy (e.g. MetaMask signature).
|
|
46
|
+
*
|
|
47
|
+
* **Algorithm**: split 32 bytes into 4 × 8 bytes, interpret each chunk as
|
|
48
|
+
* little-endian u64, reduce mod p, then hash:
|
|
49
|
+
* `session_key = Poseidon2(reduced_chunks)`
|
|
50
|
+
*
|
|
51
|
+
* The reduction via `from_noncanonical_u64` is necessary because raw
|
|
52
|
+
* signature bytes can produce values >= p.
|
|
53
|
+
*
|
|
54
|
+
* ```js
|
|
55
|
+
* const sig = ethers.getBytes(metaMaskSignature).slice(0, 32);
|
|
56
|
+
* const sk = derive_session_key(new Uint8Array(sig));
|
|
57
|
+
* // sk.length === 4
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export function derive_session_key(sig_bytes: Uint8Array): BigUint64Array;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Returns the Goldilocks prime: p = 2^64 - 2^32 + 1.
|
|
64
|
+
*/
|
|
65
|
+
export function goldilocks_modulus(): bigint;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Reduce an arbitrary u64 to its canonical representative mod p.
|
|
69
|
+
*
|
|
70
|
+
* Values already < p are returned unchanged. Values >= p are reduced.
|
|
71
|
+
* This uses `from_noncanonical_u64` internally (no panic on large values).
|
|
72
|
+
*/
|
|
73
|
+
export function goldilocks_reduce(value: bigint): bigint;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Poseidon2 hash of an arbitrary number of Goldilocks field elements.
|
|
77
|
+
*
|
|
78
|
+
* Mirrors `builder.hash_n_to_hash_no_pad::<Poseidon2Hash>(...)` inside
|
|
79
|
+
* the circuit and `Poseidon2Hash::hash_no_pad` in `src/block_builder`.
|
|
80
|
+
*
|
|
81
|
+
* **Input** : `BigUint64Array` — each element must be < `GOLDILOCKS_P`.
|
|
82
|
+
* **Output**: `BigUint64Array` of length 4 (one `HashOut`).
|
|
83
|
+
*
|
|
84
|
+
* ```js
|
|
85
|
+
* const h = poseidon2_hash(BigUint64Array.from([1n, 2n, 3n]));
|
|
86
|
+
* // h.length === 4
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export function poseidon2_hash(input: BigUint64Array): BigUint64Array;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Merkle-tree hash: Poseidon2(left[4] ‖ right[4]).
|
|
93
|
+
*
|
|
94
|
+
* Identical to `poseidon_hash(left, right)` in `src/merkletree/hash.rs`.
|
|
95
|
+
* Input ordering is critical — `left` concatenated before `right`.
|
|
96
|
+
*
|
|
97
|
+
* Both arrays **must** have exactly 4 elements (one `HashOut` each).
|
|
98
|
+
*/
|
|
99
|
+
export function poseidon2_two_to_one(left: BigUint64Array, right: BigUint64Array): BigUint64Array;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Truncated seed hash — first 2 elements of `Poseidon2(server_seed)`.
|
|
103
|
+
*
|
|
104
|
+
* This is the exact format stored in the Merkle-tree leaf and verified
|
|
105
|
+
* by the circuit. Matches `seed_hash_truncated` in
|
|
106
|
+
* `src/block_builder/builder.rs` and `src/circuit/main_circuit.rs`.
|
|
107
|
+
*
|
|
108
|
+
* Returns `BigUint64Array` of length 2: `[h[0], h[1]]`.
|
|
109
|
+
*/
|
|
110
|
+
export function seed_hash_truncated(server_seed: BigUint64Array): BigUint64Array;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Compute the public key for a session: `session_pk = Poseidon2(session_key)`.
|
|
114
|
+
*
|
|
115
|
+
* The public key is stored in the user-asset Merkle leaf and verified
|
|
116
|
+
* inside the circuit (the prover must know the preimage `session_key`).
|
|
117
|
+
*
|
|
118
|
+
* `session_key` must be exactly 4 elements (output of `derive_session_key`).
|
|
119
|
+
*/
|
|
120
|
+
export function session_public_key(session_key: BigUint64Array): BigUint64Array;
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/* @ts-self-types="./rolly_wasm_signer.d.ts" */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Full Poseidon2 hash of an 8-element server seed.
|
|
5
|
+
*
|
|
6
|
+
* Returns all 4 hash elements. Note: the circuit stores only the
|
|
7
|
+
* **first 2 elements** as the leaf commitment (see `seed_hash_truncated`).
|
|
8
|
+
* This full variant is useful for client-side verification where all
|
|
9
|
+
* 4 elements may be needed.
|
|
10
|
+
*
|
|
11
|
+
* `server_seed` must be exactly 8 elements.
|
|
12
|
+
* @param {BigUint64Array} server_seed
|
|
13
|
+
* @returns {BigUint64Array}
|
|
14
|
+
*/
|
|
15
|
+
function compute_server_seed_hash(server_seed) {
|
|
16
|
+
try {
|
|
17
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
18
|
+
const ptr0 = passArray64ToWasm0(server_seed, wasm.__wbindgen_export);
|
|
19
|
+
const len0 = WASM_VECTOR_LEN;
|
|
20
|
+
wasm.compute_server_seed_hash(retptr, ptr0, len0);
|
|
21
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
22
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
23
|
+
var v2 = getArrayU64FromWasm0(r0, r1).slice();
|
|
24
|
+
wasm.__wbindgen_export2(r0, r1 * 8, 8);
|
|
25
|
+
return v2;
|
|
26
|
+
} finally {
|
|
27
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.compute_server_seed_hash = compute_server_seed_hash;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Create a `bet_auth` MAC that proves the user authorized this specific bet.
|
|
34
|
+
*
|
|
35
|
+
* ```text
|
|
36
|
+
* bet_auth = Poseidon2(
|
|
37
|
+
* session_key[0..4], // 4 field elements (private)
|
|
38
|
+
* amount_lo, // lower 32 bits of bet_amount
|
|
39
|
+
* amount_hi, // upper 32 bits of bet_amount
|
|
40
|
+
* nonce, // monotonic counter, prevents replay
|
|
41
|
+
* )
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* The circuit verifies two things:
|
|
45
|
+
* 1. `session_pk == Poseidon2(session_key)` — knowledge of key
|
|
46
|
+
* 2. `bet_auth == Poseidon2(session_key ‖ amount_lo ‖ amount_hi ‖ nonce)`
|
|
47
|
+
*
|
|
48
|
+
* The lo/hi split matches `src/circuit/main_circuit.rs` witness assignment:
|
|
49
|
+
* `amount as u32` / `(amount >> 32) as u32`, both via `from_canonical_u32`.
|
|
50
|
+
*
|
|
51
|
+
* **Parameters**
|
|
52
|
+
* - `session_key` : 4 × u64 (private, from `derive_session_key`)
|
|
53
|
+
* - `bet_amount` : u64 (in smallest currency units)
|
|
54
|
+
* - `nonce` : u64 (incrementing per-session counter)
|
|
55
|
+
*
|
|
56
|
+
* **Returns**: 4 × u64 (`bet_auth` hash)
|
|
57
|
+
* @param {BigUint64Array} session_key
|
|
58
|
+
* @param {bigint} bet_amount
|
|
59
|
+
* @param {bigint} nonce
|
|
60
|
+
* @returns {BigUint64Array}
|
|
61
|
+
*/
|
|
62
|
+
function create_bet_auth(session_key, bet_amount, nonce) {
|
|
63
|
+
try {
|
|
64
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
65
|
+
const ptr0 = passArray64ToWasm0(session_key, wasm.__wbindgen_export);
|
|
66
|
+
const len0 = WASM_VECTOR_LEN;
|
|
67
|
+
wasm.create_bet_auth(retptr, ptr0, len0, bet_amount, nonce);
|
|
68
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
69
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
70
|
+
var v2 = getArrayU64FromWasm0(r0, r1).slice();
|
|
71
|
+
wasm.__wbindgen_export2(r0, r1 * 8, 8);
|
|
72
|
+
return v2;
|
|
73
|
+
} finally {
|
|
74
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.create_bet_auth = create_bet_auth;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Derive a session key from 32 bytes of entropy (e.g. MetaMask signature).
|
|
81
|
+
*
|
|
82
|
+
* **Algorithm**: split 32 bytes into 4 × 8 bytes, interpret each chunk as
|
|
83
|
+
* little-endian u64, reduce mod p, then hash:
|
|
84
|
+
* `session_key = Poseidon2(reduced_chunks)`
|
|
85
|
+
*
|
|
86
|
+
* The reduction via `from_noncanonical_u64` is necessary because raw
|
|
87
|
+
* signature bytes can produce values >= p.
|
|
88
|
+
*
|
|
89
|
+
* ```js
|
|
90
|
+
* const sig = ethers.getBytes(metaMaskSignature).slice(0, 32);
|
|
91
|
+
* const sk = derive_session_key(new Uint8Array(sig));
|
|
92
|
+
* // sk.length === 4
|
|
93
|
+
* ```
|
|
94
|
+
* @param {Uint8Array} sig_bytes
|
|
95
|
+
* @returns {BigUint64Array}
|
|
96
|
+
*/
|
|
97
|
+
function derive_session_key(sig_bytes) {
|
|
98
|
+
try {
|
|
99
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
100
|
+
const ptr0 = passArray8ToWasm0(sig_bytes, wasm.__wbindgen_export);
|
|
101
|
+
const len0 = WASM_VECTOR_LEN;
|
|
102
|
+
wasm.derive_session_key(retptr, ptr0, len0);
|
|
103
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
104
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
105
|
+
var v2 = getArrayU64FromWasm0(r0, r1).slice();
|
|
106
|
+
wasm.__wbindgen_export2(r0, r1 * 8, 8);
|
|
107
|
+
return v2;
|
|
108
|
+
} finally {
|
|
109
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.derive_session_key = derive_session_key;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Returns the Goldilocks prime: p = 2^64 - 2^32 + 1.
|
|
116
|
+
* @returns {bigint}
|
|
117
|
+
*/
|
|
118
|
+
function goldilocks_modulus() {
|
|
119
|
+
const ret = wasm.goldilocks_modulus();
|
|
120
|
+
return BigInt.asUintN(64, ret);
|
|
121
|
+
}
|
|
122
|
+
exports.goldilocks_modulus = goldilocks_modulus;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Reduce an arbitrary u64 to its canonical representative mod p.
|
|
126
|
+
*
|
|
127
|
+
* Values already < p are returned unchanged. Values >= p are reduced.
|
|
128
|
+
* This uses `from_noncanonical_u64` internally (no panic on large values).
|
|
129
|
+
* @param {bigint} value
|
|
130
|
+
* @returns {bigint}
|
|
131
|
+
*/
|
|
132
|
+
function goldilocks_reduce(value) {
|
|
133
|
+
const ret = wasm.goldilocks_reduce(value);
|
|
134
|
+
return BigInt.asUintN(64, ret);
|
|
135
|
+
}
|
|
136
|
+
exports.goldilocks_reduce = goldilocks_reduce;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Poseidon2 hash of an arbitrary number of Goldilocks field elements.
|
|
140
|
+
*
|
|
141
|
+
* Mirrors `builder.hash_n_to_hash_no_pad::<Poseidon2Hash>(...)` inside
|
|
142
|
+
* the circuit and `Poseidon2Hash::hash_no_pad` in `src/block_builder`.
|
|
143
|
+
*
|
|
144
|
+
* **Input** : `BigUint64Array` — each element must be < `GOLDILOCKS_P`.
|
|
145
|
+
* **Output**: `BigUint64Array` of length 4 (one `HashOut`).
|
|
146
|
+
*
|
|
147
|
+
* ```js
|
|
148
|
+
* const h = poseidon2_hash(BigUint64Array.from([1n, 2n, 3n]));
|
|
149
|
+
* // h.length === 4
|
|
150
|
+
* ```
|
|
151
|
+
* @param {BigUint64Array} input
|
|
152
|
+
* @returns {BigUint64Array}
|
|
153
|
+
*/
|
|
154
|
+
function poseidon2_hash(input) {
|
|
155
|
+
try {
|
|
156
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
157
|
+
const ptr0 = passArray64ToWasm0(input, wasm.__wbindgen_export);
|
|
158
|
+
const len0 = WASM_VECTOR_LEN;
|
|
159
|
+
wasm.poseidon2_hash(retptr, ptr0, len0);
|
|
160
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
161
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
162
|
+
var v2 = getArrayU64FromWasm0(r0, r1).slice();
|
|
163
|
+
wasm.__wbindgen_export2(r0, r1 * 8, 8);
|
|
164
|
+
return v2;
|
|
165
|
+
} finally {
|
|
166
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
exports.poseidon2_hash = poseidon2_hash;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Merkle-tree hash: Poseidon2(left[4] ‖ right[4]).
|
|
173
|
+
*
|
|
174
|
+
* Identical to `poseidon_hash(left, right)` in `src/merkletree/hash.rs`.
|
|
175
|
+
* Input ordering is critical — `left` concatenated before `right`.
|
|
176
|
+
*
|
|
177
|
+
* Both arrays **must** have exactly 4 elements (one `HashOut` each).
|
|
178
|
+
* @param {BigUint64Array} left
|
|
179
|
+
* @param {BigUint64Array} right
|
|
180
|
+
* @returns {BigUint64Array}
|
|
181
|
+
*/
|
|
182
|
+
function poseidon2_two_to_one(left, right) {
|
|
183
|
+
try {
|
|
184
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
185
|
+
const ptr0 = passArray64ToWasm0(left, wasm.__wbindgen_export);
|
|
186
|
+
const len0 = WASM_VECTOR_LEN;
|
|
187
|
+
const ptr1 = passArray64ToWasm0(right, wasm.__wbindgen_export);
|
|
188
|
+
const len1 = WASM_VECTOR_LEN;
|
|
189
|
+
wasm.poseidon2_two_to_one(retptr, ptr0, len0, ptr1, len1);
|
|
190
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
191
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
192
|
+
var v3 = getArrayU64FromWasm0(r0, r1).slice();
|
|
193
|
+
wasm.__wbindgen_export2(r0, r1 * 8, 8);
|
|
194
|
+
return v3;
|
|
195
|
+
} finally {
|
|
196
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
exports.poseidon2_two_to_one = poseidon2_two_to_one;
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Truncated seed hash — first 2 elements of `Poseidon2(server_seed)`.
|
|
203
|
+
*
|
|
204
|
+
* This is the exact format stored in the Merkle-tree leaf and verified
|
|
205
|
+
* by the circuit. Matches `seed_hash_truncated` in
|
|
206
|
+
* `src/block_builder/builder.rs` and `src/circuit/main_circuit.rs`.
|
|
207
|
+
*
|
|
208
|
+
* Returns `BigUint64Array` of length 2: `[h[0], h[1]]`.
|
|
209
|
+
* @param {BigUint64Array} server_seed
|
|
210
|
+
* @returns {BigUint64Array}
|
|
211
|
+
*/
|
|
212
|
+
function seed_hash_truncated(server_seed) {
|
|
213
|
+
try {
|
|
214
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
215
|
+
const ptr0 = passArray64ToWasm0(server_seed, wasm.__wbindgen_export);
|
|
216
|
+
const len0 = WASM_VECTOR_LEN;
|
|
217
|
+
wasm.seed_hash_truncated(retptr, ptr0, len0);
|
|
218
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
219
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
220
|
+
var v2 = getArrayU64FromWasm0(r0, r1).slice();
|
|
221
|
+
wasm.__wbindgen_export2(r0, r1 * 8, 8);
|
|
222
|
+
return v2;
|
|
223
|
+
} finally {
|
|
224
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
exports.seed_hash_truncated = seed_hash_truncated;
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Compute the public key for a session: `session_pk = Poseidon2(session_key)`.
|
|
231
|
+
*
|
|
232
|
+
* The public key is stored in the user-asset Merkle leaf and verified
|
|
233
|
+
* inside the circuit (the prover must know the preimage `session_key`).
|
|
234
|
+
*
|
|
235
|
+
* `session_key` must be exactly 4 elements (output of `derive_session_key`).
|
|
236
|
+
* @param {BigUint64Array} session_key
|
|
237
|
+
* @returns {BigUint64Array}
|
|
238
|
+
*/
|
|
239
|
+
function session_public_key(session_key) {
|
|
240
|
+
try {
|
|
241
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
242
|
+
const ptr0 = passArray64ToWasm0(session_key, wasm.__wbindgen_export);
|
|
243
|
+
const len0 = WASM_VECTOR_LEN;
|
|
244
|
+
wasm.session_public_key(retptr, ptr0, len0);
|
|
245
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
246
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
247
|
+
var v2 = getArrayU64FromWasm0(r0, r1).slice();
|
|
248
|
+
wasm.__wbindgen_export2(r0, r1 * 8, 8);
|
|
249
|
+
return v2;
|
|
250
|
+
} finally {
|
|
251
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
exports.session_public_key = session_public_key;
|
|
255
|
+
|
|
256
|
+
function __wbg_get_imports() {
|
|
257
|
+
const import0 = {
|
|
258
|
+
__proto__: null,
|
|
259
|
+
__wbg___wbindgen_throw_be289d5034ed271b: function(arg0, arg1) {
|
|
260
|
+
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
return {
|
|
264
|
+
__proto__: null,
|
|
265
|
+
"./rolly_wasm_signer_bg.js": import0,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function getArrayU64FromWasm0(ptr, len) {
|
|
270
|
+
ptr = ptr >>> 0;
|
|
271
|
+
return getBigUint64ArrayMemory0().subarray(ptr / 8, ptr / 8 + len);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
let cachedBigUint64ArrayMemory0 = null;
|
|
275
|
+
function getBigUint64ArrayMemory0() {
|
|
276
|
+
if (cachedBigUint64ArrayMemory0 === null || cachedBigUint64ArrayMemory0.byteLength === 0) {
|
|
277
|
+
cachedBigUint64ArrayMemory0 = new BigUint64Array(wasm.memory.buffer);
|
|
278
|
+
}
|
|
279
|
+
return cachedBigUint64ArrayMemory0;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
let cachedDataViewMemory0 = null;
|
|
283
|
+
function getDataViewMemory0() {
|
|
284
|
+
if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
|
|
285
|
+
cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
|
|
286
|
+
}
|
|
287
|
+
return cachedDataViewMemory0;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function getStringFromWasm0(ptr, len) {
|
|
291
|
+
ptr = ptr >>> 0;
|
|
292
|
+
return decodeText(ptr, len);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
let cachedUint8ArrayMemory0 = null;
|
|
296
|
+
function getUint8ArrayMemory0() {
|
|
297
|
+
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
|
298
|
+
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
|
299
|
+
}
|
|
300
|
+
return cachedUint8ArrayMemory0;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function passArray64ToWasm0(arg, malloc) {
|
|
304
|
+
const ptr = malloc(arg.length * 8, 8) >>> 0;
|
|
305
|
+
getBigUint64ArrayMemory0().set(arg, ptr / 8);
|
|
306
|
+
WASM_VECTOR_LEN = arg.length;
|
|
307
|
+
return ptr;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function passArray8ToWasm0(arg, malloc) {
|
|
311
|
+
const ptr = malloc(arg.length * 1, 1) >>> 0;
|
|
312
|
+
getUint8ArrayMemory0().set(arg, ptr / 1);
|
|
313
|
+
WASM_VECTOR_LEN = arg.length;
|
|
314
|
+
return ptr;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
318
|
+
cachedTextDecoder.decode();
|
|
319
|
+
function decodeText(ptr, len) {
|
|
320
|
+
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
let WASM_VECTOR_LEN = 0;
|
|
324
|
+
|
|
325
|
+
const wasmPath = `${__dirname}/rolly_wasm_signer_bg.wasm`;
|
|
326
|
+
const wasmBytes = require('fs').readFileSync(wasmPath);
|
|
327
|
+
const wasmModule = new WebAssembly.Module(wasmBytes);
|
|
328
|
+
const wasm = new WebAssembly.Instance(wasmModule, __wbg_get_imports()).exports;
|
|
Binary file
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
export const memory: WebAssembly.Memory;
|
|
4
|
+
export const compute_server_seed_hash: (a: number, b: number, c: number) => void;
|
|
5
|
+
export const create_bet_auth: (a: number, b: number, c: number, d: bigint, e: bigint) => void;
|
|
6
|
+
export const derive_session_key: (a: number, b: number, c: number) => void;
|
|
7
|
+
export const goldilocks_reduce: (a: bigint) => bigint;
|
|
8
|
+
export const poseidon2_hash: (a: number, b: number, c: number) => void;
|
|
9
|
+
export const poseidon2_two_to_one: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
10
|
+
export const seed_hash_truncated: (a: number, b: number, c: number) => void;
|
|
11
|
+
export const session_public_key: (a: number, b: number, c: number) => void;
|
|
12
|
+
export const goldilocks_modulus: () => bigint;
|
|
13
|
+
export const __wbindgen_add_to_stack_pointer: (a: number) => number;
|
|
14
|
+
export const __wbindgen_export: (a: number, b: number) => number;
|
|
15
|
+
export const __wbindgen_export2: (a: number, b: number, c: number) => void;
|