npm package: @rolly-dev/wasm-signer
Description: Poseidon2 hashing & bet signing for Rolly ZK-Rollup (WASM, Goldilocks field)
Latest version: 0.12.0

# @rolly-dev/wasm-signer

Client-side Poseidon2 hashing and bet authentication for the Rolly ZK-Rollup casino.

Built with Rust → WebAssembly (via `wasm-pack`), using the same Poseidon2 hasher
and Goldilocks field as the plonky2 proving circuit.

## Build

```bash
# requires: cargo, wasm-pack
npm run build
# → dist/node/  (Node.js, CJS, sync init)
# → dist/web/   (Browser, ESM, async init)
```

## Usage

### Node.js (CommonJS)

```javascript
const {
  poseidon2_hash,
  derive_session_key,
  session_public_key,
  create_bet_auth,
} = require('@rolly-dev/wasm-signer');

const hash = poseidon2_hash(BigUint64Array.from([1n, 2n, 3n]));
// → BigUint64Array(4)
```

### Node.js (ESM)

```javascript
import {
  poseidon2_hash,
  derive_session_key,
  create_bet_auth,
} from '@rolly-dev/wasm-signer';

const hash = poseidon2_hash(BigUint64Array.from([1n, 2n, 3n]));
```

### React

```jsx
import { useRollyWasm } from '@rolly-dev/wasm-signer/react';

function BetButton({ sessionKey, amount, nonce }) {
  const { ready, create_bet_auth } = useRollyWasm();

  if (!ready) return <span>Loading...</span>;

  const handleBet = () => {
    const auth = create_bet_auth(sessionKey, BigInt(amount), BigInt(nonce));
    // send auth to server...
  };

  return <button onClick={handleBet}>Place Bet</button>;
}
```

### Browser (vanilla ESM)

```html
<script type="module">
  import { init, poseidon2_hash } from '@rolly-dev/wasm-signer';

  await init();  // loads .wasm, must be called once
  const h = poseidon2_hash(BigUint64Array.from([1n, 2n]));
</script>
```

### Manual init (advanced)

```javascript
import init, { poseidon2_hash } from '@rolly-dev/wasm-signer/init';

// custom wasm URL or ArrayBuffer
await init('/assets/rolly_wasm_signer_bg.wasm');
poseidon2_hash(BigUint64Array.from([1n]));
```

## API

| Function                   | Input                          | Output            | Description                                    |
|----------------------------|--------------------------------|-------------------|------------------------------------------------|
| `poseidon2_hash`           | `BigUint64Array`               | `BigUint64Array(4)` | Hash N field elements                        |
| `poseidon2_two_to_one`     | `BigUint64Array(4)` × 2        | `BigUint64Array(4)` | Merkle hash: H(left‖right)                   |
| `derive_session_key`       | `Uint8Array(32)`               | `BigUint64Array(4)` | MetaMask sig → session key                   |
| `session_public_key`       | `BigUint64Array(4)`            | `BigUint64Array(4)` | session_pk = H(session_key)                  |
| `create_bet_auth`          | `(BigUint64Array(4), bigint, bigint)` | `BigUint64Array(4)` | MAC = H(sk‖amount_lo‖amount_hi‖nonce)  |
| `compute_server_seed_hash` | `BigUint64Array(8)`            | `BigUint64Array(4)` | Full hash of server seed                     |
| `seed_hash_truncated`      | `BigUint64Array(8)`            | `BigUint64Array(2)` | First 2 elements (circuit leaf format)       |
| `goldilocks_modulus`       | —                              | `bigint`          | Returns p = 2^64 - 2^32 + 1                   |
| `goldilocks_reduce`        | `bigint`                       | `bigint`          | Reduce mod p                                   |

## Bundler notes

**Vite** — add to `optimizeDeps.exclude`:
```js
optimizeDeps: { exclude: ['@rolly-dev/wasm-signer'] }
```

**Webpack 5** — enable WASM experiments:
```js
module.exports = { experiments: { asyncWebAssembly: true } };
```

**Next.js** — conditional exports auto-resolve: Node.js entry on server, browser entry on client.

## License

MIT