|
| 1 | +# vrf_fun |
| 2 | + |
| 3 | +Verifiable Random Function (VRF) implementation for secp256k1. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +This crate provides RFC 9381 compliant VRF implementations for secp256k1, supporting both: |
| 8 | +- **TAI (Try-And-Increment)** hash-to-curve method |
| 9 | +- **RFC 9380** hash-to-curve method |
| 10 | + |
| 11 | +## Features |
| 12 | + |
| 13 | +- RFC 9381 compliant VRF implementation |
| 14 | +- Support for both TAI and RFC 9380 hash-to-curve methods |
| 15 | +- Simple VRF variant for when spec compliance is not required |
| 16 | +- Generic over hash functions (SHA-256, etc.) |
| 17 | +- Deterministic proofs |
| 18 | + - Suite strings: `0xFE` for TAI, `0xFF` for RFC SSWU |
| 19 | + |
| 20 | +## Usage |
| 21 | + |
| 22 | +### High-Level API |
| 23 | + |
| 24 | +#### RFC 9381 with TAI (Try-And-Increment) |
| 25 | + |
| 26 | +```rust |
| 27 | +use secp256kfun::{prelude::*, KeyPair}; |
| 28 | +use vrf_fun::rfc9381; |
| 29 | + |
| 30 | +// Generate a keypair |
| 31 | +let keypair = KeyPair::new(Scalar::random(&mut rand::thread_rng())); |
| 32 | + |
| 33 | +// Create a VRF proof |
| 34 | +let alpha = b"test message"; |
| 35 | +let proof = rfc9381::tai::prove::<sha2::Sha256>(&keypair, alpha); |
| 36 | + |
| 37 | +// Verify the proof |
| 38 | +let verified = rfc9381::tai::verify::<sha2::Sha256>( |
| 39 | + keypair.public_key(), |
| 40 | + alpha, |
| 41 | + &proof |
| 42 | +).expect("proof should verify"); |
| 43 | + |
| 44 | +// Get the VRF output |
| 45 | +let beta = verified.rfc9381_output::<sha2::Sha256>(); |
| 46 | +``` |
| 47 | + |
| 48 | +#### RFC 9381 with RFC 9380 Hash-to-Curve |
| 49 | + |
| 50 | +```rust |
| 51 | +use vrf_fun::rfc9381; |
| 52 | + |
| 53 | +// Same keypair and message |
| 54 | +let proof = rfc9381::sswu::prove::<sha2::Sha256>(&keypair, alpha); |
| 55 | + |
| 56 | +// Verify with the RFC 9380 verifier |
| 57 | +let verified = rfc9381::sswu::verify::<sha2::Sha256>( |
| 58 | + keypair.public_key(), |
| 59 | + alpha, |
| 60 | + &proof |
| 61 | +).expect("proof should verify"); |
| 62 | + |
| 63 | +let beta = verified.rfc9381_sswu_output::<sha2::Sha256>(); |
| 64 | +``` |
| 65 | + |
| 66 | +### Low-Level API |
| 67 | + |
| 68 | +For more control over the hash-to-curve process: |
| 69 | + |
| 70 | +```rust |
| 71 | +use vrf_fun::{rfc9381::Rfc9381TaiVrf, SimpleVrf}; |
| 72 | +use secp256kfun::{prelude::*, KeyPair}; |
| 73 | + |
| 74 | +// Create VRF instance |
| 75 | +let vrf = Rfc9381TaiVrf::<sha2::Sha256>::default(); |
| 76 | + |
| 77 | +// Hash to curve yourself |
| 78 | +let h = Point::hash_to_curve_rfc9381_tai::<sha2::Sha256>(alpha, b""); |
| 79 | + |
| 80 | +// Generate proof |
| 81 | +let proof = vrf.prove(&keypair, h); |
| 82 | + |
| 83 | +// Verify |
| 84 | +let verified = vrf.verify(keypair.public_key(), h, &proof) |
| 85 | + .expect("proof should verify"); |
| 86 | +``` |
| 87 | + |
| 88 | +## Implementation Details |
| 89 | + |
| 90 | +### Challenge Generation |
| 91 | + |
| 92 | +The challenge is computed as: |
| 93 | +``` |
| 94 | +c = Hash(suite_string || 0x02 || Y || H || Gamma || U || V || 0x00) |
| 95 | +``` |
| 96 | + |
| 97 | +Where: |
| 98 | +- `suite_string`: `0xFE` for TAI, `0xFF` for RFC 9380 |
| 99 | +- `Y` is the public key |
| 100 | +- `H` is the hash-to-curve of the input |
| 101 | +- `Gamma` is the VRF output point (x*H) |
| 102 | +- `U` and `V` are the DLEQ proof commitments |
| 103 | + |
| 104 | +The hash output is truncated to 16 bytes for secp256k1. |
| 105 | + |
| 106 | +### VRF Output |
| 107 | + |
| 108 | +The VRF output beta is computed as: |
| 109 | +``` |
| 110 | +beta = Hash(suite_string || 0x03 || Gamma || 0x00) |
| 111 | +``` |
| 112 | + |
| 113 | +## Important Notes |
| 114 | + |
| 115 | +- The TAI and RFC 9380 variants use different suite strings (0xFE and 0xFF) |
| 116 | +- Proofs generated with one method cannot be verified with the other |
| 117 | +- The same input will produce different outputs with different hash-to-curve methods |
| 118 | +- This implementation includes the public key in the challenge (unlike draft-05) |
| 119 | + |
| 120 | +## Generic Hash Support |
| 121 | + |
| 122 | +The implementation is generic over the hash function, constrained by `secp256kfun::hash::Hash32`. This allows using different SHA256 implementations or other 32-byte output hash functions. |
0 commit comments