Skip to main content

snarkvm_synthesizer_program/logic/instruction/operation/
hash.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 crate::{Opcode, Operand, RegistersCircuit, RegistersTrait, StackTrait};
17use console::{
18    network::prelude::*,
19    program::{Identifier, Literal, LiteralType, Locator, Plaintext, PlaintextType, Register, RegisterType, Value},
20};
21
22use enum_iterator::Sequence;
23
24/// BHP256 is a collision-resistant hash function that processes inputs in 256-bit chunks.
25pub type HashBHP256<N> = HashInstruction<N, { HashVariant::HashBHP256 as u8 }>;
26/// BHP512 is a collision-resistant hash function that processes inputs in 512-bit chunks.
27pub type HashBHP512<N> = HashInstruction<N, { HashVariant::HashBHP512 as u8 }>;
28/// BHP768 is a collision-resistant hash function that processes inputs in 768-bit chunks.
29pub type HashBHP768<N> = HashInstruction<N, { HashVariant::HashBHP768 as u8 }>;
30/// BHP1024 is a collision-resistant hash function that processes inputs in 1024-bit chunks.
31pub type HashBHP1024<N> = HashInstruction<N, { HashVariant::HashBHP1024 as u8 }>;
32
33/// BHP256Raw is a collision-resistant hash function that processes the input's raw bits in 256-bit chunks.
34pub type HashBHP256Raw<N> = HashInstruction<N, { HashVariant::HashBHP256Raw as u8 }>;
35/// BHP512Raw is a collision-resistant hash function that processes the input's raw bits in 512-bit chunks.
36pub type HashBHP512Raw<N> = HashInstruction<N, { HashVariant::HashBHP512Raw as u8 }>;
37/// BHP768Raw is a collision-resistant hash function that processes the input's raw bits in 768-bit chunks.
38pub type HashBHP768Raw<N> = HashInstruction<N, { HashVariant::HashBHP768Raw as u8 }>;
39/// BHP1024Raw is a collision-resistant hash function that processes the input's raw bits in 1024-bit chunks.
40pub type HashBHP1024Raw<N> = HashInstruction<N, { HashVariant::HashBHP1024Raw as u8 }>;
41
42/// Keccak256 is a cryptographic hash function that outputs a 256-bit digest.
43pub type HashKeccak256<N> = HashInstruction<N, { HashVariant::HashKeccak256 as u8 }>;
44/// Keccak384 is a cryptographic hash function that outputs a 384-bit digest.
45pub type HashKeccak384<N> = HashInstruction<N, { HashVariant::HashKeccak384 as u8 }>;
46/// Keccak512 is a cryptographic hash function that outputs a 512-bit digest.
47pub type HashKeccak512<N> = HashInstruction<N, { HashVariant::HashKeccak512 as u8 }>;
48
49/// Keccak256Raw is a cryptographic hash function that outputs a 256-bit digest using the input's raw bits.
50pub type HashKeccak256Raw<N> = HashInstruction<N, { HashVariant::HashKeccak256Raw as u8 }>;
51/// Keccak384Raw is a cryptographic hash function that outputs a 384-bit digest using the input's raw bits.
52pub type HashKeccak384Raw<N> = HashInstruction<N, { HashVariant::HashKeccak384Raw as u8 }>;
53/// Keccak512Raw is a cryptographic hash function that outputs a 512-bit digest using the input's raw bits.
54pub type HashKeccak512Raw<N> = HashInstruction<N, { HashVariant::HashKeccak512Raw as u8 }>;
55
56/// Keccak256Native is a cryptographic hash function that outputs a 256-bit digest as a bit array.
57pub type HashKeccak256Native<N> = HashInstruction<N, { HashVariant::HashKeccak256Native as u8 }>;
58/// Keccak384Native is a cryptographic hash function that outputs a 384-bit digest as a bit array.
59pub type HashKeccak384Native<N> = HashInstruction<N, { HashVariant::HashKeccak384Native as u8 }>;
60/// Keccak512Native is a cryptographic hash function that outputs a 512-bit digest as a bit array.
61pub type HashKeccak512Native<N> = HashInstruction<N, { HashVariant::HashKeccak512Native as u8 }>;
62
63/// Keccak256NativeRaw is a cryptographic hash function that outputs a 256-bit digest as a bit array using the input's raw bits.
64pub type HashKeccak256NativeRaw<N> = HashInstruction<N, { HashVariant::HashKeccak256NativeRaw as u8 }>;
65/// Keccak384NativeRaw is a cryptographic hash function that outputs a 384-bit digest as a bit array using the input's raw bits.
66pub type HashKeccak384NativeRaw<N> = HashInstruction<N, { HashVariant::HashKeccak384NativeRaw as u8 }>;
67/// Keccak512NativeRaw is a cryptographic hash function that outputs a 512-bit digest as a bit array using the input's raw bits.
68pub type HashKeccak512NativeRaw<N> = HashInstruction<N, { HashVariant::HashKeccak512NativeRaw as u8 }>;
69
70/// Pedersen64 is a collision-resistant hash function that processes inputs in 64-bit chunks.
71pub type HashPED64<N> = HashInstruction<N, { HashVariant::HashPED64 as u8 }>;
72/// Pedersen128 is a collision-resistant hash function that processes inputs in 128-bit chunks.
73pub type HashPED128<N> = HashInstruction<N, { HashVariant::HashPED128 as u8 }>;
74
75/// Pedersen64Raw is a collision-resistant hash function that processes the input's raw bits in 64-bit chunks.
76pub type HashPED64Raw<N> = HashInstruction<N, { HashVariant::HashPED64Raw as u8 }>;
77/// Pedersen128Raw is a collision-resistant hash function that processes the input's raw bits in 128-bit chunks.
78pub type HashPED128Raw<N> = HashInstruction<N, { HashVariant::HashPED128Raw as u8 }>;
79
80/// Poseidon2 is a cryptographic hash function that processes inputs in 2-field chunks.
81pub type HashPSD2<N> = HashInstruction<N, { HashVariant::HashPSD2 as u8 }>;
82/// Poseidon4 is a cryptographic hash function that processes inputs in 4-field chunks.
83pub type HashPSD4<N> = HashInstruction<N, { HashVariant::HashPSD4 as u8 }>;
84/// Poseidon8 is a cryptographic hash function that processes inputs in 8-field chunks.
85pub type HashPSD8<N> = HashInstruction<N, { HashVariant::HashPSD8 as u8 }>;
86
87/// Poseidon2Raw is a cryptographic hash function that processes the input's raw fields in 2-field chunks.
88pub type HashPSD2Raw<N> = HashInstruction<N, { HashVariant::HashPSD2Raw as u8 }>;
89/// Poseidon4Raw is a cryptographic hash function that processes the input's raw fields in 4-field chunks.
90pub type HashPSD4Raw<N> = HashInstruction<N, { HashVariant::HashPSD4Raw as u8 }>;
91/// Poseidon8Raw is a cryptographic hash function that processes the input's raw fields in 8-field chunks.
92pub type HashPSD8Raw<N> = HashInstruction<N, { HashVariant::HashPSD8Raw as u8 }>;
93
94/// SHA3-256 is a cryptographic hash function that outputs a 256-bit digest.
95pub type HashSha3_256<N> = HashInstruction<N, { HashVariant::HashSha3_256 as u8 }>;
96/// SHA3-384 is a cryptographic hash function that outputs a 384-bit digest.
97pub type HashSha3_384<N> = HashInstruction<N, { HashVariant::HashSha3_384 as u8 }>;
98/// SHA3-512 is a cryptographic hash function that outputs a 512-bit digest.
99pub type HashSha3_512<N> = HashInstruction<N, { HashVariant::HashSha3_512 as u8 }>;
100
101/// SHA3-256Raw is a cryptographic hash function that outputs a 256-bit digest using the input's raw bits.
102pub type HashSha3_256Raw<N> = HashInstruction<N, { HashVariant::HashSha3_256Raw as u8 }>;
103/// SHA3-384Raw is a cryptographic hash function that outputs a 384-bit digest using the input's raw bits.
104pub type HashSha3_384Raw<N> = HashInstruction<N, { HashVariant::HashSha3_384Raw as u8 }>;
105/// SHA3-512Raw is a cryptographic hash function that outputs a 512-bit digest using the input's raw bits.
106pub type HashSha3_512Raw<N> = HashInstruction<N, { HashVariant::HashSha3_512Raw as u8 }>;
107
108/// SHA3-256Native is a cryptographic hash function that outputs a 256-bit digest as a bit array.
109pub type HashSha3_256Native<N> = HashInstruction<N, { HashVariant::HashSha3_256Native as u8 }>;
110/// SHA3-384Native is a cryptographic hash function that outputs a 384-bit digest as a bit array.
111pub type HashSha3_384Native<N> = HashInstruction<N, { HashVariant::HashSha3_384Native as u8 }>;
112/// SHA3-512Native is a cryptographic hash function that outputs a 512-bit digest as a bit array.
113pub type HashSha3_512Native<N> = HashInstruction<N, { HashVariant::HashSha3_512Native as u8 }>;
114
115/// SHA3-256NativeRaw is a cryptographic hash function that outputs a 256-bit digest as a bit array using the input's raw bits.
116pub type HashSha3_256NativeRaw<N> = HashInstruction<N, { HashVariant::HashSha3_256NativeRaw as u8 }>;
117/// SHA3-384NativeRaw is a cryptographic hash function that outputs a 384-bit digest as a bit array using the input's raw bits.
118pub type HashSha3_384NativeRaw<N> = HashInstruction<N, { HashVariant::HashSha3_384NativeRaw as u8 }>;
119/// SHA3-512NativeRaw is a cryptographic hash function that outputs a 512-bit digest as a bit array using the input's raw bits.
120pub type HashSha3_512NativeRaw<N> = HashInstruction<N, { HashVariant::HashSha3_512NativeRaw as u8 }>;
121
122/// Poseidon2 is a cryptographic hash function that processes inputs in 2-field chunks.
123pub type HashManyPSD2<N> = HashInstruction<N, { HashVariant::HashManyPSD2 as u8 }>;
124/// Poseidon4 is a cryptographic hash function that processes inputs in 4-field chunks.
125pub type HashManyPSD4<N> = HashInstruction<N, { HashVariant::HashManyPSD4 as u8 }>;
126/// Poseidon8 is a cryptographic hash function that processes inputs in 8-field chunks.
127pub type HashManyPSD8<N> = HashInstruction<N, { HashVariant::HashManyPSD8 as u8 }>;
128
129/// Which hash function to use.
130#[derive(Debug, Copy, Clone, Eq, PartialEq, Sequence)]
131pub enum HashVariant {
132    HashBHP256,
133    HashBHP512,
134    HashBHP768,
135    HashBHP1024,
136    HashKeccak256,
137    HashKeccak384,
138    HashKeccak512,
139    HashPED64,
140    HashPED128,
141    HashPSD2,
142    HashPSD4,
143    HashPSD8,
144    HashSha3_256,
145    HashSha3_384,
146    HashSha3_512,
147    HashManyPSD2,
148    HashManyPSD4,
149    HashManyPSD8,
150    // The variants that hash the raw inputs.
151    HashBHP256Raw,
152    HashBHP512Raw,
153    HashBHP768Raw,
154    HashBHP1024Raw,
155    HashKeccak256Raw,
156    HashKeccak384Raw,
157    HashKeccak512Raw,
158    HashPED64Raw,
159    HashPED128Raw,
160    HashPSD2Raw,
161    HashPSD4Raw,
162    HashPSD8Raw,
163    HashSha3_256Raw,
164    HashSha3_384Raw,
165    HashSha3_512Raw,
166    // The variants that perform the underlying hash, returning bit arrays.
167    HashKeccak256Native,
168    HashKeccak256NativeRaw,
169    HashKeccak384Native,
170    HashKeccak384NativeRaw,
171    HashKeccak512Native,
172    HashKeccak512NativeRaw,
173    HashSha3_256Native,
174    HashSha3_256NativeRaw,
175    HashSha3_384Native,
176    HashSha3_384NativeRaw,
177    HashSha3_512Native,
178    HashSha3_512NativeRaw,
179}
180
181impl HashVariant {
182    // Initializes a new `HashVariant`.
183    pub const fn new(variant: u8) -> Self {
184        match variant {
185            0 => Self::HashBHP256,
186            1 => Self::HashBHP512,
187            2 => Self::HashBHP768,
188            3 => Self::HashBHP1024,
189            4 => Self::HashKeccak256,
190            5 => Self::HashKeccak384,
191            6 => Self::HashKeccak512,
192            7 => Self::HashPED64,
193            8 => Self::HashPED128,
194            9 => Self::HashPSD2,
195            10 => Self::HashPSD4,
196            11 => Self::HashPSD8,
197            12 => Self::HashSha3_256,
198            13 => Self::HashSha3_384,
199            14 => Self::HashSha3_512,
200            15 => Self::HashManyPSD2,
201            16 => Self::HashManyPSD4,
202            17 => Self::HashManyPSD8,
203            // The variants that hash the raw inputs.
204            18 => Self::HashBHP256Raw,
205            19 => Self::HashBHP512Raw,
206            20 => Self::HashBHP768Raw,
207            21 => Self::HashBHP1024Raw,
208            22 => Self::HashKeccak256Raw,
209            23 => Self::HashKeccak384Raw,
210            24 => Self::HashKeccak512Raw,
211            25 => Self::HashPED64Raw,
212            26 => Self::HashPED128Raw,
213            27 => Self::HashPSD2Raw,
214            28 => Self::HashPSD4Raw,
215            29 => Self::HashPSD8Raw,
216            30 => Self::HashSha3_256Raw,
217            31 => Self::HashSha3_384Raw,
218            32 => Self::HashSha3_512Raw,
219            // The variants that perform the underlying hash, returning bit arrays.
220            33 => Self::HashKeccak256Native,
221            34 => Self::HashKeccak256NativeRaw,
222            35 => Self::HashKeccak384Native,
223            36 => Self::HashKeccak384NativeRaw,
224            37 => Self::HashKeccak512Native,
225            38 => Self::HashKeccak512NativeRaw,
226            39 => Self::HashSha3_256Native,
227            40 => Self::HashSha3_256NativeRaw,
228            41 => Self::HashSha3_384Native,
229            42 => Self::HashSha3_384NativeRaw,
230            43 => Self::HashSha3_512Native,
231            44 => Self::HashSha3_512NativeRaw,
232            _ => panic!("Invalid 'hash' instruction opcode"),
233        }
234    }
235
236    // Returns the opcode associated with the variant.
237    pub const fn opcode(&self) -> &'static str {
238        match self {
239            Self::HashBHP256 => "hash.bhp256",
240            Self::HashBHP512 => "hash.bhp512",
241            Self::HashBHP768 => "hash.bhp768",
242            Self::HashBHP1024 => "hash.bhp1024",
243            Self::HashKeccak256 => "hash.keccak256",
244            Self::HashKeccak384 => "hash.keccak384",
245            Self::HashKeccak512 => "hash.keccak512",
246            Self::HashPED64 => "hash.ped64",
247            Self::HashPED128 => "hash.ped128",
248            Self::HashPSD2 => "hash.psd2",
249            Self::HashPSD4 => "hash.psd4",
250            Self::HashPSD8 => "hash.psd8",
251            Self::HashSha3_256 => "hash.sha3_256",
252            Self::HashSha3_384 => "hash.sha3_384",
253            Self::HashSha3_512 => "hash.sha3_512",
254            Self::HashManyPSD2 => "hash_many.psd2",
255            Self::HashManyPSD4 => "hash_many.psd4",
256            Self::HashManyPSD8 => "hash_many.psd8",
257            // The variants that hash the raw inputs.
258            Self::HashBHP256Raw => "hash.bhp256.raw",
259            Self::HashBHP512Raw => "hash.bhp512.raw",
260            Self::HashBHP768Raw => "hash.bhp768.raw",
261            Self::HashBHP1024Raw => "hash.bhp1024.raw",
262            Self::HashKeccak256Raw => "hash.keccak256.raw",
263            Self::HashKeccak384Raw => "hash.keccak384.raw",
264            Self::HashKeccak512Raw => "hash.keccak512.raw",
265            Self::HashPED64Raw => "hash.ped64.raw",
266            Self::HashPED128Raw => "hash.ped128.raw",
267            Self::HashPSD2Raw => "hash.psd2.raw",
268            Self::HashPSD4Raw => "hash.psd4.raw",
269            Self::HashPSD8Raw => "hash.psd8.raw",
270            Self::HashSha3_256Raw => "hash.sha3_256.raw",
271            Self::HashSha3_384Raw => "hash.sha3_384.raw",
272            Self::HashSha3_512Raw => "hash.sha3_512.raw",
273            // The variants that perform the underlying hash returning bit arrays.
274            Self::HashKeccak256Native => "hash.keccak256.native",
275            Self::HashKeccak256NativeRaw => "hash.keccak256.native.raw",
276            Self::HashKeccak384Native => "hash.keccak384.native",
277            Self::HashKeccak384NativeRaw => "hash.keccak384.native.raw",
278            Self::HashKeccak512Native => "hash.keccak512.native",
279            Self::HashKeccak512NativeRaw => "hash.keccak512.native.raw",
280            Self::HashSha3_256Native => "hash.sha3_256.native",
281            Self::HashSha3_256NativeRaw => "hash.sha3_256.native.raw",
282            Self::HashSha3_384Native => "hash.sha3_384.native",
283            Self::HashSha3_384NativeRaw => "hash.sha3_384.native.raw",
284            Self::HashSha3_512Native => "hash.sha3_512.native",
285            Self::HashSha3_512NativeRaw => "hash.sha3_512.native.raw",
286        }
287    }
288
289    // Returns true if the variant requires byte alignment.
290    pub const fn requires_byte_alignment(&self) -> bool {
291        match self {
292            Self::HashBHP256
293            | Self::HashBHP512
294            | Self::HashBHP768
295            | Self::HashBHP1024
296            | Self::HashKeccak256
297            | Self::HashKeccak384
298            | Self::HashKeccak512
299            | Self::HashPED64
300            | Self::HashPED128
301            | Self::HashPSD2
302            | Self::HashPSD4
303            | Self::HashPSD8
304            | Self::HashSha3_256
305            | Self::HashSha3_384
306            | Self::HashSha3_512
307            | Self::HashManyPSD2
308            | Self::HashManyPSD4
309            | Self::HashManyPSD8 => false,
310            // The variants that hash the raw inputs.
311            Self::HashBHP256Raw | Self::HashBHP512Raw | Self::HashBHP768Raw | Self::HashBHP1024Raw => false,
312            Self::HashKeccak256Raw | Self::HashKeccak384Raw | Self::HashKeccak512Raw => true,
313            Self::HashPED64Raw | Self::HashPED128Raw | Self::HashPSD2Raw | Self::HashPSD4Raw | Self::HashPSD8Raw => {
314                false
315            }
316            Self::HashSha3_256Raw | Self::HashSha3_384Raw | Self::HashSha3_512Raw => true,
317            // The variants that perform the underlying hash returning bit arrays.
318            Self::HashKeccak256Native
319            | Self::HashKeccak256NativeRaw
320            | Self::HashKeccak384Native
321            | Self::HashKeccak384NativeRaw
322            | Self::HashKeccak512Native
323            | Self::HashKeccak512NativeRaw
324            | Self::HashSha3_256Native
325            | Self::HashSha3_256NativeRaw
326            | Self::HashSha3_384Native
327            | Self::HashSha3_384NativeRaw
328            | Self::HashSha3_512Native
329            | Self::HashSha3_512NativeRaw => true,
330        }
331    }
332
333    // Returns `true` if the variant uses raw bits.
334    pub const fn is_raw(&self) -> bool {
335        match self {
336            Self::HashBHP256
337            | Self::HashBHP512
338            | Self::HashBHP768
339            | Self::HashBHP1024
340            | Self::HashKeccak256
341            | Self::HashKeccak384
342            | Self::HashKeccak512
343            | Self::HashPED64
344            | Self::HashPED128
345            | Self::HashPSD2
346            | Self::HashPSD4
347            | Self::HashPSD8
348            | Self::HashSha3_256
349            | Self::HashSha3_384
350            | Self::HashSha3_512
351            | Self::HashManyPSD2
352            | Self::HashManyPSD4
353            | Self::HashManyPSD8 => false,
354            // The variants that hash the raw inputs.
355            Self::HashBHP256Raw
356            | Self::HashBHP512Raw
357            | Self::HashBHP768Raw
358            | Self::HashBHP1024Raw
359            | Self::HashKeccak256Raw
360            | Self::HashKeccak384Raw
361            | Self::HashKeccak512Raw
362            | Self::HashPED64Raw
363            | Self::HashPED128Raw
364            | Self::HashPSD2Raw
365            | Self::HashPSD4Raw
366            | Self::HashPSD8Raw
367            | Self::HashSha3_256Raw
368            | Self::HashSha3_384Raw
369            | Self::HashSha3_512Raw => true,
370            // The variants that perform the underlying hash returning bit arrays.
371            Self::HashKeccak256Native
372            | Self::HashKeccak256NativeRaw
373            | Self::HashKeccak384Native
374            | Self::HashKeccak384NativeRaw
375            | Self::HashKeccak512Native
376            | Self::HashKeccak512NativeRaw
377            | Self::HashSha3_256Native
378            | Self::HashSha3_256NativeRaw
379            | Self::HashSha3_384Native
380            | Self::HashSha3_384NativeRaw
381            | Self::HashSha3_512Native
382            | Self::HashSha3_512NativeRaw => true,
383        }
384    }
385
386    /// Returns the expected number of operands given the variant.
387    pub const fn expected_num_operands(&self) -> usize {
388        match self {
389            Self::HashManyPSD2 | Self::HashManyPSD4 | Self::HashManyPSD8 => 2,
390            _ => 1,
391        }
392    }
393}
394
395/// Returns 'Ok(())' if the number of operands is correct.
396/// Otherwise, returns an error.
397fn check_number_of_operands(variant: u8, opcode: Opcode, num_operands: usize) -> Result<()> {
398    let variant = HashVariant::new(variant);
399    let expected = variant.expected_num_operands();
400    if expected != num_operands {
401        bail!("Instruction '{opcode}' expects {expected} operands, found {num_operands} operands")
402    }
403    Ok(())
404}
405
406/// Returns 'true' if the destination type is valid.
407fn is_valid_destination_type<N: Network>(variant: u8, destination_type: &PlaintextType<N>) -> bool {
408    match variant {
409        0..=32 => !matches!(
410            destination_type,
411            PlaintextType::Literal(LiteralType::Boolean)
412                | PlaintextType::Literal(LiteralType::String)
413                | PlaintextType::Struct(..)
414                | PlaintextType::ExternalStruct(..)
415                | PlaintextType::Array(..)
416        ),
417        33..=44 => matches!(destination_type, PlaintextType::Array(array_type) if array_type.is_bit_array()),
418        _ => panic!("Invalid 'hash' instruction opcode"),
419    }
420}
421
422/// Hashes the operand into the declared type.
423#[derive(Clone, PartialEq, Eq, Hash)]
424pub struct HashInstruction<N: Network, const VARIANT: u8> {
425    /// The operand as `input`.
426    operands: Vec<Operand<N>>,
427    /// The destination register.
428    destination: Register<N>,
429    /// The destination register type.
430    destination_type: PlaintextType<N>,
431}
432
433impl<N: Network, const VARIANT: u8> HashInstruction<N, VARIANT> {
434    /// Initializes a new `hash` instruction.
435    pub fn new(
436        operands: Vec<Operand<N>>,
437        destination: Register<N>,
438        destination_type: PlaintextType<N>,
439    ) -> Result<Self> {
440        // Sanity check the number of operands.
441        check_number_of_operands(VARIANT, Self::opcode(), operands.len())?;
442        // Sanity check the destination type.
443        if !is_valid_destination_type(VARIANT, &destination_type) {
444            bail!("Invalid destination type for 'hash' instruction")
445        }
446        // Return the instruction.
447        Ok(Self { operands, destination, destination_type })
448    }
449
450    /// Returns the opcode.
451    pub const fn opcode() -> Opcode {
452        Opcode::Hash(HashVariant::new(VARIANT).opcode())
453    }
454
455    /// Returns the operands in the operation.
456    pub fn operands(&self) -> &[Operand<N>] {
457        // Sanity check that the operands is the correct length.
458        debug_assert!(
459            check_number_of_operands(VARIANT, Self::opcode(), self.operands.len()).is_ok(),
460            "Invalid number of operands for '{}'",
461            Self::opcode()
462        );
463        // Return the operand.
464        &self.operands
465    }
466
467    /// Returns the destination register.
468    #[inline]
469    pub fn destinations(&self) -> Vec<Register<N>> {
470        vec![self.destination.clone()]
471    }
472
473    /// Returns the destination register type.
474    #[inline]
475    pub const fn destination_type(&self) -> &PlaintextType<N> {
476        &self.destination_type
477    }
478
479    /// Returns whether this instruction refers to an external struct.
480    #[inline]
481    pub fn contains_external_struct(&self) -> bool {
482        self.destination_type.contains_external_struct()
483    }
484}
485
486// This code is nearly identical in `execute` and `evaluate`; we
487// extract it here in a macro.
488//
489// The `$q` parameter allows us to wrap a value in `Result::Ok`, since
490// the `Aleo` functions don't return a `Result` but the `Network` ones do.
491#[rustfmt::skip]
492macro_rules! do_hash {
493    ($N: ident, $variant: expr, $destination_type: expr, $input: expr, $pt: ty, $lt: ty, $q: expr) => {{
494        let bits = || $input.to_bits_le();
495        let bits_raw = || $input.to_bits_raw_le();
496
497        let fields = || $q($input.to_fields());
498        let fields_raw = || $q($input.to_fields_raw());
499
500        let check_multiple_of_8 = |bits: Vec<_>| -> Result<Vec<_>> {
501            ensure!(bits.len() % 8 == 0, "The opcode '{}' expects input whose size in bits is a multiple of 8.", $variant.opcode());
502            Ok(bits)
503        };
504
505        match ($variant, $destination_type) {
506            (HashVariant::HashBHP256,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp256(&bits()))?).cast_lossy(*literal_type)?),
507            (HashVariant::HashBHP512,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&bits()))?).cast_lossy(*literal_type)?),
508            (HashVariant::HashBHP768,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp768(&bits()))?).cast_lossy(*literal_type)?),
509            (HashVariant::HashBHP1024,   PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp1024(&bits()))?).cast_lossy(*literal_type)?),
510            (HashVariant::HashKeccak256, PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp256(&$q($N::hash_keccak256(&bits()))?))?).cast_lossy(*literal_type)?),
511            (HashVariant::HashKeccak384, PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&$q($N::hash_keccak384(&bits()))?))?).cast_lossy(*literal_type)?),
512            (HashVariant::HashKeccak512, PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&$q($N::hash_keccak512(&bits()))?))?).cast_lossy(*literal_type)?),
513            (HashVariant::HashPED64,     PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_ped64(&bits()))?).cast_lossy(*literal_type)?),
514            (HashVariant::HashPED128,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_ped128(&bits()))?).cast_lossy(*literal_type)?),
515            (HashVariant::HashPSD2,      PlaintextType::Literal(literal_type @ LiteralType::Address) | PlaintextType::Literal(literal_type @ LiteralType::Group)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_psd2(&fields()?))?).cast_lossy(*literal_type)?),
516            (HashVariant::HashPSD2,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd2(&fields()?))?).cast_lossy(*literal_type)?),
517            (HashVariant::HashPSD4,      PlaintextType::Literal(literal_type @ LiteralType::Address) | PlaintextType::Literal(literal_type @ LiteralType::Group)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_psd4(&fields()?))?).cast_lossy(*literal_type)?),
518            (HashVariant::HashPSD4,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd4(&fields()?))?).cast_lossy(*literal_type)?),
519            (HashVariant::HashPSD8,      PlaintextType::Literal(literal_type @ LiteralType::Address) | PlaintextType::Literal(literal_type @ LiteralType::Group)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_psd8(&fields()?))?).cast_lossy(*literal_type)?),
520            (HashVariant::HashPSD8,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd8(&fields()?))?).cast_lossy(*literal_type)?),
521            (HashVariant::HashSha3_256,  PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp256(&$q($N::hash_sha3_256(&bits()))?))?).cast_lossy(*literal_type)?),
522            (HashVariant::HashSha3_384,  PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&$q($N::hash_sha3_384(&bits()))?))?).cast_lossy(*literal_type)?),
523            (HashVariant::HashSha3_512,  PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&$q($N::hash_sha3_512(&bits()))?))?).cast_lossy(*literal_type)?),
524            (HashVariant::HashManyPSD2,  PlaintextType::Literal(_)) => bail!("'hash_many.psd2' is not yet implemented"),
525            (HashVariant::HashManyPSD4,  PlaintextType::Literal(_)) => bail!("'hash_many.psd4' is not yet implemented"),
526            (HashVariant::HashManyPSD8,  PlaintextType::Literal(_)) => bail!("'hash_many.psd8' is not yet implemented"),
527
528            // The variants that hash the raw inputs.
529            (HashVariant::HashBHP256Raw,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp256(&bits_raw()))?).cast_lossy(*literal_type)?),
530            (HashVariant::HashBHP512Raw,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&bits_raw()))?).cast_lossy(*literal_type)?),
531            (HashVariant::HashBHP768Raw,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp768(&bits_raw()))?).cast_lossy(*literal_type)?),
532            (HashVariant::HashBHP1024Raw,   PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp1024(&bits_raw()))?).cast_lossy(*literal_type)?),
533            (HashVariant::HashKeccak256Raw, PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp256(&$q($N::hash_keccak256(&check_multiple_of_8(bits_raw())?))?))?).cast_lossy(*literal_type)?),
534            (HashVariant::HashKeccak384Raw, PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&$q($N::hash_keccak384(&check_multiple_of_8(bits_raw())?))?))?).cast_lossy(*literal_type)?),
535            (HashVariant::HashKeccak512Raw, PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&$q($N::hash_keccak512(&check_multiple_of_8(bits_raw())?))?))?).cast_lossy(*literal_type)?),
536            (HashVariant::HashPED64Raw,     PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_ped64(&bits_raw()))?).cast_lossy(*literal_type)?),
537            (HashVariant::HashPED128Raw,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_ped128(&bits_raw()))?).cast_lossy(*literal_type)?),
538            (HashVariant::HashPSD2Raw,      PlaintextType::Literal(literal_type @ LiteralType::Address) | PlaintextType::Literal(literal_type @ LiteralType::Group)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_psd2(&fields_raw()?))?).cast_lossy(*literal_type)?),
539            (HashVariant::HashPSD2Raw,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd2(&fields_raw()?))?).cast_lossy(*literal_type)?),
540            (HashVariant::HashPSD4Raw,      PlaintextType::Literal(literal_type @ LiteralType::Address) | PlaintextType::Literal(literal_type @ LiteralType::Group)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_psd4(&fields_raw()?))?).cast_lossy(*literal_type)?),
541            (HashVariant::HashPSD4Raw,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd4(&fields_raw()?))?).cast_lossy(*literal_type)?),
542            (HashVariant::HashPSD8Raw,      PlaintextType::Literal(literal_type @ LiteralType::Address) | PlaintextType::Literal(literal_type @ LiteralType::Group)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_psd8(&fields_raw()?))?).cast_lossy(*literal_type)?),
543            (HashVariant::HashPSD8Raw,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd8(&fields_raw()?))?).cast_lossy(*literal_type)?),
544            (HashVariant::HashSha3_256Raw,  PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp256(&$q($N::hash_sha3_256(&check_multiple_of_8(bits_raw())?))?))?).cast_lossy(*literal_type)?),
545            (HashVariant::HashSha3_384Raw,  PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&$q($N::hash_sha3_384(&check_multiple_of_8(bits_raw())?))?))?).cast_lossy(*literal_type)?),
546            (HashVariant::HashSha3_512Raw,  PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&$q($N::hash_sha3_512(&check_multiple_of_8(bits_raw())?))?))?).cast_lossy(*literal_type)?),
547
548            // The variants that perform the underlying hash, returning bit arrays.
549            (HashVariant::HashKeccak256Native,    PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak256(&bits()))?, **array_type.length())?,
550            (HashVariant::HashKeccak256NativeRaw, PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak256(&check_multiple_of_8(bits_raw())?))?, **array_type.length())?,
551            (HashVariant::HashKeccak384Native,    PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak384(&bits()))?, **array_type.length())?,
552            (HashVariant::HashKeccak384NativeRaw, PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak384(&check_multiple_of_8(bits_raw())?))?, **array_type.length())?,
553            (HashVariant::HashKeccak512Native,    PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak512(&bits()))?, **array_type.length())?,
554            (HashVariant::HashKeccak512NativeRaw, PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak512(&check_multiple_of_8(bits_raw())?))?, **array_type.length())?,
555            (HashVariant::HashSha3_256Native,     PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_sha3_256(&bits()))?, **array_type.length())?,
556            (HashVariant::HashSha3_256NativeRaw,  PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_sha3_256(&check_multiple_of_8(bits_raw())?))?, **array_type.length())?,
557            (HashVariant::HashSha3_384Native,     PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_sha3_384(&bits()))?, **array_type.length())?,
558            (HashVariant::HashSha3_384NativeRaw,  PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_sha3_384(&check_multiple_of_8(bits_raw())?))?, **array_type.length())?,
559            (HashVariant::HashSha3_512Native,     PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_sha3_512(&bits()))?, **array_type.length())?,
560            (HashVariant::HashSha3_512NativeRaw,  PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_sha3_512(&check_multiple_of_8(bits_raw())?))?, **array_type.length())?,
561            (_, destination_type) => bail!("Invalid destination type '{destination_type}' for 'hash' variant: {}", $variant.opcode()),
562        }
563    }};
564}
565
566/// Evaluate a hash operation.
567///
568/// This allows running the hash without the machinery of stacks and registers.
569/// This is necessary for the Leo interpreter.
570pub fn evaluate_hash<N: Network>(
571    variant: HashVariant,
572    input: &Value<N>,
573    destination_type: &PlaintextType<N>,
574) -> Result<Plaintext<N>> {
575    evaluate_hash_internal(variant, input, destination_type)
576}
577
578fn evaluate_hash_internal<N: Network>(
579    variant: HashVariant,
580    input: &Value<N>,
581    destination_type: &PlaintextType<N>,
582) -> Result<Plaintext<N>> {
583    Ok(do_hash!(N, variant, destination_type, input, Plaintext::<N>, Literal::<N>, |x| x))
584}
585
586impl<N: Network, const VARIANT: u8> HashInstruction<N, VARIANT> {
587    /// Evaluates the instruction.
588    pub fn evaluate(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersTrait<N>) -> Result<()> {
589        // Ensure the number of operands is correct.
590        check_number_of_operands(VARIANT, Self::opcode(), self.operands.len())?;
591        // Ensure the destination type is valid.
592        ensure!(
593            is_valid_destination_type(VARIANT, &self.destination_type),
594            "Invalid destination type in 'hash' instruction"
595        );
596
597        // Load the operand.
598        let input = registers.load(stack, &self.operands[0])?;
599
600        // Compute the output.
601        let output = evaluate_hash_internal(HashVariant::new(VARIANT), &input, &self.destination_type)?;
602
603        // Store the output.
604        registers.store(stack, &self.destination, Value::Plaintext(output))
605    }
606
607    /// Executes the instruction.
608    pub fn execute<A: circuit::Aleo<Network = N>>(
609        &self,
610        stack: &impl StackTrait<N>,
611        registers: &mut impl RegistersCircuit<N, A>,
612    ) -> Result<()> {
613        use circuit::traits::{ToBits, ToBitsRaw, ToFields, ToFieldsRaw};
614
615        // Ensure the number of operands is correct.
616        check_number_of_operands(VARIANT, Self::opcode(), self.operands.len())?;
617        // Ensure the destination type is valid.
618        ensure!(
619            is_valid_destination_type(VARIANT, &self.destination_type),
620            "Invalid destination type in 'hash' instruction"
621        );
622
623        // Load the operand.
624        let input = registers.load_circuit(stack, &self.operands[0])?;
625
626        // Compute the output.
627        let output = do_hash!(
628            A,
629            HashVariant::new(VARIANT),
630            &self.destination_type,
631            input,
632            circuit::Plaintext::<A>,
633            circuit::Literal::<A>,
634            Result::<_>::Ok
635        );
636
637        // Store the output.
638        registers.store_circuit(stack, &self.destination, circuit::Value::Plaintext(output))
639    }
640
641    /// Finalizes the instruction.
642    #[inline]
643    pub fn finalize(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersTrait<N>) -> Result<()> {
644        self.evaluate(stack, registers)
645    }
646
647    /// Returns the output type from the given program and input types.
648    pub fn output_types(
649        &self,
650        stack: &impl StackTrait<N>,
651        input_types: &[RegisterType<N>],
652    ) -> Result<Vec<RegisterType<N>>> {
653        // Ensure the number of input types is correct.
654        check_number_of_operands(VARIANT, Self::opcode(), input_types.len())?;
655        // Ensure the number of operands is correct.
656        check_number_of_operands(VARIANT, Self::opcode(), self.operands.len())?;
657        // Ensure the destination type is valid.
658        ensure!(
659            is_valid_destination_type(VARIANT, &self.destination_type),
660            "Invalid destination type in 'hash' instruction"
661        );
662
663        // Get the variant.
664        let variant = HashVariant::new(VARIANT);
665
666        // If the variant needs to be byte aligned, check that its size in bits is a multiple of 8.
667        if variant.requires_byte_alignment() {
668            // Check that there is only one operand type.
669            ensure!(
670                variant.expected_num_operands() == 1,
671                "Expected one operand for '{}', found '{}'",
672                variant.opcode(),
673                variant.expected_num_operands()
674            );
675
676            // A helper to get a struct declaration.
677            let get_struct = |identifier: &Identifier<N>| stack.program().get_struct(identifier).cloned();
678
679            // A helper to get an external struct declaration.
680            let get_external_struct = |locator: &Locator<N>| {
681                stack.get_external_stack(locator.program_id())?.program().get_struct(locator.resource()).cloned()
682            };
683
684            // A helper to get a record declaration.
685            let get_record = |identifier: &Identifier<N>| stack.program().get_record(identifier).cloned();
686
687            // A helper to get an external record declaration.
688            let get_external_record = |locator: &Locator<N>| {
689                stack.get_external_stack(locator.program_id())?.program().get_record(locator.resource()).cloned()
690            };
691
692            // A helper to get the argument types of a future.
693            let get_future = |locator: &Locator<N>| {
694                Ok(match stack.program_id() == locator.program_id() {
695                    true => stack
696                        .program()
697                        .get_function_ref(locator.resource())?
698                        .finalize_logic()
699                        .ok_or_else(|| anyhow!("'{locator}' does not have a finalize scope"))?
700                        .input_types(),
701                    false => stack
702                        .get_external_stack(locator.program_id())?
703                        .program()
704                        .get_function_ref(locator.resource())?
705                        .finalize_logic()
706                        .ok_or_else(|| anyhow!("Failed to find function '{locator}'"))?
707                        .input_types(),
708                })
709            };
710
711            // Get the size in bits.
712            let size_in_bits = match variant.is_raw() {
713                false => input_types[0].size_in_bits(
714                    &get_struct,
715                    &get_external_struct,
716                    &get_record,
717                    &get_external_record,
718                    &get_future,
719                )?,
720                true => input_types[0].size_in_bits_raw(
721                    &get_struct,
722                    &get_external_struct,
723                    &get_record,
724                    &get_external_record,
725                    &get_future,
726                )?,
727            };
728            // Check the number of bits.
729            ensure!(
730                size_in_bits % 8 == 0,
731                "Expected a multiple of 8 bits for '{}', found '{size_in_bits}'",
732                variant.opcode()
733            );
734        }
735
736        // TODO (howardwu): If the operation is Pedersen, check that it is within the number of bits.
737
738        match variant {
739            HashVariant::HashManyPSD2 | HashVariant::HashManyPSD4 | HashVariant::HashManyPSD8 => {
740                bail!("'hash_many' is not yet implemented")
741            }
742            _ => Ok(vec![RegisterType::Plaintext(self.destination_type.clone())]),
743        }
744    }
745}
746
747impl<N: Network, const VARIANT: u8> Parser for HashInstruction<N, VARIANT> {
748    /// Parses a string into an operation.
749    fn parse(string: &str) -> ParserResult<Self> {
750        /// Parse the operands from the string.
751        fn parse_operands<N: Network>(string: &str, num_operands: usize) -> ParserResult<Vec<Operand<N>>> {
752            let mut operands = Vec::with_capacity(num_operands);
753            let mut string = string;
754
755            for _ in 0..num_operands {
756                // Parse the whitespace from the string.
757                let (next_string, _) = Sanitizer::parse_whitespaces(string)?;
758                // Parse the operand from the string.
759                let (next_string, operand) = Operand::parse(next_string)?;
760                // Update the string.
761                string = next_string;
762                // Push the operand.
763                operands.push(operand);
764            }
765
766            Ok((string, operands))
767        }
768
769        // Parse the opcode from the string.
770        let (string, _) = tag(*Self::opcode())(string)?;
771        // Parse the operands from the string.
772        let (string, operands) = parse_operands(string, HashVariant::new(VARIANT).expected_num_operands())?;
773        // Parse the whitespace from the string.
774        let (string, _) = Sanitizer::parse_whitespaces(string)?;
775        // Parse the "into" from the string.
776        let (string, _) = tag("into")(string)?;
777        // Parse the whitespace from the string.
778        let (string, _) = Sanitizer::parse_whitespaces(string)?;
779        // Parse the destination register from the string.
780        let (string, destination) = Register::parse(string)?;
781        // Parse the whitespace from the string.
782        let (string, _) = Sanitizer::parse_whitespaces(string)?;
783        // Parse the "as" from the string.
784        let (string, _) = tag("as")(string)?;
785        // Parse the whitespace from the string.
786        let (string, _) = Sanitizer::parse_whitespaces(string)?;
787        // Parse the destination register type from the string.
788        let (string, destination_type) = PlaintextType::parse(string)?;
789        // Ensure the destination type is allowed.
790        match destination_type {
791            PlaintextType::Literal(LiteralType::Boolean) | PlaintextType::Literal(LiteralType::String) => {
792                map_res(fail, |_: ParserResult<Self>| {
793                    Err(error(format!("Failed to parse 'hash': '{destination_type}' is invalid")))
794                })(string)
795            }
796            _ => Ok((string, Self { operands, destination, destination_type })),
797        }
798    }
799}
800
801impl<N: Network, const VARIANT: u8> FromStr for HashInstruction<N, VARIANT> {
802    type Err = Error;
803
804    /// Parses a string into an operation.
805    fn from_str(string: &str) -> Result<Self> {
806        match Self::parse(string) {
807            Ok((remainder, object)) => {
808                // Ensure the remainder is empty.
809                ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
810                // Return the object.
811                Ok(object)
812            }
813            Err(error) => bail!("Failed to parse string. {error}"),
814        }
815    }
816}
817
818impl<N: Network, const VARIANT: u8> Debug for HashInstruction<N, VARIANT> {
819    /// Prints the operation as a string.
820    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
821        Display::fmt(self, f)
822    }
823}
824
825impl<N: Network, const VARIANT: u8> Display for HashInstruction<N, VARIANT> {
826    /// Prints the operation to a string.
827    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
828        // Ensure the number of operands is correct.
829        check_number_of_operands(VARIANT, Self::opcode(), self.operands.len()).map_err(|_| fmt::Error)?;
830        // Print the operation.
831        write!(f, "{} ", Self::opcode())?;
832        self.operands.iter().try_for_each(|operand| write!(f, "{operand} "))?;
833        write!(f, "into {} as {}", self.destination, self.destination_type)
834    }
835}
836
837impl<N: Network, const VARIANT: u8> FromBytes for HashInstruction<N, VARIANT> {
838    /// Reads the operation from a buffer.
839    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
840        // Prepare the number of operands.
841        let num_operands = HashVariant::new(VARIANT).expected_num_operands();
842        // Read the operands.
843        let operands = (0..num_operands).map(|_| Operand::read_le(&mut reader)).collect::<Result<_, _>>()?;
844        // Read the destination register.
845        let destination = Register::read_le(&mut reader)?;
846        // Read the destination register type.
847        let destination_type = PlaintextType::read_le(&mut reader)?;
848        // Return the operation.
849        Ok(Self { operands, destination, destination_type })
850    }
851}
852
853impl<N: Network, const VARIANT: u8> ToBytes for HashInstruction<N, VARIANT> {
854    /// Writes the operation to a buffer.
855    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
856        // Ensure the number of operands is correct.
857        check_number_of_operands(VARIANT, Self::opcode(), self.operands.len()).map_err(|e| error(format!("{e}")))?;
858        // Write the operands.
859        self.operands.iter().try_for_each(|operand| operand.write_le(&mut writer))?;
860        // Write the destination register.
861        self.destination.write_le(&mut writer)?;
862        // Write the destination register type.
863        self.destination_type.write_le(&mut writer)
864    }
865}
866
867#[cfg(test)]
868mod tests {
869    use super::*;
870    use console::{network::MainnetV0, program::ArrayType, types::U32};
871
872    type CurrentNetwork = MainnetV0;
873
874    /// **Attention**: When changing this, also update in `tests/instruction/hash.rs`.
875    fn sample_valid_destination_types<N: Network, R: CryptoRng + Rng>(
876        variant: u8,
877        rng: &mut R,
878    ) -> Vec<PlaintextType<N>> {
879        match variant {
880            0..=32 => vec![
881                PlaintextType::Literal(LiteralType::Address),
882                PlaintextType::Literal(LiteralType::Field),
883                PlaintextType::Literal(LiteralType::Group),
884                PlaintextType::Literal(LiteralType::I8),
885                PlaintextType::Literal(LiteralType::I16),
886                PlaintextType::Literal(LiteralType::I32),
887                PlaintextType::Literal(LiteralType::I64),
888                PlaintextType::Literal(LiteralType::I128),
889                PlaintextType::Literal(LiteralType::U8),
890                PlaintextType::Literal(LiteralType::U16),
891                PlaintextType::Literal(LiteralType::U32),
892                PlaintextType::Literal(LiteralType::U64),
893                PlaintextType::Literal(LiteralType::U128),
894                PlaintextType::Literal(LiteralType::Scalar),
895            ],
896            33..=44 => (0..10)
897                .map(|_| {
898                    PlaintextType::Array(
899                        ArrayType::new(PlaintextType::Literal(LiteralType::Boolean), vec![U32::new(
900                            u32::try_from(rng.gen_range(1..=CurrentNetwork::MAX_ARRAY_ELEMENTS)).unwrap(),
901                        )])
902                        .unwrap(),
903                    )
904                })
905                .collect(),
906            _ => panic!("Invalid 'hash' instruction opcode"),
907        }
908    }
909
910    // A helper function to run a test.
911    fn run_test<N: Network, const VARIANT: u8>() {
912        // Initialize the RNG.
913        let rng = &mut TestRng::default();
914
915        // Get the opcode.
916        let opcode = HashInstruction::<N, VARIANT>::opcode();
917
918        for destination_type in sample_valid_destination_types(VARIANT, rng) {
919            let instruction = format!("{opcode} r0 into r1 as {destination_type}");
920            println!("Testing instruction: '{instruction}'");
921
922            let (string, hash) = HashInstruction::<CurrentNetwork, VARIANT>::parse(&instruction).unwrap();
923            assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
924            assert_eq!(hash.operands.len(), 1, "The number of operands is incorrect");
925            assert_eq!(hash.operands[0], Operand::Register(Register::Locator(0)), "The first operand is incorrect");
926            assert_eq!(hash.destination, Register::Locator(1), "The destination register is incorrect");
927            assert_eq!(&hash.destination_type, &destination_type, "The destination type is incorrect");
928        }
929    }
930
931    #[test]
932    fn test_parse() {
933        run_test::<CurrentNetwork, { HashVariant::HashBHP256 as u8 }>();
934        run_test::<CurrentNetwork, { HashVariant::HashBHP512 as u8 }>();
935        run_test::<CurrentNetwork, { HashVariant::HashBHP768 as u8 }>();
936        run_test::<CurrentNetwork, { HashVariant::HashBHP1024 as u8 }>();
937
938        run_test::<CurrentNetwork, { HashVariant::HashKeccak256 as u8 }>();
939        run_test::<CurrentNetwork, { HashVariant::HashKeccak384 as u8 }>();
940        run_test::<CurrentNetwork, { HashVariant::HashKeccak512 as u8 }>();
941
942        run_test::<CurrentNetwork, { HashVariant::HashPED64 as u8 }>();
943        run_test::<CurrentNetwork, { HashVariant::HashPED128 as u8 }>();
944
945        run_test::<CurrentNetwork, { HashVariant::HashPSD2 as u8 }>();
946        run_test::<CurrentNetwork, { HashVariant::HashPSD4 as u8 }>();
947        run_test::<CurrentNetwork, { HashVariant::HashPSD8 as u8 }>();
948
949        run_test::<CurrentNetwork, { HashVariant::HashSha3_256 as u8 }>();
950        run_test::<CurrentNetwork, { HashVariant::HashSha3_384 as u8 }>();
951        run_test::<CurrentNetwork, { HashVariant::HashSha3_512 as u8 }>();
952
953        // Note: `run_test` needs to be updated when `hash_many` is implemented.
954        //run_test::<CurrentNetwork, { HashVariant::HashManyPSD2 as u8 }>();
955        //run_test::<CurrentNetwork, { HashVariant::HashManyPSD4 as u8 }>();
956        //run_test::<CurrentNetwork, { HashVariant::HashManyPSD8 as u8 }>();
957
958        run_test::<CurrentNetwork, { HashVariant::HashBHP256Raw as u8 }>();
959        run_test::<CurrentNetwork, { HashVariant::HashBHP512Raw as u8 }>();
960        run_test::<CurrentNetwork, { HashVariant::HashBHP768Raw as u8 }>();
961        run_test::<CurrentNetwork, { HashVariant::HashBHP1024Raw as u8 }>();
962
963        run_test::<CurrentNetwork, { HashVariant::HashKeccak256Raw as u8 }>();
964        run_test::<CurrentNetwork, { HashVariant::HashKeccak384Raw as u8 }>();
965        run_test::<CurrentNetwork, { HashVariant::HashKeccak512Raw as u8 }>();
966
967        run_test::<CurrentNetwork, { HashVariant::HashPED64Raw as u8 }>();
968        run_test::<CurrentNetwork, { HashVariant::HashPED128Raw as u8 }>();
969
970        run_test::<CurrentNetwork, { HashVariant::HashPSD2Raw as u8 }>();
971        run_test::<CurrentNetwork, { HashVariant::HashPSD4Raw as u8 }>();
972        run_test::<CurrentNetwork, { HashVariant::HashPSD8Raw as u8 }>();
973
974        run_test::<CurrentNetwork, { HashVariant::HashSha3_256Raw as u8 }>();
975        run_test::<CurrentNetwork, { HashVariant::HashSha3_384Raw as u8 }>();
976        run_test::<CurrentNetwork, { HashVariant::HashSha3_512Raw as u8 }>();
977
978        run_test::<CurrentNetwork, { HashVariant::HashKeccak256Native as u8 }>();
979        run_test::<CurrentNetwork, { HashVariant::HashKeccak384Native as u8 }>();
980        run_test::<CurrentNetwork, { HashVariant::HashKeccak512Native as u8 }>();
981
982        run_test::<CurrentNetwork, { HashVariant::HashSha3_256Native as u8 }>();
983        run_test::<CurrentNetwork, { HashVariant::HashSha3_384Native as u8 }>();
984        run_test::<CurrentNetwork, { HashVariant::HashSha3_512Native as u8 }>();
985
986        run_test::<CurrentNetwork, { HashVariant::HashKeccak256NativeRaw as u8 }>();
987        run_test::<CurrentNetwork, { HashVariant::HashKeccak384NativeRaw as u8 }>();
988        run_test::<CurrentNetwork, { HashVariant::HashKeccak512NativeRaw as u8 }>();
989
990        run_test::<CurrentNetwork, { HashVariant::HashSha3_256NativeRaw as u8 }>();
991        run_test::<CurrentNetwork, { HashVariant::HashSha3_384NativeRaw as u8 }>();
992        run_test::<CurrentNetwork, { HashVariant::HashSha3_512NativeRaw as u8 }>();
993    }
994
995    #[test]
996    fn check_number_of_hash_variants() {
997        assert_eq!(enum_iterator::cardinality::<HashVariant>(), 45);
998    }
999
1000    #[test]
1001    fn check_byte_aligned_variants_all_have_one_opcode() {
1002        for variant in enum_iterator::all::<HashVariant>() {
1003            if variant.requires_byte_alignment() {
1004                assert_eq!(variant.expected_num_operands(), 1)
1005            }
1006        }
1007    }
1008}