decaf377/ark_curve/r1cs/
element.rs

1#![allow(non_snake_case)]
2use core::borrow::Borrow;
3
4use ark_ec::AffineRepr;
5use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget, prelude::*, R1CSVar};
6use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};
7use ark_std::vec::Vec;
8
9use crate::ark_curve::r1cs::{lazy::LazyElementVar, FqVar};
10use crate::ark_curve::{edwards::EdwardsAffine, r1cs::inner::ElementVar as InnerElementVar};
11use crate::ark_curve::{AffinePoint, Element};
12use crate::Fq;
13
14use super::inner::Decaf377EdwardsVar;
15
16#[derive(Clone, Debug)]
17/// Represents the R1CS equivalent of a `decaf377::Element`
18///
19/// Generally the suffix -`Var` will indicate that the type or variable
20/// represents in R1CS.
21pub struct ElementVar {
22    pub(crate) inner: LazyElementVar,
23}
24
25impl ElementVar {
26    /// R1CS equivalent of `Element::vartime_compress_to_field`
27    pub fn compress_to_field(&self) -> Result<FqVar, SynthesisError> {
28        self.inner.encoding()
29    }
30
31    /// R1CS equivalent of `Encoding::vartime_decompress`
32    pub fn decompress_from_field(s_var: FqVar) -> Result<ElementVar, SynthesisError> {
33        let inner = LazyElementVar::new_from_encoding(s_var);
34        // This enforces that the encoding is valid.
35        inner.element()?;
36        Ok(Self { inner })
37    }
38
39    /// R1CS equivalent of `Element::elligator_map`
40    pub(crate) fn elligator_map(r_0_var: &FqVar) -> Result<ElementVar, SynthesisError> {
41        let inner = InnerElementVar::elligator_map(r_0_var)?;
42        Ok(Self {
43            inner: LazyElementVar::new_from_element(inner),
44        })
45    }
46
47    /// Maps a field element to a decaf377 `ElementVar` suitable for CDH challenges.
48    pub fn encode_to_curve(r_var: &FqVar) -> Result<ElementVar, SynthesisError> {
49        Self::elligator_map(r_var)
50    }
51}
52
53impl EqGadget<Fq> for ElementVar {
54    fn is_eq(&self, other: &Self) -> Result<Boolean<Fq>, SynthesisError> {
55        self.inner.element()?.is_eq(&other.inner.element()?)
56    }
57
58    fn conditional_enforce_equal(
59        &self,
60        other: &Self,
61        should_enforce: &Boolean<Fq>,
62    ) -> Result<(), SynthesisError> {
63        // should_enforce = true
64        //      return self == other
65        // should_enforce = false
66        //      return true
67        self.is_eq(other)?
68            .conditional_enforce_equal(&Boolean::constant(true), should_enforce)
69    }
70
71    fn conditional_enforce_not_equal(
72        &self,
73        other: &Self,
74        should_enforce: &Boolean<Fq>,
75    ) -> Result<(), SynthesisError> {
76        self.is_eq(other)?
77            .conditional_enforce_equal(&Boolean::constant(false), should_enforce)
78    }
79}
80
81impl R1CSVar<Fq> for ElementVar {
82    type Value = Element;
83
84    fn cs(&self) -> ConstraintSystemRef<Fq> {
85        let inner = self
86            .inner
87            .element()
88            .expect("element will exist if ElementVar is allocated");
89        inner.cs()
90    }
91
92    fn value(&self) -> Result<Self::Value, SynthesisError> {
93        let inner_element = self.inner.element()?;
94        let (x, y) = (
95            inner_element.inner.x.value()?,
96            inner_element.inner.y.value()?,
97        );
98        let result = EdwardsAffine::new(x, y);
99
100        Ok(Element {
101            inner: result.into(),
102        })
103    }
104}
105
106impl CondSelectGadget<Fq> for ElementVar {
107    fn conditionally_select(
108        cond: &Boolean<Fq>,
109        true_value: &Self,
110        false_value: &Self,
111    ) -> Result<Self, SynthesisError> {
112        let true_element = true_value.inner.element()?;
113        let false_element = false_value.inner.element()?;
114        let x = cond.select(&true_element.inner.x, &false_element.inner.x)?;
115        let y = cond.select(&true_element.inner.y, &false_element.inner.y)?;
116
117        let new_element = InnerElementVar {
118            inner: Decaf377EdwardsVar::new(x, y),
119        };
120        Ok(Self {
121            inner: LazyElementVar::new_from_element(new_element),
122        })
123    }
124}
125
126// This lets us use `new_constant`, `new_input` (public), or `new_witness` to add
127// decaf elements to an R1CS constraint system.
128impl AllocVar<Element, Fq> for ElementVar {
129    fn new_variable<T: core::borrow::Borrow<Element>>(
130        cs: impl Into<ark_relations::r1cs::Namespace<Fq>>,
131        f: impl FnOnce() -> Result<T, SynthesisError>,
132        mode: AllocationMode,
133    ) -> Result<Self, SynthesisError> {
134        let ns = cs.into();
135        let cs = ns.cs();
136        match mode {
137            AllocationMode::Input => {
138                let value: Element = *f()?.borrow();
139                let compressed = value.vartime_compress_to_field();
140                Ok(Self::new_input(cs, || Ok(compressed))?)
141            }
142            _ => {
143                let inner = InnerElementVar::new_variable(cs, f, mode)?;
144                Ok(Self {
145                    inner: LazyElementVar::new_from_element(inner),
146                })
147            }
148        }
149    }
150}
151
152impl AllocVar<AffinePoint, Fq> for ElementVar {
153    fn new_variable<T: Borrow<AffinePoint>>(
154        cs: impl Into<ark_relations::r1cs::Namespace<Fq>>,
155        f: impl FnOnce() -> Result<T, SynthesisError>,
156        mode: AllocationMode,
157    ) -> Result<Self, SynthesisError> {
158        Self::new_variable(cs, || f().map(|b| b.borrow().into_group()), mode)
159    }
160}
161
162impl AllocVar<Fq, Fq> for ElementVar {
163    fn new_variable<T: Borrow<Fq>>(
164        cs: impl Into<ark_relations::r1cs::Namespace<Fq>>,
165        f: impl FnOnce() -> Result<T, SynthesisError>,
166        mode: AllocationMode,
167    ) -> Result<Self, SynthesisError> {
168        let ns = cs.into();
169        let cs = ns.cs();
170        let compressed = FqVar::new_variable(cs, f, mode)?;
171        Ok(Self {
172            inner: LazyElementVar::new_from_encoding(compressed),
173        })
174    }
175}
176
177impl ToBitsGadget<Fq> for ElementVar {
178    fn to_bits_le(&self) -> Result<Vec<Boolean<Fq>>, SynthesisError> {
179        let compressed_fq = self
180            .inner
181            .element()
182            .expect("element will exist")
183            .to_bits_le()?;
184        let encoded_bits = compressed_fq.to_bits_le()?;
185        Ok(encoded_bits)
186    }
187}
188
189impl ToBytesGadget<Fq> for ElementVar {
190    fn to_bytes(&self) -> Result<Vec<UInt8<Fq>>, SynthesisError> {
191        let compressed_fq = self
192            .inner
193            .element()
194            .expect("element will exist")
195            .to_bytes()?;
196        let encoded_bytes = compressed_fq.to_bytes()?;
197        Ok(encoded_bytes)
198    }
199}
200
201impl<'a> GroupOpsBounds<'a, Element, ElementVar> for ElementVar {}
202
203impl CurveVar<Element, Fq> for ElementVar {
204    fn zero() -> Self {
205        let new_element = InnerElementVar::zero();
206        Self {
207            inner: LazyElementVar::new_from_element(new_element),
208        }
209    }
210
211    fn constant(other: Element) -> Self {
212        let new_element = InnerElementVar::constant(other);
213        Self {
214            inner: LazyElementVar::new_from_element(new_element),
215        }
216    }
217
218    fn new_variable_omit_prime_order_check(
219        cs: impl Into<ark_relations::r1cs::Namespace<Fq>>,
220        f: impl FnOnce() -> Result<Element, SynthesisError>,
221        mode: AllocationMode,
222    ) -> Result<Self, SynthesisError> {
223        let ns = cs.into();
224        let cs = ns.cs();
225
226        match f() {
227            Ok(ge) => {
228                let new_element =
229                    InnerElementVar::new_variable_omit_prime_order_check(cs, || Ok(ge), mode)?;
230                Ok(Self {
231                    inner: LazyElementVar::new_from_element(new_element),
232                })
233            }
234            _ => Err(SynthesisError::AssignmentMissing),
235        }
236    }
237
238    fn enforce_prime_order(&self) -> Result<(), SynthesisError> {
239        // This is decaf
240        Ok(())
241    }
242
243    fn double_in_place(&mut self) -> Result<(), SynthesisError> {
244        let mut inner_element = self.inner.element().expect("element will exist");
245        inner_element.double_in_place()?;
246        *self = Self {
247            inner: LazyElementVar::new_from_element(inner_element),
248        };
249        Ok(())
250    }
251
252    fn negate(&self) -> Result<Self, SynthesisError> {
253        let negated = self.inner.element().expect("element will exist").negate()?;
254        Ok(Self {
255            inner: LazyElementVar::new_from_element(negated),
256        })
257    }
258}