decaf377/ark_curve/r1cs/
lazy.rs

1use core::cell::RefCell;
2
3use ark_relations::r1cs::SynthesisError;
4
5use super::inner::ElementVar;
6use crate::ark_curve::r1cs::FqVar;
7
8#[derive(Clone, Debug)]
9pub enum Inner {
10    Encoding(FqVar),
11    Element(ElementVar),
12    EncodingAndElement {
13        encoding: FqVar,
14        element: ElementVar,
15    },
16}
17
18#[derive(Clone, Debug)]
19pub struct LazyElementVar {
20    inner: RefCell<Inner>,
21}
22
23impl LazyElementVar {
24    pub fn new_from_element(element: ElementVar) -> Self {
25        Self {
26            inner: RefCell::new(Inner::Element(element)),
27        }
28    }
29
30    pub fn new_from_encoding(encoding: FqVar) -> Self {
31        Self {
32            inner: RefCell::new(Inner::Encoding(encoding)),
33        }
34    }
35
36    pub fn element(&self) -> Result<ElementVar, SynthesisError> {
37        if matches!(&*self.inner.borrow(), Inner::Encoding(_)) {
38            let encoding = self.encoding()?;
39            let element = ElementVar::decompress_from_field(encoding.clone())?;
40            *self.inner.borrow_mut() = Inner::EncodingAndElement { encoding, element };
41        }
42        match &*self.inner.borrow() {
43            Inner::Encoding(_) => {
44                unreachable!("encoding should have been replaced by encoding and element")
45            }
46            Inner::Element(element) => Ok(element.clone()),
47            Inner::EncodingAndElement { element, .. } => Ok(element.clone()),
48        }
49    }
50
51    pub fn encoding(&self) -> Result<FqVar, SynthesisError> {
52        if matches!(&*self.inner.borrow(), Inner::Element(_)) {
53            let element = self.element()?;
54            let encoding = element.compress_to_field()?;
55            *self.inner.borrow_mut() = Inner::EncodingAndElement { encoding, element };
56        }
57        match &*self.inner.borrow() {
58            Inner::Encoding(encoding) => Ok(encoding.clone()),
59            Inner::Element(_) => {
60                unreachable!("encoding should have been replaced by encoding and element")
61            }
62            Inner::EncodingAndElement { encoding, .. } => Ok(encoding.clone()),
63        }
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use crate::{Bls12_377, Element, Fq};
70    use ark_groth16::{r1cs_to_qap::LibsnarkReduction, Groth16, ProvingKey, VerifyingKey};
71    use ark_r1cs_std::prelude::AllocVar;
72    use ark_relations::r1cs::ConstraintSynthesizer;
73    use ark_snark::SNARK;
74    use rand_core::OsRng;
75
76    use super::*;
77
78    #[derive(Clone)]
79    struct TestCircuit {
80        // Witness
81        encoding: Fq,
82    }
83
84    impl ConstraintSynthesizer<Fq> for TestCircuit {
85        fn generate_constraints(
86            self,
87            cs: ark_relations::r1cs::ConstraintSystemRef<Fq>,
88        ) -> ark_relations::r1cs::Result<()> {
89            let encoding_var = FqVar::new_witness(cs, || Ok(self.encoding))?;
90            let lazy_var = LazyElementVar::new_from_encoding(encoding_var);
91            let _element_var = lazy_var.element()?;
92            Ok(())
93        }
94    }
95
96    impl TestCircuit {
97        fn generate_test_parameters() -> (ProvingKey<Bls12_377>, VerifyingKey<Bls12_377>) {
98            let element = Element::default();
99            let encoding = element.vartime_compress_to_field();
100            let circuit = TestCircuit { encoding };
101            let (pk, vk) = Groth16::<Bls12_377, LibsnarkReduction>::circuit_specific_setup(
102                circuit, &mut OsRng,
103            )
104            .expect("can perform circuit specific setup");
105            (pk, vk)
106        }
107    }
108
109    #[test]
110    fn lazy_element_var_evaluation() {
111        let (pk, _) = TestCircuit::generate_test_parameters();
112        let mut rng = OsRng;
113        let test_circuit = TestCircuit {
114            encoding: Element::default().vartime_compress_to_field(),
115        };
116        Groth16::<Bls12_377, LibsnarkReduction>::prove(&pk, test_circuit, &mut rng)
117            .expect("can generate proof");
118    }
119}