Skip to content

Commit ca623e5

Browse files
LLFournclaude
authored andcommitted
feat: add VRF-based certification for certpedpop
This adds the ability to use VRFs (Verifiable Random Functions) as the certification scheme in certpedpop, enabling the generation of a randomness beacon from the DKG process. Key features: - Add vrf_cert_keygen feature flag with vrf_fun and sha2 dependencies - Implement CertificationScheme for RFC 9381 SSWU and TAI VRFs - Add compute_randomness_beacon function to derive randomness from VRF outputs - Provide helper functions to create VRF certifiers The randomness beacon is computed by hashing all VRF gamma points together, ensuring no single party can predict the output as long as at least one party is honest. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 95b326a commit ca623e5

File tree

2 files changed

+114
-2
lines changed

2 files changed

+114
-2
lines changed

schnorr_fun/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ keywords = ["bitcoin", "schnorr"]
1717
secp256kfun = { path = "../secp256kfun", version = "0.11", default-features = false }
1818
bech32 = { version = "0.11", optional = true, default-features = false, features = ["alloc"] }
1919
bincode = { workspace = true, optional = true }
20+
vrf_fun = { path = "../vrf_fun", version = "0.11", optional = true, default-features = false }
21+
sha2 = { version = "0.10", optional = true }
2022

2123
[dev-dependencies]
2224
secp256kfun = { path = "../secp256kfun", version = "0.11", features = ["proptest", "bincode", "alloc"] }
@@ -49,6 +51,7 @@ libsecp_compat_0_29 = ["secp256kfun/libsecp_compat_0_29"]
4951
libsecp_compat_0_30 = ["secp256kfun/libsecp_compat_0_30"]
5052
proptest = ["secp256kfun/proptest"]
5153
share_backup = ["dep:bech32"]
54+
vrf_cert_keygen = ["dep:vrf_fun", "dep:sha2", "alloc", "secp256kfun/std", "vrf_fun/std"]
5255

5356
[package.metadata.docs.rs]
5457
all-features = true

