@rolly-dev/wasm-signer 0.13.1 → 1.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 +37 -1
- package/dist/node/README.md +37 -1
- package/dist/node/rolly_wasm_signer.d.ts +68 -4
- package/dist/node/rolly_wasm_signer.js +143 -4
- package/dist/node/rolly_wasm_signer_bg.wasm +0 -0
- package/dist/node/rolly_wasm_signer_bg.wasm.d.ts +5 -0
- package/dist/node-inline/README.md +37 -1
- package/dist/node-inline/rolly_wasm_signer.d.ts +68 -4
- package/dist/node-inline/rolly_wasm_signer.js +144 -5
- package/dist/node-inline/rolly_wasm_signer.mjs +140 -6
- package/dist/node-inline/rolly_wasm_signer_bg.wasm.d.ts +5 -0
- package/dist/web/README.md +37 -1
- package/dist/web/rolly_wasm_signer.d.ts +73 -4
- package/dist/web/rolly_wasm_signer.js +138 -4
- package/dist/web/rolly_wasm_signer_bg.wasm +0 -0
- package/dist/web/rolly_wasm_signer_bg.wasm.d.ts +5 -0
- package/js/browser.d.mts +5 -0
- package/js/browser.mjs +5 -0
- package/js/index.d.ts +5 -0
- package/js/node-inline.cjs +5 -0
- package/js/node-inline.mjs +5 -0
- package/js/node.cjs +5 -0
- package/js/node.mjs +5 -0
- package/js/react.d.mts +5 -0
- package/js/react.mjs +10 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -89,7 +89,7 @@ poseidon2_hash(BigUint64Array.from([1n]));
|
|
|
89
89
|
| `derive_session_key` | `Uint8Array(32)` | `BigUint64Array(4)` | MetaMask sig → session key |
|
|
90
90
|
| `session_public_key` | `(BigUint64Array(4), bigint)` | `BigUint64Array(4)` | pk_hash = Poseidon2(session_key, expiry) |
|
|
91
91
|
| `compute_server_seed_hash` | `BigUint64Array(8)` | `BigUint64Array(4)` | Full hash of server seed |
|
|
92
|
-
| `seed_hash_truncated` | `BigUint64Array(8)` | `BigUint64Array(
|
|
92
|
+
| `seed_hash_truncated` | `BigUint64Array(8)` | `BigUint64Array(3)` | First 3 elements (circuit leaf format, 192-bit commitment) |
|
|
93
93
|
| `goldilocks_modulus` | — | `bigint` | Returns p = 2^64 - 2^32 + 1 |
|
|
94
94
|
| `goldilocks_reduce` | `bigint` | `bigint` | Reduce mod p |
|
|
95
95
|
|
|
@@ -107,6 +107,42 @@ module.exports = { experiments: { asyncWebAssembly: true } };
|
|
|
107
107
|
|
|
108
108
|
**Next.js** — conditional exports auto-resolve: Node.js entry on server, browser entry on client.
|
|
109
109
|
|
|
110
|
+
## Dice — range constraints
|
|
111
|
+
|
|
112
|
+
Roll number: `[0, 999]` (TOTAL_RANGE = 1000).
|
|
113
|
+
win_numbers (wn): `[1, 950]` (MIN_RANGE..=MAX_RANGE).
|
|
114
|
+
|
|
115
|
+
### prediction_range constraints per mode
|
|
116
|
+
|
|
117
|
+
| Mode | wn formula | prediction\[0\] | prediction\[1\] | wn range |
|
|
118
|
+
|-------|-------------------------------------------------|-----------------|-----------------|------------|
|
|
119
|
+
| Under | `prediction[0]` | `[1, 950]` | unused (0) | `[1, 950]` |
|
|
120
|
+
| Over | `999 − prediction[0]` | `[49, 998]` | unused (0) | `[1, 950]` |
|
|
121
|
+
| In | `prediction[1] − prediction[0] + 1` | `[0, 999]` | `[0, 999]` | `[1, 950]` |
|
|
122
|
+
| Out | `1000 − (prediction[1] − prediction[0] + 1)` | `[0, 999]` | `[0, 999]` | `[1, 950]` |
|
|
123
|
+
|
|
124
|
+
**Under** — `prediction[0]` ∈ `[1, 950]` (= wn directly). Win: `roll < prediction[0]`.
|
|
125
|
+
|
|
126
|
+
**Over** — `prediction[0]` ∈ `[49, 998]` (lower: `999 − 950 = 49`, upper: `999 − 1 = 998`). Win: `roll > prediction[0]`.
|
|
127
|
+
|
|
128
|
+
**In** — `prediction[0] <= prediction[1]`, span ∈ `[1, 950]`. Win: `prediction[0] <= roll <= prediction[1]`.
|
|
129
|
+
|
|
130
|
+
**Out** — `prediction[0] <= prediction[1]`, inner span ∈ `[50, 999]` (wn = `1000 − inner` ∈ `[1, 950]`). Win: `roll < prediction[0] || roll > prediction[1]`.
|
|
131
|
+
|
|
132
|
+
### Multiplier
|
|
133
|
+
|
|
134
|
+
`multiplier = floor(9_900_000 / wn)` (scaled ×10000).
|
|
135
|
+
|
|
136
|
+
| wn | multiplier | display |
|
|
137
|
+
|-----|-----------|-----------|
|
|
138
|
+
| 1 | 9_900_000 | 990.0000x |
|
|
139
|
+
| 500 | 19_800 | 1.9800x |
|
|
140
|
+
| 950 | 10_421 | 1.0421x |
|
|
141
|
+
|
|
142
|
+
### RTP
|
|
143
|
+
|
|
144
|
+
Theoretical: **98.998%** (floor-division costs ~0.002%). House edge: **~1.002%**. Max win cap: 10,000 USDT (business rule, not formula).
|
|
145
|
+
|
|
110
146
|
## License
|
|
111
147
|
|
|
112
148
|
MIT
|
package/dist/node/README.md
CHANGED
|
@@ -89,7 +89,7 @@ poseidon2_hash(BigUint64Array.from([1n]));
|
|
|
89
89
|
| `derive_session_key` | `Uint8Array(32)` | `BigUint64Array(4)` | MetaMask sig → session key |
|
|
90
90
|
| `session_public_key` | `(BigUint64Array(4), bigint)` | `BigUint64Array(4)` | pk_hash = Poseidon2(session_key, expiry) |
|
|
91
91
|
| `compute_server_seed_hash` | `BigUint64Array(8)` | `BigUint64Array(4)` | Full hash of server seed |
|
|
92
|
-
| `seed_hash_truncated` | `BigUint64Array(8)` | `BigUint64Array(
|
|
92
|
+
| `seed_hash_truncated` | `BigUint64Array(8)` | `BigUint64Array(3)` | First 3 elements (circuit leaf format, 192-bit commitment) |
|
|
93
93
|
| `goldilocks_modulus` | — | `bigint` | Returns p = 2^64 - 2^32 + 1 |
|
|
94
94
|
| `goldilocks_reduce` | `bigint` | `bigint` | Reduce mod p |
|
|
95
95
|
|
|
@@ -107,6 +107,42 @@ module.exports = { experiments: { asyncWebAssembly: true } };
|
|
|
107
107
|
|
|
108
108
|
**Next.js** — conditional exports auto-resolve: Node.js entry on server, browser entry on client.
|
|
109
109
|
|
|
110
|
+
## Dice — range constraints
|
|
111
|
+
|
|
112
|
+
Roll number: `[0, 999]` (TOTAL_RANGE = 1000).
|
|
113
|
+
win_numbers (wn): `[1, 950]` (MIN_RANGE..=MAX_RANGE).
|
|
114
|
+
|
|
115
|
+
### prediction_range constraints per mode
|
|
116
|
+
|
|
117
|
+
| Mode | wn formula | prediction\[0\] | prediction\[1\] | wn range |
|
|
118
|
+
|-------|-------------------------------------------------|-----------------|-----------------|------------|
|
|
119
|
+
| Under | `prediction[0]` | `[1, 950]` | unused (0) | `[1, 950]` |
|
|
120
|
+
| Over | `999 − prediction[0]` | `[49, 998]` | unused (0) | `[1, 950]` |
|
|
121
|
+
| In | `prediction[1] − prediction[0] + 1` | `[0, 999]` | `[0, 999]` | `[1, 950]` |
|
|
122
|
+
| Out | `1000 − (prediction[1] − prediction[0] + 1)` | `[0, 999]` | `[0, 999]` | `[1, 950]` |
|
|
123
|
+
|
|
124
|
+
**Under** — `prediction[0]` ∈ `[1, 950]` (= wn directly). Win: `roll < prediction[0]`.
|
|
125
|
+
|
|
126
|
+
**Over** — `prediction[0]` ∈ `[49, 998]` (lower: `999 − 950 = 49`, upper: `999 − 1 = 998`). Win: `roll > prediction[0]`.
|
|
127
|
+
|
|
128
|
+
**In** — `prediction[0] <= prediction[1]`, span ∈ `[1, 950]`. Win: `prediction[0] <= roll <= prediction[1]`.
|
|
129
|
+
|
|
130
|
+
**Out** — `prediction[0] <= prediction[1]`, inner span ∈ `[50, 999]` (wn = `1000 − inner` ∈ `[1, 950]`). Win: `roll < prediction[0] || roll > prediction[1]`.
|
|
131
|
+
|
|
132
|
+
### Multiplier
|
|
133
|
+
|
|
134
|
+
`multiplier = floor(9_900_000 / wn)` (scaled ×10000).
|
|
135
|
+
|
|
136
|
+
| wn | multiplier | display |
|
|
137
|
+
|-----|-----------|-----------|
|
|
138
|
+
| 1 | 9_900_000 | 990.0000x |
|
|
139
|
+
| 500 | 19_800 | 1.9800x |
|
|
140
|
+
| 950 | 10_421 | 1.0421x |
|
|
141
|
+
|
|
142
|
+
### RTP
|
|
143
|
+
|
|
144
|
+
Theoretical: **98.998%** (floor-division costs ~0.002%). House edge: **~1.002%**. Max win cap: 10,000 USDT (business rule, not formula).
|
|
145
|
+
|
|
110
146
|
## License
|
|
111
147
|
|
|
112
148
|
MIT
|
|
@@ -18,11 +18,38 @@ export function amount_split(amount: bigint): Uint32Array;
|
|
|
18
18
|
*/
|
|
19
19
|
export function compute_address_hash(address_hex: string): BigUint64Array;
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Compute dice multiplier × 10000 from win_numbers count.
|
|
23
|
+
*
|
|
24
|
+
* Formula: `9_900_000 / win_numbers` (integer division = floor).
|
|
25
|
+
* `win_numbers` must be in [1, 950].
|
|
26
|
+
*/
|
|
27
|
+
export function compute_multi_dice(win_numbers: number): bigint;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Full dice payout computation — pure integer arithmetic, zero floats.
|
|
31
|
+
*
|
|
32
|
+
* `random`: 4 Goldilocks field elements (Poseidon2 output).
|
|
33
|
+
* `bet_atomic`: bet in atomic units (1 USDT = 1_000_000).
|
|
34
|
+
* `game_mode`: 0=Under, 1=Over, 2=In, 3=Out.
|
|
35
|
+
* `prediction_lo` / `prediction_hi`: prediction range bounds (0..999).
|
|
36
|
+
*
|
|
37
|
+
* Returns `BigUint64Array[4]`: `[win_amount, roll_number, is_win (0|1), multiplier×10000]`.
|
|
38
|
+
*/
|
|
39
|
+
export function compute_payout_dice(random: BigUint64Array, bet_atomic: bigint, game_mode: number, prediction_lo: number, prediction_hi: number): BigUint64Array;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Extract dice roll number [0, 1000) from Poseidon2 random output.
|
|
43
|
+
*
|
|
44
|
+
* `random` must be exactly 4 elements. Returns `random[0] % 1000`.
|
|
45
|
+
*/
|
|
46
|
+
export function compute_roll_dice(random: BigUint64Array): number;
|
|
47
|
+
|
|
21
48
|
/**
|
|
22
49
|
* Full Poseidon2 hash of an 8-element server seed.
|
|
23
50
|
*
|
|
24
51
|
* Returns all 4 hash elements. Note: the circuit stores only the
|
|
25
|
-
* **first
|
|
52
|
+
* **first 3 elements** as the leaf commitment (see `seed_hash_truncated`).
|
|
26
53
|
* This full variant is useful for client-side verification where all
|
|
27
54
|
* 4 elements may be needed.
|
|
28
55
|
*
|
|
@@ -86,6 +113,41 @@ export function goldilocks_modulus(): bigint;
|
|
|
86
113
|
*/
|
|
87
114
|
export function goldilocks_reduce(value: bigint): bigint;
|
|
88
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Hash a raw 7-element balance leaf → 4-element Merkle node.
|
|
118
|
+
*
|
|
119
|
+
* Raw layout: `[balance_lo, balance_hi, seed_hash_0, seed_hash_1, seed_hash_2, credit_lo, credit_hi]`
|
|
120
|
+
*
|
|
121
|
+
* Identical to `hash_balance_leaf` in `prover/circuit/src/helpers/leaf_ops.rs`.
|
|
122
|
+
*
|
|
123
|
+
* **Input** : `BigUint64Array` of exactly 7 elements (each < `GOLDILOCKS_P`).
|
|
124
|
+
* **Output**: `BigUint64Array` of length 4 (one `HashOut`).
|
|
125
|
+
*
|
|
126
|
+
* ```js
|
|
127
|
+
* const raw = BigUint64Array.from([balLo, balHi, seed0, seed1, seed2, credLo, credHi]);
|
|
128
|
+
* const balanceHash = hash_balance_leaf(raw); // length 4
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export function hash_balance_leaf(raw: BigUint64Array): BigUint64Array;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Build a main Merkle tree leaf from balance_hash, pk_hash, and address_hash.
|
|
135
|
+
*
|
|
136
|
+
* `main_leaf = Poseidon2(balance_hash[4] || pk_hash[0..2] || address_hash[0..2])`
|
|
137
|
+
*
|
|
138
|
+
* Uses truncated (128-bit) pk/address hashes to keep the preimage at 8 elements
|
|
139
|
+
* (single Poseidon2 permutation round). Identical to `make_main_leaf` in
|
|
140
|
+
* `prover/circuit/src/helpers/leaf_ops.rs`.
|
|
141
|
+
*
|
|
142
|
+
* All three inputs must be exactly 4 elements.
|
|
143
|
+
* **Output**: `BigUint64Array` of length 4 (the Merkle leaf hash).
|
|
144
|
+
*
|
|
145
|
+
* ```js
|
|
146
|
+
* const leaf = make_main_leaf(balanceHash, pkHash, addressHash);
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export function make_main_leaf(balance_hash: BigUint64Array, pk_hash: BigUint64Array, address_hash: BigUint64Array): BigUint64Array;
|
|
150
|
+
|
|
89
151
|
/**
|
|
90
152
|
* Poseidon2 hash of an arbitrary number of Goldilocks field elements.
|
|
91
153
|
*
|
|
@@ -113,13 +175,15 @@ export function poseidon2_hash(input: BigUint64Array): BigUint64Array;
|
|
|
113
175
|
export function poseidon2_two_to_one(left: BigUint64Array, right: BigUint64Array): BigUint64Array;
|
|
114
176
|
|
|
115
177
|
/**
|
|
116
|
-
* Truncated seed hash — first
|
|
178
|
+
* Truncated seed hash — first 3 elements of `Poseidon2(server_seed)`.
|
|
117
179
|
*
|
|
180
|
+
* 192 bits of commitment → ~96-bit collision resistance, which closes the
|
|
181
|
+
* multi-preimage grinding vector that an earlier 128-bit truncation left open.
|
|
118
182
|
* This is the exact format stored in the Merkle-tree leaf and verified
|
|
119
183
|
* by the circuit. Matches `seed_hash_truncated` in
|
|
120
|
-
* `src/block_builder/builder.rs` and `src/circuit/
|
|
184
|
+
* `src/block_builder/builder.rs` and `src/circuit/slot/fairness.rs`.
|
|
121
185
|
*
|
|
122
|
-
* Returns `BigUint64Array` of length
|
|
186
|
+
* Returns `BigUint64Array` of length 3: `[h[0], h[1], h[2]]`.
|
|
123
187
|
*/
|
|
124
188
|
export function seed_hash_truncated(server_seed: BigUint64Array): BigUint64Array;
|
|
125
189
|
|
|
@@ -49,11 +49,73 @@ function compute_address_hash(address_hex) {
|
|
|
49
49
|
}
|
|
50
50
|
exports.compute_address_hash = compute_address_hash;
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Compute dice multiplier × 10000 from win_numbers count.
|
|
54
|
+
*
|
|
55
|
+
* Formula: `9_900_000 / win_numbers` (integer division = floor).
|
|
56
|
+
* `win_numbers` must be in [1, 950].
|
|
57
|
+
* @param {number} win_numbers
|
|
58
|
+
* @returns {bigint}
|
|
59
|
+
*/
|
|
60
|
+
function compute_multi_dice(win_numbers) {
|
|
61
|
+
const ret = wasm.compute_multi_dice(win_numbers);
|
|
62
|
+
return BigInt.asUintN(64, ret);
|
|
63
|
+
}
|
|
64
|
+
exports.compute_multi_dice = compute_multi_dice;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Full dice payout computation — pure integer arithmetic, zero floats.
|
|
68
|
+
*
|
|
69
|
+
* `random`: 4 Goldilocks field elements (Poseidon2 output).
|
|
70
|
+
* `bet_atomic`: bet in atomic units (1 USDT = 1_000_000).
|
|
71
|
+
* `game_mode`: 0=Under, 1=Over, 2=In, 3=Out.
|
|
72
|
+
* `prediction_lo` / `prediction_hi`: prediction range bounds (0..999).
|
|
73
|
+
*
|
|
74
|
+
* Returns `BigUint64Array[4]`: `[win_amount, roll_number, is_win (0|1), multiplier×10000]`.
|
|
75
|
+
* @param {BigUint64Array} random
|
|
76
|
+
* @param {bigint} bet_atomic
|
|
77
|
+
* @param {number} game_mode
|
|
78
|
+
* @param {number} prediction_lo
|
|
79
|
+
* @param {number} prediction_hi
|
|
80
|
+
* @returns {BigUint64Array}
|
|
81
|
+
*/
|
|
82
|
+
function compute_payout_dice(random, bet_atomic, game_mode, prediction_lo, prediction_hi) {
|
|
83
|
+
try {
|
|
84
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
85
|
+
const ptr0 = passArray64ToWasm0(random, wasm.__wbindgen_export3);
|
|
86
|
+
const len0 = WASM_VECTOR_LEN;
|
|
87
|
+
wasm.compute_payout_dice(retptr, ptr0, len0, bet_atomic, game_mode, prediction_lo, prediction_hi);
|
|
88
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
89
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
90
|
+
var v2 = getArrayU64FromWasm0(r0, r1).slice();
|
|
91
|
+
wasm.__wbindgen_export2(r0, r1 * 8, 8);
|
|
92
|
+
return v2;
|
|
93
|
+
} finally {
|
|
94
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
exports.compute_payout_dice = compute_payout_dice;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Extract dice roll number [0, 1000) from Poseidon2 random output.
|
|
101
|
+
*
|
|
102
|
+
* `random` must be exactly 4 elements. Returns `random[0] % 1000`.
|
|
103
|
+
* @param {BigUint64Array} random
|
|
104
|
+
* @returns {number}
|
|
105
|
+
*/
|
|
106
|
+
function compute_roll_dice(random) {
|
|
107
|
+
const ptr0 = passArray64ToWasm0(random, wasm.__wbindgen_export3);
|
|
108
|
+
const len0 = WASM_VECTOR_LEN;
|
|
109
|
+
const ret = wasm.compute_roll_dice(ptr0, len0);
|
|
110
|
+
return ret >>> 0;
|
|
111
|
+
}
|
|
112
|
+
exports.compute_roll_dice = compute_roll_dice;
|
|
113
|
+
|
|
52
114
|
/**
|
|
53
115
|
* Full Poseidon2 hash of an 8-element server seed.
|
|
54
116
|
*
|
|
55
117
|
* Returns all 4 hash elements. Note: the circuit stores only the
|
|
56
|
-
* **first
|
|
118
|
+
* **first 3 elements** as the leaf commitment (see `seed_hash_truncated`).
|
|
57
119
|
* This full variant is useful for client-side verification where all
|
|
58
120
|
* 4 elements may be needed.
|
|
59
121
|
*
|
|
@@ -199,6 +261,81 @@ function goldilocks_reduce(value) {
|
|
|
199
261
|
}
|
|
200
262
|
exports.goldilocks_reduce = goldilocks_reduce;
|
|
201
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Hash a raw 7-element balance leaf → 4-element Merkle node.
|
|
266
|
+
*
|
|
267
|
+
* Raw layout: `[balance_lo, balance_hi, seed_hash_0, seed_hash_1, seed_hash_2, credit_lo, credit_hi]`
|
|
268
|
+
*
|
|
269
|
+
* Identical to `hash_balance_leaf` in `prover/circuit/src/helpers/leaf_ops.rs`.
|
|
270
|
+
*
|
|
271
|
+
* **Input** : `BigUint64Array` of exactly 7 elements (each < `GOLDILOCKS_P`).
|
|
272
|
+
* **Output**: `BigUint64Array` of length 4 (one `HashOut`).
|
|
273
|
+
*
|
|
274
|
+
* ```js
|
|
275
|
+
* const raw = BigUint64Array.from([balLo, balHi, seed0, seed1, seed2, credLo, credHi]);
|
|
276
|
+
* const balanceHash = hash_balance_leaf(raw); // length 4
|
|
277
|
+
* ```
|
|
278
|
+
* @param {BigUint64Array} raw
|
|
279
|
+
* @returns {BigUint64Array}
|
|
280
|
+
*/
|
|
281
|
+
function hash_balance_leaf(raw) {
|
|
282
|
+
try {
|
|
283
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
284
|
+
const ptr0 = passArray64ToWasm0(raw, wasm.__wbindgen_export3);
|
|
285
|
+
const len0 = WASM_VECTOR_LEN;
|
|
286
|
+
wasm.hash_balance_leaf(retptr, ptr0, len0);
|
|
287
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
288
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
289
|
+
var v2 = getArrayU64FromWasm0(r0, r1).slice();
|
|
290
|
+
wasm.__wbindgen_export2(r0, r1 * 8, 8);
|
|
291
|
+
return v2;
|
|
292
|
+
} finally {
|
|
293
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
exports.hash_balance_leaf = hash_balance_leaf;
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Build a main Merkle tree leaf from balance_hash, pk_hash, and address_hash.
|
|
300
|
+
*
|
|
301
|
+
* `main_leaf = Poseidon2(balance_hash[4] || pk_hash[0..2] || address_hash[0..2])`
|
|
302
|
+
*
|
|
303
|
+
* Uses truncated (128-bit) pk/address hashes to keep the preimage at 8 elements
|
|
304
|
+
* (single Poseidon2 permutation round). Identical to `make_main_leaf` in
|
|
305
|
+
* `prover/circuit/src/helpers/leaf_ops.rs`.
|
|
306
|
+
*
|
|
307
|
+
* All three inputs must be exactly 4 elements.
|
|
308
|
+
* **Output**: `BigUint64Array` of length 4 (the Merkle leaf hash).
|
|
309
|
+
*
|
|
310
|
+
* ```js
|
|
311
|
+
* const leaf = make_main_leaf(balanceHash, pkHash, addressHash);
|
|
312
|
+
* ```
|
|
313
|
+
* @param {BigUint64Array} balance_hash
|
|
314
|
+
* @param {BigUint64Array} pk_hash
|
|
315
|
+
* @param {BigUint64Array} address_hash
|
|
316
|
+
* @returns {BigUint64Array}
|
|
317
|
+
*/
|
|
318
|
+
function make_main_leaf(balance_hash, pk_hash, address_hash) {
|
|
319
|
+
try {
|
|
320
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
321
|
+
const ptr0 = passArray64ToWasm0(balance_hash, wasm.__wbindgen_export3);
|
|
322
|
+
const len0 = WASM_VECTOR_LEN;
|
|
323
|
+
const ptr1 = passArray64ToWasm0(pk_hash, wasm.__wbindgen_export3);
|
|
324
|
+
const len1 = WASM_VECTOR_LEN;
|
|
325
|
+
const ptr2 = passArray64ToWasm0(address_hash, wasm.__wbindgen_export3);
|
|
326
|
+
const len2 = WASM_VECTOR_LEN;
|
|
327
|
+
wasm.make_main_leaf(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
|
|
328
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
329
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
330
|
+
var v4 = getArrayU64FromWasm0(r0, r1).slice();
|
|
331
|
+
wasm.__wbindgen_export2(r0, r1 * 8, 8);
|
|
332
|
+
return v4;
|
|
333
|
+
} finally {
|
|
334
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
exports.make_main_leaf = make_main_leaf;
|
|
338
|
+
|
|
202
339
|
/**
|
|
203
340
|
* Poseidon2 hash of an arbitrary number of Goldilocks field elements.
|
|
204
341
|
*
|
|
@@ -263,13 +400,15 @@ function poseidon2_two_to_one(left, right) {
|
|
|
263
400
|
exports.poseidon2_two_to_one = poseidon2_two_to_one;
|
|
264
401
|
|
|
265
402
|
/**
|
|
266
|
-
* Truncated seed hash — first
|
|
403
|
+
* Truncated seed hash — first 3 elements of `Poseidon2(server_seed)`.
|
|
267
404
|
*
|
|
405
|
+
* 192 bits of commitment → ~96-bit collision resistance, which closes the
|
|
406
|
+
* multi-preimage grinding vector that an earlier 128-bit truncation left open.
|
|
268
407
|
* This is the exact format stored in the Merkle-tree leaf and verified
|
|
269
408
|
* by the circuit. Matches `seed_hash_truncated` in
|
|
270
|
-
* `src/block_builder/builder.rs` and `src/circuit/
|
|
409
|
+
* `src/block_builder/builder.rs` and `src/circuit/slot/fairness.rs`.
|
|
271
410
|
*
|
|
272
|
-
* Returns `BigUint64Array` of length
|
|
411
|
+
* Returns `BigUint64Array` of length 3: `[h[0], h[1], h[2]]`.
|
|
273
412
|
* @param {BigUint64Array} server_seed
|
|
274
413
|
* @returns {BigUint64Array}
|
|
275
414
|
*/
|
|
Binary file
|
|
@@ -3,11 +3,16 @@
|
|
|
3
3
|
export const memory: WebAssembly.Memory;
|
|
4
4
|
export const amount_split: (a: number, b: bigint) => void;
|
|
5
5
|
export const compute_address_hash: (a: number, b: number, c: number) => void;
|
|
6
|
+
export const compute_multi_dice: (a: number) => bigint;
|
|
7
|
+
export const compute_payout_dice: (a: number, b: number, c: number, d: bigint, e: number, f: number, g: number) => void;
|
|
8
|
+
export const compute_roll_dice: (a: number, b: number) => number;
|
|
6
9
|
export const compute_server_seed_hash: (a: number, b: number, c: number) => void;
|
|
7
10
|
export const derive_session_key: (a: number, b: number, c: number) => void;
|
|
8
11
|
export const generate_user_seed: (a: number) => void;
|
|
9
12
|
export const goldilocks_fields_to_hex: (a: number, b: number, c: number) => void;
|
|
10
13
|
export const goldilocks_reduce: (a: bigint) => bigint;
|
|
14
|
+
export const hash_balance_leaf: (a: number, b: number, c: number) => void;
|
|
15
|
+
export const make_main_leaf: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
11
16
|
export const poseidon2_hash: (a: number, b: number, c: number) => void;
|
|
12
17
|
export const poseidon2_two_to_one: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
13
18
|
export const seed_hash_truncated: (a: number, b: number, c: number) => void;
|
|
@@ -89,7 +89,7 @@ poseidon2_hash(BigUint64Array.from([1n]));
|
|
|
89
89
|
| `derive_session_key` | `Uint8Array(32)` | `BigUint64Array(4)` | MetaMask sig → session key |
|
|
90
90
|
| `session_public_key` | `(BigUint64Array(4), bigint)` | `BigUint64Array(4)` | pk_hash = Poseidon2(session_key, expiry) |
|
|
91
91
|
| `compute_server_seed_hash` | `BigUint64Array(8)` | `BigUint64Array(4)` | Full hash of server seed |
|
|
92
|
-
| `seed_hash_truncated` | `BigUint64Array(8)` | `BigUint64Array(
|
|
92
|
+
| `seed_hash_truncated` | `BigUint64Array(8)` | `BigUint64Array(3)` | First 3 elements (circuit leaf format, 192-bit commitment) |
|
|
93
93
|
| `goldilocks_modulus` | — | `bigint` | Returns p = 2^64 - 2^32 + 1 |
|
|
94
94
|
| `goldilocks_reduce` | `bigint` | `bigint` | Reduce mod p |
|
|
95
95
|
|
|
@@ -107,6 +107,42 @@ module.exports = { experiments: { asyncWebAssembly: true } };
|
|
|
107
107
|
|
|
108
108
|
**Next.js** — conditional exports auto-resolve: Node.js entry on server, browser entry on client.
|
|
109
109
|
|
|
110
|
+
## Dice — range constraints
|
|
111
|
+
|
|
112
|
+
Roll number: `[0, 999]` (TOTAL_RANGE = 1000).
|
|
113
|
+
win_numbers (wn): `[1, 950]` (MIN_RANGE..=MAX_RANGE).
|
|
114
|
+
|
|
115
|
+
### prediction_range constraints per mode
|
|
116
|
+
|
|
117
|
+
| Mode | wn formula | prediction\[0\] | prediction\[1\] | wn range |
|
|
118
|
+
|-------|-------------------------------------------------|-----------------|-----------------|------------|
|
|
119
|
+
| Under | `prediction[0]` | `[1, 950]` | unused (0) | `[1, 950]` |
|
|
120
|
+
| Over | `999 − prediction[0]` | `[49, 998]` | unused (0) | `[1, 950]` |
|
|
121
|
+
| In | `prediction[1] − prediction[0] + 1` | `[0, 999]` | `[0, 999]` | `[1, 950]` |
|
|
122
|
+
| Out | `1000 − (prediction[1] − prediction[0] + 1)` | `[0, 999]` | `[0, 999]` | `[1, 950]` |
|
|
123
|
+
|
|
124
|
+
**Under** — `prediction[0]` ∈ `[1, 950]` (= wn directly). Win: `roll < prediction[0]`.
|
|
125
|
+
|
|
126
|
+
**Over** — `prediction[0]` ∈ `[49, 998]` (lower: `999 − 950 = 49`, upper: `999 − 1 = 998`). Win: `roll > prediction[0]`.
|
|
127
|
+
|
|
128
|
+
**In** — `prediction[0] <= prediction[1]`, span ∈ `[1, 950]`. Win: `prediction[0] <= roll <= prediction[1]`.
|
|
129
|
+
|
|
130
|
+
**Out** — `prediction[0] <= prediction[1]`, inner span ∈ `[50, 999]` (wn = `1000 − inner` ∈ `[1, 950]`). Win: `roll < prediction[0] || roll > prediction[1]`.
|
|
131
|
+
|
|
132
|
+
### Multiplier
|
|
133
|
+
|
|
134
|
+
`multiplier = floor(9_900_000 / wn)` (scaled ×10000).
|
|
135
|
+
|
|
136
|
+
| wn | multiplier | display |
|
|
137
|
+
|-----|-----------|-----------|
|
|
138
|
+
| 1 | 9_900_000 | 990.0000x |
|
|
139
|
+
| 500 | 19_800 | 1.9800x |
|
|
140
|
+
| 950 | 10_421 | 1.0421x |
|
|
141
|
+
|
|
142
|
+
### RTP
|
|
143
|
+
|
|
144
|
+
Theoretical: **98.998%** (floor-division costs ~0.002%). House edge: **~1.002%**. Max win cap: 10,000 USDT (business rule, not formula).
|
|
145
|
+
|
|
110
146
|
## License
|
|
111
147
|
|
|
112
148
|
MIT
|
|
@@ -18,11 +18,38 @@ export function amount_split(amount: bigint): Uint32Array;
|
|
|
18
18
|
*/
|
|
19
19
|
export function compute_address_hash(address_hex: string): BigUint64Array;
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Compute dice multiplier × 10000 from win_numbers count.
|
|
23
|
+
*
|
|
24
|
+
* Formula: `9_900_000 / win_numbers` (integer division = floor).
|
|
25
|
+
* `win_numbers` must be in [1, 950].
|
|
26
|
+
*/
|
|
27
|
+
export function compute_multi_dice(win_numbers: number): bigint;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Full dice payout computation — pure integer arithmetic, zero floats.
|
|
31
|
+
*
|
|
32
|
+
* `random`: 4 Goldilocks field elements (Poseidon2 output).
|
|
33
|
+
* `bet_atomic`: bet in atomic units (1 USDT = 1_000_000).
|
|
34
|
+
* `game_mode`: 0=Under, 1=Over, 2=In, 3=Out.
|
|
35
|
+
* `prediction_lo` / `prediction_hi`: prediction range bounds (0..999).
|
|
36
|
+
*
|
|
37
|
+
* Returns `BigUint64Array[4]`: `[win_amount, roll_number, is_win (0|1), multiplier×10000]`.
|
|
38
|
+
*/
|
|
39
|
+
export function compute_payout_dice(random: BigUint64Array, bet_atomic: bigint, game_mode: number, prediction_lo: number, prediction_hi: number): BigUint64Array;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Extract dice roll number [0, 1000) from Poseidon2 random output.
|
|
43
|
+
*
|
|
44
|
+
* `random` must be exactly 4 elements. Returns `random[0] % 1000`.
|
|
45
|
+
*/
|
|
46
|
+
export function compute_roll_dice(random: BigUint64Array): number;
|
|
47
|
+
|
|
21
48
|
/**
|
|
22
49
|
* Full Poseidon2 hash of an 8-element server seed.
|
|
23
50
|
*
|
|
24
51
|
* Returns all 4 hash elements. Note: the circuit stores only the
|
|
25
|
-
* **first
|
|
52
|
+
* **first 3 elements** as the leaf commitment (see `seed_hash_truncated`).
|
|
26
53
|
* This full variant is useful for client-side verification where all
|
|
27
54
|
* 4 elements may be needed.
|
|
28
55
|
*
|
|
@@ -86,6 +113,41 @@ export function goldilocks_modulus(): bigint;
|
|
|
86
113
|
*/
|
|
87
114
|
export function goldilocks_reduce(value: bigint): bigint;
|
|
88
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Hash a raw 7-element balance leaf → 4-element Merkle node.
|
|
118
|
+
*
|
|
119
|
+
* Raw layout: `[balance_lo, balance_hi, seed_hash_0, seed_hash_1, seed_hash_2, credit_lo, credit_hi]`
|
|
120
|
+
*
|
|
121
|
+
* Identical to `hash_balance_leaf` in `prover/circuit/src/helpers/leaf_ops.rs`.
|
|
122
|
+
*
|
|
123
|
+
* **Input** : `BigUint64Array` of exactly 7 elements (each < `GOLDILOCKS_P`).
|
|
124
|
+
* **Output**: `BigUint64Array` of length 4 (one `HashOut`).
|
|
125
|
+
*
|
|
126
|
+
* ```js
|
|
127
|
+
* const raw = BigUint64Array.from([balLo, balHi, seed0, seed1, seed2, credLo, credHi]);
|
|
128
|
+
* const balanceHash = hash_balance_leaf(raw); // length 4
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export function hash_balance_leaf(raw: BigUint64Array): BigUint64Array;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Build a main Merkle tree leaf from balance_hash, pk_hash, and address_hash.
|
|
135
|
+
*
|
|
136
|
+
* `main_leaf = Poseidon2(balance_hash[4] || pk_hash[0..2] || address_hash[0..2])`
|
|
137
|
+
*
|
|
138
|
+
* Uses truncated (128-bit) pk/address hashes to keep the preimage at 8 elements
|
|
139
|
+
* (single Poseidon2 permutation round). Identical to `make_main_leaf` in
|
|
140
|
+
* `prover/circuit/src/helpers/leaf_ops.rs`.
|
|
141
|
+
*
|
|
142
|
+
* All three inputs must be exactly 4 elements.
|
|
143
|
+
* **Output**: `BigUint64Array` of length 4 (the Merkle leaf hash).
|
|
144
|
+
*
|
|
145
|
+
* ```js
|
|
146
|
+
* const leaf = make_main_leaf(balanceHash, pkHash, addressHash);
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export function make_main_leaf(balance_hash: BigUint64Array, pk_hash: BigUint64Array, address_hash: BigUint64Array): BigUint64Array;
|
|
150
|
+
|
|
89
151
|
/**
|
|
90
152
|
* Poseidon2 hash of an arbitrary number of Goldilocks field elements.
|
|
91
153
|
*
|
|
@@ -113,13 +175,15 @@ export function poseidon2_hash(input: BigUint64Array): BigUint64Array;
|
|
|
113
175
|
export function poseidon2_two_to_one(left: BigUint64Array, right: BigUint64Array): BigUint64Array;
|
|
114
176
|
|
|
115
177
|
/**
|
|
116
|
-
* Truncated seed hash — first
|
|
178
|
+
* Truncated seed hash — first 3 elements of `Poseidon2(server_seed)`.
|
|
117
179
|
*
|
|
180
|
+
* 192 bits of commitment → ~96-bit collision resistance, which closes the
|
|
181
|
+
* multi-preimage grinding vector that an earlier 128-bit truncation left open.
|
|
118
182
|
* This is the exact format stored in the Merkle-tree leaf and verified
|
|
119
183
|
* by the circuit. Matches `seed_hash_truncated` in
|
|
120
|
-
* `src/block_builder/builder.rs` and `src/circuit/
|
|
184
|
+
* `src/block_builder/builder.rs` and `src/circuit/slot/fairness.rs`.
|
|
121
185
|
*
|
|
122
|
-
* Returns `BigUint64Array` of length
|
|
186
|
+
* Returns `BigUint64Array` of length 3: `[h[0], h[1], h[2]]`.
|
|
123
187
|
*/
|
|
124
188
|
export function seed_hash_truncated(server_seed: BigUint64Array): BigUint64Array;
|
|
125
189
|
|