vrf_fun

Crates.iovrf_fun
lib.rsvrf_fun
version0.12.0
created_at2025-11-19 05:06:23.94704+00
updated_at2025-11-19 05:06:23.94704+00
descriptionRFC 9381 compliant Verifiable Random Function (VRF) for secp256k1
homepagehttps://github.com/LLFourn/secp256kfun/tree/master/vrf_fun
repositoryhttps://github.com/LLFourn/secp256kfun
max_upload_size
id1939448
size64,141
Lloyd Fournier (LLFourn)

documentation

https://docs.rs/vrf_fun

README

vrf_fun

Verifiable Random Function (VRF) implementation for secp256k1.

Use

[dependencies]
vrf_fun = "0.12"
secp256kfun = "0.12"
sha2 = "0.10"

Overview

This crate provides RFC 9381 compliant VRF implementations for secp256k1, supporting both:

  • TAI (Try-And-Increment) hash-to-curve method
  • RFC 9380 hash-to-curve method

Features

  • RFC 9381 compliant VRF implementation
  • Support for both TAI and RFC 9380 hash-to-curve methods
  • Simple VRF variant for when spec compliance is not required
  • Generic over hash functions (SHA-256, etc.)
  • Deterministic proofs
    • Suite strings: 0xFE for TAI, 0xFF for RFC SSWU

Usage

High-Level API

RFC 9381 with TAI (Try-And-Increment)

use secp256kfun::{prelude::*, KeyPair};
use vrf_fun::rfc9381;

// Generate a keypair
let keypair = KeyPair::new(Scalar::random(&mut rand::thread_rng()));

// Create a VRF proof
let alpha = b"test message";
let proof = rfc9381::tai::prove::<sha2::Sha256>(&keypair, alpha);

// Verify the proof
let verified = rfc9381::tai::verify::<sha2::Sha256>(
    keypair.public_key(), 
    alpha, 
    &proof
).expect("proof should verify");

// Get the VRF output
let beta = verified.rfc9381_output::<sha2::Sha256>();

RFC 9381 with RFC 9380 Hash-to-Curve

use vrf_fun::rfc9381;

// Same keypair and message
let proof = rfc9381::sswu::prove::<sha2::Sha256>(&keypair, alpha);

// Verify with the RFC 9380 verifier
let verified = rfc9381::sswu::verify::<sha2::Sha256>(
    keypair.public_key(), 
    alpha, 
    &proof
).expect("proof should verify");

let beta = verified.rfc9381_sswu_output::<sha2::Sha256>();

Low-Level API

For more control over the hash-to-curve process:

use vrf_fun::{rfc9381::Rfc9381TaiVrf, SimpleVrf};
use secp256kfun::{prelude::*, KeyPair};

// Create VRF instance
let vrf = Rfc9381TaiVrf::<sha2::Sha256>::default();

// Hash to curve yourself
let h = Point::hash_to_curve_rfc9381_tai::<sha2::Sha256>(alpha, b"");

// Generate proof
let proof = vrf.prove(&keypair, h);

// Verify
let verified = vrf.verify(keypair.public_key(), h, &proof)
    .expect("proof should verify");

Implementation Details

Challenge Generation

The challenge is computed as:

c = Hash(suite_string || 0x02 || Y || H || Gamma || U || V || 0x00)

Where:

  • suite_string: 0xFE for TAI, 0xFF for RFC 9380
  • Y is the public key
  • H is the hash-to-curve of the input
  • Gamma is the VRF output point (x*H)
  • U and V are the DLEQ proof commitments

The hash output is truncated to 16 bytes for secp256k1.

VRF Output

The VRF output beta is computed as:

beta = Hash(suite_string || 0x03 || Gamma || 0x00)

Important Notes

  • The TAI and RFC 9380 variants use different suite strings (0xFE and 0xFF)
  • Proofs generated with one method cannot be verified with the other
  • The same input will produce different outputs with different hash-to-curve methods
  • This implementation includes the public key in the challenge (unlike draft-05)

Generic Hash Support

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.

Commit count: 688

cargo fmt