1use crate::{Opcode, Operand, RegistersCircuit, RegistersTrait, StackTrait};
17use console::{
18 network::prelude::*,
19 program::{ArrayType, Identifier, LiteralType, 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 => Ok(()),
73 _ => bail!("Invalid literal type '{literal_type}' for 'serialize' instruction"),
74 }
75 }
76
77 match operand_type {
78 PlaintextType::Literal(literal_type) => check_literal_type(literal_type),
79 PlaintextType::Array(array_type) => match array_type.base_element_type() {
80 PlaintextType::Literal(literal_type) => check_literal_type(literal_type),
81 _ => bail!("Invalid element type '{array_type}' for 'serialize' instruction"),
82 },
83 _ => bail!("Instruction '{}' cannot take type '{operand_type}' as input", SerializeVariant::opcode(variant)),
84 }
85}
86
87fn check_destination_type_is_valid(variant: u8, destination_type: &ArrayType<impl Network>) -> Result<()> {
89 match (variant, destination_type) {
90 (0 | 1, array_type) if array_type.is_bit_array() => Ok(()),
91 _ => {
92 bail!("Instruction '{}' cannot output type '{destination_type}'", SerializeVariant::opcode(variant))
93 }
94 }
95}
96
97#[derive(Clone, PartialEq, Eq, Hash)]
99pub struct SerializeInstruction<N: Network, const VARIANT: u8> {
100 operands: Vec<Operand<N>>,
102 operand_type: PlaintextType<N>,
104 destination: Register<N>,
106 destination_type: ArrayType<N>,
108}
109
110impl<N: Network, const VARIANT: u8> SerializeInstruction<N, VARIANT> {
111 pub fn new(
113 operands: Vec<Operand<N>>,
114 operand_type: PlaintextType<N>,
115 destination: Register<N>,
116 destination_type: ArrayType<N>,
117 ) -> Result<Self> {
118 check_number_of_operands(VARIANT, operands.len())?;
120 check_operand_type_is_valid(VARIANT, &operand_type)?;
122 check_destination_type_is_valid(VARIANT, &destination_type)?;
124 Ok(Self { operands, operand_type, destination, destination_type })
126 }
127
128 pub const fn opcode() -> Opcode {
130 Opcode::Serialize(SerializeVariant::opcode(VARIANT))
131 }
132
133 pub fn operands(&self) -> &[Operand<N>] {
135 if cfg!(debug_assertions) {
137 check_number_of_operands(VARIANT, self.operands.len()).unwrap();
138 check_operand_type_is_valid(VARIANT, &self.operand_type).unwrap();
139 check_destination_type_is_valid(VARIANT, &self.destination_type).unwrap();
140 }
141 &self.operands
143 }
144
145 pub const fn operand_type(&self) -> &PlaintextType<N> {
147 &self.operand_type
148 }
149
150 #[inline]
152 pub fn destinations(&self) -> Vec<Register<N>> {
153 vec![self.destination.clone()]
154 }
155
156 #[inline]
158 pub const fn destination_type(&self) -> &ArrayType<N> {
159 &self.destination_type
160 }
161}
162
163pub fn evaluate_serialize<N: Network>(
168 variant: SerializeVariant,
169 input: &Value<N>,
170 destination_type: &ArrayType<N>,
171) -> Result<Value<N>> {
172 evaluate_serialize_internal(variant as u8, input, destination_type)
173}
174
175fn evaluate_serialize_internal<N: Network>(
176 variant: u8,
177 input: &Value<N>,
178 destination_type: &ArrayType<N>,
179) -> Result<Value<N>> {
180 match (variant, destination_type) {
181 (0, array_type) if array_type.is_bit_array() => {
182 let length = **array_type.length();
184 let bits = input.to_bits_le();
186 Ok(Value::Plaintext(Plaintext::from_bit_array(bits, length)?))
188 }
189 (1, array_type) if array_type.is_bit_array() => {
190 let length = **array_type.length();
192 let bits = input.to_bits_raw_le();
194 Ok(Value::Plaintext(Plaintext::from_bit_array(bits, length)?))
196 }
197 _ => bail!(
198 "Invalid destination type '{}' for instruction '{}'",
199 destination_type,
200 SerializeVariant::opcode(variant)
201 ),
202 }
203}
204
205impl<N: Network, const VARIANT: u8> SerializeInstruction<N, VARIANT> {
206 pub fn evaluate(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersTrait<N>) -> Result<()> {
208 check_number_of_operands(VARIANT, self.operands.len())?;
210 check_operand_type_is_valid(VARIANT, &self.operand_type)?;
212 check_destination_type_is_valid(VARIANT, &self.destination_type)?;
214
215 let input = registers.load(stack, &self.operands[0])?;
217
218 let output = evaluate_serialize_internal(VARIANT, &input, &self.destination_type)?;
219
220 registers.store(stack, &self.destination, output)
222 }
223
224 pub fn execute<A: circuit::Aleo<Network = N>>(
226 &self,
227 stack: &impl StackTrait<N>,
228 registers: &mut impl RegistersCircuit<N, A>,
229 ) -> Result<()> {
230 use crate::circuit::traits::{ToBits, ToBitsRaw};
231
232 check_number_of_operands(VARIANT, self.operands.len())?;
234 check_operand_type_is_valid(VARIANT, &self.operand_type)?;
236 check_destination_type_is_valid(VARIANT, &self.destination_type)?;
238
239 let input = registers.load_circuit(stack, &self.operands[0])?;
241
242 let output = match (VARIANT, &self.destination_type) {
243 (0, array_type) if array_type.is_bit_array() => {
244 let length = **array_type.length();
246 let bits = input.to_bits_le();
248 circuit::Value::Plaintext(circuit::Plaintext::from_bit_array(bits, length)?)
250 }
251 (1, array_type) if array_type.is_bit_array() => {
252 let length = **array_type.length();
254 let bits = input.to_bits_raw_le();
256 circuit::Value::Plaintext(circuit::Plaintext::from_bit_array(bits, length)?)
258 }
259 _ => bail!("Invalid destination type '{}' for instruction '{}'", &self.destination_type, Self::opcode(),),
260 };
261
262 registers.store_circuit(stack, &self.destination, output)
264 }
265
266 #[inline]
268 pub fn finalize(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersTrait<N>) -> Result<()> {
269 self.evaluate(stack, registers)
270 }
271
272 pub fn output_types(
274 &self,
275 stack: &impl StackTrait<N>,
276 input_types: &[RegisterType<N>],
277 ) -> Result<Vec<RegisterType<N>>> {
278 check_number_of_operands(VARIANT, self.operands.len())?;
280 check_operand_type_is_valid(VARIANT, &self.operand_type)?;
282 check_destination_type_is_valid(VARIANT, &self.destination_type)?;
284
285 ensure!(input_types.len() == 1, "Expected exactly one input type");
287 match &input_types[0] {
288 RegisterType::Plaintext(plaintext_type) => {
289 ensure!(
290 plaintext_type == &self.operand_type,
291 "Input type {} does not match operand type {}",
292 input_types[0],
293 self.operand_type
294 )
295 }
296 type_ => bail!("Input type {type_} does not match operand type {}", self.operand_type),
297 }
298
299 let get_struct = |identifier: &Identifier<N>| stack.program().get_struct(identifier).cloned();
301
302 let size_in_bits = match VARIANT {
304 0 => self.operand_type.size_in_bits(&get_struct)?,
305 1 => self.operand_type.size_in_bits_raw(&get_struct)?,
306 variant => bail!("Invalid `serialize` variant '{variant}'"),
307 };
308
309 ensure!(
311 size_in_bits == **self.destination_type.length() as usize,
312 "The number of bits of the operand '{size_in_bits}' does not match the destination '{}'",
313 **self.destination_type.length()
314 );
315
316 Ok(vec![RegisterType::Plaintext(PlaintextType::Array(self.destination_type.clone()))])
317 }
318}
319
320impl<N: Network, const VARIANT: u8> Parser for SerializeInstruction<N, VARIANT> {
321 fn parse(string: &str) -> ParserResult<Self> {
323 fn parse_operands<N: Network>(string: &str, num_operands: usize) -> ParserResult<Vec<Operand<N>>> {
325 let mut operands = Vec::with_capacity(num_operands);
326 let mut string = string;
327
328 for _ in 0..num_operands {
329 let (next_string, _) = Sanitizer::parse_whitespaces(string)?;
331 let (next_string, operand) = Operand::parse(next_string)?;
333 string = next_string;
335 operands.push(operand);
337 }
338
339 Ok((string, operands))
340 }
341
342 let (string, _) = tag(*Self::opcode())(string)?;
344 let (string, operands) = parse_operands(string, 1)?;
346
347 let (string, _) = Sanitizer::parse_whitespaces(string)?;
349 let (string, _) = tag("(")(string)?;
351 let (string, _) = Sanitizer::parse_whitespaces(string)?;
353 let (string, operand_type) = PlaintextType::parse(string)?;
355 let (string, _) = tag(")")(string)?;
357
358 let (string, _) = Sanitizer::parse_whitespaces(string)?;
360 let (string, _) = tag("into")(string)?;
362 let (string, _) = Sanitizer::parse_whitespaces(string)?;
364 let (string, destination) = Register::parse(string)?;
366
367 let (string, _) = Sanitizer::parse_whitespaces(string)?;
369 let (string, _) = tag("(")(string)?;
371 let (string, _) = Sanitizer::parse_whitespaces(string)?;
373 let (string, destination_type) = ArrayType::parse(string)?;
375 let (string, _) = tag(")")(string)?;
377
378 match Self::new(operands, operand_type, destination, destination_type) {
380 Ok(instruction) => Ok((string, instruction)),
381 Err(e) => map_res(fail, |_: ParserResult<Self>| {
382 Err(error(format!("Failed to parse '{}' instruction: {e}", Self::opcode())))
383 })(string),
384 }
385 }
386}
387
388impl<N: Network, const VARIANT: u8> FromStr for SerializeInstruction<N, VARIANT> {
389 type Err = Error;
390
391 fn from_str(string: &str) -> Result<Self> {
393 match Self::parse(string) {
394 Ok((remainder, object)) => {
395 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
397 Ok(object)
399 }
400 Err(error) => bail!("Failed to parse string. {error}"),
401 }
402 }
403}
404
405impl<N: Network, const VARIANT: u8> Debug for SerializeInstruction<N, VARIANT> {
406 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
408 Display::fmt(self, f)
409 }
410}
411
412impl<N: Network, const VARIANT: u8> Display for SerializeInstruction<N, VARIANT> {
413 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
415 write!(f, "{} ", Self::opcode())?;
416 self.operands.iter().try_for_each(|operand| write!(f, "{operand} "))?;
417 write!(f, " ({}) into {} ({})", self.operand_type, self.destination, self.destination_type)
418 }
419}
420
421impl<N: Network, const VARIANT: u8> FromBytes for SerializeInstruction<N, VARIANT> {
422 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
424 let operand = Operand::read_le(&mut reader)?;
426 let operand_type = PlaintextType::read_le(&mut reader)?;
428 let destination = Register::read_le(&mut reader)?;
430 let destination_type = ArrayType::read_le(&mut reader)?;
432 match Self::new(vec![operand], operand_type, destination, destination_type) {
434 Ok(instruction) => Ok(instruction),
435 Err(e) => Err(error(format!("Failed to read '{}' instruction: {e}", Self::opcode()))),
436 }
437 }
438}
439
440impl<N: Network, const VARIANT: u8> ToBytes for SerializeInstruction<N, VARIANT> {
441 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
443 self.operands.iter().try_for_each(|operand| operand.write_le(&mut writer))?;
445 self.operand_type.write_le(&mut writer)?;
447 self.destination.write_le(&mut writer)?;
449 self.destination_type.write_le(&mut writer)
451 }
452}
453
454#[cfg(test)]
455mod tests {
456 use super::*;
457 use console::{network::MainnetV0, types::U32};
458
459 type CurrentNetwork = MainnetV0;
460
461 fn valid_source_types<N: Network>() -> &'static [PlaintextType<N>] {
463 &[
464 PlaintextType::Literal(LiteralType::Address),
465 PlaintextType::Literal(LiteralType::Field),
466 PlaintextType::Literal(LiteralType::Group),
467 PlaintextType::Literal(LiteralType::I8),
468 PlaintextType::Literal(LiteralType::I16),
469 PlaintextType::Literal(LiteralType::I32),
470 PlaintextType::Literal(LiteralType::I128),
471 PlaintextType::Literal(LiteralType::I64),
472 PlaintextType::Literal(LiteralType::U8),
473 PlaintextType::Literal(LiteralType::U16),
474 PlaintextType::Literal(LiteralType::U32),
475 PlaintextType::Literal(LiteralType::U64),
476 PlaintextType::Literal(LiteralType::U128),
477 PlaintextType::Literal(LiteralType::Scalar),
478 ]
479 }
480
481 fn sample_destination_type<N: Network, const VARIANT: u8>(rng: &mut TestRng) -> ArrayType<N> {
483 let array_length = 1 + (u32::rand(rng) % u32::try_from(N::MAX_ARRAY_ELEMENTS).unwrap());
485 match VARIANT {
486 0 | 1 => {
487 ArrayType::new(PlaintextType::Literal(LiteralType::Boolean), vec![U32::new(array_length)]).unwrap()
488 }
489 _ => panic!("Invalid variant"),
490 }
491 }
492
493 fn run_parser_test<const VARIANT: u8>(rng: &mut TestRng) {
494 for source_type in valid_source_types() {
495 {
496 let opcode = SerializeVariant::opcode(VARIANT);
497 let destination_type = sample_destination_type::<CurrentNetwork, VARIANT>(rng);
498 let instruction = format!("{opcode} r0 ({source_type}) into r1 ({destination_type})");
499 println!("Parsing instruction: '{instruction}'");
500
501 let (string, serialize) = SerializeInstruction::<CurrentNetwork, VARIANT>::parse(&instruction).unwrap();
502 assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
503 assert_eq!(serialize.operands.len(), 1, "The number of operands is incorrect");
504 assert_eq!(
505 serialize.operands[0],
506 Operand::Register(Register::Locator(0)),
507 "The first operand is incorrect"
508 );
509 assert_eq!(&serialize.operand_type, source_type, "The operand type is incorrect");
510 assert_eq!(serialize.destination, Register::Locator(1), "The destination register is incorrect");
511 assert_eq!(&serialize.destination_type, &destination_type, "The destination type is incorrect");
512 }
513 }
514 }
515
516 #[test]
517 fn test_parse() {
518 let rng = &mut TestRng::default();
520
521 run_parser_test::<{ SerializeVariant::ToBits as u8 }>(rng);
523 run_parser_test::<{ SerializeVariant::ToBitsRaw as u8 }>(rng);
524
525 SerializeBitsRaw::<CurrentNetwork>::from_str("serialize.bits.raw r0 (boolean) into r1 ([boolean; 1u32])")
526 .unwrap();
527 }
528}