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