Skip to main content

snarkvm_synthesizer_program/closure/
bytes.rs

1// Copyright (c) 2019-2026 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 ClosureCore<N> {
19    /// Reads the closure from a buffer.
20    #[inline]
21    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
22        // Read the closure name.
23        let name = Identifier::<N>::read_le(&mut reader)?;
24
25        // Read the inputs.
26        let num_inputs = u16::read_le(&mut reader)?;
27        if num_inputs.is_zero() {
28            return Err(error("Failed to deserialize a closure: needs at least one input".to_string()));
29        }
30        if num_inputs > u16::try_from(N::MAX_INPUTS).map_err(error)? {
31            return Err(error(format!("Failed to deserialize a closure: too many inputs ({num_inputs})")));
32        }
33        let mut inputs = Vec::with_capacity(num_inputs as usize);
34        for _ in 0..num_inputs {
35            inputs.push(Input::read_le(&mut reader)?);
36        }
37
38        // Read the instructions.
39        let num_instructions = u32::read_le(&mut reader)?;
40        if num_instructions.is_zero() {
41            return Err(error("Failed to deserialize a closure: needs at least one instruction".to_string()));
42        }
43        if num_instructions > u32::try_from(N::MAX_INSTRUCTIONS).map_err(error)? {
44            return Err(error(format!("Failed to deserialize a closure: too many instructions ({num_instructions})")));
45        }
46        // Cap the reservation: the count is attacker-supplied, and the elements behind
47        // it may not exist.
48        let mut instructions = Vec::with_capacity((num_instructions as usize).min(1024));
49        for _ in 0..num_instructions {
50            instructions.push(Instruction::read_le(&mut reader)?);
51        }
52
53        // Read the outputs.
54        let num_outputs = u16::read_le(&mut reader)?;
55        if num_outputs > u16::try_from(N::MAX_OUTPUTS).map_err(error)? {
56            return Err(error(format!("Failed to deserialize a closure: too many outputs ({num_outputs})")));
57        }
58        let mut outputs = Vec::with_capacity(num_outputs as usize);
59        for _ in 0..num_outputs {
60            outputs.push(Output::read_le(&mut reader)?);
61        }
62
63        // Initialize a new closure.
64        let mut closure = Self::new(name);
65        inputs.into_iter().try_for_each(|input| closure.add_input(input)).map_err(error)?;
66        instructions.into_iter().try_for_each(|instruction| closure.add_instruction(instruction)).map_err(error)?;
67        outputs.into_iter().try_for_each(|output| closure.add_output(output)).map_err(error)?;
68
69        Ok(closure)
70    }
71}
72
73impl<N: Network> ToBytes for ClosureCore<N> {
74    /// Writes the closure to a buffer.
75    #[inline]
76    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
77        // Write the closure name.
78        self.name.write_le(&mut writer)?;
79
80        // Write the number of inputs for the closure.
81        let num_inputs = self.inputs.len();
82        match 0 < num_inputs && num_inputs <= N::MAX_INPUTS {
83            true => u16::try_from(num_inputs).map_err(error)?.write_le(&mut writer)?,
84            false => return Err(error(format!("Failed to write {num_inputs} inputs as bytes"))),
85        }
86
87        // Write the inputs.
88        for input in self.inputs.iter() {
89            input.write_le(&mut writer)?;
90        }
91
92        // Write the number of instructions for the closure.
93        let num_instructions = self.instructions.len();
94        match 0 < num_instructions && num_instructions <= N::MAX_INSTRUCTIONS {
95            true => u32::try_from(num_instructions).map_err(error)?.write_le(&mut writer)?,
96            false => return Err(error(format!("Failed to write {num_instructions} instructions as bytes"))),
97        }
98
99        // Write the instructions.
100        for instruction in self.instructions.iter() {
101            instruction.write_le(&mut writer)?;
102        }
103
104        // Write the number of outputs for the closure.
105        let num_outputs = self.outputs.len();
106        match num_outputs <= N::MAX_OUTPUTS {
107            true => u16::try_from(num_outputs).map_err(error)?.write_le(&mut writer)?,
108            false => return Err(error(format!("Failed to write {num_outputs} outputs as bytes"))),
109        }
110
111        // Write the outputs.
112        for output in self.outputs.iter() {
113            output.write_le(&mut writer)?;
114        }
115
116        Ok(())
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123    use crate::Closure;
124    use console::network::MainnetV0;
125
126    type CurrentNetwork = MainnetV0;
127
128    #[test]
129    fn test_closure_bytes() -> Result<()> {
130        let closure_string = r"
131closure main:
132    input r0 as field;
133    input r1 as field;
134    add r0 r1 into r2;
135    add r0 r1 into r3;
136    add r0 r1 into r4;
137    add r0 r1 into r5;
138    add r0 r1 into r6;
139    add r0 r1 into r7;
140    add r0 r1 into r8;
141    add r0 r1 into r9;
142    add r0 r1 into r10;
143    add r0 r1 into r11;
144    output r11 as field;";
145
146        let expected = Closure::<CurrentNetwork>::from_str(closure_string)?;
147        let expected_bytes = expected.to_bytes_le()?;
148        println!("String size: {:?}, Bytecode size: {:?}", closure_string.len(), expected_bytes.len());
149
150        let candidate = Closure::<CurrentNetwork>::from_bytes_le(&expected_bytes)?;
151        assert_eq!(expected.to_string(), candidate.to_string());
152        assert_eq!(expected_bytes, candidate.to_bytes_le()?);
153        Ok(())
154    }
155}