/** * Verifiable Random Function (VRF) — unpredictable, unforgeable, verifiable. * * Given a key pair (sk, pk) and an input x, a VRF produces (output, proof): * - output is deterministic for (sk, x): re-running yields the same bytes * - anyone with pk can verify that (x, output, proof) was computed honestly * - without sk, you can't forge a valid (output, proof) pair * - output is unpredictable to parties who don't hold sk * * Use cases in Soma: * - Leader election: each party evaluates vrf(sk, epochSeed); lowest wins. * - Random beacons: aggregate VRF outputs from multiple parties for an * unbiased, verifiable randomness source. * - Lottery / assignment: deterministic-but-unpredictable IDs. * - Commit-reveal: commit to output ahead of time; reveal proof later. * * Implementation: deterministic Ed25519 signature as the VRF proof, and * hash(signature) as the output. This is sometimes called an "Ed25519 * signature-based VRF" or "EdDSA-VRF" in the literature — simpler than * ECVRF-EDWARDS25519-SHA512-ELL2 (RFC 9381) and easier to audit, at the * cost of revealing the full signature in the proof rather than a shorter * gamma point. * * Security properties (informal): * - Uniqueness: Ed25519 signatures are deterministic (sign produces same * output for same input + key), so output is unique per (sk, input). * - Unforgeability: producing a valid proof without sk requires forging * an Ed25519 signature, which is infeasible under EUF-CMA. * - Pseudorandomness: output = H("vrf-output" || signature) — assuming * SHA-256 is a random oracle, output is indistinguishable from random * to parties without sk. * - Domain separation: input is prefixed with "soma-vrf-input:v1:" so * VRF proofs cannot be reused as general Ed25519 signatures. * * Non-goals: * - RFC 9381 compatibility — that spec uses curve points as proofs, * ~50% smaller. Migrate if interop with that ecosystem matters. * - "Malicious verifier" resistance beyond standard signature model. */ import { type CryptoProvider } from '../core/crypto-provider.js'; /** A VRF output + proof. The output is what you use; the proof lets others verify. */ export interface VrfOutput { /** Base64 output bytes (32 bytes = SHA-256). Deterministic per (sk, input). */ outputB64: string; /** Base64 proof (64 bytes — the underlying Ed25519 signature). */ proofB64: string; /** DID of the party that evaluated the VRF. */ evaluatorDid: string; /** Base64 public key of the evaluator (redundant with DID but convenient). */ evaluatorPublicKey: string; } export type VrfVerification = { valid: true; output: Uint8Array; } | { valid: false; reason: string; }; export declare function evaluateVrf(opts: { input: Uint8Array; signingKey: Uint8Array; publicKey: Uint8Array; provider?: CryptoProvider; }): VrfOutput; export declare function verifyVrf(input: Uint8Array, vrf: VrfOutput, provider?: CryptoProvider): VrfVerification; /** * Convert VRF output bytes to a uniformly-distributed integer in [0, bound). * Uses rejection sampling to avoid modulo bias. Bound must be 1..2^32. */ export declare function outputToInt(output: Uint8Array, bound: number): number; /** * Combine multiple VRF outputs into a single beacon value. * Use case: N parties each publish a VRF output; the beacon is a hash of * all of them, so the final randomness can't be biased by any single party. * Order-independent (outputs are sorted by hex representation before hashing). */ export declare function combineBeacon(outputs: readonly VrfOutput[], provider?: CryptoProvider): string; //# sourceMappingURL=vrf.d.ts.map