Skip to main content

phoenix_core/
note.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4//
5// Copyright (c) DUSK NETWORK. All rights reserved.
6
7use 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
18use crate::{
19    Error, PublicKey, SecretKey, StealthAddress, ViewKey, aes,
20    transparent_value_commitment, value_commitment,
21};
22
23#[cfg(feature = "rkyv-impl")]
24use rkyv::{Archive, Deserialize, Serialize};
25
26/// Blinder used for transparent notes.
27pub(crate) const TRANSPARENT_BLINDER: JubJubScalar = JubJubScalar::zero();
28
29/// Size of the Phoenix notes plaintext: value (8 bytes) + blinder (32 bytes)
30pub(crate) const PLAINTEXT_SIZE: usize = 40;
31
32/// Size of the Phoenix notes value_enc
33pub const VALUE_ENC_SIZE: usize = PLAINTEXT_SIZE + aes::ENCRYPTION_EXTRA_SIZE;
34
35/// The types of a Note
36#[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    /// Defines a Transparent type of Note
45    Transparent = 0,
46    /// Defines an Obfuscated type of Note
47    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/// Phoenix Note struct
71#[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    /// Creates a new phoenix output note
105    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        // Output notes have undefined position, equals to u64's MAX value
120        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    /// Creates a new transparent note
158    ///
159    /// The blinding factor will be constant zero since the value commitment
160    /// exists only to shield the value. The value is not hidden for transparent
161    /// notes, so this can be trivially treated as a constant.
162    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    /// Creates a new transparent note
181    ///
182    /// This is equivalent to [`transparent`] but taking only a stealth address
183    /// and a value. This is done to be able to generate a note
184    /// directly for a stealth address, as opposed to a public key.
185    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    /// Creates a new obfuscated note
208    ///
209    /// The provided blinding factor will be used to calculate the value
210    /// commitment of the note. The tuple (value, value_blinder), known by
211    /// the caller of this function, must be later used to prove the
212    /// knowledge of the value commitment of this note.
213    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    /// Creates a new empty [`Note`]
233    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    fn decrypt_value(
247        &self,
248        vk: &ViewKey,
249    ) -> Result<(u64, JubJubScalar), Error> {
250        let R = self.stealth_address.R();
251        let shared_secret = dhke(vk.a(), R);
252
253        let salt = self.stealth_address.to_bytes();
254
255        let dec_plaintext: [u8; PLAINTEXT_SIZE] =
256            aes::decrypt(&shared_secret, &salt, &self.value_enc)?;
257
258        let value = u64::from_slice(&dec_plaintext[..u64::SIZE])?;
259
260        // Converts the BLS Scalar into a JubJub Scalar.
261        // If the `vk` is wrong it might fails since the resulting BLS Scalar
262        // might not fit into a JubJub Scalar.
263        let value_blinder =
264            match JubJubScalar::from_slice(&dec_plaintext[u64::SIZE..])?.into()
265            {
266                Some(scalar) => scalar,
267                None => return Err(Error::InvalidData),
268            };
269
270        Ok((value, value_blinder))
271    }
272
273    /// Create a unique nullifier for the note
274    ///
275    /// This nullifier is represeted as `H(note_sk ยท G', pos)`
276    pub fn gen_nullifier(&self, sk: &SecretKey) -> BlsScalar {
277        let note_sk = sk.gen_note_sk(&self.stealth_address);
278        let pk_prime = GENERATOR_NUMS_EXTENDED * note_sk.as_ref();
279        let pk_prime = pk_prime.to_hash_inputs();
280
281        let pos = BlsScalar::from(self.pos);
282
283        Hash::digest(Domain::Other, &[pk_prime[0], pk_prime[1], pos])[0]
284    }
285
286    /// Return the internal representation of scalars to be hashed
287    pub fn hash_inputs(&self) -> [BlsScalar; 6] {
288        let note_pk =
289            self.stealth_address().note_pk().as_ref().to_hash_inputs();
290
291        [
292            BlsScalar::from(self.note_type as u64),
293            self.value_commitment.get_u(),
294            self.value_commitment.get_v(),
295            note_pk[0],
296            note_pk[1],
297            BlsScalar::from(self.pos),
298        ]
299    }
300
301    /// Return a hash represented by `H(note_type, value_commitment,
302    /// H(StealthAddress), pos, encrypted_data)
303    pub fn hash(&self) -> BlsScalar {
304        Hash::digest(Domain::Other, &self.hash_inputs())[0]
305    }
306
307    /// Return the type of the note
308    pub const fn note_type(&self) -> NoteType {
309        self.note_type
310    }
311
312    /// Return the position of the note on the tree.
313    pub const fn pos(&self) -> &u64 {
314        &self.pos
315    }
316
317    /// Returns the the stealth address associated with the note.
318    pub const fn stealth_address(&self) -> &StealthAddress {
319        &self.stealth_address
320    }
321
322    /// Set the position of the note on the tree.
323    /// This, naturally, won't reflect immediatelly on the data storage
324    pub fn set_pos(&mut self, pos: u64) {
325        self.pos = pos;
326    }
327
328    /// Return the value commitment `H(value, value_blinder)`
329    pub const fn value_commitment(&self) -> &JubJubAffine {
330        &self.value_commitment
331    }
332
333    /// Returns the cipher of the encrypted data
334    pub const fn value_enc(&self) -> &[u8; VALUE_ENC_SIZE] {
335        &self.value_enc
336    }
337
338    /// Returns elgamal encryption of the sender's [`PublicKey`] encrypted using
339    /// the [`StealthAddress::note_pk`] so only the receiver of the [`Note`]
340    /// can decrypt.
341    pub const fn sender(&self) -> &Sender {
342        &self.sender
343    }
344
345    /// Attempt to decrypt the note value provided a [`ViewKey`]. Always
346    /// succeeds for transparent notes, might fails or return random values for
347    /// obfuscated notes if the provided view key is wrong.
348    pub fn value(&self, vk: Option<&ViewKey>) -> Result<u64, Error> {
349        match (self.note_type, vk) {
350            (NoteType::Transparent, _) => {
351                let value =
352                    u64::from_slice(&self.value_enc[..u64::SIZE]).unwrap();
353                Ok(value)
354            }
355            (NoteType::Obfuscated, Some(vk)) => {
356                self.decrypt_value(vk).map(|(value, _)| value)
357            }
358            _ => Err(Error::MissingViewKey),
359        }
360    }
361
362    /// Decrypt the blinding factor with the provided [`ViewKey`]
363    ///
364    /// If the decrypt fails, a random value is returned
365    pub fn value_blinder(
366        &self,
367        vk: Option<&ViewKey>,
368    ) -> Result<JubJubScalar, Error> {
369        match (self.note_type, vk) {
370            (NoteType::Transparent, _) => Ok(TRANSPARENT_BLINDER),
371            (NoteType::Obfuscated, Some(vk)) => self
372                .decrypt_value(vk)
373                .map(|(_, value_blinder)| value_blinder),
374            _ => Err(Error::MissingViewKey),
375        }
376    }
377}
378
379const SIZE: usize = 1
380    + JubJubAffine::SIZE
381    + StealthAddress::SIZE
382    + u64::SIZE
383    + VALUE_ENC_SIZE
384    + Sender::SIZE;
385
386impl Serializable<SIZE> for Note {
387    type Error = BytesError;
388
389    /// Converts a Note into a byte representation
390    fn to_bytes(&self) -> [u8; Self::SIZE] {
391        let mut buf = [0u8; Self::SIZE];
392
393        buf[0] = self.note_type as u8;
394
395        let mut start = 1;
396
397        buf[start..start + JubJubAffine::SIZE]
398            .copy_from_slice(&self.value_commitment.to_bytes());
399        start += JubJubAffine::SIZE;
400
401        buf[start..start + StealthAddress::SIZE]
402            .copy_from_slice(&self.stealth_address.to_bytes());
403        start += StealthAddress::SIZE;
404
405        buf[start..start + u64::SIZE].copy_from_slice(&self.pos.to_le_bytes());
406        start += u64::SIZE;
407
408        buf[start..start + VALUE_ENC_SIZE].copy_from_slice(&self.value_enc);
409        start += VALUE_ENC_SIZE;
410
411        buf[start..start + Sender::SIZE]
412            .copy_from_slice(&self.sender.to_bytes());
413
414        buf
415    }
416
417    /// Attempts to convert a byte representation of a note into a `Note`,
418    /// failing if the input is invalid
419    fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
420        let note_type =
421            bytes[0].try_into().map_err(|_| BytesError::InvalidData)?;
422
423        let mut buf = &bytes[1..];
424
425        let value_commitment = JubJubAffine::from_reader(&mut buf)?;
426
427        let stealth_address = StealthAddress::from_reader(&mut buf)?;
428
429        let pos = u64::from_reader(&mut buf)?;
430
431        let mut value_enc = [0u8; VALUE_ENC_SIZE];
432        value_enc.copy_from_slice(&buf[..VALUE_ENC_SIZE]);
433        buf = &buf[VALUE_ENC_SIZE..];
434
435        let sender = Sender::from_reader(&mut buf)?;
436
437        Ok(Note {
438            note_type,
439            value_commitment,
440            stealth_address,
441            pos,
442            value_enc,
443            sender,
444        })
445    }
446}
447
448/// The sender of the `Note`.
449/// This can be either the encrypted sender's [`PublicKey`], if the [`Note`] was
450/// created as an output note of a phoenix-transaction, or some contract-data if
451/// the [`Note`] was created in another way, e.g. by withdrawing from a
452/// contract.
453#[derive(Copy, Clone, Debug, PartialEq, Eq)]
454#[cfg_attr(
455    feature = "rkyv-impl",
456    derive(Archive, Serialize, Deserialize),
457    archive_attr(derive(bytecheck::CheckBytes))
458)]
459#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
460pub enum Sender {
461    /// The sender's [`PublicKey`], encrypted using the note_pk of the
462    /// stealth-address.
463    Encryption([(JubJubAffine, JubJubAffine); 2]),
464    /// Information to identify the origin of a `Note`, if it wasn't created as
465    /// a phoenix-transaction output-note.
466    ContractInfo(
467        #[cfg_attr(
468            feature = "serde",
469            serde(with = "serde_with::As::<serde_with::hex::Hex>")
470        )]
471        [u8; 4 * JubJubAffine::SIZE],
472    ),
473}
474
475impl Sender {
476    /// Create a new [`Sender`] enum by encrypting the sender's [`PublicKey`] in
477    /// a way that only the receiver of the note can decrypt.
478    pub fn encrypt(
479        note_pk: &NotePublicKey,
480        sender_pk: &PublicKey,
481        blinder: &[JubJubScalar; 2],
482    ) -> Self {
483        let (sender_enc_A, _) = ElGamal::encrypt(
484            note_pk.as_ref(),
485            sender_pk.A(),
486            None,
487            &blinder[0],
488        );
489
490        let (sender_enc_B, _) = ElGamal::encrypt(
491            note_pk.as_ref(),
492            sender_pk.B(),
493            None,
494            &blinder[1],
495        );
496
497        let sender_enc_A: (JubJubAffine, JubJubAffine) =
498            (sender_enc_A.c1().into(), sender_enc_A.c2().into());
499        let sender_enc_B: (JubJubAffine, JubJubAffine) =
500            (sender_enc_B.c1().into(), sender_enc_B.c2().into());
501
502        Self::Encryption([sender_enc_A, sender_enc_B])
503    }
504
505    /// Decrypts the [`PublicKey`] of the sender of the [`Note`], using the
506    /// [`NoteSecretKey`] generated by the receiver's [`SecretKey`] and the
507    /// [`StealthAddress`] of the [`Note`].
508    ///
509    /// Note: Decryption with an *incorrect* [`NoteSecretKey`] will still yield
510    /// a [`PublicKey`], but in this case, the public-key will be a random one
511    /// that has nothing to do with the sender's [`PublicKey`].
512    ///
513    /// Returns an error if the sender is of type [`Sender::ContractInfo`].
514    pub fn decrypt(&self, note_sk: &NoteSecretKey) -> Result<PublicKey, Error> {
515        let sender_enc = match self {
516            Sender::Encryption(enc) => enc,
517            Sender::ContractInfo(_) => {
518                return Err(Error::InvalidEncryption);
519            }
520        };
521
522        let sender_enc_A =
523            ElGamal::new(sender_enc[0].0.into(), sender_enc[0].1.into())
524                .map_err(|_| Error::InvalidEncryption)?;
525        let sender_enc_B =
526            ElGamal::new(sender_enc[1].0.into(), sender_enc[1].1.into())
527                .map_err(|_| Error::InvalidEncryption)?;
528
529        let decrypt_A =
530            sender_enc_A.decrypt(&DecryptFrom::SecretKey(*note_sk.as_ref()));
531        let decrypt_B =
532            sender_enc_B.decrypt(&DecryptFrom::SecretKey(*note_sk.as_ref()));
533
534        Ok(PublicKey::new(decrypt_A, decrypt_B))
535    }
536}
537
538impl Serializable<{ 1 + 4 * JubJubAffine::SIZE }> for Sender {
539    type Error = BytesError;
540
541    /// Converts a Note into a byte representation
542    fn to_bytes(&self) -> [u8; Self::SIZE] {
543        let mut buf = [0u8; Self::SIZE];
544
545        match self {
546            Sender::Encryption(sender_enc) => {
547                buf[0] = 0;
548                let mut start = 1;
549
550                buf[start..start + JubJubAffine::SIZE]
551                    .copy_from_slice(&sender_enc[0].0.to_bytes());
552                start += JubJubAffine::SIZE;
553
554                buf[start..start + JubJubAffine::SIZE]
555                    .copy_from_slice(&sender_enc[0].1.to_bytes());
556                start += JubJubAffine::SIZE;
557
558                buf[start..start + JubJubAffine::SIZE]
559                    .copy_from_slice(&sender_enc[1].0.to_bytes());
560                start += JubJubAffine::SIZE;
561
562                buf[start..start + JubJubAffine::SIZE]
563                    .copy_from_slice(&sender_enc[1].1.to_bytes());
564            }
565            Sender::ContractInfo(contract_data) => {
566                buf[0] = 1;
567                buf[1..].copy_from_slice(&contract_data[..]);
568            }
569        }
570
571        buf
572    }
573
574    /// Attempts to convert a byte representation of a note into a `Note`,
575    /// failing if the input is invalid
576    fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
577        let sender = match bytes[0] {
578            0 => {
579                let mut buf = &bytes[1..];
580                let sender_enc_A_0 = JubJubAffine::from_reader(&mut buf)?;
581                let sender_enc_A_1 = JubJubAffine::from_reader(&mut buf)?;
582                let sender_enc_B_0 = JubJubAffine::from_reader(&mut buf)?;
583                let sender_enc_B_1 = JubJubAffine::from_reader(&mut buf)?;
584                Sender::Encryption([
585                    (sender_enc_A_0, sender_enc_A_1),
586                    (sender_enc_B_0, sender_enc_B_1),
587                ])
588            }
589            1 => {
590                let mut contract_data = [0u8; 4 * JubJubAffine::SIZE];
591                contract_data.copy_from_slice(&bytes[1..Self::SIZE]);
592                Sender::ContractInfo(contract_data)
593            }
594            _ => return Err(BytesError::InvalidData),
595        };
596
597        Ok(sender)
598    }
599}