schnorr_fun/src/frost/chilldkg.rs

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ use secp256kfun::{
5353
/// certifying the aggregated keygen input in certpedpop.
5454
pub trait CertificationScheme {
5555
/// The signature type produced by this scheme
56-
type Signature: Clone + core::fmt::Debug + PartialEq;
56+
type Signature: Clone + core::fmt::Debug;
5757

5858
/// Sign the AggKeygenInput with the given keypair
5959
fn certify(&self, keypair: &KeyPair, agg_input: &encpedpop::AggKeygenInput) -> Self::Signature;
@@ -91,6 +91,115 @@ impl<H: Hash32, NG: NonceGen> CertificationScheme for Schnorr<H, NG> {
9191
}
9292
}
9393

94+
/// VRF-based implementation of CertificationScheme
95+
#[cfg(feature = "vrf_cert_keygen")]
96+
pub mod vrf_cert {
97+
use super::*;
98+
use vrf_fun::VrfProof;
99+
100+
/// A wrapper type for using VRF as a certification scheme
101+
pub struct VrfCertifier<V> {
102+
/// The underlying VRF instance
103+
pub vrf: V,
104+
}
105+
106+
/// Create a VRF certification scheme with the RFC 9381 SSWU suite using SHA256
107+
pub fn sswu_vrf_sha256() -> VrfCertifier<vrf_fun::Rfc9381SswuVrf<sha2::Sha256>> {
108+
VrfCertifier {
109+
vrf: vrf_fun::Rfc9381SswuVrf::default(),
110+
}
111+
}
112+
113+
/// Create a VRF certification scheme with the RFC 9381 TAI suite using SHA256
114+
pub fn tai_vrf_sha256() -> VrfCertifier<vrf_fun::Rfc9381TaiVrf<sha2::Sha256>> {
115+
VrfCertifier {
116+
vrf: vrf_fun::Rfc9381TaiVrf::default(),
117+
}
118+
}
119+
120+
/// Implement CertificationScheme for VrfCertifier wrapping the SSWU VRF
121+
impl CertificationScheme for VrfCertifier<vrf_fun::Rfc9381SswuVrf<sha2::Sha256>> {
122+
type Signature = VrfProof;
123+
124+
fn certify(
125+
&self,
126+
keypair: &KeyPair,
127+
agg_input: &encpedpop::AggKeygenInput,
128+
) -> Self::Signature {
129+
// Use the certification bytes as the VRF input
130+
let cert_bytes = agg_input.cert_bytes();
131+
vrf_fun::rfc9381::sswu::prove::<sha2::Sha256>(keypair, &cert_bytes)
132+
}
133+
134+
fn verify_cert(
135+
&self,
136+
cert_key: Point,
137+
agg_input: &encpedpop::AggKeygenInput,
138+
signature: &Self::Signature,
139+
) -> bool {
140+
// Use the certification bytes as the VRF input
141+
let cert_bytes = agg_input.cert_bytes();
142+
vrf_fun::rfc9381::sswu::verify::<sha2::Sha256>(cert_key, &cert_bytes, signature)
143+
.is_some()
144+
}
145+
}
146+
147+
/// Implement CertificationScheme for VrfCertifier wrapping the TAI VRF
148+
impl CertificationScheme for VrfCertifier<vrf_fun::Rfc9381TaiVrf<sha2::Sha256>> {
149+
type Signature = VrfProof;
150+
151+
fn certify(
152+
&self,
153+
keypair: &KeyPair,
154+
agg_input: &encpedpop::AggKeygenInput,
155+
) -> Self::Signature {
156+
// Use the certification bytes as the VRF input
157+
let cert_bytes = agg_input.cert_bytes();
158+
vrf_fun::rfc9381::tai::prove::<sha2::Sha256>(keypair, &cert_bytes)
159+
}
160+
161+
fn verify_cert(
162+
&self,
163+
cert_key: Point,
164+
agg_input: &encpedpop::AggKeygenInput,
165+
signature: &Self::Signature,
166+
) -> bool {
167+
// Use the certification bytes as the VRF input
168+
let cert_bytes = agg_input.cert_bytes();
169+
vrf_fun::rfc9381::tai::verify::<sha2::Sha256>(cert_key, &cert_bytes, signature)
170+
.is_some()
171+
}
172+
}
173+
174+
/// Compute a randomness beacon from a set of VRF outputs
175+
///
176+
/// This function takes all the VRF outputs (gamma points) from the certificate
177+
/// and hashes them together to produce unpredictable randomness that no single
178+
/// party could have controlled (as long as at least one party is honest).
179+
pub fn compute_randomness_beacon<S>(certificate: &certpedpop::Certificate<S>) -> [u8; 32]
180+
where
181+
S: CertificationScheme,
182+
S::Signature: AsRef<VrfProof>,
183+
{
184+
use sha2::{Digest, Sha256};
185+
186+
let mut hasher = Sha256::new();
187+
188+
// Sort by public key to ensure deterministic ordering
189+
let mut sorted_entries: Vec<_> = certificate.iter().collect();
190+
sorted_entries.sort_by_key(|(pk, _)| pk.to_bytes());
191+
192+
// Hash all the VRF gamma points
193+
for (_, vrf_proof) in sorted_entries {
194+
let gamma = vrf_proof.as_ref().gamma;
195+
hasher.update(gamma.to_bytes());
196+
}
197+
198+
// Get the hash output
199+
hasher.finalize().into()
200+
}
201+
}
202+
94203
/// SimplePedPop is a bare bones secure distributed key generation algorithm that leaves a lot left
95204
/// up to the application.
96205
///
@@ -1103,7 +1212,7 @@ pub mod certpedpop {
11031212
}
11041213

11051214
/// A key generation session that has been certified by each certifying party (contributors and share receivers).
1106-
#[derive(Clone, Debug, PartialEq)]
1215+
#[derive(Clone, Debug)]
11071216
pub struct CertifiedKeygen<S: CertificationScheme> {
11081217
input: AggKeygenInput,
11091218
certificate: Certificate<S>,

0 commit comments

Comments
 (0)