use alloc::{boxed::Box, collections::BTreeMap, sync::Arc, vec::Vec};
use core::error::Error;
use miden_crypto::{Felt, Word, hash::rpo::Rpo256};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::{
EventId, EventName,
utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
};
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(
all(feature = "arbitrary", test),
miden_test_serde_macros::serde_test(winter_serde(true))
)]
pub struct PrecompileRequest {
event_id: EventId,
calldata: Vec<u8>,
}
impl PrecompileRequest {
pub fn new(event_id: EventId, calldata: Vec<u8>) -> Self {
Self { event_id, calldata }
}
pub fn calldata(&self) -> &[u8] {
&self.calldata
}
pub fn event_id(&self) -> EventId {
self.event_id
}
}
impl Serializable for PrecompileRequest {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
self.event_id.write_into(target);
self.calldata.write_into(target);
}
}
impl Deserializable for PrecompileRequest {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let event_id = EventId::read_from(source)?;
let calldata = Vec::<u8>::read_from(source)?;
Ok(Self { event_id, calldata })
}
}
pub type PrecompileTranscriptState = Word;
pub type PrecompileTranscriptDigest = Word;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PrecompileCommitment {
tag: Word,
comm: Word,
}
impl PrecompileCommitment {
pub fn new(tag: Word, comm: Word) -> Self {
Self { tag, comm }
}
pub fn tag(&self) -> Word {
self.tag
}
pub fn comm_calldata(&self) -> Word {
self.comm
}
pub fn to_elements(&self) -> [Felt; 8] {
let words = [self.tag, self.comm];
Word::words_as_elements(&words).try_into().unwrap()
}
pub fn event_id(&self) -> EventId {
EventId::from_felt(self.tag[0])
}
}
#[derive(Default, Clone)]
pub struct PrecompileVerifierRegistry {
verifiers: BTreeMap<EventId, (EventName, Arc<dyn PrecompileVerifier>)>,
}
impl PrecompileVerifierRegistry {
pub fn new() -> Self {
Self { verifiers: BTreeMap::new() }
}
pub fn with_verifier(
mut self,
event_name: &EventName,
verifier: Arc<dyn PrecompileVerifier>,
) -> Self {
let event_id = event_name.to_event_id();
self.verifiers.insert(event_id, (event_name.clone(), verifier));
self
}
pub fn merge(&mut self, other: &Self) {
for (event_id, (event_name, verifier)) in other.verifiers.iter() {
self.verifiers.insert(*event_id, (event_name.clone(), verifier.clone()));
}
}
pub fn requests_transcript(
&self,
requests: &[PrecompileRequest],
) -> Result<PrecompileTranscript, PrecompileVerificationError> {
let mut transcript = PrecompileTranscript::new();
for (index, PrecompileRequest { event_id, calldata }) in requests.iter().enumerate() {
let (event_name, verifier) = self.verifiers.get(event_id).ok_or(
PrecompileVerificationError::VerifierNotFound { index, event_id: *event_id },
)?;
let precompile_commitment = verifier.verify(calldata).map_err(|error| {
PrecompileVerificationError::PrecompileError {
index,
event_name: event_name.clone(),
error,
}
})?;
transcript.record(precompile_commitment);
}
Ok(transcript)
}
}
pub trait PrecompileVerifier: Send + Sync {
fn verify(&self, calldata: &[u8]) -> Result<PrecompileCommitment, PrecompileError>;
}
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
pub struct PrecompileTranscript {
state: Word,
}
impl PrecompileTranscript {
pub fn new() -> Self {
Self::default()
}
pub fn from_state(state: PrecompileTranscriptState) -> Self {
Self { state }
}
pub fn state(&self) -> PrecompileTranscriptState {
self.state
}
pub fn record(&mut self, commitment: PrecompileCommitment) {
let mut state =
Word::words_as_elements(&[self.state, commitment.tag(), commitment.comm_calldata()])
.try_into()
.unwrap();
Rpo256::apply_permutation(&mut state);
self.state = Word::new(state[0..4].try_into().unwrap());
}
pub fn finalize(self) -> PrecompileTranscriptDigest {
let mut state = Word::words_as_elements(&[self.state, Word::empty(), Word::empty()])
.try_into()
.unwrap();
Rpo256::apply_permutation(&mut state);
PrecompileTranscriptDigest::new(state[4..8].try_into().unwrap())
}
}
pub type PrecompileError = Box<dyn Error + Send + Sync + 'static>;
#[derive(Debug, thiserror::Error)]
pub enum PrecompileVerificationError {
#[error("no verifier found for request #{index} for event with ID: {event_id}")]
VerifierNotFound { index: usize, event_id: EventId },
#[error("verification error for request #{index} for event '{event_name}'")]
PrecompileError {
index: usize,
event_name: EventName,
#[source]
error: PrecompileError,
},
}
#[cfg(all(feature = "arbitrary", test))]
impl proptest::prelude::Arbitrary for PrecompileRequest {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
use proptest::prelude::*;
(any::<EventId>(), proptest::collection::vec(any::<u8>(), 0..=1000))
.prop_map(|(event_id, calldata)| PrecompileRequest::new(event_id, calldata))
.boxed()
}
type Strategy = proptest::prelude::BoxedStrategy<Self>;
}