snarkvm_ledger_block/transition/output/
bytes.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::*;
17
18impl<N: Network> FromBytes for Output<N> {
19    /// Reads the output from a buffer.
20    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
21        let index = Variant::read_le(&mut reader)?;
22        let literal = match index {
23            0 => {
24                let plaintext_hash: Field<N> = FromBytes::read_le(&mut reader)?;
25                let plaintext_exists: bool = FromBytes::read_le(&mut reader)?;
26                let plaintext = match plaintext_exists {
27                    true => Some(FromBytes::read_le(&mut reader)?),
28                    false => None,
29                };
30
31                Self::Constant(plaintext_hash, plaintext)
32            }
33            1 => {
34                let plaintext_hash: Field<N> = FromBytes::read_le(&mut reader)?;
35                let plaintext_exists: bool = FromBytes::read_le(&mut reader)?;
36                let plaintext = match plaintext_exists {
37                    true => Some(FromBytes::read_le(&mut reader)?),
38                    false => None,
39                };
40                Self::Public(plaintext_hash, plaintext)
41            }
42            2 => {
43                let ciphertext_hash: Field<N> = FromBytes::read_le(&mut reader)?;
44                let ciphertext_exists: bool = FromBytes::read_le(&mut reader)?;
45                let ciphertext = match ciphertext_exists {
46                    true => Some(FromBytes::read_le(&mut reader)?),
47                    false => None,
48                };
49                Self::Private(ciphertext_hash, ciphertext)
50            }
51            3 => {
52                let commitment = FromBytes::read_le(&mut reader)?;
53                let checksum = FromBytes::read_le(&mut reader)?;
54                let record_ciphertext_exists: bool = FromBytes::read_le(&mut reader)?;
55                let record_ciphertext: Option<Record<N, _>> = match record_ciphertext_exists {
56                    true => Some(FromBytes::read_le(&mut reader)?),
57                    false => None,
58                };
59                // If the record version is Version 1 or higher, read the sender ciphertext.
60                let sender_ciphertext = match &record_ciphertext {
61                    Some(record) => match record.version().is_zero() {
62                        true => None,
63                        false => {
64                            // Read the sender ciphertext version.
65                            let sender_ciphertext_version: u8 = FromBytes::read_le(&mut reader)?;
66                            // Ensure the sender ciphertext version is 0.
67                            if sender_ciphertext_version != 0 {
68                                return Err(error(format!(
69                                    "Failed to decode sender ciphertext version {sender_ciphertext_version}"
70                                )));
71                            }
72                            // Read the sender ciphertext.
73                            Some(FromBytes::read_le(&mut reader)?)
74                        }
75                    },
76                    None => None,
77                };
78
79                Self::Record(commitment, checksum, record_ciphertext, sender_ciphertext)
80            }
81            4 => {
82                let commitment = FromBytes::read_le(&mut reader)?;
83                Self::ExternalRecord(commitment)
84            }
85            5 => {
86                let future_hash: Field<N> = FromBytes::read_le(&mut reader)?;
87                let future_exists: bool = FromBytes::read_le(&mut reader)?;
88                let future = match future_exists {
89                    true => Some(FromBytes::read_le(&mut reader)?),
90                    false => None,
91                };
92                Self::Future(future_hash, future)
93            }
94            6.. => return Err(error(format!("Failed to decode output variant {index}"))),
95        };
96        Ok(literal)
97    }
98}
99
100impl<N: Network> ToBytes for Output<N> {
101    /// Writes the output to a buffer.
102    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
103        match self {
104            Self::Constant(plaintext_hash, plaintext) => {
105                (0 as Variant).write_le(&mut writer)?;
106                plaintext_hash.write_le(&mut writer)?;
107                match plaintext {
108                    Some(plaintext) => {
109                        true.write_le(&mut writer)?;
110                        plaintext.write_le(&mut writer)
111                    }
112                    None => false.write_le(&mut writer),
113                }
114            }
115            Self::Public(plaintext_hash, plaintext) => {
116                (1 as Variant).write_le(&mut writer)?;
117                plaintext_hash.write_le(&mut writer)?;
118                match plaintext {
119                    Some(plaintext) => {
120                        true.write_le(&mut writer)?;
121                        plaintext.write_le(&mut writer)
122                    }
123                    None => false.write_le(&mut writer),
124                }
125            }
126            Self::Private(ciphertext_hash, ciphertext) => {
127                (2 as Variant).write_le(&mut writer)?;
128                ciphertext_hash.write_le(&mut writer)?;
129                match ciphertext {
130                    Some(ciphertext) => {
131                        true.write_le(&mut writer)?;
132                        ciphertext.write_le(&mut writer)
133                    }
134                    None => false.write_le(&mut writer),
135                }
136            }
137            Self::Record(commitment, checksum, record_ciphertext, sender_ciphertext) => {
138                (3 as Variant).write_le(&mut writer)?;
139                commitment.write_le(&mut writer)?;
140                checksum.write_le(&mut writer)?;
141                match record_ciphertext {
142                    Some(record) => {
143                        true.write_le(&mut writer)?;
144                        record.write_le(&mut writer)?;
145                        // If the record version is Version 1 or higher, write the sender ciphertext.
146                        if !record.version().is_zero() {
147                            // Write the sender ciphertext version.
148                            0u8.write_le(&mut writer)?;
149                            // Write the sender ciphertext.
150                            match sender_ciphertext {
151                                Some(sender) => sender.write_le(&mut writer)?,
152                                None => {
153                                    return Err(error(
154                                        "Failed to encode sender ciphertext for non-zero version record",
155                                    ));
156                                }
157                            }
158                        }
159                        Ok(())
160                    }
161                    None => false.write_le(&mut writer),
162                }
163            }
164            Self::ExternalRecord(commitment) => {
165                (4 as Variant).write_le(&mut writer)?;
166                commitment.write_le(&mut writer)
167            }
168            Self::Future(future_hash, future) => {
169                (5 as Variant).write_le(&mut writer)?;
170                future_hash.write_le(&mut writer)?;
171                match future {
172                    Some(future) => {
173                        true.write_le(&mut writer)?;
174                        future.write_le(&mut writer)
175                    }
176                    None => false.write_le(&mut writer),
177                }
178            }
179        }
180    }
181}
182
183#[cfg(test)]
184mod tests {
185    use super::*;
186
187    #[test]
188    fn test_bytes() {
189        for (_, expected) in crate::transition::output::test_helpers::sample_outputs() {
190            // Check the byte representation.
191            let expected_bytes = expected.to_bytes_le().unwrap();
192            assert_eq!(expected, Output::read_le(&expected_bytes[..]).unwrap());
193        }
194    }
195}