penumbra_sdk_keys/keys/fvk/
r1cs.rs

1use ark_r1cs_std::prelude::*;
2use ark_relations::r1cs::SynthesisError;
3use decaf377::{
4    r1cs::{ElementVar, FqVar},
5    Element, Fq, Fr,
6};
7use decaf377_rdsa::{SpendAuth, VerificationKey, VerificationKeyBytes};
8use once_cell::sync::Lazy;
9
10fn generator() -> Element {
11    Element::GENERATOR
12}
13
14pub(crate) static SPENDAUTH_BASEPOINT: Lazy<Element> = Lazy::new(generator);
15
16pub struct RandomizedVerificationKey {
17    pub inner: ElementVar,
18}
19
20impl AllocVar<VerificationKey<SpendAuth>, Fq> for RandomizedVerificationKey {
21    fn new_variable<T: std::borrow::Borrow<VerificationKey<SpendAuth>>>(
22        cs: impl Into<ark_relations::r1cs::Namespace<Fq>>,
23        f: impl FnOnce() -> Result<T, SynthesisError>,
24        mode: ark_r1cs_std::prelude::AllocationMode,
25    ) -> Result<Self, SynthesisError> {
26        let ns = cs.into();
27        let cs = ns.cs();
28        let inner: VerificationKey<SpendAuth> = *f()?.borrow();
29        match mode {
30            AllocationMode::Constant => unimplemented!(),
31            AllocationMode::Input => {
32                let point = decaf377::Encoding(*inner.as_ref())
33                    .vartime_decompress()
34                    .map_err(|_| SynthesisError::MalformedVerifyingKey)?;
35                let element_var: ElementVar = AllocVar::new_input(cs, || Ok(point))?;
36                Ok(Self { inner: element_var })
37            }
38            AllocationMode::Witness => unimplemented!(),
39        }
40    }
41}
42
43impl R1CSVar<Fq> for RandomizedVerificationKey {
44    type Value = VerificationKey<SpendAuth>;
45
46    fn cs(&self) -> ark_relations::r1cs::ConstraintSystemRef<Fq> {
47        self.inner.cs()
48    }
49
50    fn value(&self) -> Result<Self::Value, SynthesisError> {
51        let point = self.inner.value()?;
52        let key_bytes = point.vartime_compress();
53        let verification_key_bytes: VerificationKeyBytes<SpendAuth> = key_bytes.0.into();
54        Ok(
55            VerificationKey::<SpendAuth>::try_from(verification_key_bytes)
56                .expect("should be able to convert from bytes"),
57        )
58    }
59}
60
61impl RandomizedVerificationKey {
62    pub fn compress_to_field(&self) -> Result<FqVar, SynthesisError> {
63        self.inner.compress_to_field()
64    }
65}
66
67impl EqGadget<Fq> for RandomizedVerificationKey {
68    fn is_eq(&self, other: &Self) -> Result<Boolean<Fq>, SynthesisError> {
69        let self_fq = self.inner.compress_to_field()?;
70        let other_fq = other.compress_to_field()?;
71        self_fq.is_eq(&other_fq)
72    }
73}
74
75pub struct AuthorizationKeyVar {
76    pub inner: ElementVar,
77}
78
79impl AllocVar<VerificationKey<SpendAuth>, Fq> for AuthorizationKeyVar {
80    fn new_variable<T: std::borrow::Borrow<VerificationKey<SpendAuth>>>(
81        cs: impl Into<ark_relations::r1cs::Namespace<Fq>>,
82        f: impl FnOnce() -> Result<T, SynthesisError>,
83        mode: ark_r1cs_std::prelude::AllocationMode,
84    ) -> Result<Self, SynthesisError> {
85        let ns = cs.into();
86        let cs = ns.cs();
87        let inner: VerificationKey<SpendAuth> = *f()?.borrow();
88        match mode {
89            AllocationMode::Constant => unimplemented!(),
90            AllocationMode::Input => unimplemented!(),
91            AllocationMode::Witness => {
92                let ak_point = decaf377::Encoding(*inner.as_ref())
93                    .vartime_decompress()
94                    .map_err(|_| SynthesisError::MalformedVerifyingKey)?;
95                let ak_element_var: ElementVar =
96                    AllocVar::<Element, Fq>::new_witness(cs.clone(), || Ok(ak_point))?;
97
98                // The ak must never be identity.
99                let identity = ElementVar::new_constant(cs, decaf377::Element::default())?;
100                identity.enforce_not_equal(&ak_element_var)?;
101                Ok(Self {
102                    inner: ak_element_var,
103                })
104            }
105        }
106    }
107}
108
109impl R1CSVar<Fq> for AuthorizationKeyVar {
110    type Value = VerificationKey<SpendAuth>;
111
112    fn cs(&self) -> ark_relations::r1cs::ConstraintSystemRef<Fq> {
113        self.inner.cs()
114    }
115
116    fn value(&self) -> Result<Self::Value, SynthesisError> {
117        let point = self.inner.value()?;
118        let key_bytes = point.vartime_compress();
119        let verification_key_bytes: VerificationKeyBytes<SpendAuth> = key_bytes.0.into();
120        Ok(
121            VerificationKey::<SpendAuth>::try_from(verification_key_bytes)
122                .expect("should be able to convert from bytes"),
123        )
124    }
125}
126
127impl AuthorizationKeyVar {
128    pub fn randomize(
129        &self,
130        spend_auth_randomizer: &SpendAuthRandomizerVar,
131    ) -> Result<RandomizedVerificationKey, SynthesisError> {
132        let cs = self.inner.cs();
133        let spend_auth_basepoint_var = ElementVar::new_constant(cs, *SPENDAUTH_BASEPOINT)?;
134        let point = self.inner.clone()
135            + spend_auth_basepoint_var
136                .scalar_mul_le(spend_auth_randomizer.inner.to_bits_le()?.iter())?;
137        Ok(RandomizedVerificationKey { inner: point })
138    }
139}
140
141pub struct SpendAuthRandomizerVar {
142    inner: Vec<UInt8<Fq>>,
143}
144
145impl AllocVar<Fr, Fq> for SpendAuthRandomizerVar {
146    fn new_variable<T: std::borrow::Borrow<Fr>>(
147        cs: impl Into<ark_relations::r1cs::Namespace<Fq>>,
148        f: impl FnOnce() -> Result<T, SynthesisError>,
149        mode: ark_r1cs_std::prelude::AllocationMode,
150    ) -> Result<Self, SynthesisError> {
151        let ns = cs.into();
152        let cs = ns.cs();
153        let inner: Fr = *f()?.borrow();
154        match mode {
155            AllocationMode::Constant => unimplemented!(),
156            AllocationMode::Input => unimplemented!(),
157            AllocationMode::Witness => {
158                let spend_auth_randomizer_arr: [u8; 32] = inner.to_bytes();
159                Ok(Self {
160                    inner: UInt8::new_witness_vec(cs, &spend_auth_randomizer_arr)?,
161                })
162            }
163        }
164    }
165}
166
167impl R1CSVar<Fq> for SpendAuthRandomizerVar {
168    type Value = Fr;
169
170    fn cs(&self) -> ark_relations::r1cs::ConstraintSystemRef<Fq> {
171        self.inner.cs()
172    }
173
174    fn value(&self) -> Result<Self::Value, SynthesisError> {
175        let mut bytes = [0u8; 32];
176        for (i, byte) in self.inner.iter().enumerate() {
177            bytes[i] = byte.value()?;
178        }
179        Ok(Fr::from_bytes_checked(&bytes).expect("can convert bytes to Fr"))
180    }
181}