1use core::convert::{TryFrom, TryInto};
8
9use dusk_bls12_381::BlsScalar;
10use dusk_bytes::{DeserializableSlice, Error as BytesError, Serializable};
11use dusk_jubjub::{dhke, JubJubAffine, JubJubScalar, GENERATOR_NUMS_EXTENDED};
12use dusk_poseidon::{Domain, Hash};
13use ff::Field;
14use jubjub_elgamal as elgamal;
15use jubjub_schnorr::{PublicKey as NotePublicKey, SecretKey as NoteSecretKey};
16use rand::{CryptoRng, RngCore};
17
18use crate::{
19 aes, transparent_value_commitment, value_commitment, Error, PublicKey,
20 SecretKey, StealthAddress, ViewKey,
21};
22
23#[cfg(feature = "rkyv-impl")]
24use rkyv::{Archive, Deserialize, Serialize};
25
26pub(crate) const TRANSPARENT_BLINDER: JubJubScalar = JubJubScalar::zero();
28
29pub(crate) const PLAINTEXT_SIZE: usize = 40;
31
32pub const VALUE_ENC_SIZE: usize = PLAINTEXT_SIZE + aes::ENCRYPTION_EXTRA_SIZE;
34
35#[derive(Debug, Clone, Copy, Eq, PartialEq)]
37#[cfg_attr(
38 feature = "rkyv-impl",
39 derive(Archive, Serialize, Deserialize),
40 archive_attr(derive(bytecheck::CheckBytes))
41)]
42pub enum NoteType {
43 Transparent = 0,
45 Obfuscated = 1,
47}
48
49impl TryFrom<u8> for NoteType {
50 type Error = Error;
51
52 fn try_from(note_type: u8) -> Result<Self, Self::Error> {
53 match note_type {
54 0 => Ok(NoteType::Transparent),
55 1 => Ok(NoteType::Obfuscated),
56 n => Err(Error::InvalidNoteType(n)),
57 }
58 }
59}
60
61impl TryFrom<i32> for NoteType {
62 type Error = Error;
63
64 fn try_from(note_type: i32) -> Result<Self, Self::Error> {
65 (note_type as u8).try_into()
66 }
67}
68
69#[derive(Clone, Debug, Eq)]
71#[cfg_attr(
72 feature = "rkyv-impl",
73 derive(Archive, Serialize, Deserialize),
74 archive_attr(derive(bytecheck::CheckBytes))
75)]
76pub struct Note {
77 pub(crate) note_type: NoteType,
78 pub(crate) value_commitment: JubJubAffine,
79 pub(crate) stealth_address: StealthAddress,
80 pub(crate) pos: u64,
81 pub(crate) value_enc: [u8; VALUE_ENC_SIZE],
82 pub(crate) sender: Sender,
83}
84
85impl PartialEq for Note {
86 fn eq(&self, other: &Self) -> bool {
87 self.value_enc == other.value_enc
88 && self.sender == other.sender
89 && self.hash() == other.hash()
90 }
91}
92
93impl Note {
94 pub fn new<R: RngCore + CryptoRng>(
96 rng: &mut R,
97 note_type: NoteType,
98 sender_pk: &PublicKey,
99 receiver_pk: &PublicKey,
100 value: u64,
101 value_blinder: JubJubScalar,
102 sender_blinder: [JubJubScalar; 2],
103 ) -> Self {
104 let r = JubJubScalar::random(&mut *rng);
105 let stealth_address = receiver_pk.gen_stealth_address(&r);
106
107 let value_commitment = value_commitment(value, value_blinder);
108
109 let pos = u64::MAX;
111
112 let value_enc = match note_type {
113 NoteType::Transparent => {
114 let mut value_enc = [0u8; VALUE_ENC_SIZE];
115 value_enc[..u64::SIZE].copy_from_slice(&value.to_bytes());
116
117 value_enc
118 }
119 NoteType::Obfuscated => {
120 let shared_secret = dhke(&r, receiver_pk.A());
121 let value_blinder = BlsScalar::from(value_blinder);
122
123 let mut plaintext = value.to_bytes().to_vec();
124 plaintext.append(&mut value_blinder.to_bytes().to_vec());
125
126 let salt = stealth_address.to_bytes();
127
128 aes::encrypt(&shared_secret, &salt, &plaintext, rng)
129 .expect("Encrypted correctly.")
130 }
131 };
132
133 Note {
134 note_type,
135 value_commitment,
136 stealth_address,
137 pos,
138 value_enc,
139 sender: Sender::encrypt(
140 stealth_address.note_pk(),
141 sender_pk,
142 &sender_blinder,
143 ),
144 }
145 }
146
147 pub fn transparent<R: RngCore + CryptoRng>(
153 rng: &mut R,
154 sender_pk: &PublicKey,
155 receiver_pk: &PublicKey,
156 value: u64,
157 sender_blinder: [JubJubScalar; 2],
158 ) -> Self {
159 Self::new(
160 rng,
161 NoteType::Transparent,
162 sender_pk,
163 receiver_pk,
164 value,
165 TRANSPARENT_BLINDER,
166 sender_blinder,
167 )
168 }
169
170 pub fn transparent_stealth(
176 stealth_address: StealthAddress,
177 value: u64,
178 sender: impl Into<Sender>,
179 ) -> Self {
180 let value_commitment = transparent_value_commitment(value);
181
182 let pos = u64::MAX;
183
184 let mut value_enc = [0u8; VALUE_ENC_SIZE];
185 value_enc[..u64::SIZE].copy_from_slice(&value.to_bytes());
186
187 Note {
188 note_type: NoteType::Transparent,
189 value_commitment,
190 stealth_address,
191 pos,
192 value_enc,
193 sender: sender.into(),
194 }
195 }
196
197 pub fn obfuscated<R: RngCore + CryptoRng>(
204 rng: &mut R,
205 sender_pk: &PublicKey,
206 receiver_pk: &PublicKey,
207 value: u64,
208 value_blinder: JubJubScalar,
209 sender_blinder: [JubJubScalar; 2],
210 ) -> Self {
211 Self::new(
212 rng,
213 NoteType::Obfuscated,
214 sender_pk,
215 receiver_pk,
216 value,
217 value_blinder,
218 sender_blinder,
219 )
220 }
221
222 pub fn empty() -> Self {
224 Self {
225 note_type: NoteType::Transparent,
226 value_commitment: JubJubAffine::default(),
227 stealth_address: StealthAddress::default(),
228 pos: 0,
229 value_enc: [0; VALUE_ENC_SIZE],
230 sender: Sender::Encryption(
231 [(JubJubAffine::default(), JubJubAffine::default()); 2],
232 ),
233 }
234 }
235
236 fn decrypt_value(
237 &self,
238 vk: &ViewKey,
239 ) -> Result<(u64, JubJubScalar), Error> {
240 let R = self.stealth_address.R();
241 let shared_secret = dhke(vk.a(), R);
242
243 let salt = self.stealth_address.to_bytes();
244
245 let dec_plaintext: [u8; PLAINTEXT_SIZE] =
246 aes::decrypt(&shared_secret, &salt, &self.value_enc)?;
247
248 let value = u64::from_slice(&dec_plaintext[..u64::SIZE])?;
249
250 let value_blinder =
254 match JubJubScalar::from_slice(&dec_plaintext[u64::SIZE..])?.into()
255 {
256 Some(scalar) => scalar,
257 None => return Err(Error::InvalidData),
258 };
259
260 Ok((value, value_blinder))
261 }
262
263 pub fn gen_nullifier(&self, sk: &SecretKey) -> BlsScalar {
267 let note_sk = sk.gen_note_sk(&self.stealth_address);
268 let pk_prime = GENERATOR_NUMS_EXTENDED * note_sk.as_ref();
269 let pk_prime = pk_prime.to_hash_inputs();
270
271 let pos = BlsScalar::from(self.pos);
272
273 Hash::digest(Domain::Other, &[pk_prime[0], pk_prime[1], pos])[0]
274 }
275
276 pub fn hash_inputs(&self) -> [BlsScalar; 6] {
278 let note_pk =
279 self.stealth_address().note_pk().as_ref().to_hash_inputs();
280
281 [
282 BlsScalar::from(self.note_type as u64),
283 self.value_commitment.get_u(),
284 self.value_commitment.get_v(),
285 note_pk[0],
286 note_pk[1],
287 BlsScalar::from(self.pos),
288 ]
289 }
290
291 pub fn hash(&self) -> BlsScalar {
294 Hash::digest(Domain::Other, &self.hash_inputs())[0]
295 }
296
297 pub const fn note_type(&self) -> NoteType {
299 self.note_type
300 }
301
302 pub const fn pos(&self) -> &u64 {
304 &self.pos
305 }
306
307 pub const fn stealth_address(&self) -> &StealthAddress {
309 &self.stealth_address
310 }
311
312 pub fn set_pos(&mut self, pos: u64) {
315 self.pos = pos;
316 }
317
318 pub const fn value_commitment(&self) -> &JubJubAffine {
320 &self.value_commitment
321 }
322
323 pub const fn value_enc(&self) -> &[u8; VALUE_ENC_SIZE] {
325 &self.value_enc
326 }
327
328 pub const fn sender(&self) -> &Sender {
332 &self.sender
333 }
334
335 pub fn value(&self, vk: Option<&ViewKey>) -> Result<u64, Error> {
339 match (self.note_type, vk) {
340 (NoteType::Transparent, _) => {
341 let value =
342 u64::from_slice(&self.value_enc[..u64::SIZE]).unwrap();
343 Ok(value)
344 }
345 (NoteType::Obfuscated, Some(vk)) => {
346 self.decrypt_value(vk).map(|(value, _)| value)
347 }
348 _ => Err(Error::MissingViewKey),
349 }
350 }
351
352 pub fn value_blinder(
356 &self,
357 vk: Option<&ViewKey>,
358 ) -> Result<JubJubScalar, Error> {
359 match (self.note_type, vk) {
360 (NoteType::Transparent, _) => Ok(TRANSPARENT_BLINDER),
361 (NoteType::Obfuscated, Some(vk)) => self
362 .decrypt_value(vk)
363 .map(|(_, value_blinder)| value_blinder),
364 _ => Err(Error::MissingViewKey),
365 }
366 }
367}
368
369const SIZE: usize = 1
370 + JubJubAffine::SIZE
371 + StealthAddress::SIZE
372 + u64::SIZE
373 + VALUE_ENC_SIZE
374 + Sender::SIZE;
375
376impl Serializable<SIZE> for Note {
377 type Error = BytesError;
378
379 fn to_bytes(&self) -> [u8; Self::SIZE] {
381 let mut buf = [0u8; Self::SIZE];
382
383 buf[0] = self.note_type as u8;
384
385 let mut start = 1;
386
387 buf[start..start + JubJubAffine::SIZE]
388 .copy_from_slice(&self.value_commitment.to_bytes());
389 start += JubJubAffine::SIZE;
390
391 buf[start..start + StealthAddress::SIZE]
392 .copy_from_slice(&self.stealth_address.to_bytes());
393 start += StealthAddress::SIZE;
394
395 buf[start..start + u64::SIZE].copy_from_slice(&self.pos.to_le_bytes());
396 start += u64::SIZE;
397
398 buf[start..start + VALUE_ENC_SIZE].copy_from_slice(&self.value_enc);
399 start += VALUE_ENC_SIZE;
400
401 buf[start..start + Sender::SIZE]
402 .copy_from_slice(&self.sender.to_bytes());
403
404 buf
405 }
406
407 fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
410 let note_type =
411 bytes[0].try_into().map_err(|_| BytesError::InvalidData)?;
412
413 let mut buf = &bytes[1..];
414
415 let value_commitment = JubJubAffine::from_reader(&mut buf)?;
416
417 let stealth_address = StealthAddress::from_reader(&mut buf)?;
418
419 let pos = u64::from_reader(&mut buf)?;
420
421 let mut value_enc = [0u8; VALUE_ENC_SIZE];
422 value_enc.copy_from_slice(&buf[..VALUE_ENC_SIZE]);
423 buf = &buf[VALUE_ENC_SIZE..];
424
425 let sender = Sender::from_reader(&mut buf)?;
426
427 Ok(Note {
428 note_type,
429 value_commitment,
430 stealth_address,
431 pos,
432 value_enc,
433 sender,
434 })
435 }
436}
437
438#[derive(Copy, Clone, Debug, PartialEq, Eq)]
444#[cfg_attr(
445 feature = "rkyv-impl",
446 derive(Archive, Serialize, Deserialize),
447 archive_attr(derive(bytecheck::CheckBytes))
448)]
449pub enum Sender {
450 Encryption([(JubJubAffine, JubJubAffine); 2]),
453 ContractInfo([u8; 4 * JubJubAffine::SIZE]),
456}
457
458impl Sender {
459 pub fn encrypt(
462 note_pk: &NotePublicKey,
463 sender_pk: &PublicKey,
464 blinder: &[JubJubScalar; 2],
465 ) -> Self {
466 let sender_enc_A =
467 elgamal::encrypt(note_pk.as_ref(), sender_pk.A(), &blinder[0]);
468
469 let sender_enc_B =
470 elgamal::encrypt(note_pk.as_ref(), sender_pk.B(), &blinder[1]);
471
472 let sender_enc_A: (JubJubAffine, JubJubAffine) =
473 (sender_enc_A.0.into(), sender_enc_A.1.into());
474 let sender_enc_B: (JubJubAffine, JubJubAffine) =
475 (sender_enc_B.0.into(), sender_enc_B.1.into());
476
477 Self::Encryption([sender_enc_A, sender_enc_B])
478 }
479
480 pub fn decrypt(&self, note_sk: &NoteSecretKey) -> Result<PublicKey, Error> {
490 let sender_enc = match self {
491 Sender::Encryption(enc) => enc,
492 Sender::ContractInfo(_) => {
493 return Err(Error::InvalidEncryption);
494 }
495 };
496
497 let sender_enc_A = sender_enc[0];
498 let sender_enc_B = sender_enc[1];
499
500 let decrypt_A = elgamal::decrypt(
501 note_sk.as_ref(),
502 &(sender_enc_A.0.into(), sender_enc_A.1.into()),
503 );
504 let decrypt_B = elgamal::decrypt(
505 note_sk.as_ref(),
506 &(sender_enc_B.0.into(), sender_enc_B.1.into()),
507 );
508
509 Ok(PublicKey::new(decrypt_A, decrypt_B))
510 }
511}
512
513impl Serializable<{ 1 + 4 * JubJubAffine::SIZE }> for Sender {
514 type Error = BytesError;
515
516 fn to_bytes(&self) -> [u8; Self::SIZE] {
518 let mut buf = [0u8; Self::SIZE];
519
520 match self {
521 Sender::Encryption(sender_enc) => {
522 buf[0] = 0;
523 let mut start = 1;
524
525 buf[start..start + JubJubAffine::SIZE]
526 .copy_from_slice(&sender_enc[0].0.to_bytes());
527 start += JubJubAffine::SIZE;
528
529 buf[start..start + JubJubAffine::SIZE]
530 .copy_from_slice(&sender_enc[0].1.to_bytes());
531 start += JubJubAffine::SIZE;
532
533 buf[start..start + JubJubAffine::SIZE]
534 .copy_from_slice(&sender_enc[1].0.to_bytes());
535 start += JubJubAffine::SIZE;
536
537 buf[start..start + JubJubAffine::SIZE]
538 .copy_from_slice(&sender_enc[1].1.to_bytes());
539 }
540 Sender::ContractInfo(contract_data) => {
541 buf[0] = 1;
542 buf[1..].copy_from_slice(&contract_data[..]);
543 }
544 }
545
546 buf
547 }
548
549 fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
552 let sender = match bytes[0] {
553 0 => {
554 let mut buf = &bytes[1..];
555 let sender_enc_A_0 = JubJubAffine::from_reader(&mut buf)?;
556 let sender_enc_A_1 = JubJubAffine::from_reader(&mut buf)?;
557 let sender_enc_B_0 = JubJubAffine::from_reader(&mut buf)?;
558 let sender_enc_B_1 = JubJubAffine::from_reader(&mut buf)?;
559 Sender::Encryption([
560 (sender_enc_A_0, sender_enc_A_1),
561 (sender_enc_B_0, sender_enc_B_1),
562 ])
563 }
564 1 => {
565 let mut contract_data = [0u8; 4 * JubJubAffine::SIZE];
566 contract_data.copy_from_slice(&bytes[1..Self::SIZE]);
567 Sender::ContractInfo(contract_data)
568 }
569 _ => return Err(BytesError::InvalidData),
570 };
571
572 Ok(sender)
573 }
574}