jf_vrf/
blsvrf.rs

1// Copyright (c) 2022 Espresso Systems (espressosys.com)
2// This file is part of the Jellyfish library.
3
4// You should have received a copy of the MIT License
5// along with the Jellyfish library. If not, see <https://mit-license.org/>.
6
7//! BLS signature based VRF
8use super::Vrf;
9use ark_std::{
10    boxed::Box,
11    rand::{CryptoRng, RngCore},
12    string::{String, ToString},
13    vec::Vec,
14};
15use digest::{Digest, DynDigest};
16use displaydoc::Display;
17use jf_signature::{
18    bls_over_bls12381::{BLSSignKey, BLSSignature, BLSSignatureScheme, BLSVerKey},
19    SignatureScheme,
20};
21use sha2::{Sha256, Sha512};
22
23/// Supported Cipher Suites for BLS VRF.
24#[allow(non_camel_case_types)]
25#[derive(Debug)]
26pub enum BLSVRFCipherSuite {
27    /// using blst library and VRF output from SHA256 hashing
28    VRF_BLS_12_381_SHA256,
29    /// using blst library and VRF output from SHA512 hashing
30    VRF_BLS_12_381_SHA512,
31}
32
33/// BLS VRF scheme.
34/// Optimized for signature size, i.e.: PK in G2 and sig in G1
35pub struct BLSVRFScheme {
36    hasher: Box<dyn DynDigest>,
37}
38
39impl BLSVRFScheme {
40    /// Creates a new BLS VRF instance with the given ciphersuite.
41    pub fn new(cs_id: BLSVRFCipherSuite) -> Self {
42        match cs_id {
43            BLSVRFCipherSuite::VRF_BLS_12_381_SHA256 => Self {
44                hasher: Box::new(Sha256::new()),
45            },
46            BLSVRFCipherSuite::VRF_BLS_12_381_SHA512 => Self {
47                hasher: Box::new(Sha512::new()),
48            },
49        }
50    }
51}
52
53/// VRF Error: {0}
54#[derive(Debug, Display)]
55pub struct BLSVRFError(String);
56impl ark_std::error::Error for BLSVRFError {}
57
58impl Vrf for BLSVRFScheme {
59    /// Public Parameter.
60    /// For BLS signatures, we want to use default
61    /// prime subgroup generators. So here we don't need
62    /// to specify which PP it is.
63    type PublicParameter = ();
64
65    /// VRF public key.
66    type PublicKey = BLSVerKey;
67
68    /// VRF secret key.
69    type SecretKey = BLSSignKey;
70
71    /// VRF signature.
72    type Proof = BLSSignature;
73
74    /// The input of VRF proof.
75    type Input = Vec<u8>;
76
77    /// The output of VRF evaluation.
78    type Output = Vec<u8>;
79
80    /// VRF Error
81    type Error = BLSVRFError;
82
83    /// generate public parameters from RNG.
84    fn param_gen<R: CryptoRng + RngCore>(
85        &self,
86        _prng: Option<&mut R>,
87    ) -> Result<Self::PublicParameter, BLSVRFError> {
88        Ok(())
89    }
90
91    /// Creates a pair of VRF public and private keys.
92    fn key_gen<R: CryptoRng + RngCore>(
93        &self,
94        pp: &Self::PublicParameter,
95        prng: &mut R,
96    ) -> Result<(Self::SecretKey, Self::PublicKey), BLSVRFError> {
97        <BLSSignatureScheme as SignatureScheme>::key_gen(pp, prng)
98            .map_err(|e| BLSVRFError(e.to_string()))
99    }
100
101    /// Creates the VRF proof associated with a VRF secret key.
102    fn prove<R: CryptoRng + RngCore>(
103        &self,
104        pp: &Self::PublicParameter,
105        secret_key: &Self::SecretKey,
106        input: &Self::Input,
107        prng: &mut R,
108    ) -> Result<Self::Proof, BLSVRFError> {
109        <BLSSignatureScheme as SignatureScheme>::sign(pp, secret_key, input, prng)
110            .map_err(|e| BLSVRFError(e.to_string()))
111    }
112
113    /// Computes the VRF output associated with a VRF proof.
114    fn proof_to_hash(
115        &mut self,
116        _pp: &Self::PublicParameter,
117        proof: &Self::Proof,
118    ) -> Result<Self::Output, BLSVRFError> {
119        let proof_serialized = proof.serialize();
120        let mut hasher = (*self.hasher).box_clone();
121        hasher.update(&proof_serialized);
122        let output = hasher.finalize();
123        Ok(output.to_vec())
124    }
125
126    /// Verifies a VRF proof.
127    fn verify(
128        &mut self,
129        pp: &Self::PublicParameter,
130        proof: &Self::Proof,
131        public_key: &Self::PublicKey,
132        input: &Self::Input,
133    ) -> Result<(bool, Option<Self::Output>), BLSVRFError> {
134        if <BLSSignatureScheme as SignatureScheme>::verify(pp, public_key, input, proof).is_ok() {
135            Ok((true, Some(Self::proof_to_hash(self, pp, proof).unwrap())))
136        } else {
137            Ok((false, None))
138        }
139    }
140}
141
142#[cfg(test)]
143mod test {
144    use super::*;
145    use ark_std::rand::Rng;
146    use jf_utils::test_rng;
147
148    pub(crate) fn sign_and_verify<H: Digest>(
149        vrf: &mut BLSVRFScheme,
150        message: &<BLSVRFScheme as Vrf>::Input,
151        bad_message: &<BLSVRFScheme as Vrf>::Input,
152    ) {
153        let rng = &mut test_rng();
154
155        let (sk, pk) = vrf.key_gen(&(), rng).unwrap();
156        let vrf_proof = vrf.prove(&(), &sk, message, rng).unwrap();
157        let vrf_output = vrf.proof_to_hash(&(), &vrf_proof).unwrap();
158        let (is_correct, output) = vrf.verify(&(), &vrf_proof, &pk, message).unwrap();
159        assert!(is_correct);
160        // need to use the result
161        assert!(output.is_some());
162
163        // check that proof_to_hash(proof) == evaluate(sk, message)
164        let out = vrf.evaluate(&(), &sk, message, rng).unwrap();
165        assert_eq!(out, vrf_output);
166
167        // check the VRF output vs. hashing the proof directly
168        let mut hasher = H::new();
169        hasher.update(vrf_proof.serialize());
170        let direct_hash_output = hasher.finalize().to_vec();
171        assert_eq!(direct_hash_output, vrf_output);
172
173        // now test for bad message. User can choose to ignore the output if they really
174        // want to.
175        let (is_correct, _) = vrf.verify(&(), &vrf_proof, &pk, bad_message).unwrap();
176        assert!(!is_correct);
177    }
178
179    #[test]
180    fn test_bls_vrf() {
181        let rng = &mut test_rng();
182        for _ in 0..10 {
183            let message = rng.gen::<[u8; 32]>().to_vec();
184            // bad message is truncated
185            let message_bad = message.clone()[..31].to_vec();
186            let mut blsvrf256 = BLSVRFScheme::new(BLSVRFCipherSuite::VRF_BLS_12_381_SHA256);
187
188            sign_and_verify::<Sha256>(&mut blsvrf256, &message, &message_bad);
189
190            let mut blsvrf512 = BLSVRFScheme::new(BLSVRFCipherSuite::VRF_BLS_12_381_SHA512);
191            sign_and_verify::<Sha512>(&mut blsvrf512, &message, &message_bad);
192        }
193    }
194}