penumbra_sdk_keys/address/
r1cs.rs

1use crate::Address;
2use ark_ff::ToConstraintField;
3use ark_r1cs_std::prelude::*;
4use ark_relations::r1cs::SynthesisError;
5use decaf377::{
6    r1cs::{ElementVar, FqVar},
7    Element, Fq,
8};
9
10#[derive(Clone)]
11pub struct AddressVar {
12    pub diversified_generator: ElementVar,
13    pub transmission_key: ElementVar,
14    pub clue_key: FqVar,
15}
16
17impl AddressVar {
18    pub fn diversified_generator(&self) -> ElementVar {
19        self.diversified_generator.clone()
20    }
21
22    pub fn transmission_key(&self) -> ElementVar {
23        self.transmission_key.clone()
24    }
25
26    pub fn clue_key(&self) -> FqVar {
27        self.clue_key.clone()
28    }
29}
30
31impl AllocVar<Address, Fq> for AddressVar {
32    fn new_variable<T: std::borrow::Borrow<Address>>(
33        cs: impl Into<ark_relations::r1cs::Namespace<Fq>>,
34        f: impl FnOnce() -> Result<T, SynthesisError>,
35        mode: ark_r1cs_std::prelude::AllocationMode,
36    ) -> Result<Self, SynthesisError> {
37        let ns = cs.into();
38        let cs = ns.cs();
39        let address: Address = f()?.borrow().to_owned();
40
41        let diversified_generator: ElementVar = AllocVar::<Element, Fq>::new_variable(
42            cs.clone(),
43            || Ok(address.diversified_generator()),
44            mode,
45        )?;
46        // Check the diversified base is not identity.
47        let identity = ElementVar::new_constant(cs.clone(), decaf377::Element::default())?;
48        identity.enforce_not_equal(&diversified_generator)?;
49
50        let element_transmission_key = decaf377::Encoding(address.transmission_key().0)
51            .vartime_decompress()
52            .map_err(|_| SynthesisError::AssignmentMissing)?;
53        let transmission_key: ElementVar = AllocVar::<Element, Fq>::new_variable(
54            cs.clone(),
55            || Ok(element_transmission_key),
56            mode,
57        )?;
58        let clue_key = FqVar::new_variable(
59            cs,
60            || Ok(Fq::from_le_bytes_mod_order(&address.clue_key().0[..])),
61            mode,
62        )?;
63
64        Ok(Self {
65            diversified_generator,
66            transmission_key,
67            clue_key,
68        })
69    }
70}
71
72// We do not implement the R1CSVar trait for AddressVar since we do not have the
73// diversifier in-circuit in order to construct an Address.
74
75impl ToConstraintField<Fq> for Address {
76    fn to_field_elements(&self) -> Option<Vec<Fq>> {
77        let mut elements = Vec::new();
78        elements.extend(self.diversified_generator().to_field_elements()?);
79        let transmission_key_fq = decaf377::Encoding(self.transmission_key().0)
80            .vartime_decompress()
81            .expect("transmission key is valid decaf377 Element");
82        elements.extend([transmission_key_fq.vartime_compress_to_field()]);
83        elements.extend(Fq::from_bytes_checked(&self.clue_key().0));
84        Some(elements)
85    }
86}