feat: refactor simple smt to use empty subtree constants
Prior to this commit, there was an internal procedure with the merkle trees to compute empty sub-tree for arbitrary depths. However, this isn't ideal as this code can be reused in any merkle implementation that uses RPO as backend. This commit introduces a structure that will generate these empty subtrees values.
This commit is contained in:
parent
7ffa0cd97d
commit
3a6a4fcce6
6 changed files with 560 additions and 77 deletions
|
@ -18,7 +18,7 @@ fn smt_rpo(c: &mut Criterion) {
|
||||||
(i, word)
|
(i, word)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let tree = SimpleSmt::new(entries, depth).unwrap();
|
let tree = SimpleSmt::new(depth).unwrap().with_leaves(entries).unwrap();
|
||||||
trees.push(tree);
|
trees.push(tree);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use core::{cmp::Ordering, ops::Deref};
|
||||||
pub struct RpoDigest([Felt; DIGEST_SIZE]);
|
pub struct RpoDigest([Felt; DIGEST_SIZE]);
|
||||||
|
|
||||||
impl RpoDigest {
|
impl RpoDigest {
|
||||||
pub fn new(value: [Felt; DIGEST_SIZE]) -> Self {
|
pub const fn new(value: [Felt; DIGEST_SIZE]) -> Self {
|
||||||
Self(value)
|
Self(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
454
src/merkle/empty_roots.rs
Normal file
454
src/merkle/empty_roots.rs
Normal file
|
@ -0,0 +1,454 @@
|
||||||
|
use super::{Felt, RpoDigest, WORD_SIZE, ZERO};
|
||||||
|
use core::slice;
|
||||||
|
|
||||||
|
// EMPTY NODES SUBTREES
|
||||||
|
// ================================================================================================
|
||||||
|
|
||||||
|
/// Contains precomputed roots of empty subtrees in a Merkle rtee of depth 64.
|
||||||
|
pub struct EmptySubtreeRoots;
|
||||||
|
|
||||||
|
impl EmptySubtreeRoots {
|
||||||
|
/// Returns a static slice with roots of empty subtrees of a Merkle tree starting at the
|
||||||
|
/// specified depth.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// This function will panic if the provided `depth` is greater than `64`.
|
||||||
|
pub const fn empty_hashes(depth: u8) -> &'static [RpoDigest] {
|
||||||
|
assert!(depth < 65);
|
||||||
|
let ptr = &EMPTY_SUBTREES_64[64 - depth as usize] as *const RpoDigest;
|
||||||
|
// Safety: this is a static/constant array, so it will never be outlived. If we attempt to
|
||||||
|
// use regular slices, this wouldn't be a `const` function, meaning we won't be able to use
|
||||||
|
// the returned value for static/constant definitions.
|
||||||
|
unsafe { slice::from_raw_parts(ptr, depth as usize + 1) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const EMPTY_SUBTREES_64: [RpoDigest; 65] = [
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(15321474589252129342),
|
||||||
|
Felt::new(17373224439259377994),
|
||||||
|
Felt::new(15071539326562317628),
|
||||||
|
Felt::new(3312677166725950353),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(12146678323567200178),
|
||||||
|
Felt::new(14288630174929498478),
|
||||||
|
Felt::new(13374892366980833045),
|
||||||
|
Felt::new(11840636859983936891),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(15220380953028059006),
|
||||||
|
Felt::new(2981707349961006045),
|
||||||
|
Felt::new(7409523958661360004),
|
||||||
|
Felt::new(2816116826688969892),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(7829641133220670678),
|
||||||
|
Felt::new(6170216088031698405),
|
||||||
|
Felt::new(11814483661801576435),
|
||||||
|
Felt::new(1762887097744793975),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(1299421782687082884),
|
||||||
|
Felt::new(9938699043036414489),
|
||||||
|
Felt::new(10193025806762503939),
|
||||||
|
Felt::new(12073246492422971113),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(3774016405860870757),
|
||||||
|
Felt::new(2584714598467121158),
|
||||||
|
Felt::new(7418645462301488344),
|
||||||
|
Felt::new(1016804897028793820),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(13238072489118494737),
|
||||||
|
Felt::new(6917129315345826393),
|
||||||
|
Felt::new(13736362398490889690),
|
||||||
|
Felt::new(4929049375601714136),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(2433738165854950976),
|
||||||
|
Felt::new(6710644905925382197),
|
||||||
|
Felt::new(10571480102433401045),
|
||||||
|
Felt::new(16853295309134271298),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(3162775558610426184),
|
||||||
|
Felt::new(11944004899624546116),
|
||||||
|
Felt::new(55767976185223284),
|
||||||
|
Felt::new(5892480272697245897),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(12582634330812132159),
|
||||||
|
Felt::new(6886254574119140332),
|
||||||
|
Felt::new(4407453795368410417),
|
||||||
|
Felt::new(6959805977831121004),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(16001070406220863863),
|
||||||
|
Felt::new(4426773743735082930),
|
||||||
|
Felt::new(6860108527212616559),
|
||||||
|
Felt::new(3994703491288516722),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(9755907048710665826),
|
||||||
|
Felt::new(13697078808748604851),
|
||||||
|
Felt::new(17210321635283113095),
|
||||||
|
Felt::new(1203394006092675979),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(3332855817731547893),
|
||||||
|
Felt::new(1068928372599561798),
|
||||||
|
Felt::new(17119375903210334455),
|
||||||
|
Felt::new(8148601736624954416),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(17265634841675424144),
|
||||||
|
Felt::new(18322832739735580203),
|
||||||
|
Felt::new(17896992777163902308),
|
||||||
|
Felt::new(6189383326950297131),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(9329637674239983584),
|
||||||
|
Felt::new(2512861030579248721),
|
||||||
|
Felt::new(10833150484884266896),
|
||||||
|
Felt::new(7470498642428983444),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(3611140194800558886),
|
||||||
|
Felt::new(17185933650781587767),
|
||||||
|
Felt::new(7835232399818923215),
|
||||||
|
Felt::new(7974155618002781326),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(17483286922353768131),
|
||||||
|
Felt::new(353378057542380712),
|
||||||
|
Felt::new(1935183237414585408),
|
||||||
|
Felt::new(4820339620987989650),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(16172462385444809646),
|
||||||
|
Felt::new(3268597753131435459),
|
||||||
|
Felt::new(3481491333654579291),
|
||||||
|
Felt::new(16487779176137683725),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(16595012576192613315),
|
||||||
|
Felt::new(16028552537812484518),
|
||||||
|
Felt::new(13016887826405546773),
|
||||||
|
Felt::new(14649690775021494057),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(11300236651178143890),
|
||||||
|
Felt::new(15307634289168527196),
|
||||||
|
Felt::new(2834866419963148279),
|
||||||
|
Felt::new(7512874625395280090),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(1148273481270068529),
|
||||||
|
Felt::new(7411276436636897120),
|
||||||
|
Felt::new(14325955409748352141),
|
||||||
|
Felt::new(15577038614919538356),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(13911627859049081064),
|
||||||
|
Felt::new(13298542751859672529),
|
||||||
|
Felt::new(18341014824837028242),
|
||||||
|
Felt::new(5587966507704160144),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(10957185917743597702),
|
||||||
|
Felt::new(15815185767119166433),
|
||||||
|
Felt::new(17883994521792846784),
|
||||||
|
Felt::new(15958104556930886663),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(13148367538964199489),
|
||||||
|
Felt::new(7372139436485928380),
|
||||||
|
Felt::new(13408383191801051600),
|
||||||
|
Felt::new(2114382634401123096),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(14448157482521530067),
|
||||||
|
Felt::new(17865161921504959156),
|
||||||
|
Felt::new(10319385198642448897),
|
||||||
|
Felt::new(364163501511998552),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(9722640569118951143),
|
||||||
|
Felt::new(16371655672847089887),
|
||||||
|
Felt::new(12379452272155069993),
|
||||||
|
Felt::new(11605969747977185617),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(2782512273606877924),
|
||||||
|
Felt::new(3656296563981095117),
|
||||||
|
Felt::new(5947388149010135441),
|
||||||
|
Felt::new(1678144343036748885),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(10347491038074052866),
|
||||||
|
Felt::new(11061756013655443653),
|
||||||
|
Felt::new(8901792852813329415),
|
||||||
|
Felt::new(10002477867799577447),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(16688151588649906570),
|
||||||
|
Felt::new(12937054427339650762),
|
||||||
|
Felt::new(2125115528195796454),
|
||||||
|
Felt::new(4796610823085621719),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(3032620037225059051),
|
||||||
|
Felt::new(13522881885116127385),
|
||||||
|
Felt::new(6010511038055304264),
|
||||||
|
Felt::new(8199256447383686121),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(11250302734399433639),
|
||||||
|
Felt::new(4970037623163209776),
|
||||||
|
Felt::new(15776613712371118341),
|
||||||
|
Felt::new(5554382612311754837),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(5116523511540088640),
|
||||||
|
Felt::new(12381059245485642368),
|
||||||
|
Felt::new(2176361879916914688),
|
||||||
|
Felt::new(11209293198464735683),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(11677748883385181208),
|
||||||
|
Felt::new(15891398395707500576),
|
||||||
|
Felt::new(3790704659934033620),
|
||||||
|
Felt::new(2126099371106695189),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(13948603355603496603),
|
||||||
|
Felt::new(15902438544472945077),
|
||||||
|
Felt::new(1969361494026622497),
|
||||||
|
Felt::new(17326911676634210553),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(16081431322775411514),
|
||||||
|
Felt::new(13201312030265587002),
|
||||||
|
Felt::new(18283434127959076535),
|
||||||
|
Felt::new(9889802180847551599),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(8490051641633132830),
|
||||||
|
Felt::new(11985660456681176415),
|
||||||
|
Felt::new(12193381039977027251),
|
||||||
|
Felt::new(17563185381678568385),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(3870617340693651786),
|
||||||
|
Felt::new(2748490321246408799),
|
||||||
|
Felt::new(8501743976565218963),
|
||||||
|
Felt::new(1660720190266083389),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(2121119282758520982),
|
||||||
|
Felt::new(9042267662074029772),
|
||||||
|
Felt::new(15431993929052434204),
|
||||||
|
Felt::new(10659345458998811701),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(15206763021853065070),
|
||||||
|
Felt::new(15268692497656424421),
|
||||||
|
Felt::new(13335448435922172445),
|
||||||
|
Felt::new(3421340628484408379),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(5175159910654039438),
|
||||||
|
Felt::new(10258564296733764665),
|
||||||
|
Felt::new(235961379704359454),
|
||||||
|
Felt::new(18007006485615491006),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(9455184082727641653),
|
||||||
|
Felt::new(6634498452861935579),
|
||||||
|
Felt::new(18189776179964984407),
|
||||||
|
Felt::new(3546641211720870472),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(2566088177506289568),
|
||||||
|
Felt::new(7785941571143323572),
|
||||||
|
Felt::new(13948908169667863201),
|
||||||
|
Felt::new(8557252288425473395),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(8801845050152766755),
|
||||||
|
Felt::new(514652983374395586),
|
||||||
|
Felt::new(13975919271481418443),
|
||||||
|
Felt::new(17480955484347349170),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(7078477424334594989),
|
||||||
|
Felt::new(9975053207879493059),
|
||||||
|
Felt::new(5220656123503260168),
|
||||||
|
Felt::new(13795787984352794188),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(1478357986561897612),
|
||||||
|
Felt::new(3963701567400985039),
|
||||||
|
Felt::new(10269836564499521403),
|
||||||
|
Felt::new(11874873630603798755),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(936391814816943993),
|
||||||
|
Felt::new(6085855616346025677),
|
||||||
|
Felt::new(5782721339195502211),
|
||||||
|
Felt::new(10409491632083436908),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(11138475264090866271),
|
||||||
|
Felt::new(17799626597540451271),
|
||||||
|
Felt::new(17968790388406362807),
|
||||||
|
Felt::new(9539434947296310791),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(13051724588530357940),
|
||||||
|
Felt::new(8058102530250142518),
|
||||||
|
Felt::new(1861782711432586670),
|
||||||
|
Felt::new(2928050228215055187),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(10650694022550988030),
|
||||||
|
Felt::new(5634734408638476525),
|
||||||
|
Felt::new(9233115969432897632),
|
||||||
|
Felt::new(1437907447409278328),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(9720135276484706819),
|
||||||
|
Felt::new(9350120041401976641),
|
||||||
|
Felt::new(1348777594376050933),
|
||||||
|
Felt::new(13138246165242825648),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(10866643979409126085),
|
||||||
|
Felt::new(13790633638103642042),
|
||||||
|
Felt::new(6374461622011119670),
|
||||||
|
Felt::new(5702679962735491362),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(5257277882444261955),
|
||||||
|
Felt::new(8511211402794551302),
|
||||||
|
Felt::new(3294838877645533839),
|
||||||
|
Felt::new(4084864647832858048),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(7948776578097466250),
|
||||||
|
Felt::new(8630046431048474853),
|
||||||
|
Felt::new(11549811661672434609),
|
||||||
|
Felt::new(14329713552208961509),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(734617692582477804),
|
||||||
|
Felt::new(11871516935077749937),
|
||||||
|
Felt::new(12085935336918533812),
|
||||||
|
Felt::new(11028098016323141988),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(10937083382606895486),
|
||||||
|
Felt::new(12203867463821771187),
|
||||||
|
Felt::new(13369919265612777227),
|
||||||
|
Felt::new(2521482611471096233),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(1242037330294600071),
|
||||||
|
Felt::new(8643213198640797337),
|
||||||
|
Felt::new(14112360612081236212),
|
||||||
|
Felt::new(11296904697431650998),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(11958494925108187724),
|
||||||
|
Felt::new(6059642826232274823),
|
||||||
|
Felt::new(1563918267677757605),
|
||||||
|
Felt::new(266509853282035592),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(17288335252189973373),
|
||||||
|
Felt::new(3243363076395469373),
|
||||||
|
Felt::new(8880515798614590986),
|
||||||
|
Felt::new(10260780639137628077),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(1839714959437284152),
|
||||||
|
Felt::new(12088193186987715006),
|
||||||
|
Felt::new(10200898335013164008),
|
||||||
|
Felt::new(12768529781145127245),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(1537615626967151439),
|
||||||
|
Felt::new(11731506816677487155),
|
||||||
|
Felt::new(4748463589169553420),
|
||||||
|
Felt::new(17495851576537541106),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(957733314860117562),
|
||||||
|
Felt::new(15623410588944187169),
|
||||||
|
Felt::new(4321611031548662227),
|
||||||
|
Felt::new(12856104259650439278),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(14827447693720375746),
|
||||||
|
Felt::new(17296925942589213350),
|
||||||
|
Felt::new(13524332314559504765),
|
||||||
|
Felt::new(15663886706087995199),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(18185978518863914335),
|
||||||
|
Felt::new(936586966360019113),
|
||||||
|
Felt::new(497299419609993926),
|
||||||
|
Felt::new(1977881506773614749),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([
|
||||||
|
Felt::new(8635338869442206704),
|
||||||
|
Felt::new(11671305615285950885),
|
||||||
|
Felt::new(15253023094703789604),
|
||||||
|
Felt::new(7398108415970215319),
|
||||||
|
]),
|
||||||
|
RpoDigest::new([ZERO; WORD_SIZE]),
|
||||||
|
];
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn all_depths_opens_to_zero() {
|
||||||
|
use super::Rpo256;
|
||||||
|
|
||||||
|
for depth in 1..=64 {
|
||||||
|
// fetch the subtrees and reverse it so the path is leaf -> root
|
||||||
|
let mut subtree = EmptySubtreeRoots::empty_hashes(depth).to_vec();
|
||||||
|
subtree.reverse();
|
||||||
|
|
||||||
|
// the length of the subtrees set must be equal to depth + 1 as we also
|
||||||
|
// include the root
|
||||||
|
assert_eq!(depth as usize + 1, subtree.len());
|
||||||
|
|
||||||
|
// assert the opening is zero
|
||||||
|
let initial = RpoDigest::new([ZERO; WORD_SIZE]);
|
||||||
|
assert_eq!(initial, subtree.remove(0));
|
||||||
|
|
||||||
|
// compute every node of the path manually and compare with the output
|
||||||
|
subtree
|
||||||
|
.into_iter()
|
||||||
|
.scan(initial, |state, x| {
|
||||||
|
*state = Rpo256::merge(&[*state; 2]);
|
||||||
|
Some((x, *state))
|
||||||
|
})
|
||||||
|
.for_each(|(x, computed)| assert_eq!(x, computed));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn arbitrary_inputs_will_generate_sound_slices() {
|
||||||
|
let min = &EMPTY_SUBTREES_64[0] as *const RpoDigest;
|
||||||
|
let max = unsafe { min.add(64) };
|
||||||
|
for depth in 0..=64 {
|
||||||
|
let subtree = EmptySubtreeRoots::empty_hashes(depth);
|
||||||
|
let first = &subtree[0] as *const RpoDigest;
|
||||||
|
let last = &subtree[depth as usize] as *const RpoDigest;
|
||||||
|
assert!(min <= first && first <= max);
|
||||||
|
assert!(min <= last && last <= max);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,16 @@
|
||||||
use super::{
|
use super::{
|
||||||
hash::rpo::{Rpo256, RpoDigest},
|
hash::rpo::{Rpo256, RpoDigest},
|
||||||
utils::collections::{vec, BTreeMap, Vec},
|
utils::collections::{vec, BTreeMap, Vec},
|
||||||
Felt, StarkField, Word, ZERO,
|
Felt, StarkField, Word, WORD_SIZE, ZERO,
|
||||||
};
|
};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
// REEXPORTS
|
// REEXPORTS
|
||||||
// ================================================================================================
|
// ================================================================================================
|
||||||
|
|
||||||
|
mod empty_roots;
|
||||||
|
pub use empty_roots::EmptySubtreeRoots;
|
||||||
|
|
||||||
mod index;
|
mod index;
|
||||||
pub use index::NodeIndex;
|
pub use index::NodeIndex;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use super::{BTreeMap, MerkleError, MerklePath, NodeIndex, Rpo256, RpoDigest, Vec, Word};
|
use super::{
|
||||||
|
BTreeMap, EmptySubtreeRoots, MerkleError, MerklePath, NodeIndex, Rpo256, RpoDigest, Vec, Word,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
@ -29,38 +31,55 @@ impl SimpleSmt {
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Creates a new simple SMT.
|
/// Creates a new simple SMT with the provided depth.
|
||||||
///
|
pub fn new(depth: u8) -> Result<Self, MerkleError> {
|
||||||
/// The provided entries will be tuples of the leaves and their corresponding keys.
|
// validate the range of the depth.
|
||||||
|
if depth < Self::MIN_DEPTH {
|
||||||
|
return Err(MerkleError::DepthTooSmall(depth));
|
||||||
|
} else if Self::MAX_DEPTH < depth {
|
||||||
|
return Err(MerkleError::DepthTooBig(depth as u64));
|
||||||
|
}
|
||||||
|
|
||||||
|
let (store, root) = Store::new(depth);
|
||||||
|
Ok(Self { root, depth, store })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Appends the provided entries as leaves of the tree.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// The function will fail if the provided entries count exceed the maximum tree capacity, that
|
/// The function will fail if the provided entries count exceed the maximum tree capacity, that
|
||||||
/// is `2^{depth}`.
|
/// is `2^{depth}`.
|
||||||
pub fn new<R, I>(entries: R, depth: u8) -> Result<Self, MerkleError>
|
pub fn with_leaves<R, I>(mut self, entries: R) -> Result<Self, MerkleError>
|
||||||
where
|
where
|
||||||
R: IntoIterator<IntoIter = I>,
|
R: IntoIterator<IntoIter = I>,
|
||||||
I: Iterator<Item = (u64, Word)> + ExactSizeIterator,
|
I: Iterator<Item = (u64, Word)> + ExactSizeIterator,
|
||||||
{
|
{
|
||||||
|
// check if the leaves count will fit the depth setup
|
||||||
let mut entries = entries.into_iter();
|
let mut entries = entries.into_iter();
|
||||||
|
let max = 1 << self.depth;
|
||||||
// validate the range of the depth.
|
if entries.len() > max {
|
||||||
let max = 1 << depth;
|
|
||||||
if depth < Self::MIN_DEPTH {
|
|
||||||
return Err(MerkleError::DepthTooSmall(depth));
|
|
||||||
} else if Self::MAX_DEPTH < depth {
|
|
||||||
return Err(MerkleError::DepthTooBig(depth as u64));
|
|
||||||
} else if entries.len() > max {
|
|
||||||
return Err(MerkleError::InvalidEntriesCount(max, entries.len()));
|
return Err(MerkleError::InvalidEntriesCount(max, entries.len()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (store, root) = Store::new(depth);
|
// append leaves and return
|
||||||
let mut tree = Self { root, depth, store };
|
entries.try_for_each(|(key, leaf)| self.insert_leaf(key, leaf))?;
|
||||||
entries.try_for_each(|(key, leaf)| tree.insert_leaf(key, leaf))?;
|
Ok(self)
|
||||||
|
|
||||||
Ok(tree)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Replaces the internal empty digests used when a given depth doesn't contain a node.
|
||||||
|
pub fn with_empty_subtrees<I>(mut self, hashes: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = RpoDigest>,
|
||||||
|
{
|
||||||
|
self.store
|
||||||
|
.replace_empty_subtrees(hashes.into_iter().collect());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUBLIC ACCESSORS
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Returns the root of this Merkle tree.
|
/// Returns the root of this Merkle tree.
|
||||||
pub const fn root(&self) -> Word {
|
pub const fn root(&self) -> Word {
|
||||||
self.root
|
self.root
|
||||||
|
@ -71,6 +90,9 @@ impl SimpleSmt {
|
||||||
self.depth
|
self.depth
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PROVIDERS
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Returns the set count of the keys of the leaves.
|
/// Returns the set count of the keys of the leaves.
|
||||||
pub fn leaves_count(&self) -> usize {
|
pub fn leaves_count(&self) -> usize {
|
||||||
self.store.leaves_count()
|
self.store.leaves_count()
|
||||||
|
@ -81,16 +103,24 @@ impl SimpleSmt {
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// Returns an error if:
|
/// Returns an error if:
|
||||||
/// * The specified depth is greater than the depth of the tree.
|
/// * The specified depth is greater than the depth of the tree.
|
||||||
/// * The specified key does not exist
|
|
||||||
pub fn get_node(&self, index: &NodeIndex) -> Result<Word, MerkleError> {
|
pub fn get_node(&self, index: &NodeIndex) -> Result<Word, MerkleError> {
|
||||||
if index.is_root() {
|
if index.is_root() {
|
||||||
Err(MerkleError::DepthTooSmall(index.depth()))
|
Err(MerkleError::DepthTooSmall(index.depth()))
|
||||||
} else if index.depth() > self.depth() {
|
} else if index.depth() > self.depth() {
|
||||||
Err(MerkleError::DepthTooBig(index.depth() as u64))
|
Err(MerkleError::DepthTooBig(index.depth() as u64))
|
||||||
} else if index.depth() == self.depth() {
|
} else if index.depth() == self.depth() {
|
||||||
self.store.get_leaf_node(index.value())
|
self.store
|
||||||
|
.get_leaf_node(index.value())
|
||||||
|
.or_else(|| {
|
||||||
|
self.store
|
||||||
|
.empty_hashes
|
||||||
|
.get(index.depth() as usize)
|
||||||
|
.copied()
|
||||||
|
.map(Word::from)
|
||||||
|
})
|
||||||
|
.ok_or(MerkleError::InvalidIndex(*index))
|
||||||
} else {
|
} else {
|
||||||
let branch_node = self.store.get_branch_node(index)?;
|
let branch_node = self.store.get_branch_node(index);
|
||||||
Ok(Rpo256::merge(&[branch_node.left, branch_node.right]).into())
|
Ok(Rpo256::merge(&[branch_node.left, branch_node.right]).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,23 +130,19 @@ impl SimpleSmt {
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// Returns an error if:
|
/// Returns an error if:
|
||||||
/// * The specified key does not exist as a branch or leaf node
|
|
||||||
/// * The specified depth is greater than the depth of the tree.
|
/// * The specified depth is greater than the depth of the tree.
|
||||||
pub fn get_path(&self, mut index: NodeIndex) -> Result<MerklePath, MerkleError> {
|
pub fn get_path(&self, mut index: NodeIndex) -> Result<MerklePath, MerkleError> {
|
||||||
if index.is_root() {
|
if index.is_root() {
|
||||||
return Err(MerkleError::DepthTooSmall(index.depth()));
|
return Err(MerkleError::DepthTooSmall(index.depth()));
|
||||||
} else if index.depth() > self.depth() {
|
} else if index.depth() > self.depth() {
|
||||||
return Err(MerkleError::DepthTooBig(index.depth() as u64));
|
return Err(MerkleError::DepthTooBig(index.depth() as u64));
|
||||||
} else if index.depth() == self.depth() && !self.store.check_leaf_node_exists(index.value())
|
|
||||||
{
|
|
||||||
return Err(MerkleError::InvalidIndex(index.with_depth(self.depth())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut path = Vec::with_capacity(index.depth() as usize);
|
let mut path = Vec::with_capacity(index.depth() as usize);
|
||||||
for _ in 0..index.depth() {
|
for _ in 0..index.depth() {
|
||||||
let is_right = index.is_value_odd();
|
let is_right = index.is_value_odd();
|
||||||
index.move_up();
|
index.move_up();
|
||||||
let BranchNode { left, right } = self.store.get_branch_node(&index)?;
|
let BranchNode { left, right } = self.store.get_branch_node(&index);
|
||||||
let value = if is_right { left } else { right };
|
let value = if is_right { left } else { right };
|
||||||
path.push(*value);
|
path.push(*value);
|
||||||
}
|
}
|
||||||
|
@ -133,6 +159,9 @@ impl SimpleSmt {
|
||||||
self.get_path(NodeIndex::new(self.depth(), key))
|
self.get_path(NodeIndex::new(self.depth(), key))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// STATE MUTATORS
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Replaces the leaf located at the specified key, and recomputes hashes by walking up the tree
|
/// Replaces the leaf located at the specified key, and recomputes hashes by walking up the tree
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
|
@ -156,10 +185,7 @@ impl SimpleSmt {
|
||||||
for _ in 0..index.depth() {
|
for _ in 0..index.depth() {
|
||||||
let is_right = index.is_value_odd();
|
let is_right = index.is_value_odd();
|
||||||
index.move_up();
|
index.move_up();
|
||||||
let BranchNode { left, right } = self
|
let BranchNode { left, right } = self.store.get_branch_node(&index);
|
||||||
.store
|
|
||||||
.get_branch_node(&index)
|
|
||||||
.unwrap_or_else(|_| self.store.get_empty_node(index.depth() as usize + 1));
|
|
||||||
let (left, right) = if is_right {
|
let (left, right) = if is_right {
|
||||||
(left, value)
|
(left, value)
|
||||||
} else {
|
} else {
|
||||||
|
@ -200,16 +226,7 @@ impl Store {
|
||||||
let leaves = BTreeMap::new();
|
let leaves = BTreeMap::new();
|
||||||
|
|
||||||
// Construct empty node digests for each layer of the tree
|
// Construct empty node digests for each layer of the tree
|
||||||
let empty_hashes: Vec<RpoDigest> = (0..depth + 1)
|
let empty_hashes = EmptySubtreeRoots::empty_hashes(depth).to_vec();
|
||||||
.scan(Word::default().into(), |state, _| {
|
|
||||||
let value = *state;
|
|
||||||
*state = Rpo256::merge(&[value, value]);
|
|
||||||
Some(value)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.into_iter()
|
|
||||||
.rev()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let root = empty_hashes[0].into();
|
let root = empty_hashes[0].into();
|
||||||
let store = Self {
|
let store = Self {
|
||||||
|
@ -222,34 +239,30 @@ impl Store {
|
||||||
(store, root)
|
(store, root)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_empty_node(&self, depth: usize) -> BranchNode {
|
fn replace_empty_subtrees(&mut self, hashes: Vec<RpoDigest>) {
|
||||||
let digest = self.empty_hashes[depth];
|
self.empty_hashes = hashes;
|
||||||
BranchNode {
|
|
||||||
left: digest,
|
|
||||||
right: digest,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_leaf_node_exists(&self, key: u64) -> bool {
|
fn check_leaf_node_exists(&self, key: u64) -> bool {
|
||||||
self.leaves.contains_key(&key)
|
self.leaves.contains_key(&key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_leaf_node(&self, key: u64) -> Result<Word, MerkleError> {
|
fn get_leaf_node(&self, key: u64) -> Option<Word> {
|
||||||
self.leaves
|
self.leaves.get(&key).copied()
|
||||||
.get(&key)
|
|
||||||
.cloned()
|
|
||||||
.ok_or(MerkleError::InvalidIndex(NodeIndex::new(self.depth, key)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_leaf_node(&mut self, key: u64, node: Word) {
|
fn insert_leaf_node(&mut self, key: u64, node: Word) {
|
||||||
self.leaves.insert(key, node);
|
self.leaves.insert(key, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_branch_node(&self, index: &NodeIndex) -> Result<BranchNode, MerkleError> {
|
fn get_branch_node(&self, index: &NodeIndex) -> BranchNode {
|
||||||
self.branches
|
self.branches.get(index).cloned().unwrap_or_else(|| {
|
||||||
.get(index)
|
let node = self.empty_hashes[index.depth() as usize + 1];
|
||||||
.cloned()
|
BranchNode {
|
||||||
.ok_or(MerkleError::InvalidIndex(*index))
|
left: node,
|
||||||
|
right: node,
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_branch_node(&mut self, index: NodeIndex, left: RpoDigest, right: RpoDigest) {
|
fn insert_branch_node(&mut self, index: NodeIndex, left: RpoDigest, right: RpoDigest) {
|
||||||
|
|
|
@ -2,7 +2,6 @@ use super::{
|
||||||
super::{int_to_node, MerkleTree, RpoDigest, SimpleSmt},
|
super::{int_to_node, MerkleTree, RpoDigest, SimpleSmt},
|
||||||
NodeIndex, Rpo256, Vec, Word,
|
NodeIndex, Rpo256, Vec, Word,
|
||||||
};
|
};
|
||||||
use core::iter;
|
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use rand_utils::prng_array;
|
use rand_utils::prng_array;
|
||||||
|
|
||||||
|
@ -31,7 +30,7 @@ const ZERO_VALUES8: [Word; 8] = [int_to_node(0); 8];
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn build_empty_tree() {
|
fn build_empty_tree() {
|
||||||
let smt = SimpleSmt::new(iter::empty(), 3).unwrap();
|
let smt = SimpleSmt::new(3).unwrap();
|
||||||
let mt = MerkleTree::new(ZERO_VALUES8.to_vec()).unwrap();
|
let mt = MerkleTree::new(ZERO_VALUES8.to_vec()).unwrap();
|
||||||
assert_eq!(mt.root(), smt.root());
|
assert_eq!(mt.root(), smt.root());
|
||||||
}
|
}
|
||||||
|
@ -39,7 +38,7 @@ fn build_empty_tree() {
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_digests_are_consistent() {
|
fn empty_digests_are_consistent() {
|
||||||
let depth = 5;
|
let depth = 5;
|
||||||
let root = SimpleSmt::new(iter::empty(), depth).unwrap().root();
|
let root = SimpleSmt::new(depth).unwrap().root();
|
||||||
let computed: [RpoDigest; 2] = (0..depth).fold([Default::default(); 2], |state, _| {
|
let computed: [RpoDigest; 2] = (0..depth).fold([Default::default(); 2], |state, _| {
|
||||||
let digest = Rpo256::merge(&state);
|
let digest = Rpo256::merge(&state);
|
||||||
[digest; 2]
|
[digest; 2]
|
||||||
|
@ -50,7 +49,7 @@ fn empty_digests_are_consistent() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn build_sparse_tree() {
|
fn build_sparse_tree() {
|
||||||
let mut smt = SimpleSmt::new(iter::empty(), 3).unwrap();
|
let mut smt = SimpleSmt::new(3).unwrap();
|
||||||
let mut values = ZERO_VALUES8.to_vec();
|
let mut values = ZERO_VALUES8.to_vec();
|
||||||
|
|
||||||
// insert single value
|
// insert single value
|
||||||
|
@ -82,7 +81,10 @@ fn build_sparse_tree() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn build_full_tree() {
|
fn build_full_tree() {
|
||||||
let tree = SimpleSmt::new(KEYS4.into_iter().zip(VALUES4.into_iter()), 2).unwrap();
|
let tree = SimpleSmt::new(2)
|
||||||
|
.unwrap()
|
||||||
|
.with_leaves(KEYS4.into_iter().zip(VALUES4.into_iter()))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let (root, node2, node3) = compute_internal_nodes();
|
let (root, node2, node3) = compute_internal_nodes();
|
||||||
assert_eq!(root, tree.root());
|
assert_eq!(root, tree.root());
|
||||||
|
@ -92,7 +94,10 @@ fn build_full_tree() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_values() {
|
fn get_values() {
|
||||||
let tree = SimpleSmt::new(KEYS4.into_iter().zip(VALUES4.into_iter()), 2).unwrap();
|
let tree = SimpleSmt::new(2)
|
||||||
|
.unwrap()
|
||||||
|
.with_leaves(KEYS4.into_iter().zip(VALUES4.into_iter()))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// check depth 2
|
// check depth 2
|
||||||
assert_eq!(VALUES4[0], tree.get_node(&NodeIndex::new(2, 0)).unwrap());
|
assert_eq!(VALUES4[0], tree.get_node(&NodeIndex::new(2, 0)).unwrap());
|
||||||
|
@ -103,7 +108,10 @@ fn get_values() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_path() {
|
fn get_path() {
|
||||||
let tree = SimpleSmt::new(KEYS4.into_iter().zip(VALUES4.into_iter()), 2).unwrap();
|
let tree = SimpleSmt::new(2)
|
||||||
|
.unwrap()
|
||||||
|
.with_leaves(KEYS4.into_iter().zip(VALUES4.into_iter()))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let (_, node2, node3) = compute_internal_nodes();
|
let (_, node2, node3) = compute_internal_nodes();
|
||||||
|
|
||||||
|
@ -132,17 +140,19 @@ fn get_path() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn update_leaf() {
|
fn update_leaf() {
|
||||||
let mut tree = SimpleSmt::new(KEYS8.into_iter().zip(VALUES8.into_iter()), 3).unwrap();
|
let mut tree = SimpleSmt::new(3)
|
||||||
|
.unwrap()
|
||||||
|
.with_leaves(KEYS8.into_iter().zip(VALUES8.into_iter()))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// update one value
|
// update one value
|
||||||
let key = 3;
|
let key = 3;
|
||||||
let new_node = int_to_node(9);
|
let new_node = int_to_node(9);
|
||||||
let mut expected_values = VALUES8.to_vec();
|
let mut expected_values = VALUES8.to_vec();
|
||||||
expected_values[key] = new_node;
|
expected_values[key] = new_node;
|
||||||
let expected_tree = SimpleSmt::new(
|
let expected_tree = SimpleSmt::new(3)
|
||||||
KEYS8.into_iter().zip(expected_values.clone().into_iter()),
|
.unwrap()
|
||||||
3,
|
.with_leaves(KEYS8.into_iter().zip(expected_values.clone().into_iter()))
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
tree.update_leaf(key as u64, new_node).unwrap();
|
tree.update_leaf(key as u64, new_node).unwrap();
|
||||||
|
@ -152,8 +162,10 @@ fn update_leaf() {
|
||||||
let key = 6;
|
let key = 6;
|
||||||
let new_node = int_to_node(10);
|
let new_node = int_to_node(10);
|
||||||
expected_values[key] = new_node;
|
expected_values[key] = new_node;
|
||||||
let expected_tree =
|
let expected_tree = SimpleSmt::new(3)
|
||||||
SimpleSmt::new(KEYS8.into_iter().zip(expected_values.into_iter()), 3).unwrap();
|
.unwrap()
|
||||||
|
.with_leaves(KEYS8.into_iter().zip(expected_values.into_iter()))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
tree.update_leaf(key as u64, new_node).unwrap();
|
tree.update_leaf(key as u64, new_node).unwrap();
|
||||||
assert_eq!(expected_tree.root, tree.root);
|
assert_eq!(expected_tree.root, tree.root);
|
||||||
|
@ -188,7 +200,7 @@ fn small_tree_opening_is_consistent() {
|
||||||
|
|
||||||
let depth = 3;
|
let depth = 3;
|
||||||
let entries = vec![(0, a), (1, b), (4, c), (7, d)];
|
let entries = vec![(0, a), (1, b), (4, c), (7, d)];
|
||||||
let tree = SimpleSmt::new(entries, depth).unwrap();
|
let tree = SimpleSmt::new(depth).unwrap().with_leaves(entries).unwrap();
|
||||||
|
|
||||||
assert_eq!(tree.root(), Word::from(k));
|
assert_eq!(tree.root(), Word::from(k));
|
||||||
|
|
||||||
|
@ -219,7 +231,7 @@ proptest! {
|
||||||
key in prop::num::u64::ANY,
|
key in prop::num::u64::ANY,
|
||||||
leaf in prop::num::u64::ANY,
|
leaf in prop::num::u64::ANY,
|
||||||
) {
|
) {
|
||||||
let mut tree = SimpleSmt::new(iter::empty(), depth).unwrap();
|
let mut tree = SimpleSmt::new(depth).unwrap();
|
||||||
|
|
||||||
let key = key % (1 << depth as u64);
|
let key = key % (1 << depth as u64);
|
||||||
let leaf = int_to_node(leaf);
|
let leaf = int_to_node(leaf);
|
||||||
|
@ -240,7 +252,7 @@ proptest! {
|
||||||
count in 2u8..10u8,
|
count in 2u8..10u8,
|
||||||
ref seed in any::<[u8; 32]>()
|
ref seed in any::<[u8; 32]>()
|
||||||
) {
|
) {
|
||||||
let mut tree = SimpleSmt::new(iter::empty(), depth).unwrap();
|
let mut tree = SimpleSmt::new(depth).unwrap();
|
||||||
let mut seed = *seed;
|
let mut seed = *seed;
|
||||||
let leaves = (1 << depth) - 1;
|
let leaves = (1 << depth) - 1;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue