Skip to main content

drive/verify/shielded/verify_shielded_encrypted_notes/
mod.rs

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