From 515e61f5a1c35978408ecf39dad2213c79203aef Mon Sep 17 00:00:00 2001 From: Victor Dumitrescu Date: Wed, 18 Sep 2024 17:06:21 +0200 Subject: [PATCH] RISC-V: compute Merkle root hash for PVM state --- .../lib/src/machine_state/bus/main_memory.rs | 13 ++++- .../src/machine_state/csregisters/values.rs | 9 +++ src/riscv/lib/src/pvm/node_pvm.rs | 3 +- src/riscv/lib/src/state_backend/hash.rs | 58 +++++++++++++++++++ src/riscv/lib/src/state_backend/region.rs | 21 +++++++ 5 files changed, 102 insertions(+), 2 deletions(-) diff --git a/src/riscv/lib/src/machine_state/bus/main_memory.rs b/src/riscv/lib/src/machine_state/bus/main_memory.rs index 147afb639c8c..0aa5030e4868 100644 --- a/src/riscv/lib/src/machine_state/bus/main_memory.rs +++ b/src/riscv/lib/src/machine_state/bus/main_memory.rs @@ -3,7 +3,11 @@ // SPDX-License-Identifier: MIT use super::{Address, AddressableRead, AddressableWrite}; -use crate::state_backend::{self as backend, ManagerDeserialise, ManagerSerialise}; +use crate::state_backend::{ + self as backend, + hash::{Hash, HashError, RootHashable}, + ManagerDeserialise, ManagerSerialise, +}; use serde::{Deserialize, Serialize}; use std::mem; @@ -273,6 +277,13 @@ where } } +impl RootHashable for MainMemory { + // TODO RV-230: Finer-grained hashing for memory + fn hash(&self) -> Result { + Hash::blake2b_hash(self) + } +} + #[cfg(test)] pub mod tests { use crate::{ diff --git a/src/riscv/lib/src/machine_state/csregisters/values.rs b/src/riscv/lib/src/machine_state/csregisters/values.rs index 0850a1808de2..39c24122db06 100644 --- a/src/riscv/lib/src/machine_state/csregisters/values.rs +++ b/src/riscv/lib/src/machine_state/csregisters/values.rs @@ -13,6 +13,7 @@ use super::{ use crate::{ bits::Bits64, state_backend::{ + hash::{Hash, HashError, RootHashable}, AllocatedOf, Choreographer, EffectCell, EffectCellLayout, Layout, ManagerAlloc, ManagerBase, ManagerRead, ManagerReadWrite, ManagerWrite, PlacedOf, Ref, }, @@ -1393,6 +1394,14 @@ impl CSRValuesF { } } +impl RootHashable + for CSRValuesF +{ + fn hash(&self) -> Result { + Hash::blake2b_hash(self) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/riscv/lib/src/pvm/node_pvm.rs b/src/riscv/lib/src/pvm/node_pvm.rs index 09dcae3d1f13..1bbceab38d53 100644 --- a/src/riscv/lib/src/pvm/node_pvm.rs +++ b/src/riscv/lib/src/pvm/node_pvm.rs @@ -11,6 +11,7 @@ use crate::{ pvm::common::{Pvm, PvmHooks, PvmLayout, PvmStatus}, state_backend::{ self, + hash::RootHashable, memory_backend::{InMemoryBackend, SliceManager, SliceManagerRO}, Backend, Layout, }, @@ -163,7 +164,7 @@ impl NodePvm { } pub fn hash(&self) -> Hash { - Hash::blake2b_hash_bytes(self.to_bytes()).unwrap() + self.with_backend(|state| state.struct_ref().hash().unwrap()) } pub fn set_input_message(&self, level: u32, message_counter: u64, input: Vec) -> Self { diff --git a/src/riscv/lib/src/state_backend/hash.rs b/src/riscv/lib/src/state_backend/hash.rs index 3124b122ecdb..85c2a8fdaee7 100644 --- a/src/riscv/lib/src/state_backend/hash.rs +++ b/src/riscv/lib/src/state_backend/hash.rs @@ -77,3 +77,61 @@ impl AsRef<[u8]> for Hash { &self.digest } } + +pub trait RootHashable { + /// Build the root hash corresponding to the Merkle tree described by the + /// layout of the data. + fn hash(&self) -> Result; +} + +impl RootHashable for Hash { + fn hash(&self) -> Result { + Ok(*self) + } +} + +impl RootHashable for &[T] { + fn hash(&self) -> Result { + let mut hashes: Vec = Vec::new(); + + self.iter().try_for_each(|e| { + let hash: [u8; DIGEST_SIZE] = e.hash()?.into(); + hashes.extend_from_slice(&hash); + Ok::<(), HashError>(()) + })?; + + Hash::blake2b_hash_bytes(&hashes) + } +} + +impl RootHashable for Vec { + fn hash(&self) -> Result { + let values: &[T] = self.as_ref(); + values.hash() + } +} + +impl RootHashable for [T; N] { + fn hash(&self) -> Result { + self.as_ref().hash() + } +} + +macro_rules! impl_roothash_for_tuple { + ($($name:ident),*) => { + impl<$($name: RootHashable),*> RootHashable for ($($name,)*) { + fn hash(&self) -> Result { + #[allow(non_snake_case)] + let ($($name,)*) = self; + let hashes: Result, HashError> = [$($name.hash(),)*].into_iter().collect(); + hashes?.hash() + } + } + } +} + +impl_roothash_for_tuple!(A, B); +impl_roothash_for_tuple!(A, B, C); +impl_roothash_for_tuple!(A, B, C, D); +impl_roothash_for_tuple!(A, B, C, D, E); +impl_roothash_for_tuple!(A, B, C, D, E, F); diff --git a/src/riscv/lib/src/state_backend/region.rs b/src/riscv/lib/src/state_backend/region.rs index ed724d9253a6..427c20f5d610 100644 --- a/src/riscv/lib/src/state_backend/region.rs +++ b/src/riscv/lib/src/state_backend/region.rs @@ -3,6 +3,7 @@ // SPDX-License-Identifier: MIT use super::{ + hash::{Hash, HashError, RootHashable}, AllocatedOf, Array, Atom, Elem, ManagerBase, ManagerDeserialise, ManagerRead, ManagerReadWrite, ManagerSerialise, ManagerWrite, Ref, }; @@ -77,6 +78,12 @@ impl<'de, E: serde::Deserialize<'de> + Elem, M: ManagerDeserialise> serde::Deser } } +impl RootHashable for Cell { + fn hash(&self) -> Result { + Hash::blake2b_hash(self) + } +} + /// A [Cell] wrapper that holds an additional in-memory /// representation of the stored value. This value is lazily /// constructed on the first [read] or [replace]. @@ -366,6 +373,14 @@ impl<'de, E: serde::Deserialize<'de> + Elem, const LEN: usize, M: ManagerDeseria } } +impl RootHashable + for Cells +{ + fn hash(&self) -> Result { + Hash::blake2b_hash(self) + } +} + /// Multiple elements of an unspecified type pub struct DynCells { region: M::DynRegion, @@ -438,6 +453,12 @@ impl<'de, const LEN: usize, M: ManagerDeserialise> serde::Deserialize<'de> for D } } +impl RootHashable for DynCells { + fn hash(&self) -> Result { + Hash::blake2b_hash(self) + } +} + #[cfg(test)] pub(crate) mod tests { use crate::{ -- GitLab