Skip to main content

drive/verify/shielded/verify_shielded_encrypted_notes/
mod.rs

1mod v0;
2
3use crate::drive::Drive;
4use crate::error::drive::DriveError;
5use crate::error::Error;
6use crate::verify::RootHash;
7use dpp::version::PlatformVersion;
8
9/// On-wire size of the Orchard `TransmittedNoteCiphertext` with Dash's 36-byte
10/// memo: `epk(32) + enc_ciphertext(104) + out_ciphertext(80)`. grovedb's
11/// commitment tree size-locks the stored ciphertext to this length, so every
12/// well-formed note item is exactly `32 + 32 + 32 + 216 = 312` bytes.
13pub const SHIELDED_ENCRYPTED_NOTE_LEN: usize = 216;
14
15/// A single shielded note item recovered from a verified
16/// `GetShieldedEncryptedNotes` proof: the fixed-layout bytes copied out of the
17/// stored `cmx || nullifier || cv_net || encrypted_note` commitment-tree item.
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct VerifiedShieldedEncryptedNote {
20    /// Note commitment.
21    pub cmx: [u8; 32],
22    /// Nullifier of the note spent in this action — Orchard reuses it as this
23    /// output note's ρ (rho) for trial decryption. Not the nullifier of the
24    /// note committed by `cmx`.
25    pub nullifier: [u8; 32],
26    /// Orchard value commitment (used for OVK outgoing-note recovery).
27    pub cv_net: [u8; 32],
28    /// Encrypted note ciphertext (`epk || enc_ciphertext || out_ciphertext`).
29    pub encrypted_note: [u8; SHIELDED_ENCRYPTED_NOTE_LEN],
30}
31
32impl Drive {
33    /// Verifies a proof for shielded encrypted notes.
34    ///
35    /// Returns `(root_hash, notes, total_count)`. `total_count` is the
36    /// on-chain total number of notes in the shielded `CommitmentTree`,
37    /// extracted from the SAME proof (the parent CommitmentTree element is
38    /// always present in a note-fetch proof) — wallets get the sync
39    /// progress-bar denominator for free on every chunk fetch.
40    pub fn verify_shielded_encrypted_notes(
41        proof: &[u8],
42        start_index: u64,
43        count: u32,
44        max_elements: u32,
45        verify_subset_of_proof: bool,
46        platform_version: &PlatformVersion,
47    ) -> Result<(RootHash, Vec<VerifiedShieldedEncryptedNote>, u64), Error> {
48        match platform_version
49            .drive
50            .methods
51            .verify
52            .shielded
53            .verify_shielded_encrypted_notes
54        {
55            0 => Self::verify_shielded_encrypted_notes_v0(
56                proof,
57                start_index,
58                count,
59                max_elements,
60                verify_subset_of_proof,
61                platform_version,
62            ),
63            version => Err(Error::Drive(DriveError::UnknownVersionMismatch {
64                method: "verify_shielded_encrypted_notes".to_string(),
65                known_versions: vec![0],
66                received: version,
67            })),
68        }
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75    use dpp::version::PlatformVersion;
76
77    #[test]
78    fn test_verify_shielded_encrypted_notes_unknown_version_mismatch() {
79        let mut platform_version = PlatformVersion::latest().clone();
80        platform_version
81            .drive
82            .methods
83            .verify
84            .shielded
85            .verify_shielded_encrypted_notes = 255;
86
87        let result = Drive::verify_shielded_encrypted_notes(&[], 0, 0, 0, false, &platform_version);
88
89        assert!(
90            matches!(
91                result,
92                Err(Error::Drive(DriveError::UnknownVersionMismatch { .. }))
93            ),
94            "expected UnknownVersionMismatch, got {:?}",
95            result,
96        );
97    }
98}