-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
706 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
use banderwagon::{msm::MSMPrecompWnaf, Element, Fr, Zero}; | ||
use once_cell::sync::Lazy; | ||
|
||
use crate::{constants::VERKLE_NODE_WIDTH, crs::CRS}; | ||
|
||
pub static DEFAULT_COMMITER: Lazy<Committer> = Lazy::new(Committer::new); | ||
|
||
pub struct Committer { | ||
precomp: MSMPrecompWnaf, | ||
} | ||
|
||
impl Committer { | ||
fn new() -> Self { | ||
Self { | ||
precomp: MSMPrecompWnaf::new(CRS.as_slice(), 12), | ||
} | ||
} | ||
|
||
// Commit to a lagrange polynomial, evaluations.len() must equal the size of the CRS at the moment | ||
pub fn commit_lagrange(&self, evaluations: &[Fr]) -> Element { | ||
// Preliminary benchmarks indicate that the parallel version is faster | ||
// for vectors of length 64 or more | ||
if evaluations.len() >= 64 { | ||
self.precomp.mul_par(evaluations) | ||
} else { | ||
self.precomp.mul(evaluations) | ||
} | ||
} | ||
|
||
pub fn scalar_mul(&self, index: usize, value: Fr) -> Element { | ||
self.precomp.mul_index(value, index) | ||
} | ||
|
||
pub fn commit_sparse(&self, evaluations: Vec<(usize, Fr)>) -> Element { | ||
// TODO consider if 64 is good value | ||
if evaluations.len() >= 64 { | ||
let mut dense = [Fr::zero(); VERKLE_NODE_WIDTH]; | ||
for (index, value) in evaluations { | ||
dense[index] = value; | ||
} | ||
self.commit_lagrange(&dense) | ||
} else { | ||
let mut result = Element::zero(); | ||
for (index, value) in evaluations { | ||
result += self.scalar_mul(index, value) | ||
} | ||
result | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub const VERKLE_NODE_WIDTH: usize = 256; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,34 @@ | ||
use alloy_primitives::{B256, U256}; | ||
use derive_more::{Deref, Index}; | ||
|
||
use banderwagon::Fr; | ||
pub use stem::Stem as TrieStem; | ||
|
||
mod committer; | ||
mod constants; | ||
pub mod crs; | ||
pub mod nodes; | ||
mod stem; | ||
pub mod trie; | ||
mod utils; | ||
|
||
pub type TrieValue = U256; | ||
|
||
type Db = dyn db::Db<Fr, Vec<u8>>; | ||
|
||
#[derive(PartialEq, Eq, Clone, Index, Deref)] | ||
pub struct TrieKey(B256); | ||
|
||
impl TrieKey { | ||
pub fn length() -> usize { | ||
B256::len_bytes() | ||
} | ||
|
||
pub fn stem(&self) -> stem::Stem { | ||
self.into() | ||
} | ||
|
||
pub fn last(&self) -> u8 { | ||
self[self.len() - 1] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
use std::{array, collections::BTreeMap, ops::DerefMut}; | ||
|
||
use alloy_primitives::B256; | ||
use anyhow::Result; | ||
use banderwagon::{Element, Fr}; | ||
use ssz::{Decode, Encode}; | ||
|
||
use crate::{ | ||
committer::DEFAULT_COMMITER, | ||
constants::VERKLE_NODE_WIDTH, | ||
utils::{b256_to_fr, fr_to_b256}, | ||
Db, TrieKey, TrieValue, | ||
}; | ||
|
||
use super::{node::NodeTrait, Node}; | ||
|
||
pub struct BranchNode { | ||
values: Box<[Node; VERKLE_NODE_WIDTH]>, | ||
cp: Element, | ||
} | ||
|
||
impl BranchNode { | ||
pub fn new() -> Self { | ||
Self { | ||
values: array::from_fn(|_| Node::Empty).into(), | ||
cp: Element::zero(), | ||
} | ||
} | ||
|
||
pub fn set(&mut self, index: usize, node: Node) { | ||
let node_at_index = &mut self.values[index]; | ||
let pre_commitment = node_at_index.commit(); | ||
*node_at_index = node; | ||
let post_commitment = node_at_index.commit(); | ||
self.cp += DEFAULT_COMMITER.scalar_mul(index, post_commitment - pre_commitment); | ||
} | ||
|
||
pub(super) fn get_mut(&mut self, index: usize) -> &mut Node { | ||
&mut self.values[index] | ||
} | ||
|
||
pub fn insert(&mut self, depth: usize, key: TrieKey, value: TrieValue, db: &Db) -> Result<()> { | ||
let index = key[depth] as usize; | ||
let node = &mut self.values[index]; | ||
let pre_commitment = node.commit(); | ||
node.insert(depth + 1, key, value, db)?; | ||
let post_commitment = node.commit(); | ||
self.cp += DEFAULT_COMMITER.scalar_mul(index, post_commitment - pre_commitment); | ||
Ok(()) | ||
} | ||
|
||
pub fn write_and_commit(&mut self, db: &mut Db) -> Result<Fr> { | ||
for node in self.values.deref_mut() { | ||
node.write_and_commit(db)?; | ||
} | ||
Ok(self.commit()) | ||
} | ||
} | ||
|
||
impl Default for BranchNode { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} | ||
|
||
impl NodeTrait for BranchNode { | ||
fn commit(&self) -> Fr { | ||
self.cp.map_to_scalar_field() | ||
} | ||
} | ||
|
||
impl Encode for BranchNode { | ||
fn is_ssz_fixed_len() -> bool { | ||
false | ||
} | ||
|
||
fn ssz_append(&self, buf: &mut Vec<u8>) { | ||
let commitments: BTreeMap<u8, B256> = self | ||
.values | ||
.iter() | ||
.enumerate() | ||
.filter_map(|(index, node)| { | ||
if node.is_empty() { | ||
None | ||
} else { | ||
Some((index as u8, fr_to_b256(&node.commit()))) | ||
} | ||
}) | ||
.collect(); | ||
commitments.ssz_append(buf); | ||
} | ||
|
||
fn ssz_bytes_len(&self) -> usize { | ||
// TODO: optimize this | ||
// let number_of_non_empty_items = self.values.iter().filter(|node| !node.is_empty()).count(); | ||
// let size_per_item = <(u8, B256) as Decode>::ssz_fixed_len() ; | ||
// number_of_non_empty_items * size_per_item | ||
self.as_ssz_bytes().len() | ||
} | ||
} | ||
|
||
impl Decode for BranchNode { | ||
fn is_ssz_fixed_len() -> bool { | ||
false | ||
} | ||
|
||
fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> { | ||
let commitments = BTreeMap::<u8, B256>::from_ssz_bytes(bytes)?; | ||
let commitments: BTreeMap<usize, Fr> = commitments | ||
.iter() | ||
.map(|(index, commitment)| (*index as usize, b256_to_fr(commitment))) | ||
.collect(); | ||
|
||
let values = array::from_fn(|i| { | ||
commitments | ||
.get(&i) | ||
.map(|c| Node::Commitment(*c)) | ||
.unwrap_or_default() | ||
}); | ||
let cp = DEFAULT_COMMITER.commit_sparse(commitments.into_iter().collect()); | ||
|
||
Ok(Self { | ||
values: values.into(), | ||
cp, | ||
}) | ||
} | ||
} |
Oops, something went wrong.