https://github.com/eignex/kpermute
Kotlin library for shuffling lists too big for memory or for ID obfuscation. Using bijective integer permutations with fast cycle-walking hash mixing.
https://github.com/eignex/kpermute
algorithm bijective-permutation data-masking integer-permutation kotlin kotlin-library kotlin-multiplatform permutation shuffling
Last synced: about 12 hours ago
JSON representation
Kotlin library for shuffling lists too big for memory or for ID obfuscation. Using bijective integer permutations with fast cycle-walking hash mixing.
- Host: GitHub
- URL: https://github.com/eignex/kpermute
- Owner: Eignex
- License: apache-2.0
- Created: 2025-11-03T20:28:52.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2026-04-23T06:42:11.000Z (5 days ago)
- Last Synced: 2026-04-23T08:26:49.714Z (5 days ago)
- Topics: algorithm, bijective-permutation, data-masking, integer-permutation, kotlin, kotlin-library, kotlin-multiplatform, permutation, shuffling
- Language: Kotlin
- Homepage: https://eignex.com/
- Size: 219 KB
- Stars: 18
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# KPermute
Fast, deterministic integer permutation library for Kotlin.
[](https://central.sonatype.com/artifact/com.eignex/kpermute)
[](https://github.com/eignex/kpermute/actions/workflows/build.yml)
[](https://codecov.io/gh/eignex/kpermute)
[](https://github.com/eignex/kpermute/blob/main/LICENSE)
> Shuffle or obfuscate large integer domains efficiently using bijective,
> reversible hash mixing.
**Not intended for cryptographic use.**
Suitable for data masking, sampling, and reproducible pseudo-randomization
where reversibility is required. You decide if your use-case is cryptographic.
---
## Overview
kpermute generates stable, deterministic pseudo-random permutations over
integer ranges. Each seed defines a unique bijection between `[0, size)`.
The result acts like a keyed shuffle, repeatable, memory-efficient, and
invertible.
Typical use cases:
- Repeatable pseudo-random shuffles
- Obfuscating integer IDs (e.g., user IDs, session numbers)
- Collision-free sampling or load balancing
- Data masking for non-sensitive identifiers
---
## Installation
Add the dependency from Maven Central:
```kotlin
implementation("com.eignex:kpermute:1.1.2")
```
---
## Example Usage
### Obfuscate numeric IDs reproducibly
```kotlin
val idPerm = longPermutation(seed = 1L)
val longId = 49102490812045L
val encoded = idPerm.encode(longId)
println("encoded: $encoded (always prints 3631103739497407856)")
```
### Shuffle a large list lazily
```kotlin
val largeList = object : AbstractList() {
override val size: Int get() = Int.MAX_VALUE
override fun get(index: Int) = index
}
val perm = intPermutation(largeList.size)
val shuffled = largeList.permuted(perm)
println("shuffled: ${shuffled.take(20)}")
val unshuffled = shuffled.unpermuted(perm)
println("unshuffled: ${unshuffled.take(20)}")
```
### Custom range permutation with negatives
```kotlin
val rangePerm = intPermutation(-100..199)
println("encode(-50): ${rangePerm.encode(-50)}")
println("decode(...): ${rangePerm.decode(rangePerm.encode(-50))}")
```
### Full 2^32-bit domain permutation
```kotlin
val fullPerm = intPermutation(-1, seed = 1L)
println(fullPerm.encode(0)) // 1339315335
println(fullPerm.encode(1)) // -897806455
```
---
## How It Works
KPermute builds **keyed, reversible permutations** over integer domains using
xor-shift-multiply mixers and cycle-walking.
It never stores lookup tables and always supports decoding back to the original
value.
### Domains and Implementations
Each permutation has a `size`:
* `size > 0` → finite domain `[0, size)`
* `size == -1` / `-1L` → full 32- or 64-bit domain
* `size < 0` (not `-1`) → unsigned variants via `UIntPermutation` /
`ULongPermutation`
Factory functions select implementations:
| Domain Type | Implementation | Description |
|-------------------|------------------------------|---------------------------------|
| Tiny (`≤16`) | `Array[Int/Long]Permutation` | Uses shuffled array and inverse |
| Finite | `Half[Int/Long]Permutation` | Uses cycle-walking |
| Full bit-width | `Full[Int/Long]Permutation` | No cycle-walking |
| Unsigned variants | `U[Int/Long]Permutation` | Modulo `2^32` or `2^64` | |
Range factories like `intPermutation(range)` and `longPermutation(range)` wrap
these with a `range(...)` view, so you can permute directly on intervals such as
`-100..199`.
---
### Mixing and Cycle-Walking
Each permutation round:
1. Multiplies by an odd constant.
2. Adds or xors a secret per-round key.
3. Applies xor-shift steps (`x ^= x >>> s`) to diffuse bits.
All steps are invertible using modular inverses and xor-shift
inversion [1] [3] [4] [5].
For non-power-of-two domains, KPermute uses **cycle-walking** [1] [2]: permute
in
the next power-of-two space and retry until the output falls in `[0, size)`.
---
## References
[1]: https://web.cs.ucdavis.edu/~rogaway/papers/subset.pdf
[2]: https://csrc.nist.gov/csrc/media/projects/block-cipher-techniques/documents/bcm/proposed-modes/ffx/ffx-spec.pdf
[3]: https://www-cs-faculty.stanford.edu/~knuth/taocp.html
[4]: http://burtleburtle.net/bob/hash/integer.html
[5]: https://arxiv.org/pdf/1402.6246.pdf
[6]: https://github.com/Cyan4973/xxHash
1. P. Rogaway and T. Shrimpton,
“Ciphers with Arbitrary Finite Domains,” *CT-RSA 2002*. [PDF][1]
2. M. Bellare, P. Rogaway, and T. Spies,
“The FFX Mode of Operation for Format-Preserving Encryption,” *NIST
submission, 2010.* [Spec][2]
3. D. E. Knuth,
*The Art of Computer Programming, Vol. 2: Seminumerical Algorithms,* 3rd ed.,
1997. [Info][3]
4. B. Jenkins,
“Integer Hash Functions,” 1997. [Web][4]
5. S. Vigna,
“An Experimental Exploration of Marsaglia’s Xorshift Generators, Scrambled,”
*TOMS 42(4), 2016.* [Preprint][5]
6. Y. Collet,
“xxHash – Extremely fast hash algorithm,” 2014. [GitHub][6]
---