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