extern crate alloc;
use alloc::{collections::VecDeque, vec::Vec};
use core::fmt;
use borsh::{BorshDeserialize, BorshSerialize};
use risc0_zkp::core::{digest::Digest, hash::sha::Sha256};
use serde::{Deserialize, Serialize};
use crate::{tagged_struct, Digestible};
#[derive(Clone, Serialize, Deserialize, PartialEq, BorshSerialize, BorshDeserialize)]
pub struct SystemState {
pub pc: u32,
pub merkle_root: Digest,
}
impl SystemState {
pub fn decode(flat: &mut VecDeque<u32>) -> Result<Self, DecodeError> {
Ok(Self {
pc: read_u32_bytes(flat)?,
merkle_root: read_sha_halfs(flat)?,
})
}
pub fn encode(&self, flat: &mut Vec<u32>) {
write_u32_bytes(flat, self.pc);
write_sha_halfs(flat, &self.merkle_root);
}
}
impl fmt::Debug for SystemState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SystemState")
.field("pc", &format_args!("0x{:08x}", self.pc))
.field("merkle_root", &self.merkle_root)
.finish()
}
}
impl Eq for SystemState {}
impl Digestible for SystemState {
fn digest<S: Sha256>(&self) -> Digest {
tagged_struct::<S>("risc0.SystemState", &[self.merkle_root], &[self.pc])
}
}
pub fn read_sha_halfs(flat: &mut VecDeque<u32>) -> Result<Digest, DecodeError> {
let mut bytes = Vec::<u8>::new();
if flat.len() < 16 {
return Err(DecodeError::EndOfStream);
}
for half in flat.drain(0..16) {
bytes.push((half & 0xff).try_into().unwrap());
bytes.push(
(half >> 8)
.try_into()
.map_err(|_| DecodeError::OutOfRange)?,
);
}
Ok(bytes.try_into().unwrap())
}
fn read_u32_bytes(flat: &mut VecDeque<u32>) -> Result<u32, DecodeError> {
if flat.len() < 4 {
return Err(DecodeError::EndOfStream);
}
Ok(u32::from_le_bytes(
flat.drain(0..4)
.map(|x| x as u8)
.collect::<Vec<u8>>()
.try_into()
.unwrap(),
))
}
pub fn write_sha_halfs(flat: &mut Vec<u32>, digest: &Digest) {
for x in digest.as_words() {
flat.push(*x & 0xffff);
flat.push(*x >> 16);
}
}
fn write_u32_bytes(flat: &mut Vec<u32>, word: u32) {
for x in word.to_le_bytes() {
flat.push(x as u32);
}
}
#[derive(Debug, Copy, Clone)]
pub enum DecodeError {
EndOfStream,
OutOfRange,
}
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::EndOfStream => write!(f, "end of stream reached when more data was expected"),
Self::OutOfRange => write!(f, "value outside of expected range"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for DecodeError {}