penumbra_sdk_shielded_pool/note/
r1cs.rs1use ark_ff::ToConstraintField;
2use ark_r1cs_std::prelude::*;
3use ark_relations::r1cs::SynthesisError;
4use decaf377::{
5 r1cs::{ElementVar, FqVar},
6 Fq,
7};
8use penumbra_sdk_asset::ValueVar;
9use penumbra_sdk_keys::address::AddressVar;
10use penumbra_sdk_tct::r1cs::StateCommitmentVar;
11
12use crate::Note;
13
14use super::NOTECOMMIT_DOMAIN_SEP;
15
16pub struct NoteVar {
17 pub value: ValueVar,
18 pub note_blinding: FqVar,
19 pub address: AddressVar,
20}
21
22impl NoteVar {
23 pub fn amount(&self) -> FqVar {
24 self.value.amount()
25 }
26
27 pub fn value(&self) -> ValueVar {
28 self.value.clone()
29 }
30
31 #[allow(dead_code)]
32 pub fn asset_id(&self) -> FqVar {
33 self.value.asset_id()
34 }
35
36 #[allow(dead_code)]
37 pub fn note_blinding(&self) -> FqVar {
38 self.note_blinding.clone()
39 }
40
41 pub fn diversified_generator(&self) -> ElementVar {
42 self.address.diversified_generator.clone()
43 }
44
45 pub fn transmission_key(&self) -> ElementVar {
46 self.address.transmission_key.clone()
47 }
48
49 #[allow(dead_code)]
50 pub fn clue_key(&self) -> FqVar {
51 self.address.clue_key.clone()
52 }
53}
54
55impl AllocVar<Note, Fq> for NoteVar {
56 fn new_variable<T: std::borrow::Borrow<Note>>(
57 cs: impl Into<ark_relations::r1cs::Namespace<Fq>>,
58 f: impl FnOnce() -> Result<T, SynthesisError>,
59 mode: ark_r1cs_std::prelude::AllocationMode,
60 ) -> Result<Self, SynthesisError> {
61 let ns = cs.into();
63 let cs = ns.cs();
64 let note1 = f()?;
65 let note: &Note = note1.borrow();
66 let note_blinding = FqVar::new_variable(cs.clone(), || Ok(note.note_blinding()), mode)?;
67 let value = ValueVar::new_variable(cs.clone(), || Ok(note.value()), mode)?;
68 let address = AddressVar::new_variable(cs, || Ok(note.address()), mode)?;
69
70 Ok(Self {
71 note_blinding,
72 value,
73 address,
74 })
75 }
76}
77
78impl ToConstraintField<Fq> for Note {
79 fn to_field_elements(&self) -> Option<Vec<Fq>> {
80 let mut elements = Vec::new();
81 let note_blinding = self.note_blinding();
82 elements.extend([note_blinding]);
83 elements.extend(self.value().to_field_elements()?);
84 elements.extend(self.address().to_field_elements()?);
85 Some(elements)
86 }
87}
88
89impl NoteVar {
94 pub fn commit(&self) -> Result<StateCommitmentVar, SynthesisError> {
95 let cs = self.amount().cs();
96 let domain_sep = FqVar::new_constant(cs.clone(), *NOTECOMMIT_DOMAIN_SEP)?;
97 let compressed_g_d = self.address.diversified_generator().compress_to_field()?;
98
99 let commitment = poseidon377::r1cs::hash_6(
100 cs,
101 &domain_sep,
102 (
103 self.note_blinding.clone(),
104 self.value.amount(),
105 self.value.asset_id(),
106 compressed_g_d,
107 self.address.transmission_key().compress_to_field()?,
108 self.address.clue_key(),
109 ),
110 )?;
111
112 Ok(StateCommitmentVar { inner: commitment })
113 }
114}