1use core::convert::{TryFrom, TryInto};
8
9use dusk_bls12_381::BlsScalar;
10use dusk_bytes::{DeserializableSlice, Error as BytesError, Serializable};
11use dusk_jubjub::{GENERATOR_NUMS_EXTENDED, JubJubAffine, JubJubScalar, dhke};
12use dusk_poseidon::{Domain, Hash};
13use ff::Field;
14use jubjub_elgamal::{DecryptFrom, Encryption as ElGamal};
15use jubjub_schnorr::{PublicKey as NotePublicKey, SecretKey as NoteSecretKey};
16use rand::{CryptoRng, RngCore};
17#[cfg(feature = "rkyv-impl")]
18use rkyv::{Archive, Deserialize, Serialize};
19
20use crate::stealth_address::affine_from_slice_legacy_compat;
21use crate::{
22 Error, PublicKey, SecretKey, StealthAddress, ViewKey, aes,
23 transparent_value_commitment, value_commitment,
24};
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)]
42#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
43pub enum NoteType {
44 Transparent = 0,
46 Obfuscated = 1,
48}
49
50impl TryFrom<u8> for NoteType {
51 type Error = Error;
52
53 fn try_from(note_type: u8) -> Result<Self, Self::Error> {
54 match note_type {
55 0 => Ok(NoteType::Transparent),
56 1 => Ok(NoteType::Obfuscated),
57 n => Err(Error::InvalidNoteType(n)),
58 }
59 }
60}
61
62impl TryFrom<i32> for NoteType {
63 type Error = Error;
64
65 fn try_from(note_type: i32) -> Result<Self, Self::Error> {
66 (note_type as u8).try_into()
67 }
68}
69
70#[derive(Clone, Debug, Eq)]
72#[cfg_attr(
73 feature = "rkyv-impl",
74 derive(Archive, Serialize, Deserialize),
75 archive_attr(derive(bytecheck::CheckBytes))
76)]
77#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
78pub struct Note {
79 pub(crate) note_type: NoteType,
80 pub(crate) value_commitment: JubJubAffine,
81 pub(crate) stealth_address: StealthAddress,
82 #[cfg_attr(
83 feature = "serde",
84 serde(with = "serde_with::As::<serde_with::DisplayFromStr>")
85 )]
86 pub(crate) pos: u64,
87 #[cfg_attr(
88 feature = "serde",
89 serde(with = "serde_with::As::<serde_with::hex::Hex>")
90 )]
91 pub(crate) value_enc: [u8; VALUE_ENC_SIZE],
92 pub(crate) sender: Sender,
93}
94
95impl PartialEq for Note {
96 fn eq(&self, other: &Self) -> bool {
97 self.value_enc == other.value_enc
98 && self.sender == other.sender
99 && self.hash() == other.hash()
100 }
101}
102
103impl Note {
104 pub fn new<R: RngCore + CryptoRng>(
106 rng: &mut R,
107 note_type: NoteType,
108 sender_pk: &PublicKey,
109 receiver_pk: &PublicKey,
110 value: u64,
111 value_blinder: JubJubScalar,
112 sender_blinder: [JubJubScalar; 2],
113 ) -> Self {
114 let r = JubJubScalar::random(&mut *rng);
115 let stealth_address = receiver_pk.gen_stealth_address(&r);
116
117 let value_commitment = value_commitment(value, value_blinder);
118
119 let pos = u64::MAX;
121
122 let value_enc = match note_type {
123 NoteType::Transparent => {
124 let mut value_enc = [0u8; VALUE_ENC_SIZE];
125 value_enc[..u64::SIZE].copy_from_slice(&value.to_bytes());
126
127 value_enc
128 }
129 NoteType::Obfuscated => {
130 let shared_secret = dhke(&r, receiver_pk.A());
131 let value_blinder = BlsScalar::from(value_blinder);
132
133 let mut plaintext = value.to_bytes().to_vec();
134 plaintext.append(&mut value_blinder.to_bytes().to_vec());
135
136 let salt = stealth_address.to_bytes();
137
138 aes::encrypt(&shared_secret, &salt, &plaintext, rng)
139 .expect("Encrypted correctly.")
140 }
141 };
142
143 Note {
144 note_type,
145 value_commitment,
146 stealth_address,
147 pos,
148 value_enc,
149 sender: Sender::encrypt(
150 stealth_address.note_pk(),
151 sender_pk,
152 &sender_blinder,
153 ),
154 }
155 }
156
157 pub fn transparent<R: RngCore + CryptoRng>(
163 rng: &mut R,
164 sender_pk: &PublicKey,
165 receiver_pk: &PublicKey,
166 value: u64,
167 sender_blinder: [JubJubScalar; 2],
168 ) -> Self {
169 Self::new(
170 rng,
171 NoteType::Transparent,
172 sender_pk,
173 receiver_pk,
174 value,
175 TRANSPARENT_BLINDER,
176 sender_blinder,
177 )
178 }
179
180 pub fn transparent_stealth(
186 stealth_address: StealthAddress,
187 value: u64,
188 sender: impl Into<Sender>,
189 ) -> Self {
190 let value_commitment = transparent_value_commitment(value);
191
192 let pos = u64::MAX;
193
194 let mut value_enc = [0u8; VALUE_ENC_SIZE];
195 value_enc[..u64::SIZE].copy_from_slice(&value.to_bytes());
196
197 Note {
198 note_type: NoteType::Transparent,
199 value_commitment,
200 stealth_address,
201 pos,
202 value_enc,
203 sender: sender.into(),
204 }
205 }
206
207 pub fn obfuscated<R: RngCore + CryptoRng>(
214 rng: &mut R,
215 sender_pk: &PublicKey,
216 receiver_pk: &PublicKey,
217 value: u64,
218 value_blinder: JubJubScalar,
219 sender_blinder: [JubJubScalar; 2],
220 ) -> Self {
221 Self::new(
222 rng,
223 NoteType::Obfuscated,
224 sender_pk,
225 receiver_pk,
226 value,
227 value_blinder,
228 sender_blinder,
229 )
230 }
231
232 pub fn empty() -> Self {
234 Self {
235 note_type: NoteType::Transparent,
236 value_commitment: JubJubAffine::default(),
237 stealth_address: StealthAddress::default(),
238 pos: 0,
239 value_enc: [0; VALUE_ENC_SIZE],
240 sender: Sender::Encryption(
241 [(JubJubAffine::default(), JubJubAffine::default()); 2],
242 ),
243 }
244 }
245
246 #[cfg(feature = "alloc")]
247 pub(crate) fn read_strict(reader: &mut &[u8]) -> Result<Self, BytesError> {
248 Self::from_reader(reader)
249 }
250
251 #[cfg(feature = "alloc")]
252 pub(crate) fn read_legacy_compat(
253 reader: &mut &[u8],
254 ) -> Result<Self, BytesError> {
255 let bytes = take_fixed_bytes::<SIZE>(reader)?;
256 Self::from_bytes_legacy_compat(bytes)
257 }
258
259 #[cfg(feature = "alloc")]
260 pub(crate) fn from_bytes_legacy_compat(
261 bytes: &[u8; Self::SIZE],
262 ) -> Result<Self, BytesError> {
263 let note_type =
264 bytes[0].try_into().map_err(|_| BytesError::InvalidData)?;
265
266 let mut buf = &bytes[1..];
267 let value_commitment =
268 affine_from_slice_legacy_compat(&buf[..JubJubAffine::SIZE])?;
269 buf = &buf[JubJubAffine::SIZE..];
270
271 let mut stealth_address_bytes = [0u8; StealthAddress::SIZE];
272 stealth_address_bytes.copy_from_slice(&buf[..StealthAddress::SIZE]);
273 let stealth_address =
274 StealthAddress::from_bytes_legacy_compat(&stealth_address_bytes)?;
275 buf = &buf[StealthAddress::SIZE..];
276
277 let pos = u64::from_reader(&mut buf)?;
278
279 let mut value_enc = [0u8; VALUE_ENC_SIZE];
280 value_enc.copy_from_slice(&buf[..VALUE_ENC_SIZE]);
281 buf = &buf[VALUE_ENC_SIZE..];
282
283 let mut sender_bytes = [0u8; Sender::SIZE];
284 sender_bytes.copy_from_slice(&buf[..Sender::SIZE]);
285 let sender = Sender::from_bytes_legacy_compat(&sender_bytes)?;
286
287 Ok(Self {
288 note_type,
289 value_commitment,
290 stealth_address,
291 pos,
292 value_enc,
293 sender,
294 })
295 }
296
297 fn decrypt_value(
298 &self,
299 vk: &ViewKey,
300 ) -> Result<(u64, JubJubScalar), Error> {
301 let R = self.stealth_address.R();
302 let shared_secret = dhke(vk.a(), R);
303
304 let salt = self.stealth_address.to_bytes();
305
306 let dec_plaintext: [u8; PLAINTEXT_SIZE] =
307 aes::decrypt(&shared_secret, &salt, &self.value_enc)?;
308
309 let value = u64::from_slice(&dec_plaintext[..u64::SIZE])?;
310
311 let value_blinder =
315 match JubJubScalar::from_slice(&dec_plaintext[u64::SIZE..])?.into()
316 {
317 Some(scalar) => scalar,
318 None => return Err(Error::InvalidData),
319 };
320
321 Ok((value, value_blinder))
322 }
323
324 pub fn gen_nullifier(&self, sk: &SecretKey) -> BlsScalar {
328 let note_sk = sk.gen_note_sk(&self.stealth_address);
329 let pk_prime = GENERATOR_NUMS_EXTENDED * note_sk.as_ref();
330 let pk_prime = pk_prime.to_hash_inputs();
331
332 let pos = BlsScalar::from(self.pos);
333
334 Hash::digest(Domain::Other, &[pk_prime[0], pk_prime[1], pos])[0]
335 }
336
337 pub fn hash_inputs(&self) -> [BlsScalar; 6] {
339 let note_pk =
340 self.stealth_address().note_pk().as_ref().to_hash_inputs();
341
342 [
343 BlsScalar::from(self.note_type as u64),
344 self.value_commitment.get_u(),
345 self.value_commitment.get_v(),
346 note_pk[0],
347 note_pk[1],
348 BlsScalar::from(self.pos),
349 ]
350 }
351
352 pub fn hash(&self) -> BlsScalar {
355 Hash::digest(Domain::Other, &self.hash_inputs())[0]
356 }
357
358 pub const fn note_type(&self) -> NoteType {
360 self.note_type
361 }
362
363 pub const fn pos(&self) -> &u64 {
365 &self.pos
366 }
367
368 pub const fn stealth_address(&self) -> &StealthAddress {
370 &self.stealth_address
371 }
372
373 pub fn set_pos(&mut self, pos: u64) {
376 self.pos = pos;
377 }
378
379 pub const fn value_commitment(&self) -> &JubJubAffine {
381 &self.value_commitment
382 }
383
384 pub const fn value_enc(&self) -> &[u8; VALUE_ENC_SIZE] {
386 &self.value_enc
387 }
388
389 pub const fn sender(&self) -> &Sender {
393 &self.sender
394 }
395
396 pub fn value(&self, vk: Option<&ViewKey>) -> Result<u64, Error> {
400 match (self.note_type, vk) {
401 (NoteType::Transparent, _) => {
402 let value =
403 u64::from_slice(&self.value_enc[..u64::SIZE]).unwrap();
404 Ok(value)
405 }
406 (NoteType::Obfuscated, Some(vk)) => {
407 self.decrypt_value(vk).map(|(value, _)| value)
408 }
409 _ => Err(Error::MissingViewKey),
410 }
411 }
412
413 pub fn value_blinder(
417 &self,
418 vk: Option<&ViewKey>,
419 ) -> Result<JubJubScalar, Error> {
420 match (self.note_type, vk) {
421 (NoteType::Transparent, _) => Ok(TRANSPARENT_BLINDER),
422 (NoteType::Obfuscated, Some(vk)) => self
423 .decrypt_value(vk)
424 .map(|(_, value_blinder)| value_blinder),
425 _ => Err(Error::MissingViewKey),
426 }
427 }
428}
429
430const SIZE: usize = 1
431 + JubJubAffine::SIZE
432 + StealthAddress::SIZE
433 + u64::SIZE
434 + VALUE_ENC_SIZE
435 + Sender::SIZE;
436
437impl Serializable<SIZE> for Note {
438 type Error = BytesError;
439
440 fn to_bytes(&self) -> [u8; Self::SIZE] {
442 let mut buf = [0u8; Self::SIZE];
443
444 buf[0] = self.note_type as u8;
445
446 let mut start = 1;
447
448 buf[start..start + JubJubAffine::SIZE]
449 .copy_from_slice(&self.value_commitment.to_bytes());
450 start += JubJubAffine::SIZE;
451
452 buf[start..start + StealthAddress::SIZE]
453 .copy_from_slice(&self.stealth_address.to_bytes());
454 start += StealthAddress::SIZE;
455
456 buf[start..start + u64::SIZE].copy_from_slice(&self.pos.to_le_bytes());
457 start += u64::SIZE;
458
459 buf[start..start + VALUE_ENC_SIZE].copy_from_slice(&self.value_enc);
460 start += VALUE_ENC_SIZE;
461
462 buf[start..start + Sender::SIZE]
463 .copy_from_slice(&self.sender.to_bytes());
464
465 buf
466 }
467
468 fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
471 let note_type =
472 bytes[0].try_into().map_err(|_| BytesError::InvalidData)?;
473
474 let mut buf = &bytes[1..];
475
476 let value_commitment = JubJubAffine::from_reader(&mut buf)?;
477
478 let stealth_address = StealthAddress::from_reader(&mut buf)?;
479
480 let pos = u64::from_reader(&mut buf)?;
481
482 let mut value_enc = [0u8; VALUE_ENC_SIZE];
483 value_enc.copy_from_slice(&buf[..VALUE_ENC_SIZE]);
484 buf = &buf[VALUE_ENC_SIZE..];
485
486 let sender = Sender::from_reader(&mut buf)?;
487
488 Ok(Note {
489 note_type,
490 value_commitment,
491 stealth_address,
492 pos,
493 value_enc,
494 sender,
495 })
496 }
497}
498
499#[derive(Copy, Clone, Debug, PartialEq, Eq)]
505#[cfg_attr(
506 feature = "rkyv-impl",
507 derive(Archive, Serialize, Deserialize),
508 archive_attr(derive(bytecheck::CheckBytes))
509)]
510#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
511pub enum Sender {
512 Encryption([(JubJubAffine, JubJubAffine); 2]),
515 ContractInfo(
518 #[cfg_attr(
519 feature = "serde",
520 serde(with = "serde_with::As::<serde_with::hex::Hex>")
521 )]
522 [u8; 4 * JubJubAffine::SIZE],
523 ),
524}
525
526impl Sender {
527 pub fn encrypt(
530 note_pk: &NotePublicKey,
531 sender_pk: &PublicKey,
532 blinder: &[JubJubScalar; 2],
533 ) -> Self {
534 let (sender_enc_A, _) = ElGamal::encrypt(
535 note_pk.as_ref(),
536 sender_pk.A(),
537 None,
538 &blinder[0],
539 );
540
541 let (sender_enc_B, _) = ElGamal::encrypt(
542 note_pk.as_ref(),
543 sender_pk.B(),
544 None,
545 &blinder[1],
546 );
547
548 let sender_enc_A: (JubJubAffine, JubJubAffine) =
549 (sender_enc_A.c1().into(), sender_enc_A.c2().into());
550 let sender_enc_B: (JubJubAffine, JubJubAffine) =
551 (sender_enc_B.c1().into(), sender_enc_B.c2().into());
552
553 Self::Encryption([sender_enc_A, sender_enc_B])
554 }
555
556 pub fn decrypt(&self, note_sk: &NoteSecretKey) -> Result<PublicKey, Error> {
566 let sender_enc = match self {
567 Sender::Encryption(enc) => enc,
568 Sender::ContractInfo(_) => {
569 return Err(Error::InvalidEncryption);
570 }
571 };
572
573 let sender_enc_A =
574 ElGamal::new(sender_enc[0].0.into(), sender_enc[0].1.into())
575 .map_err(|_| Error::InvalidEncryption)?;
576 let sender_enc_B =
577 ElGamal::new(sender_enc[1].0.into(), sender_enc[1].1.into())
578 .map_err(|_| Error::InvalidEncryption)?;
579
580 let decrypt_A =
581 sender_enc_A.decrypt(&DecryptFrom::SecretKey(*note_sk.as_ref()));
582 let decrypt_B =
583 sender_enc_B.decrypt(&DecryptFrom::SecretKey(*note_sk.as_ref()));
584
585 Ok(PublicKey::new(decrypt_A, decrypt_B))
586 }
587}
588
589impl Serializable<{ 1 + 4 * JubJubAffine::SIZE }> for Sender {
590 type Error = BytesError;
591
592 fn to_bytes(&self) -> [u8; Self::SIZE] {
594 let mut buf = [0u8; Self::SIZE];
595
596 match self {
597 Sender::Encryption(sender_enc) => {
598 buf[0] = 0;
599 let mut start = 1;
600
601 buf[start..start + JubJubAffine::SIZE]
602 .copy_from_slice(&sender_enc[0].0.to_bytes());
603 start += JubJubAffine::SIZE;
604
605 buf[start..start + JubJubAffine::SIZE]
606 .copy_from_slice(&sender_enc[0].1.to_bytes());
607 start += JubJubAffine::SIZE;
608
609 buf[start..start + JubJubAffine::SIZE]
610 .copy_from_slice(&sender_enc[1].0.to_bytes());
611 start += JubJubAffine::SIZE;
612
613 buf[start..start + JubJubAffine::SIZE]
614 .copy_from_slice(&sender_enc[1].1.to_bytes());
615 }
616 Sender::ContractInfo(contract_data) => {
617 buf[0] = 1;
618 buf[1..].copy_from_slice(&contract_data[..]);
619 }
620 }
621
622 buf
623 }
624
625 fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
628 let sender = match bytes[0] {
629 0 => {
630 let mut buf = &bytes[1..];
631 let sender_enc_A_0 = JubJubAffine::from_reader(&mut buf)?;
632 let sender_enc_A_1 = JubJubAffine::from_reader(&mut buf)?;
633 let sender_enc_B_0 = JubJubAffine::from_reader(&mut buf)?;
634 let sender_enc_B_1 = JubJubAffine::from_reader(&mut buf)?;
635 Sender::Encryption([
636 (sender_enc_A_0, sender_enc_A_1),
637 (sender_enc_B_0, sender_enc_B_1),
638 ])
639 }
640 1 => {
641 let mut contract_data = [0u8; 4 * JubJubAffine::SIZE];
642 contract_data.copy_from_slice(&bytes[1..Self::SIZE]);
643 Sender::ContractInfo(contract_data)
644 }
645 _ => return Err(BytesError::InvalidData),
646 };
647
648 Ok(sender)
649 }
650}
651
652impl Sender {
653 pub fn from_bytes_legacy_compat(
656 bytes: &[u8; Self::SIZE],
657 ) -> Result<Self, BytesError> {
658 match bytes[0] {
659 0 => {
660 let mut buf = &bytes[1..];
661 let sender_enc_A_0 = affine_from_slice_legacy_compat(
662 &buf[..JubJubAffine::SIZE],
663 )?;
664 buf = &buf[JubJubAffine::SIZE..];
665 let sender_enc_A_1 = affine_from_slice_legacy_compat(
666 &buf[..JubJubAffine::SIZE],
667 )?;
668 buf = &buf[JubJubAffine::SIZE..];
669 let sender_enc_B_0 = affine_from_slice_legacy_compat(
670 &buf[..JubJubAffine::SIZE],
671 )?;
672 buf = &buf[JubJubAffine::SIZE..];
673 let sender_enc_B_1 = affine_from_slice_legacy_compat(
674 &buf[..JubJubAffine::SIZE],
675 )?;
676
677 Ok(Sender::Encryption([
678 (sender_enc_A_0, sender_enc_A_1),
679 (sender_enc_B_0, sender_enc_B_1),
680 ]))
681 }
682 1 => {
683 let mut contract_data = [0u8; 4 * JubJubAffine::SIZE];
684 contract_data.copy_from_slice(&bytes[1..Self::SIZE]);
685 Ok(Sender::ContractInfo(contract_data))
686 }
687 _ => Err(BytesError::InvalidData),
688 }
689 }
690}
691
692#[cfg(feature = "alloc")]
693fn take_fixed_bytes<'a, const N: usize>(
694 reader: &mut &'a [u8],
695) -> Result<&'a [u8; N], BytesError> {
696 if reader.len() < N {
697 return Err(BytesError::InvalidData);
698 }
699
700 let (bytes, rest) = reader.split_at(N);
701 *reader = rest;
702 bytes.try_into().map_err(|_| BytesError::InvalidData)
703}