fil_sapling_crypto/primitives/
mod.rs1use fff::{Field, PrimeField, PrimeFieldRepr};
2
3use crate::constants;
4
5use crate::group_hash::group_hash;
6
7use crate::pedersen_hash::{pedersen_hash, Personalization};
8
9use byteorder::{LittleEndian, WriteBytesExt};
10
11use crate::jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder};
12
13use blake2s_simd::Params;
14
15#[derive(Clone)]
16pub struct ValueCommitment<E: JubjubEngine> {
17 pub value: u64,
18 pub randomness: E::Fs,
19}
20
21impl<E: JubjubEngine> ValueCommitment<E> {
22 pub fn cm(&self, params: &E::Params) -> edwards::Point<E, PrimeOrder> {
23 params
24 .generator(FixedGenerators::ValueCommitmentValue)
25 .mul(self.value, params)
26 .add(
27 ¶ms
28 .generator(FixedGenerators::ValueCommitmentRandomness)
29 .mul(self.randomness, params),
30 params,
31 )
32 }
33}
34
35#[derive(Clone)]
36pub struct ProofGenerationKey<E: JubjubEngine> {
37 pub ak: edwards::Point<E, PrimeOrder>,
38 pub nsk: E::Fs,
39}
40
41impl<E: JubjubEngine> ProofGenerationKey<E> {
42 pub fn into_viewing_key(&self, params: &E::Params) -> ViewingKey<E> {
43 ViewingKey {
44 ak: self.ak.clone(),
45 nk: params
46 .generator(FixedGenerators::ProofGenerationKey)
47 .mul(self.nsk, params),
48 }
49 }
50}
51
52pub struct ViewingKey<E: JubjubEngine> {
53 pub ak: edwards::Point<E, PrimeOrder>,
54 pub nk: edwards::Point<E, PrimeOrder>,
55}
56
57impl<E: JubjubEngine> ViewingKey<E> {
58 pub fn rk(&self, ar: E::Fs, params: &E::Params) -> edwards::Point<E, PrimeOrder> {
59 self.ak.add(
60 ¶ms
61 .generator(FixedGenerators::SpendingKeyGenerator)
62 .mul(ar, params),
63 params,
64 )
65 }
66
67 pub fn ivk(&self) -> E::Fs {
68 let mut preimage = [0; 64];
69
70 self.ak.write(&mut preimage[0..32]).unwrap();
71 self.nk.write(&mut preimage[32..64]).unwrap();
72
73 let mut params = Params::new();
74 params.hash_length(32);
75 params.personal(constants::CRH_IVK_PERSONALIZATION);
76 params.key(&[]);
77 params.salt(&[]);
78
79 let mut h = params.to_state();
80 h.update(&preimage);
81 let mut h = h.finalize().as_ref().to_vec();
82
83 h[31] &= 0b0000_0111;
85
86 let mut e = <E::Fs as PrimeField>::Repr::default();
87 e.read_le(&h[..]).unwrap();
88
89 E::Fs::from_repr(e).expect("should be a valid scalar")
90 }
91
92 pub fn into_payment_address(
93 &self,
94 diversifier: Diversifier,
95 params: &E::Params,
96 ) -> Option<PaymentAddress<E>> {
97 diversifier.g_d(params).map(|g_d| {
98 let pk_d = g_d.mul(self.ivk(), params);
99
100 PaymentAddress {
101 pk_d: pk_d,
102 diversifier: diversifier,
103 }
104 })
105 }
106}
107
108#[derive(Copy, Clone)]
109pub struct Diversifier(pub [u8; 11]);
110
111impl Diversifier {
112 pub fn g_d<E: JubjubEngine>(
113 &self,
114 params: &E::Params,
115 ) -> Option<edwards::Point<E, PrimeOrder>> {
116 group_hash::<E>(
117 &self.0,
118 constants::KEY_DIVERSIFICATION_PERSONALIZATION,
119 params,
120 )
121 }
122}
123
124#[derive(Clone)]
125pub struct PaymentAddress<E: JubjubEngine> {
126 pub pk_d: edwards::Point<E, PrimeOrder>,
127 pub diversifier: Diversifier,
128}
129
130impl<E: JubjubEngine> PaymentAddress<E> {
131 pub fn g_d(&self, params: &E::Params) -> Option<edwards::Point<E, PrimeOrder>> {
132 self.diversifier.g_d(params)
133 }
134
135 pub fn create_note(
136 &self,
137 value: u64,
138 randomness: E::Fs,
139 params: &E::Params,
140 ) -> Option<Note<E>> {
141 self.g_d(params).map(|g_d| Note {
142 value: value,
143 r: randomness,
144 g_d: g_d,
145 pk_d: self.pk_d.clone(),
146 })
147 }
148}
149
150pub struct Note<E: JubjubEngine> {
151 pub value: u64,
153 pub g_d: edwards::Point<E, PrimeOrder>,
155 pub pk_d: edwards::Point<E, PrimeOrder>,
157 pub r: E::Fs,
159}
160
161impl<E: JubjubEngine> Note<E> {
162 pub fn uncommitted() -> E::Fr {
163 E::Fr::one()
169 }
170
171 fn cm_full_point(&self, params: &E::Params) -> edwards::Point<E, PrimeOrder> {
173 let mut note_contents = vec![];
175
176 (&mut note_contents)
178 .write_u64::<LittleEndian>(self.value)
179 .unwrap();
180
181 self.g_d.write(&mut note_contents).unwrap();
183
184 self.pk_d.write(&mut note_contents).unwrap();
186
187 assert_eq!(note_contents.len(), 32 + 32 + 8);
188
189 let hash_of_contents = pedersen_hash(
191 Personalization::NoteCommitment,
192 note_contents
193 .into_iter()
194 .flat_map(|byte| (0..8).map(move |i| ((byte >> i) & 1) == 1)),
195 params,
196 );
197
198 params
200 .generator(FixedGenerators::NoteCommitmentRandomness)
201 .mul(self.r, params)
202 .add(&hash_of_contents, params)
203 }
204
205 pub fn nf(&self, viewing_key: &ViewingKey<E>, position: u64, params: &E::Params) -> Vec<u8> {
208 let rho = self.cm_full_point(params).add(
210 ¶ms
211 .generator(FixedGenerators::NullifierPosition)
212 .mul(position, params),
213 params,
214 );
215
216 let mut nf_preimage = [0u8; 64];
218 viewing_key.nk.write(&mut nf_preimage[0..32]).unwrap();
219 rho.write(&mut nf_preimage[32..64]).unwrap();
220
221 let mut params = Params::new();
222 params.hash_length(32);
223 params.personal(constants::PRF_NF_PERSONALIZATION);
224 params.key(&[]);
225 params.salt(&[]);
226
227 let mut h = params.to_state();
228 h.update(&nf_preimage);
229 h.finalize().as_ref().to_vec()
230 }
231
232 pub fn cm(&self, params: &E::Params) -> E::Fr {
234 self.cm_full_point(params).into_xy().0
237 }
238}