1use crate::{Opcode, Operand, RegistersCircuit, RegistersTrait, StackTrait};
17use console::{
18 network::prelude::*,
19 program::{ArrayType, Identifier, LiteralType, Locator, Plaintext, PlaintextType, Register, RegisterType, Value},
20};
21
22pub type SerializeBits<N> = SerializeInstruction<N, { SerializeVariant::ToBits as u8 }>;
24pub type SerializeBitsRaw<N> = SerializeInstruction<N, { SerializeVariant::ToBitsRaw as u8 }>;
26
27#[derive(Debug, Clone, Eq, PartialEq)]
29pub enum SerializeVariant {
30 ToBits,
31 ToBitsRaw,
32}
33
34impl SerializeVariant {
35 pub const fn opcode(variant: u8) -> &'static str {
37 match variant {
38 0 => "serialize.bits",
39 1 => "serialize.bits.raw",
40 _ => panic!("Invalid 'serialize' instruction opcode"),
41 }
42 }
43}
44
45fn check_number_of_operands(variant: u8, num_operands: usize) -> Result<()> {
47 if num_operands != 1 {
48 bail!("Instruction '{}' expects 1 operand, found {num_operands} operands", SerializeVariant::opcode(variant))
49 }
50 Ok(())
51}
52
53fn check_operand_type_is_valid(variant: u8, operand_type: &PlaintextType<impl Network>) -> Result<()> {
55 fn check_literal_type(literal_type: &LiteralType) -> Result<()> {
57 match literal_type {
58 LiteralType::Address
59 | LiteralType::Boolean
60 | LiteralType::Field
61 | LiteralType::Group
62 | LiteralType::I8
63 | LiteralType::I16
64 | LiteralType::I32
65 | LiteralType::I64
66 | LiteralType::I128
67 | LiteralType::U8
68 | LiteralType::U16
69 | LiteralType::U32
70 | LiteralType::U64
71 | LiteralType::U128
72 | LiteralType::Scalar
73 | LiteralType::Identifier => Ok(()),
74 _ => bail!("Invalid literal type '{literal_type}' for 'serialize' instruction"),
75 }
76 }
77
78 match operand_type {
79 PlaintextType::Literal(literal_type) => check_literal_type(literal_type),
80 PlaintextType::Array(array_type) => match array_type.base_element_type() {
81 PlaintextType::Literal(literal_type) => check_literal_type(literal_type),
82 _ => bail!("Invalid element type '{array_type}' for 'serialize' instruction"),
83 },
84 _ => bail!("Instruction '{}' cannot take type '{operand_type}' as input", SerializeVariant::opcode(variant)),
85 }
86}
87
88fn check_destination_type_is_valid(variant: u8, destination_type: &ArrayType<impl Network>) -> Result<()> {
90 match (variant, destination_type) {
91 (0 | 1, array_type) if array_type.is_bit_array() => Ok(()),
92 _ => {
93 bail!("Instruction '{}' cannot output type '{destination_type}'", SerializeVariant::opcode(variant))
94 }
95 }
96}
97
98#[derive(Clone, PartialEq, Eq, Hash)]
100pub struct SerializeInstruction<N: Network, const VARIANT: u8> {
101 operands: Vec<Operand<N>>,
103 operand_type: PlaintextType<N>,
105 destination: Register<N>,
107 destination_type: ArrayType<N>,
109}
110
111impl<N: Network, const VARIANT: u8> SerializeInstruction<N, VARIANT> {
112 pub fn new(
114 operands: Vec<Operand<N>>,
115 operand_type: PlaintextType<N>,
116 destination: Register<N>,
117 destination_type: ArrayType<N>,
118 ) -> Result<Self> {
119 check_number_of_operands(VARIANT, operands.len())?;
121 check_operand_type_is_valid(VARIANT, &operand_type)?;
123 check_destination_type_is_valid(VARIANT, &destination_type)?;
125 Ok(Self { operands, operand_type, destination, destination_type })
127 }
128
129 pub const fn opcode() -> Opcode {
131 Opcode::Serialize(SerializeVariant::opcode(VARIANT))
132 }
133
134 pub fn operands(&self) -> &[Operand<N>] {
136 if cfg!(debug_assertions) {
138 check_number_of_operands(VARIANT, self.operands.len()).unwrap();
139 check_operand_type_is_valid(VARIANT, &self.operand_type).unwrap();
140 check_destination_type_is_valid(VARIANT, &self.destination_type).unwrap();
141 }
142 &self.operands
144 }
145
146 pub const fn operand_type(&self) -> &PlaintextType<N> {
148 &self.operand_type
149 }
150
151 #[inline]
153 pub fn destinations(&self) -> Vec<Register<N>> {
154 vec![self.destination.clone()]
155 }
156
157 #[inline]
159 pub const fn destination_type(&self) -> &ArrayType<N> {
160 &self.destination_type
161 }
162
163 #[inline]
165 pub fn contains_external_struct(&self) -> bool {
166 self.operand_type.contains_external_struct()
167 }
168}
169
170pub fn evaluate_serialize<N: Network>(
175 variant: SerializeVariant,
176 input: &Value<N>,
177 destination_type: &ArrayType<N>,
178) -> Result<Value<N>> {
179 evaluate_serialize_internal(variant as u8, input, destination_type)
180}
181
182fn evaluate_serialize_internal<N: Network>(
183 variant: u8,
184 input: &Value<N>,
185 destination_type: &ArrayType<N>,
186) -> Result<Value<N>> {
187 match (variant, destination_type) {
188 (0, array_type) if array_type.is_bit_array() => {
189 let length = **array_type.length();
191 let bits = input.to_bits_le();
193 Ok(Value::Plaintext(Plaintext::from_bit_array(bits, length)?))
195 }
196 (1, array_type) if array_type.is_bit_array() => {
197 let length = **array_type.length();
199 let bits = input.to_bits_raw_le();
201 Ok(Value::Plaintext(Plaintext::from_bit_array(bits, length)?))
203 }
204 _ => bail!(
205 "Invalid destination type '{}' for instruction '{}'",
206 destination_type,
207 SerializeVariant::opcode(variant)
208 ),
209 }
210}
211
212impl<N: Network, const VARIANT: u8> SerializeInstruction<N, VARIANT> {
213 pub fn evaluate(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersTrait<N>) -> Result<()> {
215 check_number_of_operands(VARIANT, self.operands.len())?;
217 check_operand_type_is_valid(VARIANT, &self.operand_type)?;
219 check_destination_type_is_valid(VARIANT, &self.destination_type)?;
221
222 let input = registers.load(stack, &self.operands[0])?;
224
225 let output = evaluate_serialize_internal(VARIANT, &input, &self.destination_type)?;
226
227 registers.store(stack, &self.destination, output)
229 }
230
231 pub fn execute<A: circuit::Aleo<Network = N>>(
233 &self,
234 stack: &impl StackTrait<N>,
235 registers: &mut impl RegistersCircuit<N, A>,
236 ) -> Result<()> {
237 use crate::circuit::traits::{ToBits, ToBitsRaw};
238
239 check_number_of_operands(VARIANT, self.operands.len())?;
241 check_operand_type_is_valid(VARIANT, &self.operand_type)?;
243 check_destination_type_is_valid(VARIANT, &self.destination_type)?;
245
246 let input = registers.load_circuit(stack, &self.operands[0])?;
248
249 let output = match (VARIANT, &self.destination_type) {
250 (0, array_type) if array_type.is_bit_array() => {
251 let length = **array_type.length();
253 let bits = input.to_bits_le();
255 circuit::Value::Plaintext(circuit::Plaintext::from_bit_array(bits, length)?)
257 }
258 (1, array_type) if array_type.is_bit_array() => {
259 let length = **array_type.length();
261 let bits = input.to_bits_raw_le();
263 circuit::Value::Plaintext(circuit::Plaintext::from_bit_array(bits, length)?)
265 }
266 _ => bail!("Invalid destination type '{}' for instruction '{}'", &self.destination_type, Self::opcode(),),
267 };
268
269 registers.store_circuit(stack, &self.destination, output)
271 }
272
273 #[inline]
275 pub fn finalize(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersTrait<N>) -> Result<()> {
276 self.evaluate(stack, registers)
277 }
278
279 pub fn output_types(
281 &self,
282 stack: &impl StackTrait<N>,
283 input_types: &[RegisterType<N>],
284 ) -> Result<Vec<RegisterType<N>>> {
285 check_number_of_operands(VARIANT, self.operands.len())?;
287 check_operand_type_is_valid(VARIANT, &self.operand_type)?;
289 check_destination_type_is_valid(VARIANT, &self.destination_type)?;
291
292 ensure!(input_types.len() == 1, "Expected exactly one input type");
294 match &input_types[0] {
295 RegisterType::Plaintext(plaintext_type) => {
296 ensure!(
297 plaintext_type == &self.operand_type,
298 "Input type {} does not match operand type {}",
299 input_types[0],
300 self.operand_type
301 )
302 }
303 type_ => bail!("Input type {type_} does not match operand type {}", self.operand_type),
304 }
305
306 let get_struct = |identifier: &Identifier<N>| stack.program().get_struct(identifier).cloned();
308
309 let get_external_struct = |locator: &Locator<N>| {
311 stack.get_external_stack(locator.program_id())?.program().get_struct(locator.resource()).cloned()
312 };
313
314 let size_in_bits = match VARIANT {
316 0 => self.operand_type.size_in_bits(&get_struct, &get_external_struct)?,
317 1 => self.operand_type.size_in_bits_raw(&get_struct, &get_external_struct)?,
318 variant => bail!("Invalid `serialize` variant '{variant}'"),
319 };
320
321 ensure!(
323 size_in_bits == **self.destination_type.length() as usize,
324 "The number of bits of the operand '{size_in_bits}' does not match the destination '{}'",
325 **self.destination_type.length()
326 );
327
328 Ok(vec![RegisterType::Plaintext(PlaintextType::Array(self.destination_type.clone()))])
329 }
330}
331
332impl<N: Network, const VARIANT: u8> Parser for SerializeInstruction<N, VARIANT> {
333 fn parse(string: &str) -> ParserResult<Self> {
335 fn parse_operands<N: Network>(string: &str, num_operands: usize) -> ParserResult<Vec<Operand<N>>> {
337 let mut operands = Vec::with_capacity(num_operands);
338 let mut string = string;
339
340 for _ in 0..num_operands {
341 let (next_string, _) = Sanitizer::parse_whitespaces(string)?;
343 let (next_string, operand) = Operand::parse(next_string)?;
345 string = next_string;
347 operands.push(operand);
349 }
350
351 Ok((string, operands))
352 }
353
354 let (string, _) = tag(*Self::opcode())(string)?;
356 let (string, operands) = parse_operands(string, 1)?;
358
359 let (string, _) = Sanitizer::parse_whitespaces(string)?;
361 let (string, _) = tag("(")(string)?;
363 let (string, _) = Sanitizer::parse_whitespaces(string)?;
365 let (string, operand_type) = PlaintextType::parse(string)?;
367 let (string, _) = tag(")")(string)?;
369
370 let (string, _) = Sanitizer::parse_whitespaces(string)?;
372 let (string, _) = tag("into")(string)?;
374 let (string, _) = Sanitizer::parse_whitespaces(string)?;
376 let (string, destination) = Register::parse(string)?;
378
379 let (string, _) = Sanitizer::parse_whitespaces(string)?;
381 let (string, _) = tag("(")(string)?;
383 let (string, _) = Sanitizer::parse_whitespaces(string)?;
385 let (string, destination_type) = ArrayType::parse(string)?;
387 let (string, _) = tag(")")(string)?;
389
390 match Self::new(operands, operand_type, destination, destination_type) {
392 Ok(instruction) => Ok((string, instruction)),
393 Err(e) => map_res(fail, |_: ParserResult<Self>| {
394 Err(error(format!("Failed to parse '{}' instruction: {e}", Self::opcode())))
395 })(string),
396 }
397 }
398}
399
400impl<N: Network, const VARIANT: u8> FromStr for SerializeInstruction<N, VARIANT> {
401 type Err = Error;
402
403 fn from_str(string: &str) -> Result<Self> {
405 match Self::parse(string) {
406 Ok((remainder, object)) => {
407 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
409 Ok(object)
411 }
412 Err(error) => bail!("Failed to parse string. {error}"),
413 }
414 }
415}
416
417impl<N: Network, const VARIANT: u8> Debug for SerializeInstruction<N, VARIANT> {
418 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
420 Display::fmt(self, f)
421 }
422}
423
424impl<N: Network, const VARIANT: u8> Display for SerializeInstruction<N, VARIANT> {
425 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
427 write!(f, "{} ", Self::opcode())?;
428 self.operands.iter().try_for_each(|operand| write!(f, "{operand} "))?;
429 write!(f, " ({}) into {} ({})", self.operand_type, self.destination, self.destination_type)
430 }
431}
432
433impl<N: Network, const VARIANT: u8> FromBytes for SerializeInstruction<N, VARIANT> {
434 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
436 let operand = Operand::read_le(&mut reader)?;
438 let operand_type = PlaintextType::read_le(&mut reader)?;
440 let destination = Register::read_le(&mut reader)?;
442 let destination_type = ArrayType::read_le(&mut reader)?;
444 match Self::new(vec![operand], operand_type, destination, destination_type) {
446 Ok(instruction) => Ok(instruction),
447 Err(e) => Err(error(format!("Failed to read '{}' instruction: {e}", Self::opcode()))),
448 }
449 }
450}
451
452impl<N: Network, const VARIANT: u8> ToBytes for SerializeInstruction<N, VARIANT> {
453 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
455 self.operands.iter().try_for_each(|operand| operand.write_le(&mut writer))?;
457 self.operand_type.write_le(&mut writer)?;
459 self.destination.write_le(&mut writer)?;
461 self.destination_type.write_le(&mut writer)
463 }
464}
465
466#[cfg(test)]
467mod tests {
468 use super::*;
469 use console::{network::MainnetV0, types::U32};
470
471 type CurrentNetwork = MainnetV0;
472
473 fn valid_source_types<N: Network>() -> &'static [PlaintextType<N>] {
475 &[
476 PlaintextType::Literal(LiteralType::Address),
477 PlaintextType::Literal(LiteralType::Field),
478 PlaintextType::Literal(LiteralType::Group),
479 PlaintextType::Literal(LiteralType::I8),
480 PlaintextType::Literal(LiteralType::I16),
481 PlaintextType::Literal(LiteralType::I32),
482 PlaintextType::Literal(LiteralType::I128),
483 PlaintextType::Literal(LiteralType::I64),
484 PlaintextType::Literal(LiteralType::U8),
485 PlaintextType::Literal(LiteralType::U16),
486 PlaintextType::Literal(LiteralType::U32),
487 PlaintextType::Literal(LiteralType::U64),
488 PlaintextType::Literal(LiteralType::U128),
489 PlaintextType::Literal(LiteralType::Scalar),
490 PlaintextType::Literal(LiteralType::Identifier),
491 ]
492 }
493
494 fn sample_destination_type<N: Network, const VARIANT: u8>(rng: &mut TestRng) -> ArrayType<N> {
496 let array_length = 1 + (u32::rand(rng) % u32::try_from(N::LATEST_MAX_ARRAY_ELEMENTS()).unwrap());
498 match VARIANT {
499 0 | 1 => {
500 ArrayType::new(PlaintextType::Literal(LiteralType::Boolean), vec![U32::new(array_length)]).unwrap()
501 }
502 _ => panic!("Invalid variant"),
503 }
504 }
505
506 fn run_parser_test<const VARIANT: u8>(rng: &mut TestRng) {
507 for source_type in valid_source_types() {
508 {
509 let opcode = SerializeVariant::opcode(VARIANT);
510 let destination_type = sample_destination_type::<CurrentNetwork, VARIANT>(rng);
511 let instruction = format!("{opcode} r0 ({source_type}) into r1 ({destination_type})");
512 println!("Parsing instruction: '{instruction}'");
513
514 let (string, serialize) = SerializeInstruction::<CurrentNetwork, VARIANT>::parse(&instruction).unwrap();
515 assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
516 assert_eq!(serialize.operands.len(), 1, "The number of operands is incorrect");
517 assert_eq!(
518 serialize.operands[0],
519 Operand::Register(Register::Locator(0)),
520 "The first operand is incorrect"
521 );
522 assert_eq!(&serialize.operand_type, source_type, "The operand type is incorrect");
523 assert_eq!(serialize.destination, Register::Locator(1), "The destination register is incorrect");
524 assert_eq!(&serialize.destination_type, &destination_type, "The destination type is incorrect");
525 }
526 }
527 }
528
529 #[test]
530 fn test_parse() {
531 let rng = &mut TestRng::default();
533
534 run_parser_test::<{ SerializeVariant::ToBits as u8 }>(rng);
536 run_parser_test::<{ SerializeVariant::ToBitsRaw as u8 }>(rng);
537
538 SerializeBitsRaw::<CurrentNetwork>::from_str("serialize.bits.raw r0 (boolean) into r1 ([boolean; 1u32])")
539 .unwrap();
540 }
541}