Triton-backed ChaCha20 CSPRNG and GPU sampling primitives for PyTorch/FHE workloads
Project description
triton-csprng
triton-csprng is a small PyTorch/Triton package for counter-based random
streams on NVIDIA GPUs. It provides ChaCha20-backed CUDA tensor generation and a
few sampling primitives that are useful for cryptography-adjacent, simulation,
and FHE-style workloads.
The package exposes low-level stream and sampling building blocks without depending on any downstream library's RNG API.
What is implemented
- ChaCha20 block generation in Triton.
- Explicit key / nonce / counter stream state.
- Raw
uint32(...)andbytes(...)APIs returning ordinary CUDA tensors. - Bounded integer sampling with scalar or per-channel bounds.
- Centered integer discrete Gaussian sampling from a 128-bit half-plane CDT.
- Stochastic rounding for CUDA floating tensors.
RnsRandomStreams, a convenience manager for RNS-like layouts with:- independent streams per device for non-repeated channels;
- repeated channels that reproduce the same values across devices;
- state-dict roundtrip for deterministic continuation.
- No C++/CUDA extension or
torch.opsregistration step.
Installation
For ordinary package use after a PyPI release:
python -m pip install triton-csprng
For development:
git clone git@github.com:visualDust/triton-csprng.git
cd triton-csprng
python -m pip install -e ".[dev]"
Runtime dependencies are PyTorch, Triton, and mpmath for high-precision CDT
construction. The current implementation is CUDA-only because Triton kernels
require CUDA tensors. In production-like CUDA environments, install the
PyTorch/Triton build that matches the target CUDA stack first, then install this
package.
Quick start
import torch
from triton_csprng import ChaCha20Rng
rng = ChaCha20Rng(
key=list(range(8)), # 8 little-endian uint32 words = 256 bits
nonce=[123, 456], # 2 little-endian uint32 words = 64 bits
counter=0,
device="cuda:0",
)
words = rng.uint32((1024,))
raw = rng.bytes((4096,))
mod_q = rng.randint([17, 257], (2, 1024))
gauss = rng.discrete_gaussian((4, 1024), sigma=3.2)
rounded = rng.stochastic_round(torch.randn(1024, device="cuda:0"))
Every result above is a normal PyTorch CUDA tensor. Triton kernels are launched directly from Python with PyTorch tensor pointers, so callers can pass outputs straight into ordinary PyTorch code.
Stream semantics
ChaCha20Rng is a deterministic counter-based stream:
from triton_csprng import ChaCha20Rng
rng1 = ChaCha20Rng(key=list(range(8)), nonce=[1, 2], counter=9)
rng2 = ChaCha20Rng(key=list(range(8)), nonce=[1, 2], counter=9)
assert torch.equal(rng1.uint32((3, 7)), rng2.uint32((3, 7)))
The stream buffers unused bytes internally, so chunked reads are equivalent to a single larger read:
one_shot = ChaCha20Rng(key=list(range(8)), nonce=[5, 6])
chunked = ChaCha20Rng(key=list(range(8)), nonce=[5, 6])
expected = one_shot.uint32(40)
got = torch.cat([chunked.uint32(17), chunked.uint32(23)])
assert torch.equal(got, expected)
Stream state can be checkpointed:
state = rng1.state_dict()
restored = ChaCha20Rng.from_state_dict(state)
Sampling APIs
Bounded integers
x = rng.randint(17, (4, 1024))
y = rng.randint([17, 257, 65537], (3, 1024))
The output dtype is torch.int64; bounds therefore must fit in signed int64.
Multiple bounds are interpreted as leading channels. Internally the sampler
consumes a 128-bit ChaCha word U and returns floor(bound * U / 2**128). This
has no retry or fallback branch. Over the finite 128-bit source domain, output
bucket counts differ by at most one, so the statistical distance from the ideal
uniform distribution is bounded by roughly bound / 2**128.
Discrete Gaussian
e = rng.discrete_gaussian((8, 32768), sigma=3.2)
The sampler builds a 128-bit half-plane cumulative distribution table using
mpmath precision 2 * security_bits, chooses
num_sampling_points = 2**ceil(log2(6*sigma)), reserves one random bit for the
sign, and folds the remaining truncated tail into the last bucket. This keeps the
CUDA path compact and constant-shape while making the finite table construction
explicit and testable.
Stochastic rounding
rounded = rng.stochastic_round(values)
values must be a CUDA floating tensor on the same device as the RNG stream.
The result is torch.int64 with Bernoulli rounding by the fractional part of
abs(values), then sign restoration.
RNS-style stream manager
RnsRandomStreams helps express layouts where each GPU gets independent
non-repeated channels, while repeated channels are generated from matching
streams on every GPU.
from triton_csprng import RnsRandomStreams
streams = RnsRandomStreams(
num_coeffs=32768,
channel_counts=[8, 8],
repeated_channels=2,
devices=["cuda:0", "cuda:1"],
key=list(range(8)),
nonce=[1, 2],
)
u32 = streams.uint32_channels()
gauss = streams.discrete_gaussian_channels(sigma=3.2)
ints = streams.randint_channels([
[17] * 8 + [257] * 2,
[19] * 8 + [257] * 2,
])
For each returned list item:
shape = [non_repeated_channels + repeated_channels, num_coeffs]
The repeated tail channels are reproducible across devices when their bounds and distribution parameters match.
Why there is no torch op wrapper
A Triton kernel can be launched directly with PyTorch CUDA tensors:
out = torch.empty_like(x)
_kernel[grid](x, out, ...)
That is what this package does. A torch.ops.* custom op is unnecessary for
normal Python/PyTorch integration and would reintroduce dispatcher/wrapper
maintenance. A torch.library wrapper can still be added later if a downstream
project needs formal fake-tensor or torch.compile dispatcher integration.
Developer checks
Install the optional development tools and pre-commit hooks:
python -m pip install -e ".[dev]"
pre-commit install
Run the same checks manually:
python -m ruff check .
python -m ruff format --check .
python -m pytest tests -q
Validation
Current local validation:
python -m ruff check .
python -m ruff format --check .
python -m pre_commit run --all-files
python -m pytest tests -q
The tests cover:
- ChaCha20 Triton output against a Python reference implementation;
- non-multiple block counts;
- stream determinism and chunking behavior;
- state-dict restore;
- bounded integer range and multiply-high mapping checks;
- difficult bounds and distribution sanity;
- half-plane CDT table shape/range checks;
- rough discrete Gaussian moments and symmetry;
- stochastic-rounding determinism and integer cases;
- RNS repeated-channel equality across two GPUs.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file triton_csprng-0.1.1.tar.gz.
File metadata
- Download URL: triton_csprng-0.1.1.tar.gz
- Upload date:
- Size: 14.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
21a389886c8f95784e91f32e7f1b3e3860e6cc68fc5d1cc169a0d2eef5bfa096
|
|
| MD5 |
fb2ccd411f46f9c19bf2bf2ffb6728ca
|
|
| BLAKE2b-256 |
2ecd88a38564221b22608154d5894701a2351bd6f899962ee4e36c1c8f1699bb
|
Provenance
The following attestation bundles were made for triton_csprng-0.1.1.tar.gz:
Publisher:
build-and-publish-pypi.yaml on visualDust/triton-csprng
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
triton_csprng-0.1.1.tar.gz -
Subject digest:
21a389886c8f95784e91f32e7f1b3e3860e6cc68fc5d1cc169a0d2eef5bfa096 - Sigstore transparency entry: 1677186265
- Sigstore integration time:
-
Permalink:
visualDust/triton-csprng@f047d8de638e49e25f6f00798ad0b78034b0f8e9 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/visualDust
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build-and-publish-pypi.yaml@f047d8de638e49e25f6f00798ad0b78034b0f8e9 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file triton_csprng-0.1.1-py3-none-any.whl.
File metadata
- Download URL: triton_csprng-0.1.1-py3-none-any.whl
- Upload date:
- Size: 14.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d30392f6d5978c5a71f8a8f45e5ebe64d1ccb3f5af85c480b6988b334ee65746
|
|
| MD5 |
869e0a1eb23517b61586b4237a4e89e6
|
|
| BLAKE2b-256 |
43a91eaa402b4ccab2c03787f9a50256510723cedaec9d33e855c97fd804ef04
|
Provenance
The following attestation bundles were made for triton_csprng-0.1.1-py3-none-any.whl:
Publisher:
build-and-publish-pypi.yaml on visualDust/triton-csprng
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
triton_csprng-0.1.1-py3-none-any.whl -
Subject digest:
d30392f6d5978c5a71f8a8f45e5ebe64d1ccb3f5af85c480b6988b334ee65746 - Sigstore transparency entry: 1677186297
- Sigstore integration time:
-
Permalink:
visualDust/triton-csprng@f047d8de638e49e25f6f00798ad0b78034b0f8e9 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/visualDust
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build-and-publish-pypi.yaml@f047d8de638e49e25f6f00798ad0b78034b0f8e9 -
Trigger Event:
workflow_dispatch
-
Statement type: