sonobe_primitives/algebra/group/
emulated.rs1use ark_ec::{AffineRepr, short_weierstrass::SWFlags};
11use ark_ff::Zero;
12use ark_r1cs_std::{
13 GR1CSVar,
14 alloc::{AllocVar, AllocationMode},
15 eq::EqGadget,
16 fields::fp::FpVar,
17 prelude::Boolean,
18 select::CondSelectGadget,
19};
20use ark_relations::gr1cs::{ConstraintSystemRef, Namespace, SynthesisError};
21use ark_serialize::{CanonicalSerialize, CanonicalSerializeWithFlags};
22use ark_std::borrow::Borrow;
23
24use crate::{
25 algebra::{field::emulated::EmulatedFieldVar, group::SonobeCurve},
26 traits::SonobeField,
27 transcripts::AbsorbableVar,
28};
29
30#[derive(Debug, Clone)]
35pub struct EmulatedAffineVar<Base: SonobeField, Target: SonobeCurve> {
36 pub x: EmulatedFieldVar<Base, Target::BaseField>,
39 pub y: EmulatedFieldVar<Base, Target::BaseField>,
42}
43
44impl<Base: SonobeField, Target: SonobeCurve> AllocVar<Target, Base>
45 for EmulatedAffineVar<Base, Target>
46{
47 fn new_variable<T: Borrow<Target>>(
48 cs: impl Into<Namespace<Base>>,
49 f: impl FnOnce() -> Result<T, SynthesisError>,
50 mode: AllocationMode,
51 ) -> Result<Self, SynthesisError> {
52 f().and_then(|val| {
53 let cs = cs.into();
54
55 let affine = val.borrow().into_affine();
56 let (x, y) = affine.xy().unwrap_or_default();
57
58 let x = EmulatedFieldVar::new_variable(cs.clone(), || Ok(x), mode)?;
59 let y = EmulatedFieldVar::new_variable(cs.clone(), || Ok(y), mode)?;
60
61 Ok(Self { x, y })
62 })
63 }
64}
65
66impl<Base: SonobeField, Target: SonobeCurve> GR1CSVar<Base> for EmulatedAffineVar<Base, Target> {
67 type Value = Target;
68
69 fn cs(&self) -> ConstraintSystemRef<Base> {
70 self.x.cs().or(self.y.cs())
71 }
72
73 fn value(&self) -> Result<Self::Value, SynthesisError> {
74 let x = self.x.value()?;
75 let y = self.y.value()?;
76 let mut bytes = vec![];
80 x.serialize_uncompressed(&mut bytes).unwrap();
84 y.serialize_with_flags(
86 &mut bytes,
87 if x.is_zero() && y.is_zero() {
88 SWFlags::PointAtInfinity
89 } else if y <= -y {
90 SWFlags::YIsPositive
91 } else {
92 SWFlags::YIsNegative
93 },
94 )
95 .unwrap();
96 Ok(Target::deserialize_uncompressed_unchecked(&bytes[..]).unwrap())
100 }
101}
102
103impl<Base: SonobeField, Target: SonobeCurve> EqGadget<Base> for EmulatedAffineVar<Base, Target> {
104 fn is_eq(&self, other: &Self) -> Result<Boolean<Base>, SynthesisError> {
105 Ok(self.x.is_eq(&other.x)? & self.y.is_eq(&other.y)?)
106 }
107
108 fn enforce_equal(&self, other: &Self) -> Result<(), SynthesisError> {
109 self.x.enforce_equal(&other.x)?;
110 self.y.enforce_equal(&other.y)?;
111 Ok(())
112 }
113}
114
115impl<Base: SonobeField, Target: SonobeCurve> EmulatedAffineVar<Base, Target> {
116 pub fn zero() -> Self {
119 Self::new_constant(ConstraintSystemRef::None, Target::zero()).unwrap()
122 }
123}
124
125impl<Base: SonobeField, Target: SonobeCurve> AbsorbableVar<Base>
126 for EmulatedAffineVar<Base, Target>
127{
128 fn absorb_into(&self, dest: &mut Vec<FpVar<Base>>) -> Result<(), SynthesisError> {
129 (&self.x, &self.y).absorb_into(dest)
130 }
131}
132
133impl<Base: SonobeField, Target: SonobeCurve> CondSelectGadget<Base>
134 for EmulatedAffineVar<Base, Target>
135{
136 fn conditionally_select(
137 cond: &Boolean<Base>,
138 true_value: &Self,
139 false_value: &Self,
140 ) -> Result<Self, SynthesisError> {
141 Ok(Self {
142 x: cond.select(&true_value.x, &false_value.x)?,
143 y: cond.select(&true_value.y, &false_value.y)?,
144 })
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use ark_pallas::{Fq, Fr, PallasConfig, Projective};
151 use ark_r1cs_std::groups::curves::short_weierstrass::ProjectiveVar;
152 use ark_relations::gr1cs::ConstraintSystem;
153 use ark_std::{UniformRand, error::Error, rand::thread_rng};
154 #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
155 use wasm_bindgen_test::wasm_bindgen_test as test;
156
157 use super::*;
158 use crate::{
159 traits::{Inputize, InputizeEmulated},
160 transcripts::Absorbable,
161 };
162
163 #[test]
164 fn test_alloc_zero() {
165 let cs = ConstraintSystem::<Fr>::new_ref();
166
167 let p = Projective::zero();
169 assert!(EmulatedAffineVar::<Fr, Projective>::new_witness(cs.clone(), || Ok(p)).is_ok());
170 }
171
172 #[test]
173 fn test_to_hash_preimage() -> Result<(), Box<dyn Error>> {
174 let cs = ConstraintSystem::<Fr>::new_ref();
175
176 let mut rng = thread_rng();
177 let p = Projective::rand(&mut rng);
178 let p_var = EmulatedAffineVar::<Fr, Projective>::new_witness(cs.clone(), || Ok(p))?;
179
180 let mut v = vec![];
181 let mut v_var = vec![];
182 p.absorb_into(&mut v);
183 p_var.absorb_into(&mut v_var)?;
184
185 assert_eq!(v_var.value()?, v);
186 Ok(())
187 }
188
189 #[test]
190 fn test_inputize() -> Result<(), Box<dyn Error>> {
191 let mut rng = thread_rng();
192 let p = Projective::rand(&mut rng);
193
194 let cs = ConstraintSystem::<Fr>::new_ref();
195 let p_var = EmulatedAffineVar::<Fr, Projective>::new_witness(cs.clone(), || Ok(p))?;
196 assert_eq!(
197 [p_var.x.limbs.value()?, p_var.y.limbs.value()?].concat(),
198 p.inputize_emulated()
199 );
200
201 let cs = ConstraintSystem::<Fq>::new_ref();
202 let p_var = ProjectiveVar::<PallasConfig, FpVar<Fq>>::new_witness(cs.clone(), || Ok(p))?;
203 assert_eq!(
204 vec![p_var.x.value()?, p_var.y.value()?, p_var.z.value()?],
205 p.inputize()
206 );
207 Ok(())
208 }
209}