snarkvm_synthesizer_program/function/
bytes.rs

1// Copyright 2024-2025 Aleo Network Foundation
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>, Command: CommandTrait<N>> FromBytes
19    for FunctionCore<N, Instruction, Command>
20{
21    /// Reads the function from a buffer.
22    #[inline]
23    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
24        // Read the function name.
25        let name = Identifier::<N>::read_le(&mut reader)?;
26
27        // Read the inputs.
28        let num_inputs = u16::read_le(&mut reader)?;
29        if num_inputs > u16::try_from(N::MAX_INPUTS).map_err(error)? {
30            return Err(error(format!("Failed to deserialize a function: too many inputs ({num_inputs})")));
31        }
32        let mut inputs = Vec::with_capacity(num_inputs as usize);
33        for _ in 0..num_inputs {
34            inputs.push(Input::read_le(&mut reader)?);
35        }
36
37        // Read the instructions.
38        let num_instructions = u32::read_le(&mut reader)?;
39        if num_instructions > u32::try_from(N::MAX_INSTRUCTIONS).map_err(error)? {
40            return Err(error(format!("Failed to deserialize a function: too many instructions ({num_instructions})")));
41        }
42        let mut instructions = Vec::with_capacity(num_instructions as usize);
43        for _ in 0..num_instructions {
44            instructions.push(Instruction::read_le(&mut reader)?);
45        }
46
47        // Read the outputs.
48        let num_outputs = u16::read_le(&mut reader)?;
49        if num_outputs > u16::try_from(N::MAX_OUTPUTS).map_err(error)? {
50            return Err(error(format!("Failed to deserialize a function: too many outputs ({num_outputs})")));
51        }
52        let mut outputs = Vec::with_capacity(num_outputs as usize);
53        for _ in 0..num_outputs {
54            outputs.push(Output::read_le(&mut reader)?);
55        }
56
57        // Determine if there is a finalize scope.
58        let variant = u8::read_le(&mut reader)?;
59        let finalize = match variant {
60            0 => None,
61            1 => Some(FinalizeCore::read_le(&mut reader)?),
62            _ => return Err(error(format!("Failed to deserialize a function: invalid finalize variant ({variant})"))),
63        };
64
65        // Initialize a new function.
66        let mut function = Self::new(name);
67        inputs.into_iter().try_for_each(|input| function.add_input(input)).map_err(error)?;
68        instructions.into_iter().try_for_each(|instruction| function.add_instruction(instruction)).map_err(error)?;
69        outputs.into_iter().try_for_each(|output| function.add_output(output)).map_err(error)?;
70        finalize.map(|finalize| function.add_finalize(finalize));
71
72        Ok(function)
73    }
74}
75
76impl<N: Network, Instruction: InstructionTrait<N>, Command: CommandTrait<N>> ToBytes
77    for FunctionCore<N, Instruction, Command>
78{
79    /// Writes the function to a buffer.
80    #[inline]
81    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
82        // Write the function name.
83        self.name.write_le(&mut writer)?;
84
85        // Write the number of inputs for the function.
86        let num_inputs = self.inputs.len();
87        match num_inputs <= N::MAX_INPUTS {
88            true => u16::try_from(num_inputs).map_err(error)?.write_le(&mut writer)?,
89            false => return Err(error(format!("Failed to write {num_inputs} inputs as bytes"))),
90        }
91
92        // Write the inputs.
93        for input in self.inputs.iter() {
94            input.write_le(&mut writer)?;
95        }
96
97        // Write the number of instructions for the function.
98        let num_instructions = self.instructions.len();
99        match num_instructions <= N::MAX_INSTRUCTIONS {
100            true => u32::try_from(num_instructions).map_err(error)?.write_le(&mut writer)?,
101            false => return Err(error(format!("Failed to write {num_instructions} instructions as bytes"))),
102        }
103
104        // Write the instructions.
105        for instruction in self.instructions.iter() {
106            instruction.write_le(&mut writer)?;
107        }
108
109        // Write the number of outputs for the function.
110        let num_outputs = self.outputs.len();
111        match num_outputs <= N::MAX_OUTPUTS {
112            true => u16::try_from(num_outputs).map_err(error)?.write_le(&mut writer)?,
113            false => return Err(error(format!("Failed to write {num_outputs} outputs as bytes"))),
114        }
115
116        // Write the outputs.
117        for output in self.outputs.iter() {
118            output.write_le(&mut writer)?;
119        }
120
121        // If the finalize scope exists, write it.
122        match &self.finalize_logic {
123            None => 0u8.write_le(&mut writer)?,
124            Some(logic) => {
125                1u8.write_le(&mut writer)?;
126                // Write the finalize scope logic.
127                logic.write_le(&mut writer)?;
128            }
129        }
130
131        Ok(())
132    }
133}
134
135#[cfg(test)]
136mod tests {
137    use super::*;
138    use crate::Function;
139    use console::network::MainnetV0;
140
141    type CurrentNetwork = MainnetV0;
142
143    #[test]
144    fn test_function_bytes() -> Result<()> {
145        let function_string = r"
146function main:
147    input r0 as field.public;
148    input r1 as field.private;
149    add r0 r1 into r2;
150    add r0 r1 into r3;
151    add r0 r1 into r4;
152    add r0 r1 into r5;
153    add r0 r1 into r6;
154    add r0 r1 into r7;
155    add r0 r1 into r8;
156    add r0 r1 into r9;
157    add r0 r1 into r10;
158    add r0 r1 into r11;
159    output r11 as field.private;";
160
161        let expected = Function::<CurrentNetwork>::from_str(function_string)?;
162        let expected_bytes = expected.to_bytes_le()?;
163        println!("String size: {:?}, Bytecode size: {:?}", function_string.as_bytes().len(), expected_bytes.len());
164
165        let candidate = Function::<CurrentNetwork>::from_bytes_le(&expected_bytes)?;
166        assert_eq!(expected.to_string(), candidate.to_string());
167        assert_eq!(expected_bytes, candidate.to_bytes_le()?);
168        Ok(())
169    }
170}