Skip to main content

miden_stdlib_sys/intrinsics/
crypto.rs

1//! Cryptographic intrinsics for the Miden VM.
2//!
3//! This module provides Rust bindings for cryptographic operations available in the Miden VM.
4#![allow(warnings, clippy::infallible_try_from)]
5
6use core::convert::Infallible;
7
8use crate::intrinsics::{Felt, Word};
9
10/// A cryptographic digest representing a 256-bit hash value.
11///
12/// This is a wrapper around `Word` which contains 4 field elements.
13#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
14#[repr(transparent)]
15pub struct Digest {
16    pub inner: Word,
17}
18
19impl Digest {
20    /// Creates a new `Digest` from a `[Felt; 4]` array.
21    #[inline]
22    pub fn new(felts: [Felt; 4]) -> Self {
23        Self {
24            inner: Word::from(felts),
25        }
26    }
27
28    /// Creates a new `Digest` from a `Word`.
29    #[inline]
30    pub const fn from_word(word: Word) -> Self {
31        Self { inner: word }
32    }
33}
34
35impl TryFrom<Word> for Digest {
36    type Error = Infallible;
37
38    #[inline]
39    fn try_from(word: Word) -> Result<Self, Self::Error> {
40        Ok(Self::from_word(word))
41    }
42}
43
44impl From<Digest> for Word {
45    #[inline]
46    fn from(digest: Digest) -> Self {
47        digest.inner
48    }
49}
50
51impl From<[Felt; 4]> for Digest {
52    #[inline]
53    fn from(felts: [Felt; 4]) -> Self {
54        Self::new(felts)
55    }
56}
57
58impl From<Digest> for [Felt; 4] {
59    #[inline]
60    fn from(digest: Digest) -> Self {
61        (&digest.inner).into()
62    }
63}
64
65#[cfg(all(target_family = "wasm", miden))]
66unsafe extern "C" {
67    /// Merges two words (256-bit digests) via Poseidon2.
68    ///
69    /// This maps to `miden::core::crypto::hashes::poseidon2::merge`.
70    ///
71    /// Inputs:  `[A, B, ...]`
72    /// Outputs: `[C, ...]` where `C = Poseidon2(A || B)`
73    ///
74    /// The digest output is returned to the caller via `result_ptr`.
75    #[link_name = "miden::core::crypto::hashes::poseidon2::merge"]
76    fn extern_poseidon2_merge(
77        a0: Felt,
78        a1: Felt,
79        a2: Felt,
80        a3: Felt,
81        b0: Felt,
82        b1: Felt,
83        b2: Felt,
84        b3: Felt,
85        result_ptr: *mut Felt,
86    );
87}
88
89/// Computes the hash of two digests using the Rescue Prime Optimized (RPO)
90/// permutation in 2-to-1 mode.
91///
92/// This directly maps to the `hmerge` VM instruction.
93///
94/// # Arguments
95/// * `digests` - An array of two digests to be merged. The function internally
96///   reorders them as required by the VM instruction (from [A, B] to [B, A] on the stack).
97#[inline]
98#[cfg(all(target_family = "wasm", miden))]
99pub fn merge(digests: [Digest; 2]) -> Digest {
100    unsafe {
101        let mut ret_area = ::core::mem::MaybeUninit::<Word>::uninit();
102        let result_ptr = ret_area.as_mut_ptr() as *mut Felt;
103
104        extern_poseidon2_merge(
105            digests[0].inner.a,
106            digests[0].inner.b,
107            digests[0].inner.c,
108            digests[0].inner.d,
109            digests[1].inner.a,
110            digests[1].inner.b,
111            digests[1].inner.c,
112            digests[1].inner.d,
113            result_ptr,
114        );
115
116        Digest::from_word(ret_area.assume_init())
117    }
118}
119
120/// Computes the hash of two digests using the Rescue Prime Optimized (RPO) permutation in 2-to-1
121/// mode.
122#[inline]
123#[cfg(not(all(target_family = "wasm", miden)))]
124pub fn merge(_digests: [Digest; 2]) -> Digest {
125    unimplemented!("crypto intrinsics are only available when targeting the Miden VM")
126}