# primitives/ristretto255 _(no submodules)_ ## Purpose The `ristretto255` namespace exposes libsodium's Ristretto255 group operations — a prime-order group construction over Curve25519 that eliminates the cofactor pitfalls present in raw Edwards25519 arithmetic. Ristretto255 is used in zero-knowledge proofs, Oblivious Pseudorandom Functions (OPRFs), Password-Authenticated Key Exchanges (PAKEs), and Verifiable Random Functions (VRFs). By wrapping libsodium's `crypto_core_ristretto255_*` and `crypto_scalarmult_ristretto255_*` APIs, this module provides the building blocks for advanced cryptographic protocols without requiring callers to reason about low-level curve arithmetic or cofactor clearing. ## Features - Group element addition (`add`) and subtraction (`sub`) via `crypto_core_ristretto255_add/sub`. - Scalar multiplication (`mul`) via `crypto_scalarmult_ristretto255`. - Hash-to-curve via `fromHash` using `crypto_core_ristretto255_from_hash` (64-byte input). - Point serialisation (`toBytes`) and deserialisation with validation (`fromBytes`). - Random group element generation (`random`) via `crypto_core_ristretto255_random`. - All operations are async and call `sodiumReady()` internally. - `fromBytes` throws `RangeError` for invalid or identity points. ## Usage: Basic Example ```ts import { ristretto255 } from "@suaveplan/crypto-sodium/primitives/ristretto255"; // Generate two random group elements const p = await ristretto255.random(); const q = await ristretto255.random(); // Add them const sum = await ristretto255.add(p, q); // Verify commutativity const sumQP = await ristretto255.add(q, p); // sum deepEquals sumQP ``` ## Usage: Advanced Example Hash-to-curve for OPRF input blinding: ```ts import { ristretto255 } from "@suaveplan/crypto-sodium/primitives/ristretto255"; // Hash the password to a group element (hash-to-curve) // In a real OPRF you'd use a proper H2C function; fromHash works for demos async function hashToPoint(input: Uint8Array): Promise { // Pad/hash input to 64 bytes with SHA-512 first in production: const padded = new Uint8Array(64); padded.set(input.subarray(0, Math.min(input.length, 64))); return ristretto255.fromHash(padded); } // Scalar multiplication: client blinds the point with a random scalar const blindScalar = new Uint8Array(32); crypto.getRandomValues(blindScalar); const point = await hashToPoint(new TextEncoder().encode("password")); const blinded = await ristretto255.mul(blindScalar, point); ``` ## API Reference ### `ristretto255.add(p, q): Promise` Adds two group elements. Commutative: `add(p, q) === add(q, p)`. ### `ristretto255.sub(p, q): Promise` Subtracts `q` from `p`. Inverse of `add`. ### `ristretto255.mul(scalar, point): Promise` Scalar multiplication: computes `scalar * point`. Scalar is a 32-byte little-endian integer. ### `ristretto255.fromHash(hash): Promise` Maps a 64-byte hash uniformly to a group element via `crypto_core_ristretto255_from_hash`. ### `ristretto255.toBytes(point): Promise` Returns a copy of the 32-byte canonical encoding of `point`. ### `ristretto255.fromBytes(bytes): Promise` Validates and returns a group element. **Throws `RangeError`** if `bytes` is not a valid, non-identity Ristretto255 point. ### `ristretto255.random(): Promise` Generates a uniformly random 32-byte group element. ## Implementation Notes Ristretto255 represents each group element as a 32-byte canonical encoding. Unlike raw Edwards25519, every 32-byte encoding maps to at most one group element — there are no encoding ambiguities or cofactor issues. `fromBytes` calls `crypto_core_ristretto255_is_valid_point` before returning, which rejects the identity element (all-zeros) and any bytes that do not correspond to a valid Ristretto255 point. This prevents callers from accidentally working with invalid inputs in downstream protocols. All operations return new `Uint8Array` allocations; the input arrays are not mutated.