Skip to main content

snarkvm_synthesizer_program/logic/instruction/operation/
hash.rs

1// Copyright (c) 2019-2026 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::Literal(LiteralType::Identifier)
414                | PlaintextType::Struct(..)
415                | PlaintextType::ExternalStruct(..)
416                | PlaintextType::Array(..)
417        ),
418        33..=44 => matches!(destination_type, PlaintextType::Array(array_type) if array_type.is_bit_array()),
419        _ => panic!("Invalid 'hash' instruction opcode"),
420    }
421}
422
423/// Hashes the operand into the declared type.
424#[derive(Clone, PartialEq, Eq, Hash)]
425pub struct HashInstruction<N: Network, const VARIANT: u8> {
426    /// The operand as `input`.
427    operands: Vec<Operand<N>>,
428    /// The destination register.
429    destination: Register<N>,
430    /// The destination register type.
431    destination_type: PlaintextType<N>,
432}
433
434impl<N: Network, const VARIANT: u8> HashInstruction<N, VARIANT> {
435    /// Initializes a new `hash` instruction.
436    pub fn new(
437        operands: Vec<Operand<N>>,
438        destination: Register<N>,
439        destination_type: PlaintextType<N>,
440    ) -> Result<Self> {
441        // Sanity check the number of operands.
442        check_number_of_operands(VARIANT, Self::opcode(), operands.len())?;
443        // Sanity check the destination type.
444        if !is_valid_destination_type(VARIANT, &destination_type) {
445            bail!("Invalid destination type for 'hash' instruction")
446        }
447        // Return the instruction.
448        Ok(Self { operands, destination, destination_type })
449    }
450
451    /// Returns the opcode.
452    pub const fn opcode() -> Opcode {
453        Opcode::Hash(HashVariant::new(VARIANT).opcode())
454    }
455
456    /// Returns the operands in the operation.
457    pub fn operands(&self) -> &[Operand<N>] {
458        // Sanity check that the operands is the correct length.
459        debug_assert!(
460            check_number_of_operands(VARIANT, Self::opcode(), self.operands.len()).is_ok(),
461            "Invalid number of operands for '{}'",
462            Self::opcode()
463        );
464        // Return the operand.
465        &self.operands
466    }
467
468    /// Returns the destination register.
469    #[inline]
470    pub fn destinations(&self) -> Vec<Register<N>> {
471        vec![self.destination.clone()]
472    }
473
474    /// Returns the destination register type.
475    #[inline]
476    pub const fn destination_type(&self) -> &PlaintextType<N> {
477        &self.destination_type
478    }
479
480    /// Returns whether this instruction refers to an external struct.
481    #[inline]
482    pub fn contains_external_struct(&self) -> bool {
483        self.destination_type.contains_external_struct()
484    }
485}
486
487// This code is nearly identical in `execute` and `evaluate`; we
488// extract it here in a macro.
489//
490// The `$q` parameter allows us to wrap a value in `Result::Ok`, since
491// the `Aleo` functions don't return a `Result` but the `Network` ones do.
492#[rustfmt::skip]
493macro_rules! do_hash {
494    ($N: ident, $variant: expr, $destination_type: expr, $input: expr, $pt: ty, $lt: ty, $q: expr) => {{
495        let bits = || $input.to_bits_le();
496        let bits_raw = || $input.to_bits_raw_le();
497
498        let fields = || $q($input.to_fields());
499        let fields_raw = || $q($input.to_fields_raw());
500
501        let check_multiple_of_8 = |bits: Vec<_>| -> Result<Vec<_>> {
502            ensure!(bits.len() % 8 == 0, "The opcode '{}' expects input whose size in bits is a multiple of 8.", $variant.opcode());
503            Ok(bits)
504        };
505
506        match ($variant, $destination_type) {
507            (HashVariant::HashBHP256,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp256(&bits()))?).cast_lossy(*literal_type)?),
508            (HashVariant::HashBHP512,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&bits()))?).cast_lossy(*literal_type)?),
509            (HashVariant::HashBHP768,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp768(&bits()))?).cast_lossy(*literal_type)?),
510            (HashVariant::HashBHP1024,   PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp1024(&bits()))?).cast_lossy(*literal_type)?),
511            (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)?),
512            (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)?),
513            (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)?),
514            (HashVariant::HashPED64,     PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_ped64(&bits()))?).cast_lossy(*literal_type)?),
515            (HashVariant::HashPED128,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_ped128(&bits()))?).cast_lossy(*literal_type)?),
516            (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)?),
517            (HashVariant::HashPSD2,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd2(&fields()?))?).cast_lossy(*literal_type)?),
518            (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)?),
519            (HashVariant::HashPSD4,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd4(&fields()?))?).cast_lossy(*literal_type)?),
520            (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)?),
521            (HashVariant::HashPSD8,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd8(&fields()?))?).cast_lossy(*literal_type)?),
522            (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)?),
523            (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)?),
524            (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)?),
525            (HashVariant::HashManyPSD2,  PlaintextType::Literal(_)) => bail!("'hash_many.psd2' is not yet implemented"),
526            (HashVariant::HashManyPSD4,  PlaintextType::Literal(_)) => bail!("'hash_many.psd4' is not yet implemented"),
527            (HashVariant::HashManyPSD8,  PlaintextType::Literal(_)) => bail!("'hash_many.psd8' is not yet implemented"),
528
529            // The variants that hash the raw inputs.
530            (HashVariant::HashBHP256Raw,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp256(&bits_raw()))?).cast_lossy(*literal_type)?),
531            (HashVariant::HashBHP512Raw,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&bits_raw()))?).cast_lossy(*literal_type)?),
532            (HashVariant::HashBHP768Raw,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp768(&bits_raw()))?).cast_lossy(*literal_type)?),
533            (HashVariant::HashBHP1024Raw,   PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp1024(&bits_raw()))?).cast_lossy(*literal_type)?),
534            (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)?),
535            (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)?),
536            (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)?),
537            (HashVariant::HashPED64Raw,     PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_ped64(&bits_raw()))?).cast_lossy(*literal_type)?),
538            (HashVariant::HashPED128Raw,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_ped128(&bits_raw()))?).cast_lossy(*literal_type)?),
539            (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)?),
540            (HashVariant::HashPSD2Raw,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd2(&fields_raw()?))?).cast_lossy(*literal_type)?),
541            (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)?),
542            (HashVariant::HashPSD4Raw,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd4(&fields_raw()?))?).cast_lossy(*literal_type)?),
543            (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)?),
544            (HashVariant::HashPSD8Raw,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd8(&fields_raw()?))?).cast_lossy(*literal_type)?),
545            (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)?),
546            (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)?),
547            (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)?),
548
549            // The variants that perform the underlying hash, returning bit arrays.
550            (HashVariant::HashKeccak256Native,    PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak256(&bits()))?, **array_type.length())?,
551            (HashVariant::HashKeccak256NativeRaw, PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak256(&check_multiple_of_8(bits_raw())?))?, **array_type.length())?,
552            (HashVariant::HashKeccak384Native,    PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak384(&bits()))?, **array_type.length())?,
553            (HashVariant::HashKeccak384NativeRaw, PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak384(&check_multiple_of_8(bits_raw())?))?, **array_type.length())?,
554            (HashVariant::HashKeccak512Native,    PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak512(&bits()))?, **array_type.length())?,
555            (HashVariant::HashKeccak512NativeRaw, PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak512(&check_multiple_of_8(bits_raw())?))?, **array_type.length())?,
556            (HashVariant::HashSha3_256Native,     PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_sha3_256(&bits()))?, **array_type.length())?,
557            (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())?,
558            (HashVariant::HashSha3_384Native,     PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_sha3_384(&bits()))?, **array_type.length())?,
559            (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())?,
560            (HashVariant::HashSha3_512Native,     PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_sha3_512(&bits()))?, **array_type.length())?,
561            (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())?,
562            (_, destination_type) => bail!("Invalid destination type '{destination_type}' for 'hash' variant: {}", $variant.opcode()),
563        }
564    }};
565}
566
567/// Evaluate a hash operation.
568///
569/// This allows running the hash without the machinery of stacks and registers.
570/// This is necessary for the Leo interpreter.
571pub fn evaluate_hash<N: Network>(
572    variant: HashVariant,
573    input: &Value<N>,
574    destination_type: &PlaintextType<N>,
575) -> Result<Plaintext<N>> {
576    evaluate_hash_internal(variant, input, destination_type)
577}
578
579fn evaluate_hash_internal<N: Network>(
580    variant: HashVariant,
581    input: &Value<N>,
582    destination_type: &PlaintextType<N>,
583) -> Result<Plaintext<N>> {
584    Ok(do_hash!(N, variant, destination_type, input, Plaintext::<N>, Literal::<N>, |x| x))
585}
586
587impl<N: Network, const VARIANT: u8> HashInstruction<N, VARIANT> {
588    /// Evaluates the instruction.
589    pub fn evaluate(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersTrait<N>) -> Result<()> {
590        // Ensure the number of operands is correct.
591        check_number_of_operands(VARIANT, Self::opcode(), self.operands.len())?;
592        // Ensure the destination type is valid.
593        ensure!(
594            is_valid_destination_type(VARIANT, &self.destination_type),
595            "Invalid destination type in 'hash' instruction"
596        );
597
598        // Load the operand.
599        let input = registers.load(stack, &self.operands[0])?;
600
601        // Compute the output.
602        let output = evaluate_hash_internal(HashVariant::new(VARIANT), &input, &self.destination_type)?;
603
604        // Store the output.
605        registers.store(stack, &self.destination, Value::Plaintext(output))
606    }
607
608    /// Executes the instruction.
609    pub fn execute<A: circuit::Aleo<Network = N>>(
610        &self,
611        stack: &impl StackTrait<N>,
612        registers: &mut impl RegistersCircuit<N, A>,
613    ) -> Result<()> {
614        use circuit::traits::{ToBits, ToBitsRaw, ToFields, ToFieldsRaw};
615
616        // Ensure the number of operands is correct.
617        check_number_of_operands(VARIANT, Self::opcode(), self.operands.len())?;
618        // Ensure the destination type is valid.
619        ensure!(
620            is_valid_destination_type(VARIANT, &self.destination_type),
621            "Invalid destination type in 'hash' instruction"
622        );
623
624        // Load the operand.
625        let input = registers.load_circuit(stack, &self.operands[0])?;
626
627        // Compute the output.
628        let output = do_hash!(
629            A,
630            HashVariant::new(VARIANT),
631            &self.destination_type,
632            input,
633            circuit::Plaintext::<A>,
634            circuit::Literal::<A>,
635            Result::<_>::Ok
636        );
637
638        // Store the output.
639        registers.store_circuit(stack, &self.destination, circuit::Value::Plaintext(output))
640    }
641
642    /// Finalizes the instruction.
643    #[inline]
644    pub fn finalize(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersTrait<N>) -> Result<()> {
645        self.evaluate(stack, registers)
646    }
647
648    /// Returns the output type from the given program and input types.
649    pub fn output_types(
650        &self,
651        stack: &impl StackTrait<N>,
652        input_types: &[RegisterType<N>],
653    ) -> Result<Vec<RegisterType<N>>> {
654        // Ensure the number of input types is correct.
655        check_number_of_operands(VARIANT, Self::opcode(), input_types.len())?;
656        // Ensure the number of operands is correct.
657        check_number_of_operands(VARIANT, Self::opcode(), self.operands.len())?;
658        // Ensure the destination type is valid.
659        ensure!(
660            is_valid_destination_type(VARIANT, &self.destination_type),
661            "Invalid destination type in 'hash' instruction"
662        );
663
664        // Get the variant.
665        let variant = HashVariant::new(VARIANT);
666
667        // If the variant needs to be byte aligned, check that its size in bits is a multiple of 8.
668        if variant.requires_byte_alignment() {
669            // Check that there is only one operand type.
670            ensure!(
671                variant.expected_num_operands() == 1,
672                "Expected one operand for '{}', found '{}'",
673                variant.opcode(),
674                variant.expected_num_operands()
675            );
676
677            // A helper to get a struct declaration.
678            let get_struct = |identifier: &Identifier<N>| stack.program().get_struct(identifier).cloned();
679
680            // A helper to get an external struct declaration.
681            let get_external_struct = |locator: &Locator<N>| {
682                stack.get_external_stack(locator.program_id())?.program().get_struct(locator.resource()).cloned()
683            };
684
685            // A helper to get a record declaration.
686            let get_record = |identifier: &Identifier<N>| stack.program().get_record(identifier).cloned();
687
688            // A helper to get an external record declaration.
689            let get_external_record = |locator: &Locator<N>| {
690                stack.get_external_stack(locator.program_id())?.program().get_record(locator.resource()).cloned()
691            };
692
693            // A helper to get the argument types of a future.
694            let get_future = |locator: &Locator<N>| {
695                Ok(match stack.program_id() == locator.program_id() {
696                    true => stack
697                        .program()
698                        .get_function_ref(locator.resource())?
699                        .finalize_logic()
700                        .ok_or_else(|| anyhow!("'{locator}' does not have a finalize scope"))?
701                        .input_types(),
702                    false => stack
703                        .get_external_stack(locator.program_id())?
704                        .program()
705                        .get_function_ref(locator.resource())?
706                        .finalize_logic()
707                        .ok_or_else(|| anyhow!("Failed to find function '{locator}'"))?
708                        .input_types(),
709                })
710            };
711
712            // Get the size in bits.
713            let size_in_bits = match variant.is_raw() {
714                false => input_types[0].size_in_bits(
715                    &get_struct,
716                    &get_external_struct,
717                    &get_record,
718                    &get_external_record,
719                    &get_future,
720                )?,
721                true => input_types[0].size_in_bits_raw(
722                    &get_struct,
723                    &get_external_struct,
724                    &get_record,
725                    &get_external_record,
726                    &get_future,
727                )?,
728            };
729            // Check the number of bits.
730            ensure!(
731                size_in_bits % 8 == 0,
732                "Expected a multiple of 8 bits for '{}', found '{size_in_bits}'",
733                variant.opcode()
734            );
735        }
736
737        // TODO (howardwu): If the operation is Pedersen, check that it is within the number of bits.
738
739        match variant {
740            HashVariant::HashManyPSD2 | HashVariant::HashManyPSD4 | HashVariant::HashManyPSD8 => {
741                bail!("'hash_many' is not yet implemented")
742            }
743            _ => Ok(vec![RegisterType::Plaintext(self.destination_type.clone())]),
744        }
745    }
746}
747
748impl<N: Network, const VARIANT: u8> Parser for HashInstruction<N, VARIANT> {
749    /// Parses a string into an operation.
750    fn parse(string: &str) -> ParserResult<Self> {
751        /// Parse the operands from the string.
752        fn parse_operands<N: Network>(string: &str, num_operands: usize) -> ParserResult<Vec<Operand<N>>> {
753            let mut operands = Vec::with_capacity(num_operands);
754            let mut string = string;
755
756            for _ in 0..num_operands {
757                // Parse the whitespace from the string.
758                let (next_string, _) = Sanitizer::parse_whitespaces(string)?;
759                // Parse the operand from the string.
760                let (next_string, operand) = Operand::parse(next_string)?;
761                // Update the string.
762                string = next_string;
763                // Push the operand.
764                operands.push(operand);
765            }
766
767            Ok((string, operands))
768        }
769
770        // Parse the opcode from the string.
771        let (string, _) = tag(*Self::opcode())(string)?;
772        // Parse the operands from the string.
773        let (string, operands) = parse_operands(string, HashVariant::new(VARIANT).expected_num_operands())?;
774        // Parse the whitespace from the string.
775        let (string, _) = Sanitizer::parse_whitespaces(string)?;
776        // Parse the "into" from the string.
777        let (string, _) = tag("into")(string)?;
778        // Parse the whitespace from the string.
779        let (string, _) = Sanitizer::parse_whitespaces(string)?;
780        // Parse the destination register from the string.
781        let (string, destination) = Register::parse(string)?;
782        // Parse the whitespace from the string.
783        let (string, _) = Sanitizer::parse_whitespaces(string)?;
784        // Parse the "as" from the string.
785        let (string, _) = tag("as")(string)?;
786        // Parse the whitespace from the string.
787        let (string, _) = Sanitizer::parse_whitespaces(string)?;
788        // Parse the destination register type from the string.
789        let (string, destination_type) = PlaintextType::parse(string)?;
790        // Ensure the destination type is allowed.
791        match destination_type {
792            PlaintextType::Literal(LiteralType::Boolean)
793            | PlaintextType::Literal(LiteralType::String)
794            | PlaintextType::Literal(LiteralType::Identifier) => map_res(fail, |_: ParserResult<Self>| {
795                Err(error(format!("Failed to parse 'hash': '{destination_type}' is invalid")))
796            })(string),
797            _ => Ok((string, Self { operands, destination, destination_type })),
798        }
799    }
800}
801
802impl<N: Network, const VARIANT: u8> FromStr for HashInstruction<N, VARIANT> {
803    type Err = Error;
804
805    /// Parses a string into an operation.
806    fn from_str(string: &str) -> Result<Self> {
807        match Self::parse(string) {
808            Ok((remainder, object)) => {
809                // Ensure the remainder is empty.
810                ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
811                // Return the object.
812                Ok(object)
813            }
814            Err(error) => bail!("Failed to parse string. {error}"),
815        }
816    }
817}
818
819impl<N: Network, const VARIANT: u8> Debug for HashInstruction<N, VARIANT> {
820    /// Prints the operation as a string.
821    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
822        Display::fmt(self, f)
823    }
824}
825
826impl<N: Network, const VARIANT: u8> Display for HashInstruction<N, VARIANT> {
827    /// Prints the operation to a string.
828    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
829        // Ensure the number of operands is correct.
830        check_number_of_operands(VARIANT, Self::opcode(), self.operands.len()).map_err(|_| fmt::Error)?;
831        // Print the operation.
832        write!(f, "{} ", Self::opcode())?;
833        self.operands.iter().try_for_each(|operand| write!(f, "{operand} "))?;
834        write!(f, "into {} as {}", self.destination, self.destination_type)
835    }
836}
837
838impl<N: Network, const VARIANT: u8> FromBytes for HashInstruction<N, VARIANT> {
839    /// Reads the operation from a buffer.
840    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
841        // Prepare the number of operands.
842        let num_operands = HashVariant::new(VARIANT).expected_num_operands();
843        // Read the operands.
844        let operands = (0..num_operands).map(|_| Operand::read_le(&mut reader)).collect::<Result<_, _>>()?;
845        // Read the destination register.
846        let destination = Register::read_le(&mut reader)?;
847        // Read the destination register type.
848        let destination_type = PlaintextType::read_le(&mut reader)?;
849        // Return the operation.
850        Ok(Self { operands, destination, destination_type })
851    }
852}
853
854impl<N: Network, const VARIANT: u8> ToBytes for HashInstruction<N, VARIANT> {
855    /// Writes the operation to a buffer.
856    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
857        // Ensure the number of operands is correct.
858        check_number_of_operands(VARIANT, Self::opcode(), self.operands.len()).map_err(|e| error(format!("{e}")))?;
859        // Write the operands.
860        self.operands.iter().try_for_each(|operand| operand.write_le(&mut writer))?;
861        // Write the destination register.
862        self.destination.write_le(&mut writer)?;
863        // Write the destination register type.
864        self.destination_type.write_le(&mut writer)
865    }
866}
867
868#[cfg(test)]
869mod tests {
870    use super::*;
871    use console::{network::MainnetV0, program::ArrayType, types::U32};
872
873    type CurrentNetwork = MainnetV0;
874
875    /// **Attention**: When changing this, also update in `tests/instruction/hash.rs`.
876    fn sample_valid_destination_types<N: Network, R: CryptoRng + Rng>(
877        variant: u8,
878        rng: &mut R,
879    ) -> Vec<PlaintextType<N>> {
880        match variant {
881            0..=32 => vec![
882                PlaintextType::Literal(LiteralType::Address),
883                PlaintextType::Literal(LiteralType::Field),
884                PlaintextType::Literal(LiteralType::Group),
885                PlaintextType::Literal(LiteralType::I8),
886                PlaintextType::Literal(LiteralType::I16),
887                PlaintextType::Literal(LiteralType::I32),
888                PlaintextType::Literal(LiteralType::I64),
889                PlaintextType::Literal(LiteralType::I128),
890                PlaintextType::Literal(LiteralType::U8),
891                PlaintextType::Literal(LiteralType::U16),
892                PlaintextType::Literal(LiteralType::U32),
893                PlaintextType::Literal(LiteralType::U64),
894                PlaintextType::Literal(LiteralType::U128),
895                PlaintextType::Literal(LiteralType::Scalar),
896            ],
897            33..=44 => (0..10)
898                .map(|_| {
899                    PlaintextType::Array(
900                        ArrayType::new(PlaintextType::Literal(LiteralType::Boolean), vec![U32::new(
901                            u32::try_from(rng.gen_range(1..=CurrentNetwork::LATEST_MAX_ARRAY_ELEMENTS())).unwrap(),
902                        )])
903                        .unwrap(),
904                    )
905                })
906                .collect(),
907            _ => panic!("Invalid 'hash' instruction opcode"),
908        }
909    }
910
911    // A helper function to run a test.
912    fn run_test<N: Network, const VARIANT: u8>() {
913        // Initialize the RNG.
914        let rng = &mut TestRng::default();
915
916        // Get the opcode.
917        let opcode = HashInstruction::<N, VARIANT>::opcode();
918
919        for destination_type in sample_valid_destination_types(VARIANT, rng) {
920            let instruction = format!("{opcode} r0 into r1 as {destination_type}");
921            println!("Testing instruction: '{instruction}'");
922
923            let (string, hash) = HashInstruction::<CurrentNetwork, VARIANT>::parse(&instruction).unwrap();
924            assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
925            assert_eq!(hash.operands.len(), 1, "The number of operands is incorrect");
926            assert_eq!(hash.operands[0], Operand::Register(Register::Locator(0)), "The first operand is incorrect");
927            assert_eq!(hash.destination, Register::Locator(1), "The destination register is incorrect");
928            assert_eq!(&hash.destination_type, &destination_type, "The destination type is incorrect");
929        }
930    }
931
932    #[test]
933    fn test_parse() {
934        run_test::<CurrentNetwork, { HashVariant::HashBHP256 as u8 }>();
935        run_test::<CurrentNetwork, { HashVariant::HashBHP512 as u8 }>();
936        run_test::<CurrentNetwork, { HashVariant::HashBHP768 as u8 }>();
937        run_test::<CurrentNetwork, { HashVariant::HashBHP1024 as u8 }>();
938
939        run_test::<CurrentNetwork, { HashVariant::HashKeccak256 as u8 }>();
940        run_test::<CurrentNetwork, { HashVariant::HashKeccak384 as u8 }>();
941        run_test::<CurrentNetwork, { HashVariant::HashKeccak512 as u8 }>();
942
943        run_test::<CurrentNetwork, { HashVariant::HashPED64 as u8 }>();
944        run_test::<CurrentNetwork, { HashVariant::HashPED128 as u8 }>();
945
946        run_test::<CurrentNetwork, { HashVariant::HashPSD2 as u8 }>();
947        run_test::<CurrentNetwork, { HashVariant::HashPSD4 as u8 }>();
948        run_test::<CurrentNetwork, { HashVariant::HashPSD8 as u8 }>();
949
950        run_test::<CurrentNetwork, { HashVariant::HashSha3_256 as u8 }>();
951        run_test::<CurrentNetwork, { HashVariant::HashSha3_384 as u8 }>();
952        run_test::<CurrentNetwork, { HashVariant::HashSha3_512 as u8 }>();
953
954        // Note: `run_test` needs to be updated when `hash_many` is implemented.
955        //run_test::<CurrentNetwork, { HashVariant::HashManyPSD2 as u8 }>();
956        //run_test::<CurrentNetwork, { HashVariant::HashManyPSD4 as u8 }>();
957        //run_test::<CurrentNetwork, { HashVariant::HashManyPSD8 as u8 }>();
958
959        run_test::<CurrentNetwork, { HashVariant::HashBHP256Raw as u8 }>();
960        run_test::<CurrentNetwork, { HashVariant::HashBHP512Raw as u8 }>();
961        run_test::<CurrentNetwork, { HashVariant::HashBHP768Raw as u8 }>();
962        run_test::<CurrentNetwork, { HashVariant::HashBHP1024Raw as u8 }>();
963
964        run_test::<CurrentNetwork, { HashVariant::HashKeccak256Raw as u8 }>();
965        run_test::<CurrentNetwork, { HashVariant::HashKeccak384Raw as u8 }>();
966        run_test::<CurrentNetwork, { HashVariant::HashKeccak512Raw as u8 }>();
967
968        run_test::<CurrentNetwork, { HashVariant::HashPED64Raw as u8 }>();
969        run_test::<CurrentNetwork, { HashVariant::HashPED128Raw as u8 }>();
970
971        run_test::<CurrentNetwork, { HashVariant::HashPSD2Raw as u8 }>();
972        run_test::<CurrentNetwork, { HashVariant::HashPSD4Raw as u8 }>();
973        run_test::<CurrentNetwork, { HashVariant::HashPSD8Raw as u8 }>();
974
975        run_test::<CurrentNetwork, { HashVariant::HashSha3_256Raw as u8 }>();
976        run_test::<CurrentNetwork, { HashVariant::HashSha3_384Raw as u8 }>();
977        run_test::<CurrentNetwork, { HashVariant::HashSha3_512Raw as u8 }>();
978
979        run_test::<CurrentNetwork, { HashVariant::HashKeccak256Native as u8 }>();
980        run_test::<CurrentNetwork, { HashVariant::HashKeccak384Native as u8 }>();
981        run_test::<CurrentNetwork, { HashVariant::HashKeccak512Native as u8 }>();
982
983        run_test::<CurrentNetwork, { HashVariant::HashSha3_256Native as u8 }>();
984        run_test::<CurrentNetwork, { HashVariant::HashSha3_384Native as u8 }>();
985        run_test::<CurrentNetwork, { HashVariant::HashSha3_512Native as u8 }>();
986
987        run_test::<CurrentNetwork, { HashVariant::HashKeccak256NativeRaw as u8 }>();
988        run_test::<CurrentNetwork, { HashVariant::HashKeccak384NativeRaw as u8 }>();
989        run_test::<CurrentNetwork, { HashVariant::HashKeccak512NativeRaw as u8 }>();
990
991        run_test::<CurrentNetwork, { HashVariant::HashSha3_256NativeRaw as u8 }>();
992        run_test::<CurrentNetwork, { HashVariant::HashSha3_384NativeRaw as u8 }>();
993        run_test::<CurrentNetwork, { HashVariant::HashSha3_512NativeRaw as u8 }>();
994    }
995
996    #[test]
997    fn check_number_of_hash_variants() {
998        assert_eq!(enum_iterator::cardinality::<HashVariant>(), 45);
999    }
1000
1001    #[test]
1002    fn check_byte_aligned_variants_all_have_one_opcode() {
1003        for variant in enum_iterator::all::<HashVariant>() {
1004            if variant.requires_byte_alignment() {
1005                assert_eq!(variant.expected_num_operands(), 1)
1006            }
1007        }
1008    }
1009}