Accelerated Ristretto255 primitives for Python, backed by libsodium.
Project description
pyristretto
Accelerated Ristretto255 primitives for Python, backed by libsodium.
pyristretto is an optimized native CPython extension exposing low-level
Ristretto255 operations with minimal overhead and explicit, protocol-friendly
Python APIs.
Features
Ristretto255 EC Operations
point_add,point_sub,point_sumpoint_mul,base_mulassert_valid_point,is_valid_point
Hash Primitives
Hs: hash → scalar (Fiat–Shamir friendly)Hp: hash → Ristretto point
Generator Derivation
- Deterministic, domain-separated generator derivation
- Optimized via hash-state reuse
Optimized Naive MSM
- ~3–5× faster than manual Python MSM loops
- Scalars reduced once, points copied once
- GIL released during inner crypto loops
- Efficient even for small MSM sizes (or even for one!)
Pedersen Commitments
pedersen_commitof the forma·G + r·H
Installation
Requirements
- Python 3.9+
libsodium(with Ristretto255 support)- A C compiler (GCC recommended)
Install with pip
pip install pyristretto
Build from source
pip install .
For development:
pip install -e .
Quick Example
from pyristretto import *
a = sc_rand()
b = sc_rand()
P = base_mul(a)
Q = base_mul(b)
R = point_add(P, Q)
S = point_mul(5, R)
assert_valid_point("Point S", S)
Hashing Helpers
Hash → Scalar (Fiat–Shamir)
c = Hs(b"domain", P, Q)
Hash → Point
H = Hp(b"domain", b"context")
Multi-Scalar Multiplication (MSM)
scalars = [a, b, 7]
points = [P, Q, H]
R = msm(scalars, points)
- Scalars are reduced once
- Points are copied once into contiguous buffers
- Zero scalars are skipped
- GIL released during scalar-mult loops
This is a naive MSM, but significantly faster than Python-level loops and well-suited for protocol inner loops.
Generator Derivation
Gs = derive_generators(b"G", 64)
Hs = derive_generators(b"H", 64)
Pedersen Commitments
C = pedersen_commit(amount=42, blinding=sc_rand())
Defined as:
C = a·G + r·H
Where:
G = base_mul(1)H = Hp(b"Ristretto255:H")
API Overview
Constants
The following curve and subgroup constants are exposed for convenience:
qRistretto255 subgroup order (2²⁵² + 27742317777372353535851937790883648493)GCanonical Ristretto base point (base_mul(1))HSecondary generator defined asHp(b"Ristretto255:H")IDENTITYThe Ristretto identity element (32-byte encoding)
Scalars
sc_rand() -> intsc_add(a, b) -> intsc_sub(a, b) -> intsc_mul(a, b) -> intfrom_bytes32(b) -> intto_bytes32(i) -> bytes
Points
base_mul(s) -> bytespoint_mul(s, P) -> bytespoint_add(P, Q) -> bytespoint_sub(P, Q) -> bytespoint_sum(list[P]) -> bytes
Validation
is_valid_point(P) -> boolassert_valid_point(name, P)
Benchmarks
The following benchmarks compare pyristretto against pysodium and PyNaCl
using protocol-style workloads.
Environment
- Python 3.12
- Intel i5-10400F
- N = 512, MSM_N = 128
- Averaged over 5 runs
| Library | base_mul | point_mul | point_add | generators | Pedersen | MSM |
|---|---|---|---|---|---|---|
| pyristretto | 0.0086 s | 0.0268 s | 0.0114 s | 0.0015 s | 0.0436 s | 0.0255 s |
| pysodium | 0.0204 s | 0.0573 s | 0.0127 s | 0.0036 s | 0.0908 s | 0.0695 s |
| PyNaCl | 0.0205 s | 0.0984 s | 0.0121 s | N/A | 0.1298 s | 0.1098 s |
pyristretto achieves ~2× speedups over pysodium and up to ~3× over PyNaCl
in MSM-heavy and EC-heavy workloads by minimizing Python↔C crossings, reducing
redundant processing, and releasing the GIL during inner crypto loops.
Operations per second
| Operation | pysodium (Python) | pyristretto (C) | Speedup |
|---|---|---|---|
Hs (hash → scalar) |
400k ops/s | 1.45M ops/s | 3.6× |
Hp (hash → point) |
39k ops/s | 66k ops/s | 1.7× |
derive_generators |
618 ops/s | 1.06k ops/s | 1.7× |
| Operation | pysodium (Python) | pyristretto (C) | Speedup |
|---|---|---|---|
point_add |
40.8k ops/s | 41.1k ops/s | 1.0× |
point_sub |
41.0k ops/s | 41.2k ops/s | 1.0× |
point_sum |
649 ops/s | 817 ops/s | 1.3× |
point_mul |
8.9k ops/s | 16.7k ops/s | 1.9× |
base_mul |
24.7k ops/s | 52.8k ops/s | 2.1× |
| Operation | pysodium (Python) | pyristretto (C) | Speedup |
|---|---|---|---|
assert_valid_point |
121k ops/s | 163k ops/s | 1.3× |
is_valid_point |
113k ops/s | 204k ops/s | 1.8× |
* Point addition and subtraction are already dominated by libsodium internals; as a result, performance differences are negligible.
License
MIT.
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 pyristretto-0.1.0.tar.gz.
File metadata
- Download URL: pyristretto-0.1.0.tar.gz
- Upload date:
- Size: 12.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4b6f349d49988b112c456540d4761a9b0b0ee5c7adab278081c45a03710541bf
|
|
| MD5 |
fd495bbb4d40a6aa6afe0e8c1415825b
|
|
| BLAKE2b-256 |
4a91ef101db5465c97cb84c62bacb4d0a8fb309c472a4be7d80126b2dac42905
|
File details
Details for the file pyristretto-0.1.0-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: pyristretto-0.1.0-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 23.1 kB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
001af7ea19ef170ab841b7484e2da9ecdddc0ac9f7cab31914a2e8b4c471fbc2
|
|
| MD5 |
a44acb7e09f832636a05f60edf61c330
|
|
| BLAKE2b-256 |
13fd73a7498bd644c4916eaf735220178992f602db6472f9eb4ddc2cb0aaf48e
|