Skip to content

FeistelPerm, SwapOrNotPerm, MitchellPerm: keyed-bijection permutations - #88

Open
jowens wants to merge 1 commit into
mainfrom
bijection-perms
Open

jowens wants to merge 1 commit into
mainfrom
bijection-perms

Conversation

@jowens

@jowens jowens commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

Ports the paper's three keyed-bijection permutations (perm[i] = f(i)) to Gridwise primitives, after MultisplitPerm and ShunPerm.

  • FeistelPerm: a balanced Feistel network with a triple32 or multiply-shift round function, cycle-walked to [0, n).
  • SwapOrNotPerm: Hoang, Morris and Rogaway's swap-or-not cipher, directly on [0, n).
  • MitchellPerm: Mitchell et al. (ACM TOPC 2022), as NVIDIA Thrust's thrust::shuffle does it.
    • mode: "scan" (default) gives Thrust's output in three steps: count, then DLDFScan, then write. Thrust's single-pass version needs forward progress, which WebGPU doesn't promise.
    • mode: "walk" cycle-walks in one kernel.

Shared base class. All three extend a small BijectionPerm class. A subclass supplies:

  • the WGSL fn bijection(x);
  • its bit-exact JS mirror;
  • the round keys;
  • a UniformStruct that starts with n.

The base provides the buffers, the cycle-walking kernel, gather (out[i] = in[f(i)], 64-bit values by default), reference() and validate().

Smaller changes

  • random.mjs exports MULHI_WGSL and mulhiJS, which Philox and Mitchell's bijection share.
  • benchmark_node.mjs adds feistel, swapornot and mitchell.
  • Regression tests: 12 small, 3 large.
  • New section in docs/random-permutations.md.

Verification (lavapipe)

  • Output is bit-identical to the paper's hand-written modules for n = 1, 2, 7, 256, 1000, 4096, 65537, 100003 and 2^20. This covers both round functions, 4 and 24 rounds, gather, and both Mitchell modes.
  • The new regression tests pass.
  • The suite's only failures on lavapipe are the existing OneSweep sorts on its narrow subgroups.

Separately: without subgroups on lavapipe, DLDFScan gives wrong output from element 128 on, for example at 256 or 1024 elements. That affects MitchellPerm's scan mode and the old paper module alike. It looks like the emulated subgroups depending on spin-waits that lavapipe doesn't support. The macOS emulated CI job covers that path.


Generated by Claude Code

Three random permutations of the form perm[i] = f(i) for a keyed
pseudorandom bijection f, ported from the random-permutations paper:

- FeistelPerm: balanced Feistel network (triple32 or multiply-shift
  round function), cycle-walked to [0, n)
- SwapOrNotPerm: Hoang, Morris and Rogaway's swap-or-not cipher
- MitchellPerm: Mitchell et al. as in Thrust's thrust::shuffle; "scan"
  mode (count, DLDFScan, write) gives Thrust's output, "walk" mode
  cycle-walks in one kernel

They share a base class, BijectionPerm: a subclass supplies the WGSL
bijection, its bit-exact JS mirror, round keys and a parameters struct;
the base provides buffers, the cycle-walking kernel, gather
(out[i] = in[f(i)], 64-bit values by default), reference() and
validate(). Output is bit-identical to the paper's modules (lavapipe,
n from 1 to 2^20, both round functions, gather, both Mitchell modes).

random.mjs exports MULHI_WGSL and mulhiJS (the 32x32 high product,
which Philox and Mitchell's bijection share). benchmark_node gains
feistel, swapornot and mitchell; regression tests and docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015kfNC6id65zEHzuAAH4jtJ

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants