├── packages └── ff_utils │ ├── .gitignore │ ├── src │ ├── lib.rs │ ├── utils.rs │ ├── bn256_fr.rs │ └── bn256_fs.rs │ ├── Cargo.toml │ └── Cargo.lock ├── .gitignore ├── src ├── verkle_tree │ ├── mod.rs │ ├── utils.rs │ └── witness.rs ├── verkle_tree_fs │ ├── mod.rs │ ├── utils.rs │ ├── witness.rs │ └── trie.rs ├── ipa_fr │ ├── rns.rs │ ├── proof.rs │ ├── transcript.rs │ ├── utils.rs │ ├── config.rs │ └── mod.rs ├── lib.rs ├── ipa_fs │ ├── proof.rs │ ├── config.rs │ ├── transcript.rs │ ├── utils.rs │ └── mod.rs ├── main.rs ├── bn256_verkle_tree │ ├── path.rs │ ├── leaf.rs │ └── mod.rs ├── bn256_verkle_tree_fs │ ├── leaf.rs │ └── mod.rs ├── batch_proof_fs │ └── mod.rs └── batch_proof_fr │ └── mod.rs ├── .vscode ├── settings.json └── launch.json ├── Cargo.toml ├── test_cases ├── fr_case1 │ └── proof.json └── fs_case1 │ └── proof.json └── README.md /packages/ff_utils/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /test_cases/*/elements.json -------------------------------------------------------------------------------- /src/verkle_tree/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod trie; 2 | pub mod utils; 3 | pub mod witness; 4 | -------------------------------------------------------------------------------- /src/verkle_tree_fs/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod trie; 2 | pub mod utils; 3 | pub mod witness; 4 | -------------------------------------------------------------------------------- /packages/ff_utils/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod bn256_fr; 2 | pub mod bn256_fs; 3 | pub mod utils; 4 | -------------------------------------------------------------------------------- /src/ipa_fr/rns.rs: -------------------------------------------------------------------------------- 1 | use franklin_crypto::bellman::pairing::Engine; 2 | use franklin_crypto::bellman::CurveAffine; 3 | use franklin_crypto::plonk::circuit::bigint::field::RnsParameters; 4 | 5 | #[warn(type_alias_bounds)] 6 | pub type BaseRnsParameters = RnsParameters::G1Affine as CurveAffine>::Base>; 7 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod batch_proof_fr; 2 | pub mod batch_proof_fs; 3 | pub mod bn256_verkle_tree; 4 | pub mod bn256_verkle_tree_fs; 5 | pub mod ipa_fr; 6 | pub mod ipa_fs; 7 | pub mod verkle_tree; 8 | pub mod verkle_tree_fs; 9 | 10 | pub extern crate ff; 11 | pub extern crate ff_utils; 12 | pub extern crate franklin_crypto; 13 | pub extern crate neptune; 14 | -------------------------------------------------------------------------------- /packages/ff_utils/src/utils.rs: -------------------------------------------------------------------------------- 1 | use hex::FromHexError; 2 | 3 | pub trait ToBytes { 4 | fn to_bytes_be(&self) -> Result, FromHexError>; 5 | fn to_bytes_le(&self) -> Result, FromHexError>; 6 | } 7 | 8 | pub trait FromBytes 9 | where 10 | Self: Sized, 11 | { 12 | fn from_bytes_be(value: &[u8]) -> Option; 13 | fn from_bytes_le(value: &[u8]) -> Option; 14 | } 15 | -------------------------------------------------------------------------------- /packages/ff_utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ff_utils" 3 | version = "1.0.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | ff = { version = "0.11.0", features = ["default", "derive"] } 8 | group = "0.10" 9 | pairing_ce = "0.24.2" 10 | subtle = "2.4" 11 | byteorder = "1" 12 | bitvec = "0.22" 13 | rand_core = "0.6" 14 | num = "0.4" 15 | hex = "0.4.3" 16 | serde = { version = "^1.0.101", features = ["derive"] } 17 | anyhow = "1.0" 18 | thiserror = "1.0" 19 | num_cpus = "1" 20 | crossbeam = "0.7" 21 | 22 | [lib] 23 | name = "ff_utils" 24 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.formatOnPaste": true, 4 | "[rust]": { 5 | "editor.formatOnSave": true, 6 | "files.insertFinalNewline": true, 7 | "files.trimFinalNewlines": true, 8 | "files.trimTrailingWhitespace": true 9 | }, 10 | "cSpell.words": [ 11 | "coeff", 12 | "coeffs", 13 | "coord", 14 | "eval", 15 | "evals", 16 | "groth", 17 | "hasher", 18 | "ifft", 19 | "inputize", 20 | "interp", 21 | "interpolant", 22 | "Jubjub", 23 | "mkdir", 24 | "multipack", 25 | "polyn", 26 | "repr", 27 | "serde", 28 | "structopt", 29 | "vals", 30 | "verkle" 31 | ], 32 | "rust.wait_to_build": 1000 33 | } 34 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "lldb", 9 | "request": "launch", 10 | "name": "Debug `test_ipa_proof_create_verify` in library 'verkle-tree'", 11 | "cargo": { 12 | "args": ["test", "--no-run", "--lib", "--package=verkle-tree"], 13 | "filter": { 14 | "name": "verkle-tree", 15 | "kind": "lib" 16 | } 17 | }, 18 | "args": ["test_ipa_proof_create_verify"], 19 | "cwd": "${workspaceFolder}" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "verkle-tree" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | anyhow = "1.0" 10 | blake2s_simd = "1.0.0" 11 | bytes = "1.1" 12 | byteorder = "1.4" 13 | cfg-if = "1.0.0" 14 | ff = { version = "0.11.0", features = ["derive"] } 15 | generic-array = "0.14.5" 16 | hex = "0.4" 17 | neptune = "5.1.0" 18 | num-bigint = "0.3" 19 | rand = "0.4" 20 | serde = { version = "1.0", features = ["derive"] } 21 | serde_json = "1.0" 22 | sha2 = "0.10" 23 | thiserror = "1.0" 24 | franklin-crypto = {git = "https://github.com/matter-labs/franklin-crypto", branch = "beta", features = ["multicore", "plonk"]} 25 | ff_utils = { version = "1.0.0", path = "./packages/ff_utils" } 26 | 27 | [lib] 28 | name = "verkle_tree" 29 | -------------------------------------------------------------------------------- /src/verkle_tree/utils.rs: -------------------------------------------------------------------------------- 1 | use franklin_crypto::bellman::{CurveAffine, PrimeField}; 2 | 3 | use crate::ipa_fr::utils::{read_field_element_le, write_field_element_le}; 4 | 5 | pub fn point_to_field_element(point: &GA) -> anyhow::Result 6 | where 7 | GA::Base: PrimeField, 8 | { 9 | let (_point_x, point_y) = point.into_xy_unchecked(); 10 | let mut point_bytes = write_field_element_le(&point_y); 11 | // let mut point_bytes_x = write_field_element_le(&_point_x); 12 | // point_bytes.append(&mut point_bytes_x); 13 | 14 | // let num_bits_rest = GA::Scalar::NUM_BITS - 248; 15 | // let mask = (1 << (num_bits_rest - 1)) - 1; 16 | let mask = 0b00011111; 17 | point_bytes[31] &= mask; 18 | let result = read_field_element_le(&point_bytes)?; 19 | 20 | Ok(result) 21 | } 22 | 23 | pub fn equal_stems(key1: &[u8], key2: &[u8]) -> bool { 24 | key1[..31] == key2[..31] 25 | } 26 | -------------------------------------------------------------------------------- /src/ipa_fs/proof.rs: -------------------------------------------------------------------------------- 1 | use franklin_crypto::babyjubjub::edwards::Point; 2 | use franklin_crypto::babyjubjub::fs::Fs; 3 | use franklin_crypto::babyjubjub::{JubjubEngine, Unknown}; 4 | use franklin_crypto::bellman::pairing::bn256::Bn256; 5 | 6 | use super::transcript::Bn256Transcript; 7 | 8 | #[derive(Clone)] 9 | pub struct IpaProof { 10 | pub l: Vec>, 11 | pub r: Vec>, 12 | pub a: E::Fs, 13 | } 14 | 15 | pub fn generate_challenges( 16 | ipa_proof: &IpaProof, 17 | transcript: &mut T, 18 | ) -> anyhow::Result> { 19 | let mut challenges: Vec = Vec::with_capacity(ipa_proof.l.len()); 20 | for (l, r) in ipa_proof.l.iter().zip(&ipa_proof.r) { 21 | transcript.commit_point(l)?; // L[i] 22 | transcript.commit_point(r)?; // R[i] 23 | 24 | let c = transcript.get_challenge(); 25 | challenges.push(c); 26 | } 27 | 28 | Ok(challenges) 29 | } 30 | -------------------------------------------------------------------------------- /src/ipa_fr/proof.rs: -------------------------------------------------------------------------------- 1 | use franklin_crypto::bellman::pairing::bn256::{Bn256, Fr, G1Affine}; 2 | use franklin_crypto::bellman::CurveAffine; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | use super::rns::BaseRnsParameters; 6 | use super::transcript::Bn256Transcript; 7 | 8 | #[derive(Clone, Debug, PartialEq, Eq)] 9 | pub struct IpaProof { 10 | pub l: Vec, 11 | pub r: Vec, 12 | pub a: GA::Scalar, 13 | } 14 | 15 | pub fn generate_challenges( 16 | ipa_proof: &IpaProof, 17 | rns_params: &BaseRnsParameters, 18 | transcript: &mut T, 19 | ) -> anyhow::Result> { 20 | let mut challenges: Vec = Vec::with_capacity(ipa_proof.l.len()); 21 | for (l, r) in ipa_proof.l.iter().zip(&ipa_proof.r) { 22 | transcript.commit_point(l, rns_params)?; // L[i] 23 | transcript.commit_point(r, rns_params)?; // R[i] 24 | 25 | let c = transcript.get_challenge(); 26 | challenges.push(c); 27 | } 28 | 29 | Ok(challenges) 30 | } 31 | 32 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 33 | pub struct SerializableIpaProof { 34 | pub l: Vec<(String, String)>, // affine form 35 | pub r: Vec<(String, String)>, // affine form 36 | pub a: String, 37 | } 38 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use verkle_tree::bn256_verkle_tree::proof::{EncodedVerkleProof, VerkleProof}; 2 | use verkle_tree::bn256_verkle_tree::VerkleTreeWith32BytesKeyValue; 3 | use verkle_tree::ipa_fr::config::IpaConfig; 4 | 5 | fn sample_code() -> Result<(), Box> { 6 | let domain_size = 256; // = tree width 7 | let committer = IpaConfig::new(domain_size); 8 | 9 | // prover's view 10 | 11 | let mut tree = VerkleTreeWith32BytesKeyValue::new(committer.clone()); 12 | 13 | let key = [1u8; 32]; 14 | let value = [255u8; 32]; 15 | let old_value: Option<[u8; 32]> = tree.insert(key, value); 16 | println!("old_value: {:?}", old_value); 17 | 18 | let stored_value: Option<&[u8; 32]> = tree.get(&key); 19 | println!("stored_value: {:?}", stored_value); 20 | 21 | let digest = tree.compute_digest()?; 22 | println!("digest: {:?}", digest); 23 | 24 | let keys = [key]; 25 | let (proof, _) = VerkleProof::create(&mut tree, &keys)?; 26 | let encoded_proof = EncodedVerkleProof::encode(&proof); 27 | println!("encoded_proof: {:?}", encoded_proof); 28 | 29 | // verifier's view 30 | 31 | let (proof, zs, ys) = encoded_proof.decode(&committer)?; 32 | let is_valid: bool = proof.check(&zs, &ys, &committer)?; 33 | println!("is_valid: {:?}", is_valid); 34 | 35 | // // prover's view 36 | 37 | // let old_value: Option<[u8; 32]> = VerkleTreeWith32BytesKeyValue::remove(&mut tree, &key); 38 | // println!("old_value: {:?}", old_value); 39 | 40 | // let keys = [key]; 41 | // let (proof, _) = VerkleProof::create(&mut tree, &keys)?; 42 | // let encoded_proof = EncodedVerkleProof::encode(&proof); 43 | // println!("encoded_proof: {:?}", encoded_proof); 44 | 45 | // // verifier's view 46 | 47 | // let (decoded_proof, zs, ys) = encoded_proof.decode()?; 48 | // let is_valid: bool = VerkleProof::check(&decoded_proof, &zs, &ys, &committer)?; 49 | // println!("is_valid: {:?}", is_valid); 50 | 51 | Ok(()) 52 | } 53 | 54 | fn main() { 55 | sample_code().unwrap(); 56 | } 57 | -------------------------------------------------------------------------------- /src/ipa_fs/config.rs: -------------------------------------------------------------------------------- 1 | use franklin_crypto::babyjubjub::{edwards, JubjubEngine, Unknown}; 2 | use franklin_crypto::babyjubjub::{FixedGenerators, JubjubParams}; 3 | 4 | use crate::ipa_fr::config::PrecomputedWeights; 5 | 6 | use super::utils::{commit, generate_random_points}; 7 | 8 | pub const NUM_IPA_ROUNDS: usize = 8; // log_2(common.POLY_DEGREE); 9 | pub const DOMAIN_SIZE: usize = 256; // common.POLY_DEGREE; 10 | 11 | #[derive(Clone)] 12 | pub struct IpaConfig<'a, E: JubjubEngine> { 13 | pub srs: Vec>, 14 | pub q: edwards::Point, 15 | pub precomputed_weights: PrecomputedWeights, 16 | pub jubjub_params: &'a E::Params, 17 | } 18 | 19 | impl<'a, E: JubjubEngine> IpaConfig<'a, E> { 20 | pub fn new(domain_size: usize, jubjub_params: &'a E::Params) -> Self { 21 | let start = std::time::Instant::now(); 22 | let srs = generate_random_points(domain_size, jubjub_params).unwrap(); 23 | println!("srs: {} s", start.elapsed().as_micros() as f64 / 1000000.0); 24 | let q = edwards::Point::::from( 25 | jubjub_params 26 | .generator(FixedGenerators::ProofGenerationKey) 27 | .clone(), 28 | ); 29 | let precomputed_weights = PrecomputedWeights::new(domain_size); 30 | 31 | Self { 32 | srs, 33 | q, 34 | precomputed_weights, 35 | jubjub_params, 36 | } 37 | } 38 | 39 | pub fn get_srs(&self) -> &Vec> { 40 | &self.srs 41 | } 42 | 43 | pub fn get_q(&self) -> &edwards::Point { 44 | &self.q 45 | } 46 | 47 | pub fn get_precomputed_weights(&self) -> &PrecomputedWeights { 48 | &self.precomputed_weights 49 | } 50 | } 51 | 52 | pub trait Committer { 53 | type Err: Send + Sync + 'static; 54 | 55 | fn get_domain_size(&self) -> usize; 56 | 57 | fn commit(&self, polynomial: &[E::Fs]) -> Result, Self::Err>; 58 | } 59 | 60 | impl<'a, E: JubjubEngine> Committer for IpaConfig<'a, E> { 61 | type Err = anyhow::Error; 62 | 63 | fn get_domain_size(&self) -> usize { 64 | self.precomputed_weights.get_domain_size() 65 | } 66 | 67 | fn commit(&self, polynomial: &[E::Fs]) -> anyhow::Result> { 68 | let basis = &self.srs; 69 | let result = commit(basis, polynomial, self.jubjub_params)?; 70 | 71 | Ok(result) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/verkle_tree_fs/utils.rs: -------------------------------------------------------------------------------- 1 | use franklin_crypto::{ 2 | babyjubjub::{edwards, JubjubEngine, Unknown}, 3 | bellman::PrimeField, 4 | }; 5 | 6 | use crate::ipa_fs::utils::{read_field_element_le, write_field_element_le}; 7 | 8 | pub fn point_to_field_element( 9 | point: &edwards::Point, 10 | ) -> anyhow::Result { 11 | let (_point_x, point_y) = point.into_xy(); 12 | let mut point_bytes = write_field_element_le(&point_y); 13 | // let mut point_bytes_x = write_field_element_le(&_point_x); 14 | // point_bytes.append(&mut point_bytes_x); 15 | 16 | // let num_bits_rest = E::Fs::NUM_BITS - 248; 17 | // let mask = (1 << (num_bits_rest - 1)) - 1; 18 | let mask = 0b00000011; 19 | point_bytes[31] &= mask; 20 | let result = read_field_element_le(&point_bytes)?; 21 | 22 | Ok(result) 23 | } 24 | 25 | // This function returns the number of non-empty leaves. 26 | pub fn fill_leaf_tree_poly( 27 | dest: &mut [F], 28 | src: &[Option<[u8; 32]>], 29 | num_limbs: usize, 30 | ) -> anyhow::Result { 31 | let domain_size = dest.len(); 32 | assert_eq!(domain_size % num_limbs, 0); 33 | let mut count = 0; 34 | for (idx, val) in src.iter().enumerate() { 35 | if let Some(v) = val { 36 | count += 1; 37 | let start_index = (num_limbs * idx) % domain_size; 38 | leaf_to_commitments( 39 | &mut dest[start_index..(start_index + num_limbs)], 40 | *v, 41 | num_limbs, 42 | )?; 43 | } 44 | } 45 | 46 | Ok(count) 47 | } 48 | 49 | pub fn leaf_to_commitments( 50 | poly: &mut [F], 51 | val: [u8; 32], 52 | num_limbs: usize, 53 | ) -> anyhow::Result<()> { 54 | assert_eq!(num_limbs, 2); // TODO: `num_limbs` takes any positive number. 55 | let bits_of_value = 256; 56 | let limb_size = bits_of_value / num_limbs; 57 | let limb_size_bytes = limb_size / 8; // 16 58 | debug_assert!(poly.len() >= num_limbs); 59 | debug_assert!(limb_size + 1 < F::NUM_BITS as usize); 60 | 61 | let mut val_lo_with_marker = val.to_vec(); 62 | val_lo_with_marker.resize(limb_size_bytes, 0u8); 63 | val_lo_with_marker.push(1); // 2 ** limb_size 64 | 65 | poly[0] = read_field_element_le(&val_lo_with_marker)?; 66 | if val.len() >= limb_size_bytes { 67 | poly[1] = read_field_element_le(&val[limb_size_bytes..])?; 68 | } 69 | 70 | Ok(()) 71 | } 72 | 73 | pub fn equal_stems(key1: &[u8], key2: &[u8]) -> bool { 74 | key1[..31] == key2[..31] 75 | } 76 | -------------------------------------------------------------------------------- /packages/ff_utils/src/bn256_fr.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::{FromBytes, ToBytes}; 2 | use core::iter::FromIterator; 3 | use ff::PrimeField; 4 | use hex::{FromHexError, ToHex}; 5 | use num::bigint::BigUint; 6 | 7 | #[derive(PrimeField)] 8 | #[PrimeFieldModulus = "21888242871839275222246405745257275088548364400416034343698204186575808495617"] 9 | #[PrimeFieldGenerator = "7"] 10 | #[PrimeFieldReprEndianness = "little"] 11 | pub struct Bn256Fr([u64; 4]); 12 | 13 | impl ToHex for Bn256Fr { 14 | // Parse a Bn256Fr value to a hex string with 0x-prefix. 15 | fn encode_hex>(&self) -> T { 16 | let repr = format!("{:?}", self.to_repr()); 17 | T::from_iter(repr[2..].chars()) 18 | } 19 | 20 | fn encode_hex_upper>(&self) -> T { 21 | let repr = format!("{:?}", self.to_repr()); 22 | T::from_iter(repr.to_uppercase()[2..].chars()) 23 | } 24 | } 25 | 26 | #[test] 27 | fn test_fp_to_hex() { 28 | let input = 31; 29 | let x = Bn256Fr::from(input); 30 | assert_eq!(x.encode_hex::(), format!("{:064x}", input)); 31 | assert_eq!(x.encode_hex_upper::(), format!("{:064X}", input)); 32 | } 33 | 34 | impl ToBytes for Bn256Fr { 35 | fn to_bytes_be(&self) -> Result, FromHexError> { 36 | hex::decode(&self.encode_hex::()) 37 | } 38 | fn to_bytes_le(&self) -> Result, FromHexError> { 39 | let mut res = self.to_bytes_be()?; 40 | res.reverse(); 41 | Ok(res) 42 | } 43 | } 44 | 45 | #[test] 46 | fn test_fp_to_bytes() { 47 | let input = 31; 48 | let x = Bn256Fr::from(input); 49 | let x_bytes_be = x.to_bytes_be().unwrap(); 50 | let x_bytes_le = x.to_bytes_le().unwrap(); 51 | assert_eq!( 52 | x_bytes_be, 53 | vec![ 54 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55 | 0, 0, 31 56 | ] 57 | ); 58 | assert_eq!(x_bytes_be.len(), 32); 59 | assert_eq!( 60 | x_bytes_le, 61 | vec![ 62 | 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63 | 0, 0, 0 64 | ] 65 | ); 66 | assert_eq!(x_bytes_le.len(), 32); 67 | } 68 | 69 | impl FromBytes for Bn256Fr { 70 | fn from_bytes_be(value: &[u8]) -> Option { 71 | Self::from_str_vartime(&BigUint::from_bytes_be(value.as_ref()).to_str_radix(10)) 72 | } 73 | fn from_bytes_le(value: &[u8]) -> Option { 74 | Self::from_str_vartime(&BigUint::from_bytes_le(value.as_ref()).to_str_radix(10)) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /test_cases/fr_case1/proof.json: -------------------------------------------------------------------------------- 1 | {"multi_proof":{"ipa":{"l":["0xf0151ae3f291870e7636c1a940d491bc2924d74b0c9f7c1075bf219dd7149c92","0x7fd3d81100bbcd2a002b49676c43c625017aec264d9cad99292480ce8bad1c2f","0xea704affdacf071bb126095d83ecddd4b9e3c04d801241a02d568e6b7246508a","0x1a9028363c743b387be3b7bbc75486b76758acb1e044a2c10880f8f592df28a5","0x0718f529dd31f4235fbe5d4acd1bfe60789a933376da188e6f4f2e7620719e88","0x4db3a66ee723addab16ae372003a95c52e6de8b635a4b5828ebd695fa460eba9","0xabbb7f047a3f994b51def5dafbe0ee8961c291bc948e1369fee9bb983ec0a585","0x87b829f3178359411e5d845c3c1d8b0de9195a097a9e4d418a0283c08bc4e90a"],"r":["0x3c1567b407bde7c1f822b7f77efd5dc3eadd3125c65e66f6d1f5b279e007a714","0x973817e5092e65de8e44cae5fd43e7c56242e296092dd1829383ef8260bd26a4","0xf608768bdebd1e2038106d377f4f188a092374c08c00d3387ca72a810e310423","0xa049424219ed940d1d9c66f134145aa7c8a8b423813a69ca856515870c673a22","0x6ae8016f7d51548a08326a184bdabe5a4245236fd6c759765bdecb7d0bd08598","0x0ddfd3f7ecc89efb83ed622041a3226d466568ee78864d0e3295d0050402580a","0xf6579b9a987613d8b7fbc0e67f65e98933c792af50074d113c6528eef9c61683","0x0d65bcc7ae251e4001dcdec925f4304182ba5dfd62eb1e9482dffbccb4c4b29e"],"a":"0x13e73e95ae3d7a4c0a11ca7177edf24604cd98fc0b60dbbdaaa77b6ff52bbd47"},"d":"0x7ee768a988459e14f4c6c6be6d1c5d578ecd7d7bfd51a77265267b02f040c219"},"keys":["0xfea400000000000000000000000000000000000000000000000000000000650d","0x11a400000000000000000000000000000000000000000000000000000000670d","0xfda400000000000000000000000000000000000000000000000000000000670d","0xfea400000000000000000000000000000000000000000000000000000000670d","0xff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"],"values":["0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x8800000000000000000000000000003cc10000000000000000000000000000eb","0x0000000000000000000000000000000000000000000000000000000000000000"],"extra_data_list":["0x1000000000000000000000000000000000000000000000000000000000000000","0x1200000000000000000000000000000000000000000000000000000000000000","0x1300000000000000000000000000000000000000000000000000000000000000","0x1400000000000000000000000000000000000000000000000000000000000000","0x09ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"],"commitments":["0xc72ccd1f0b3d00992fa2905481889fdb3d04397f88cdf7af62746345c7692797","0xb3f5625fa6be78b9a08bb27e81761f2b7af54288c19b879543003c876e8bc897","0x01f41b0fd9af91b7e8d4a41120ca393e9bc7d56a4504fe4f6fba374a61e31095","0x421e3f1467b697029ce8b8ab9b50667233fa198d6df465364345b444feb12889","0x421e3f1467b697029ce8b8ab9b50667233fa198d6df465364345b444feb12889","0x6c22e00bd93741977adc8482bd6d11c6c7121848fef301f1b76251ed85bee30c"]} -------------------------------------------------------------------------------- /test_cases/fs_case1/proof.json: -------------------------------------------------------------------------------- 1 | {"multi_proof":{"ipa":{"l":["0x9759f2c1df18e37de0c560a8cbfa3862c604f43279732e702d6103da364d37c9","0xabdcccfcd1dff7eb7bfc0951dbe9946b0ca921e3460a81f66d6e0269cba107d0","0x15bb326182588a796067c9888df33a45779615fd12304c8ff43c6befaa90b207","0xa2bdfcb9351970e00d1a58752903e62ce71224f4263a0a22faf2cada6e54fc14","0x12815792641d493710b33cddea5a5a4e6ff07592bf99b2e389e3f273ac7763a1","0x8d9f40b12296b22eeebd2223a2f769dbe1f5f9888975551a8b6dbc18969f4b11","0x9c75b65649dfd2fef529dbdb161edb15e00030f45e431d5247e164711f53ca43","0x8c72ca5fcae6622ced6fa86550890134ae52b6db17f040747e5804c39d57f9d1"],"r":["0x02e40bf3a17b8f8a6125db48d45991fc5a103e1c606c07ac9994c9cbc79f986a","0x9627478b3ee1a004f00ede485606bf6fa6652f36013aa22e9d2a9262591baa2a","0x8a744b30721b8bfb4ee0ddc99c4c2a7eff4c0be25555e3e7066f5e2045f82236","0x990f23face3789a3c10c2167632f70db840627d465c8c947cb1a2c8f19910704","0x088cd08943e45c6f8ce951110423eee3253ca586eb9436b33b6155af4258816a","0x2c14d751b9430d2f9b2c66103234556e56e45fbd378b8da92ab6f9182593ac4b","0x1179c36cbe800bfdc43588b58b3cb929b09155441f4c42de17468e47c66cabaa","0xa5447512186085ad4eeb6727dc7d0bc2492c39f411bd5a3a73439e0b311aa1eb"],"a":"0x05f6c81b49a1a3fd82195c22d3e09b07401ff4bcd61406c489ee3caf1dac345e"},"d":"0x18b578957ff1dd2ea09a6d55587fed406a45fc95b16ce668f9235a2732aab431"},"keys":["0xfea400000000000000000000000000000000000000000000000000000000650d","0x11a400000000000000000000000000000000000000000000000000000000670d","0xfda400000000000000000000000000000000000000000000000000000000670d","0xfea400000000000000000000000000000000000000000000000000000000670d","0xff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"],"values":["0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x8800000000000000000000000000003cc10000000000000000000000000000eb","0x0000000000000000000000000000000000000000000000000000000000000000"],"extra_data_list":["0x1000000000000000000000000000000000000000000000000000000000000000","0x1200000000000000000000000000000000000000000000000000000000000000","0x1300000000000000000000000000000000000000000000000000000000000000","0x1400000000000000000000000000000000000000000000000000000000000000","0x09ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"],"commitments":["0x8b24eddd9cdc482653871fa7e72a034c889641075aa5700610e4389d45532973","0x2beaa7c7c963e0a648c5d2a365ee433ead176c42bce99365144eac99e439f6c0","0x1a024376b231f491c49027d050705246ca013db7dd6090fd28a54818e54efc7a","0x2b1917bf216838f24bb0b9689dd5371f3054d4f8b2e1ed3a29e848888a402e77","0x2b1917bf216838f24bb0b9689dd5371f3054d4f8b2e1ed3a29e848888a402e77","0x9db5ddc5a9104dfb0584da2deda5660f97ed8912a40d4372a5ae730fc868e6c1"]} -------------------------------------------------------------------------------- /packages/ff_utils/src/bn256_fs.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::{FromBytes, ToBytes}; 2 | use core::iter::FromIterator; 3 | use ff::PrimeField; 4 | use hex::{FromHexError, ToHex}; 5 | use num::bigint::BigUint; 6 | 7 | #[derive(PrimeField)] 8 | #[PrimeFieldModulus = "2736030358979909402780800718157159386076813972158567259200215660948447373041"] 9 | // #[PrimeFieldGenerator = "679638403160184741879882486296176694152956900548039552939252414651485059416"] // 6 * (2**256) mod s 10 | #[PrimeFieldGenerator = "6"] // 6 11 | #[PrimeFieldReprEndianness = "little"] 12 | pub struct Bn256Fs([u64; 4]); 13 | 14 | impl ToHex for Bn256Fs { 15 | // Parse a Bn256Fs value to a hex string with 0x-prefix. 16 | fn encode_hex>(&self) -> T { 17 | let repr = format!("{:?}", self.to_repr()); 18 | T::from_iter(repr[2..].chars()) 19 | } 20 | 21 | fn encode_hex_upper>(&self) -> T { 22 | let repr = format!("{:?}", self.to_repr()); 23 | T::from_iter(repr.to_uppercase()[2..].chars()) 24 | } 25 | } 26 | 27 | #[test] 28 | fn test_fp_to_hex() { 29 | let input = 31; 30 | let x = Bn256Fs::from(input); 31 | assert_eq!(x.encode_hex::(), format!("{:064x}", input)); 32 | assert_eq!(x.encode_hex_upper::(), format!("{:064X}", input)); 33 | } 34 | 35 | impl ToBytes for Bn256Fs { 36 | fn to_bytes_be(&self) -> Result, FromHexError> { 37 | hex::decode(&self.encode_hex::()) 38 | } 39 | fn to_bytes_le(&self) -> Result, FromHexError> { 40 | let mut res = self.to_bytes_be()?; 41 | res.reverse(); 42 | Ok(res) 43 | } 44 | } 45 | 46 | #[test] 47 | fn test_fp_to_bytes() { 48 | let input = 31; 49 | let x = Bn256Fs::from(input); 50 | let x_bytes_be = x.to_bytes_be().unwrap(); 51 | let x_bytes_le = x.to_bytes_le().unwrap(); 52 | assert_eq!( 53 | x_bytes_be, 54 | vec![ 55 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56 | 0, 0, 31 57 | ] 58 | ); 59 | assert_eq!(x_bytes_be.len(), 32); 60 | assert_eq!( 61 | x_bytes_le, 62 | vec![ 63 | 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64 | 0, 0, 0 65 | ] 66 | ); 67 | assert_eq!(x_bytes_le.len(), 32); 68 | } 69 | 70 | impl FromBytes for Bn256Fs { 71 | fn from_bytes_be(value: &[u8]) -> Option { 72 | Self::from_str_vartime(&BigUint::from_bytes_be(value.as_ref()).to_str_radix(10)) 73 | } 74 | fn from_bytes_le(value: &[u8]) -> Option { 75 | Self::from_str_vartime(&BigUint::from_bytes_le(value.as_ref()).to_str_radix(10)) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/verkle_tree/witness.rs: -------------------------------------------------------------------------------- 1 | use franklin_crypto::bellman::{CurveAffine, PrimeField, SqrtField}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | use super::trie::{AbstractKey, ExtStatus}; 5 | 6 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 7 | pub struct Elements { 8 | pub zs: Vec, 9 | pub ys: Vec, 10 | pub fs: Vec>, 11 | } 12 | 13 | impl Default for Elements { 14 | fn default() -> Self { 15 | Self { 16 | zs: vec![], 17 | ys: vec![], 18 | fs: vec![], 19 | } 20 | } 21 | } 22 | 23 | impl Elements { 24 | pub fn merge(&mut self, other: &mut Self) { 25 | self.zs.append(&mut other.zs); 26 | self.ys.append(&mut other.ys); 27 | self.fs.append(&mut other.fs); 28 | } 29 | } 30 | 31 | #[derive(Clone, Debug, PartialEq, Eq)] 32 | pub struct CommitmentElements { 33 | pub commitments: Vec, 34 | pub elements: Elements, 35 | } 36 | 37 | impl Default for CommitmentElements { 38 | fn default() -> Self { 39 | Self { 40 | commitments: vec![], 41 | elements: Elements::default(), 42 | } 43 | } 44 | } 45 | 46 | impl CommitmentElements { 47 | pub fn merge(&mut self, other: &mut Self) { 48 | self.commitments.append(&mut other.commitments); 49 | self.elements.merge(&mut other.elements); 50 | } 51 | } 52 | 53 | #[derive(Clone, Debug, PartialEq, Eq)] 54 | pub struct ExtraProofData { 55 | pub depth: usize, 56 | pub status: ExtStatus, // the extension status of each stem 57 | pub poa_stem: K::Stem, // stems proving another stem is absent 58 | } 59 | 60 | // #[derive(Clone, Debug, PartialEq, Eq)] 61 | // pub struct ProofCommitments { 62 | // pub commitment_elements: CommitmentElements, 63 | // pub extra_data: ExtraProofData, 64 | // } 65 | 66 | #[derive(Clone, Debug, PartialEq, Eq)] 67 | pub struct MultiProofWitnesses { 68 | pub commitment_elements: CommitmentElements, 69 | pub extra_data_list: Vec>, 70 | } 71 | 72 | impl Default for MultiProofWitnesses { 73 | fn default() -> Self { 74 | Self { 75 | commitment_elements: CommitmentElements::default(), 76 | extra_data_list: vec![], 77 | } 78 | } 79 | } 80 | 81 | impl MultiProofWitnesses { 82 | pub fn merge(&mut self, other: &mut Self) { 83 | self.commitment_elements 84 | .merge(&mut other.commitment_elements); 85 | self.extra_data_list.append(&mut other.extra_data_list); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/verkle_tree_fs/witness.rs: -------------------------------------------------------------------------------- 1 | use franklin_crypto::babyjubjub::{edwards, JubjubEngine, Unknown}; 2 | 3 | use crate::verkle_tree::{ 4 | trie::AbstractKey, 5 | witness::{Elements, ExtraProofData}, 6 | }; 7 | 8 | // #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 9 | // pub struct Elements { 10 | // pub zs: Vec, 11 | // pub ys: Vec, 12 | // pub fs: Vec>, 13 | // } 14 | 15 | // impl Default for Elements { 16 | // fn default() -> Self { 17 | // Self { 18 | // zs: vec![], 19 | // ys: vec![], 20 | // fs: vec![], 21 | // } 22 | // } 23 | // } 24 | 25 | // impl Elements { 26 | // pub fn merge(&mut self, other: &mut Self) { 27 | // self.zs.append(&mut other.zs); 28 | // self.ys.append(&mut other.ys); 29 | // self.fs.append(&mut other.fs); 30 | // } 31 | // } 32 | 33 | #[derive(Clone, PartialEq)] 34 | pub struct CommitmentElements { 35 | pub commitments: Vec>, 36 | pub elements: Elements, 37 | } 38 | 39 | impl Default for CommitmentElements { 40 | fn default() -> Self { 41 | Self { 42 | commitments: vec![], 43 | elements: Elements::default(), 44 | } 45 | } 46 | } 47 | 48 | impl CommitmentElements { 49 | pub fn merge(&mut self, other: &mut Self) { 50 | self.commitments.append(&mut other.commitments); 51 | self.elements.merge(&mut other.elements); 52 | } 53 | } 54 | 55 | // #[derive(Clone, Debug, PartialEq, Eq)] 56 | // pub struct ExtraProofData { 57 | // pub depth: usize, 58 | // pub status: ExtStatus, // the extension status of each stem 59 | // pub poa_stem: K::Stem, // stems proving another stem is absent 60 | // } 61 | 62 | // #[derive(Clone, Debug, PartialEq, Eq)] 63 | // pub struct ProofCommitments { 64 | // pub commitment_elements: CommitmentElements, 65 | // pub extra_data: ExtraProofData, 66 | // } 67 | 68 | #[derive(Clone, PartialEq)] 69 | pub struct MultiProofWitnesses { 70 | pub commitment_elements: CommitmentElements, 71 | pub extra_data_list: Vec>, 72 | } 73 | 74 | impl Default for MultiProofWitnesses { 75 | fn default() -> Self { 76 | Self { 77 | commitment_elements: CommitmentElements::default(), 78 | extra_data_list: vec![], 79 | } 80 | } 81 | } 82 | 83 | impl MultiProofWitnesses { 84 | pub fn merge(&mut self, other: &mut Self) { 85 | self.commitment_elements 86 | .merge(&mut other.commitment_elements); 87 | self.extra_data_list.append(&mut other.extra_data_list); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/bn256_verkle_tree/path.rs: -------------------------------------------------------------------------------- 1 | use franklin_crypto::bellman::PrimeField; 2 | 3 | use crate::ipa_fr::utils::read_field_element_le; 4 | use crate::verkle_tree::trie::{AbstractKey, AbstractPath, AbstractStem, IntoFieldElement}; 5 | 6 | // 32 bytes key 7 | impl AbstractKey for [u8; 32] { 8 | type Stem = Option<[u8; 31]>; 9 | type Path = Vec; 10 | 11 | fn get_stem(&self) -> Option<[u8; 31]> { 12 | let result: [u8; 31] = self[..31].to_vec().try_into().unwrap(); 13 | 14 | Some(result) 15 | } 16 | 17 | fn get_suffix(&self) -> usize { 18 | usize::from(self[31]) 19 | } 20 | 21 | fn to_path(&self) -> Vec { 22 | self.iter().map(|&x| x as usize).collect::>() 23 | } 24 | 25 | fn get_branch_at(&self, depth: usize) -> usize { 26 | self[depth] as usize 27 | } 28 | } 29 | 30 | impl AbstractStem for Option<[u8; 31]> { 31 | type Path = Vec; 32 | 33 | fn to_path(&self) -> Vec { 34 | let bytes = match self { 35 | Some(inner) => inner.to_vec(), 36 | None => vec![], 37 | }; 38 | 39 | bytes.iter().map(|x| *x as usize).collect::>() 40 | } 41 | } 42 | 43 | impl IntoFieldElement for Option<[u8; 31]> { 44 | type Err = anyhow::Error; 45 | 46 | fn into_field_element(self) -> anyhow::Result { 47 | match self { 48 | Some(bytes) => read_field_element_le(&bytes), 49 | None => { 50 | anyhow::bail!("None is not converted into a field element.") 51 | } 52 | } 53 | } 54 | } 55 | 56 | impl AbstractPath for Vec { 57 | type RemovePrefixError = anyhow::Error; 58 | 59 | fn get_next_path_and_branch(&self) -> (Self, usize) { 60 | let next_branch = *self.first().expect("`next_branch` must be a value."); 61 | 62 | let next_path = self[1..].to_vec(); 63 | 64 | (next_path, next_branch) 65 | } 66 | 67 | fn get_suffix(&self) -> usize { 68 | self[self.len() - 1] 69 | } 70 | 71 | fn is_proper_prefix_of(&self, full_path: &Self) -> bool { 72 | if self.is_empty() { 73 | return true; 74 | } 75 | 76 | if self.len() >= full_path.len() { 77 | return false; 78 | } 79 | 80 | full_path[..self.len()].eq(self) 81 | } 82 | 83 | fn remove_prefix(&self, prefix: &Self) -> anyhow::Result { 84 | if !prefix.is_proper_prefix_of(self) { 85 | anyhow::bail!("{:?} is not proper prefix of {:?}", prefix, self,); 86 | } 87 | 88 | let result = Self::from(&self[prefix.len()..]); 89 | 90 | Ok(result) 91 | } 92 | 93 | fn len(&self) -> usize { 94 | Vec::len(self) 95 | } 96 | 97 | fn is_empty(&self) -> bool { 98 | Vec::is_empty(self) 99 | } 100 | 101 | fn push(&mut self, value: usize) { 102 | Vec::push(self, value) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/ipa_fs/transcript.rs: -------------------------------------------------------------------------------- 1 | use ff_utils::bn256_fr::Bn256Fr; 2 | use franklin_crypto::babyjubjub::edwards::Point; 3 | use franklin_crypto::babyjubjub::fs::Fs; 4 | use franklin_crypto::bellman::pairing::bn256::{Bn256, Fr}; 5 | use franklin_crypto::bellman::PrimeField; 6 | use generic_array::typenum; 7 | use neptune::poseidon::PoseidonConstants; 8 | use neptune::Poseidon; 9 | 10 | use super::utils::{convert_fr_to_fs, convert_fs_to_fr, read_field_element_le}; 11 | 12 | pub trait Bn256Transcript: Sized + Clone { 13 | type Params; 14 | 15 | fn new(init_state: &Self::Params) -> Self; 16 | fn commit_field_element(&mut self, element: &Fs) -> anyhow::Result<()>; 17 | fn commit_point(&mut self, point: &Point) -> anyhow::Result<()>; 18 | fn into_params(self) -> Self::Params; 19 | fn get_challenge(&self) -> Fs; 20 | } 21 | 22 | #[derive(Clone)] 23 | pub struct PoseidonBn256Transcript { 24 | pub state: Bn256Fr, 25 | } 26 | 27 | #[test] 28 | fn test_fs_poseidon_hash() { 29 | let constants = PoseidonConstants::new(); 30 | let mut preimage = vec![::zero(); 2]; 31 | let input1: Fr = read_field_element_le(&[1]).unwrap(); 32 | let input2: Fr = read_field_element_le(&[2]).unwrap(); 33 | preimage[0] = convert_ff_ce_to_ff(input1).unwrap(); 34 | preimage[1] = convert_ff_ce_to_ff(input2).unwrap(); 35 | let mut h = Poseidon::::new_with_preimage(&preimage, &constants); 36 | let output = h.hash(); 37 | println!("output: {:?}", output); 38 | } 39 | 40 | impl Bn256Transcript for PoseidonBn256Transcript { 41 | type Params = Fr; 42 | 43 | fn new(init_state: &Self::Params) -> Self { 44 | // let blake_2s_state = Blake2sTranscript::new(); 45 | 46 | Self { 47 | state: convert_ff_ce_to_ff(*init_state).unwrap(), 48 | } 49 | } 50 | 51 | fn commit_field_element(&mut self, element: &Fs) -> anyhow::Result<()> { 52 | let element_fr = convert_fs_to_fr::(element)?; 53 | self.commit_fr(&element_fr)?; 54 | 55 | Ok(()) 56 | } 57 | 58 | fn commit_point(&mut self, point: &Point) -> anyhow::Result<()> { 59 | let (point_x, point_y) = point.into_xy(); 60 | self.commit_fr(&point_x)?; 61 | self.commit_fr(&point_y)?; 62 | 63 | Ok(()) 64 | } 65 | 66 | fn into_params(self) -> Self::Params { 67 | convert_ff_to_ff_ce(self.state).unwrap() 68 | } 69 | 70 | fn get_challenge(&self) -> Fs { 71 | convert_fr_to_fs::(&convert_ff_to_ff_ce(self.state).unwrap()).unwrap() 72 | } 73 | } 74 | 75 | impl PoseidonBn256Transcript { 76 | pub fn with_bytes(bytes: &[u8]) -> Self { 77 | let chunk_size = (Fr::NUM_BITS / 8) as usize; 78 | assert!(chunk_size != 0); 79 | assert!(bytes.len() <= chunk_size); 80 | let element = read_field_element_le::(bytes).unwrap(); 81 | 82 | Self { 83 | state: convert_ff_ce_to_ff(element).unwrap(), 84 | } 85 | } 86 | 87 | pub fn commit_bytes(&mut self, bytes: &[u8]) -> anyhow::Result<()> { 88 | let chunk_size = (Fr::NUM_BITS / 8) as usize; 89 | assert!(chunk_size != 0); 90 | for b in bytes.chunks(chunk_size) { 91 | let element = read_field_element_le::(b).unwrap(); 92 | self.commit_fr(&element)?; 93 | } 94 | 95 | Ok(()) 96 | } 97 | 98 | pub fn commit_fr(&mut self, element: &Fr) -> anyhow::Result<()> { 99 | let mut preimage = vec![::zero(); 2]; 100 | let constants = PoseidonConstants::new(); 101 | preimage[0] = self.state; 102 | preimage[1] = convert_ff_ce_to_ff(*element).unwrap(); 103 | 104 | let mut h = Poseidon::::new_with_preimage(&preimage, &constants); 105 | self.state = h.hash(); 106 | 107 | Ok(()) 108 | } 109 | } 110 | 111 | // uncheck overflow 112 | pub fn from_bytes_le(bytes: &[u8]) -> anyhow::Result { 113 | let mut value = F::zero(); 114 | let mut factor = F::one(); 115 | for b in bytes { 116 | value += factor * F::from(*b as u64); 117 | factor *= F::from(256u64); 118 | } 119 | 120 | Ok(value) 121 | } 122 | 123 | pub fn to_bytes_le(scalar: &F) -> Vec { 124 | scalar.to_repr().as_ref().to_vec() 125 | } 126 | 127 | #[test] 128 | fn test_read_write_ff_ce_fs() { 129 | let bytes = [ 130 | 206u8, 104, 6, 65, 140, 79, 39, 170, 187, 254, 154, 245, 57, 39, 73, 145, 82, 144, 26, 62, 131 | 229, 65, 168, 197, 168, 198, 162, 203, 73, 241, 49, 5, 132 | ]; 133 | let point = from_bytes_le::(&bytes).unwrap(); 134 | assert_eq!( 135 | format!("{:?}", point), 136 | "Bn256Fr(0x0531f149cba2c6a8c5a841e53e1a905291492739f59afebbaa274f8c410668ce)" 137 | ); 138 | 139 | let recovered_bytes = to_bytes_le(&point); 140 | assert_eq!(recovered_bytes, bytes); 141 | } 142 | 143 | pub fn convert_ff_to_ff_ce(value: Bn256Fr) -> anyhow::Result { 144 | read_field_element_le(&to_bytes_le(&value)) 145 | } 146 | 147 | pub fn convert_ff_ce_to_ff(value: Fr) -> anyhow::Result { 148 | from_bytes_le(&super::utils::write_field_element_le(&value)) 149 | } 150 | -------------------------------------------------------------------------------- /src/ipa_fr/transcript.rs: -------------------------------------------------------------------------------- 1 | use ff_utils::bn256_fr::Bn256Fr; 2 | use franklin_crypto::bellman::pairing::bn256::{Bn256, Fr}; 3 | use franklin_crypto::bellman::pairing::{CurveAffine, Engine}; 4 | use franklin_crypto::bellman::PrimeField; 5 | use franklin_crypto::plonk::circuit::bigint::field::value_to_limbs; 6 | use generic_array::typenum; 7 | use neptune::poseidon::PoseidonConstants; 8 | use neptune::Poseidon; 9 | 10 | use super::rns::BaseRnsParameters; 11 | use super::utils::read_field_element_le; 12 | 13 | pub trait Bn256Transcript: Sized + Clone { 14 | type Params; 15 | 16 | fn new(init_state: &Fr) -> Self; 17 | fn commit_field_element(&mut self, element: &Fr) -> anyhow::Result<()>; 18 | fn commit_point( 19 | &mut self, 20 | point: &::G1Affine, 21 | rns_params: &BaseRnsParameters, 22 | ) -> anyhow::Result<()>; 23 | fn into_params(self) -> Self::Params; 24 | fn get_challenge(&self) -> Fr; 25 | } 26 | 27 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] 28 | pub struct PoseidonBn256Transcript { 29 | pub state: Bn256Fr, 30 | } 31 | 32 | #[test] 33 | fn test_fs_poseidon_hash() { 34 | let constants = PoseidonConstants::new(); 35 | let mut preimage = vec![::zero(); 2]; 36 | let input1 = read_field_element_le::(&[1]).unwrap(); 37 | let input2 = read_field_element_le::(&[2]).unwrap(); 38 | preimage[0] = convert_ff_ce_to_ff(input1).unwrap(); 39 | preimage[1] = convert_ff_ce_to_ff(input2).unwrap(); 40 | let mut h = Poseidon::::new_with_preimage(&preimage, &constants); 41 | let output = h.hash(); 42 | println!("output: {:?}", output); 43 | } 44 | 45 | impl Bn256Transcript for PoseidonBn256Transcript { 46 | type Params = Fr; 47 | 48 | fn new(init_state: &Self::Params) -> Self { 49 | // let blake_2s_state = Blake2sTranscript::new(); 50 | 51 | Self { 52 | // blake_2s_state, 53 | state: convert_ff_ce_to_ff(*init_state).unwrap(), 54 | // _marker: std::marker::PhantomData, 55 | } 56 | } 57 | 58 | fn commit_field_element(&mut self, element: &Fr) -> anyhow::Result<()> { 59 | let mut preimage = vec![::zero(); 2]; 60 | let constants = PoseidonConstants::new(); 61 | preimage[0] = self.state; 62 | preimage[1] = convert_ff_ce_to_ff(*element).unwrap(); 63 | 64 | let mut h = Poseidon::::new_with_preimage(&preimage, &constants); 65 | self.state = h.hash(); 66 | 67 | Ok(()) 68 | } 69 | 70 | fn commit_point( 71 | &mut self, 72 | point: &::G1Affine, 73 | rns_params: &BaseRnsParameters, 74 | ) -> anyhow::Result<()> { 75 | let (point_x, point_y) = point.into_xy_unchecked(); 76 | let (binary_limbs, _) = value_to_limbs(Some(point_x), rns_params); 77 | for limb in binary_limbs { 78 | self.commit_field_element(&limb.unwrap())?; 79 | } 80 | let (binary_limbs, _) = value_to_limbs(Some(point_y), rns_params); 81 | for limb in binary_limbs { 82 | self.commit_field_element(&limb.unwrap())?; 83 | } 84 | 85 | Ok(()) 86 | } 87 | 88 | fn into_params(self) -> Self::Params { 89 | convert_ff_to_ff_ce(self.state).unwrap() 90 | } 91 | 92 | fn get_challenge(&self) -> Fr { 93 | convert_ff_to_ff_ce(self.state).unwrap() 94 | } 95 | } 96 | 97 | impl PoseidonBn256Transcript { 98 | pub fn with_bytes(bytes: &[u8]) -> Self { 99 | let chunk_size = (Fr::NUM_BITS / 8) as usize; 100 | assert!(chunk_size != 0); 101 | assert!(bytes.len() <= chunk_size); 102 | let element = read_field_element_le::(bytes).unwrap(); 103 | 104 | Self { 105 | state: convert_ff_ce_to_ff(element).unwrap(), 106 | } 107 | } 108 | 109 | pub fn commit_bytes(&mut self, bytes: &[u8]) -> anyhow::Result<()> { 110 | let chunk_size = (Fr::NUM_BITS / 8) as usize; 111 | assert!(chunk_size != 0); 112 | for b in bytes.chunks(chunk_size) { 113 | let element = read_field_element_le::(b).unwrap(); 114 | self.commit_field_element(&element)?; 115 | } 116 | 117 | Ok(()) 118 | } 119 | } 120 | 121 | // uncheck overflow 122 | pub fn from_bytes_le(bytes: &[u8]) -> anyhow::Result { 123 | let mut value = F::zero(); 124 | let mut factor = F::one(); 125 | for b in bytes { 126 | value += factor * F::from(*b as u64); 127 | factor *= F::from(256u64); 128 | } 129 | 130 | Ok(value) 131 | } 132 | 133 | pub fn to_bytes_le(scalar: &F) -> Vec { 134 | scalar.to_repr().as_ref().to_vec() 135 | } 136 | 137 | #[test] 138 | fn test_read_write_ff_ce() { 139 | let bytes = [ 140 | 101u8, 121, 238, 208, 145, 118, 73, 126, 4, 129, 129, 133, 67, 167, 1, 64, 164, 189, 107, 141 | 239, 228, 126, 238, 70, 205, 50, 174, 80, 238, 181, 137, 47, 142 | ]; 143 | let point = from_bytes_le::(&bytes).unwrap(); 144 | assert_eq!( 145 | format!("{:?}", point), 146 | "Bn256Fr(0x2f89b5ee50ae32cd46ee7ee4ef6bbda44001a743858181047e497691d0ee7965)" 147 | ); 148 | 149 | let recovered_bytes = to_bytes_le(&point); 150 | assert_eq!(recovered_bytes, bytes); 151 | } 152 | 153 | pub fn convert_ff_to_ff_ce(value: Bn256Fr) -> anyhow::Result { 154 | read_field_element_le::(&to_bytes_le(&value)) 155 | } 156 | 157 | pub fn convert_ff_ce_to_ff(value: Fr) -> anyhow::Result { 158 | from_bytes_le(&super::utils::write_field_element_le(&value)) 159 | } 160 | -------------------------------------------------------------------------------- /src/bn256_verkle_tree_fs/leaf.rs: -------------------------------------------------------------------------------- 1 | use franklin_crypto::babyjubjub::{edwards, JubjubEngine, Unknown}; 2 | use franklin_crypto::bellman::{Field, PrimeField}; 3 | use std::collections::HashMap; 4 | 5 | use crate::ipa_fs::config::Committer; 6 | use crate::verkle_tree::trie::{AbstractKey, AbstractPath, AbstractStem, IntoFieldElement}; 7 | use crate::verkle_tree_fs::trie::{LeafNodeValue, NodeValue}; 8 | use crate::verkle_tree_fs::utils::{fill_leaf_tree_poly, point_to_field_element}; 9 | 10 | #[derive(Clone, PartialEq)] 11 | pub struct LeafNodeWith32BytesValue 12 | where 13 | E: JubjubEngine, 14 | { 15 | /// The number of leaves which are `Some` rather than `None`. 16 | pub(crate) num_nonempty_children: usize, 17 | 18 | pub(crate) leaves: HashMap, // HashMap 19 | 20 | pub(crate) s_commitments: Option>>, // Option<[GA; 2]> 21 | 22 | /// The commitment of this node. 23 | /// If it has not computed yet, `commitment` set `None`. 24 | pub(crate) commitment: Option>, 25 | 26 | /// The digest of `commitment`. 27 | /// If it has not computed yet, `digest` set `None`. 28 | pub(crate) digest: Option, 29 | } 30 | 31 | impl Default for LeafNodeWith32BytesValue 32 | where 33 | E: JubjubEngine, 34 | { 35 | fn default() -> Self { 36 | Self { 37 | num_nonempty_children: 0, 38 | leaves: HashMap::new(), 39 | s_commitments: None, 40 | commitment: None, 41 | digest: None, 42 | } 43 | } 44 | } 45 | 46 | impl NodeValue for LeafNodeWith32BytesValue 47 | where 48 | E: JubjubEngine, 49 | { 50 | fn len(&self) -> usize { 51 | self.num_nonempty_children 52 | } 53 | 54 | fn get_digest_mut(&mut self) -> &mut Option { 55 | &mut self.digest 56 | } 57 | 58 | fn get_digest(&self) -> Option<&E::Fs> { 59 | let digest = &self.digest; 60 | 61 | digest.into() 62 | } 63 | } 64 | 65 | impl LeafNodeWith32BytesValue 66 | where 67 | E: JubjubEngine, 68 | { 69 | pub fn get_commitment_mut(&mut self) -> &mut Option> { 70 | &mut self.commitment 71 | } 72 | 73 | pub fn get_commitment(&self) -> Option<&edwards::Point> { 74 | let commitment = &self.commitment; 75 | 76 | commitment.into() 77 | } 78 | } 79 | 80 | pub fn compute_commitment_of_leaf_node( 81 | committer: &C, 82 | stem: &mut K::Stem, 83 | info: &mut LeafNodeWith32BytesValue, 84 | ) -> anyhow::Result 85 | where 86 | P: Default + AbstractPath, 87 | K: AbstractKey, 88 | K::Stem: AbstractStem + IntoFieldElement, 89 | E: JubjubEngine, 90 | C: Committer, 91 | { 92 | let width = committer.get_domain_size(); 93 | let num_limbs = as LeafNodeValue>::num_limbs(); 94 | let bits_of_value = as LeafNodeValue>::bits_of_value(); 95 | // let bits_of_value = width; 96 | let limb_bits_size = bits_of_value / num_limbs; 97 | debug_assert!(limb_bits_size < E::Fs::NUM_BITS as usize); 98 | 99 | let poly_0 = E::Fs::one(); 100 | let poly_1 = stem 101 | .clone() 102 | .into_field_element() 103 | .map_err(|_| anyhow::anyhow!("unreachable code"))?; 104 | let mut poly = vec![poly_0, poly_1]; 105 | 106 | let mut leaves_array = vec![None; width]; 107 | for (&i, &v) in info.leaves.iter() { 108 | leaves_array[i] = Some(v); 109 | } 110 | let mut s_commitments = vec![]; 111 | for limb in leaves_array.chunks(limb_bits_size) { 112 | let mut sub_poly = vec![E::Fs::zero(); width]; 113 | let _count = fill_leaf_tree_poly(&mut sub_poly, limb, num_limbs)?; 114 | let tmp_s_commitment = committer 115 | .commit(&sub_poly) 116 | .or_else(|_| anyhow::bail!("Fail to compute the commitment of the polynomial."))?; 117 | poly.push(point_to_field_element(&tmp_s_commitment)?); 118 | s_commitments.push(tmp_s_commitment); 119 | } 120 | 121 | // let infinity_point_fs = point_to_field_element(&edwards::Point::::zero())?; 122 | poly.resize(width, E::Fs::zero()); 123 | 124 | let tmp_commitment = committer 125 | .commit(&poly) 126 | .or_else(|_| anyhow::bail!("Fail to compute the commitment of the polynomial."))?; 127 | 128 | let tmp_digest = point_to_field_element(&tmp_commitment)?; 129 | 130 | let _ = std::mem::replace(&mut info.s_commitments, Some(s_commitments)); 131 | let _ = std::mem::replace(&mut info.commitment, Some(tmp_commitment)); 132 | let _ = std::mem::replace(&mut info.digest, Some(tmp_digest)); 133 | 134 | Ok(tmp_digest) 135 | } 136 | 137 | impl LeafNodeValue for LeafNodeWith32BytesValue 138 | where 139 | P: Default + AbstractPath, 140 | K: AbstractKey, 141 | K::Stem: AbstractStem + IntoFieldElement, 142 | E: JubjubEngine, 143 | { 144 | type Value = [u8; 32]; 145 | 146 | fn new() -> Self { 147 | Self::default() 148 | } 149 | 150 | fn insert(&mut self, key: usize, value: [u8; 32]) -> Option<[u8; 32]> { 151 | let _ = self.commitment.take(); 152 | let _ = self.digest.take(); 153 | let old_leaf = self.leaves.insert(key, value); 154 | if old_leaf.is_none() { 155 | self.num_nonempty_children += 1; 156 | } 157 | 158 | old_leaf 159 | } 160 | 161 | fn get(&self, key: &usize) -> Option<&[u8; 32]> { 162 | self.leaves.get(key) 163 | } 164 | 165 | fn remove(&mut self, key: &usize) -> Option<[u8; 32]> { 166 | let old_leaf = self.leaves.remove(key); 167 | if old_leaf.is_some() { 168 | let _ = self.commitment.take(); 169 | let _ = self.digest.take(); 170 | self.num_nonempty_children -= 1; 171 | } 172 | 173 | old_leaf 174 | } 175 | 176 | fn compute_digest>( 177 | &mut self, 178 | stem: &mut K::Stem, 179 | committer: &C, 180 | ) -> anyhow::Result { 181 | compute_commitment_of_leaf_node::<_, K, _, _>(committer, stem, self) 182 | } 183 | 184 | fn bits_of_value() -> usize { 185 | 256 186 | } 187 | 188 | fn num_limbs() -> usize { 189 | 2 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/bn256_verkle_tree/leaf.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::Debug; 2 | use franklin_crypto::bellman::{CurveAffine, Field, PrimeField}; 3 | use std::collections::HashMap; 4 | 5 | use crate::ipa_fr::config::Committer; 6 | use crate::verkle_tree::trie::{ 7 | AbstractKey, AbstractPath, AbstractStem, AbstractValue, IntoFieldElement, LeafNodeValue, 8 | NodeValue, 9 | }; 10 | use crate::verkle_tree::utils::point_to_field_element; 11 | use crate::verkle_tree_fs::utils::fill_leaf_tree_poly; 12 | 13 | #[derive(Clone, Debug, PartialEq, Eq)] 14 | pub struct LeafNodeWith32BytesValue 15 | where 16 | GA: CurveAffine, 17 | { 18 | /// The number of leaves which are `Some` rather than `None`. 19 | pub(crate) num_nonempty_children: usize, 20 | 21 | pub(crate) leaves: HashMap, // HashMap 22 | 23 | pub(crate) s_commitments: Option>, // Option<[GA; 2]> 24 | 25 | /// The commitment of this node. 26 | /// If it has not computed yet, `commitment` set `None`. 27 | pub(crate) commitment: Option, 28 | 29 | /// The digest of `commitment`. 30 | /// If it has not computed yet, `digest` set `None`. 31 | pub(crate) digest: Option, 32 | } 33 | 34 | impl Default for LeafNodeWith32BytesValue 35 | where 36 | GA: CurveAffine, 37 | { 38 | fn default() -> Self { 39 | Self { 40 | num_nonempty_children: 0, 41 | leaves: HashMap::new(), 42 | s_commitments: None, 43 | commitment: None, 44 | digest: None, 45 | } 46 | } 47 | } 48 | 49 | impl NodeValue for LeafNodeWith32BytesValue 50 | where 51 | GA: CurveAffine, 52 | { 53 | fn len(&self) -> usize { 54 | self.num_nonempty_children 55 | } 56 | 57 | fn get_digest_mut(&mut self) -> &mut Option { 58 | &mut self.digest 59 | } 60 | 61 | fn get_digest(&self) -> Option<&GA::Scalar> { 62 | let digest = &self.digest; 63 | 64 | digest.into() 65 | } 66 | } 67 | 68 | impl LeafNodeWith32BytesValue 69 | where 70 | GA: CurveAffine, 71 | { 72 | pub fn get_commitment_mut(&mut self) -> &mut Option { 73 | &mut self.commitment 74 | } 75 | 76 | pub fn get_commitment(&self) -> Option<&GA> { 77 | let commitment = &self.commitment; 78 | 79 | commitment.into() 80 | } 81 | } 82 | 83 | // 32 bytes value 84 | impl AbstractValue for [u8; 32] {} 85 | 86 | pub fn compute_commitment_of_leaf_node( 87 | committer: &C, 88 | stem: &mut K::Stem, 89 | info: &mut LeafNodeWith32BytesValue, 90 | ) -> anyhow::Result 91 | where 92 | P: Default + AbstractPath, 93 | K: AbstractKey, 94 | K::Stem: AbstractStem + IntoFieldElement, 95 | GA: CurveAffine, 96 | GA::Base: PrimeField, 97 | C: Committer, 98 | { 99 | let width = committer.get_domain_size(); 100 | let num_limbs = as LeafNodeValue>::num_limbs(); 101 | let bits_of_value = as LeafNodeValue>::bits_of_value(); 102 | // let bits_of_value = width; 103 | let limb_bits_size = bits_of_value / num_limbs; 104 | debug_assert!(limb_bits_size < GA::Scalar::NUM_BITS as usize); 105 | 106 | let poly_0 = GA::Scalar::one(); 107 | let poly_1 = stem 108 | .clone() 109 | .into_field_element() 110 | .map_err(|_| anyhow::anyhow!("unreachable code"))?; 111 | let mut poly = vec![poly_0, poly_1]; 112 | 113 | let mut leaves_array = vec![None; width]; 114 | for (&i, &v) in info.leaves.iter() { 115 | leaves_array[i] = Some(v); 116 | } 117 | let mut s_commitments = vec![]; 118 | for limb in leaves_array.chunks(limb_bits_size) { 119 | let mut sub_poly = vec![GA::Scalar::zero(); width]; 120 | let _count = fill_leaf_tree_poly(&mut sub_poly, limb, num_limbs)?; 121 | let tmp_s_commitment = committer 122 | .commit(&sub_poly) 123 | .or_else(|_| anyhow::bail!("Fail to compute the commitment of the polynomial."))?; 124 | s_commitments.push(tmp_s_commitment); 125 | poly.push(point_to_field_element(&tmp_s_commitment)?); 126 | } 127 | 128 | // let infinity_point_fs = point_to_field_element(&GA::zero())?; 129 | poly.resize(width, GA::Scalar::zero()); 130 | 131 | let tmp_commitment = committer 132 | .commit(&poly) 133 | .or_else(|_| anyhow::bail!("Fail to compute the commitment of the polynomial."))?; 134 | 135 | let tmp_digest = point_to_field_element(&tmp_commitment)?; 136 | 137 | let _ = std::mem::replace(&mut info.s_commitments, Some(s_commitments)); 138 | let _ = std::mem::replace(&mut info.commitment, Some(tmp_commitment)); 139 | let _ = std::mem::replace(&mut info.digest, Some(tmp_digest)); 140 | 141 | Ok(tmp_digest) 142 | } 143 | 144 | impl LeafNodeValue for LeafNodeWith32BytesValue 145 | where 146 | P: Default + AbstractPath, 147 | K: AbstractKey, 148 | K::Stem: AbstractStem + IntoFieldElement, 149 | GA: CurveAffine, 150 | GA::Base: PrimeField, 151 | { 152 | type Value = [u8; 32]; 153 | 154 | fn new() -> Self { 155 | Self::default() 156 | } 157 | 158 | fn insert(&mut self, key: usize, value: [u8; 32]) -> Option<[u8; 32]> { 159 | let _ = self.commitment.take(); 160 | let _ = self.digest.take(); 161 | let old_leaf = self.leaves.insert(key, value); 162 | if old_leaf.is_none() { 163 | self.num_nonempty_children += 1; 164 | } 165 | 166 | old_leaf 167 | } 168 | 169 | fn get(&self, key: &usize) -> Option<&[u8; 32]> { 170 | self.leaves.get(key) 171 | } 172 | 173 | fn remove(&mut self, key: &usize) -> Option<[u8; 32]> { 174 | let old_leaf = self.leaves.remove(key); 175 | if old_leaf.is_some() { 176 | let _ = self.commitment.take(); 177 | let _ = self.digest.take(); 178 | self.num_nonempty_children -= 1; 179 | } 180 | 181 | old_leaf 182 | } 183 | 184 | fn compute_digest>( 185 | &mut self, 186 | stem: &mut K::Stem, 187 | committer: &C, 188 | ) -> anyhow::Result { 189 | compute_commitment_of_leaf_node::<_, K, _, _>(committer, stem, self) 190 | } 191 | 192 | fn bits_of_value() -> usize { 193 | 256 194 | } 195 | 196 | fn num_limbs() -> usize { 197 | 2 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/ipa_fr/utils.rs: -------------------------------------------------------------------------------- 1 | use franklin_crypto::bellman::pairing::CurveAffine; 2 | use franklin_crypto::bellman::{CurveProjective, Field, PrimeField, PrimeFieldRepr, SqrtField}; 3 | use sha2::{Digest, Sha256}; 4 | 5 | pub fn log2_ceil(value: usize) -> u32 { 6 | assert!(value != 0, "The first argument must be a positive number."); 7 | 8 | if value == 1 { 9 | return 0; 10 | } 11 | 12 | let mut log_value = 1; 13 | let mut tmp_value = value - 1; 14 | while tmp_value > 1 { 15 | tmp_value /= 2; 16 | log_value += 1; 17 | } 18 | 19 | log_value 20 | } 21 | 22 | #[test] 23 | #[should_panic] 24 | pub fn test_error_log2_ceil() { 25 | log2_ceil(0); 26 | } 27 | 28 | #[test] 29 | pub fn test_log2_ceil() { 30 | let res0 = log2_ceil(1); 31 | assert_eq!(res0, 0); 32 | 33 | let res1 = log2_ceil(2); 34 | assert_eq!(res1, 1); 35 | 36 | let res2 = log2_ceil(3); 37 | assert_eq!(res2, 2); 38 | 39 | let res3 = log2_ceil(4); 40 | assert_eq!(res3, 2); 41 | 42 | let res4 = log2_ceil(5); 43 | assert_eq!(res4, 3); 44 | 45 | let res5 = log2_ceil(127); 46 | assert_eq!(res5, 7); 47 | } 48 | 49 | pub fn read_field_element_le(bytes: &[u8]) -> anyhow::Result { 50 | let mut repr = F::Repr::default(); 51 | let mut padded_bytes = bytes.to_vec(); 52 | let num_bits = F::NUM_BITS as usize; 53 | // assert!(bytes.len() <= (num_bits + 7) / 8); 54 | // for _ in bytes.len()..num_bits { 55 | // padded_bytes.push(0); 56 | // } 57 | padded_bytes.resize((num_bits + 7) / 8, 0); 58 | repr.read_le::<&[u8]>(padded_bytes.as_ref())?; 59 | let value = F::from_repr(repr)?; 60 | 61 | Ok(value) 62 | } 63 | 64 | pub fn read_field_element_be(bytes: &[u8]) -> anyhow::Result { 65 | let mut padded_bytes = bytes.to_vec(); 66 | padded_bytes.reverse(); 67 | read_field_element_le(&padded_bytes) 68 | } 69 | 70 | pub fn write_field_element_le(scalar: &F) -> Vec { 71 | let scalar_u64_vec = scalar.into_repr().as_ref().to_vec(); 72 | let mut result = vec![0; scalar_u64_vec.len() * 8]; 73 | for (bytes, tmp) in scalar_u64_vec 74 | .iter() 75 | .map(|x| x.to_le_bytes()) 76 | .zip(result.chunks_mut(8)) 77 | { 78 | // for i in 0..bytes.len() { 79 | // tmp[i] = bytes[i]; 80 | // } 81 | tmp[..bytes.len()].clone_from_slice(&bytes[..]); 82 | } 83 | 84 | result 85 | } 86 | 87 | pub fn write_field_element_be(scalar: &F) -> Vec { 88 | let mut result = write_field_element_le(scalar); 89 | result.reverse(); 90 | 91 | result 92 | } 93 | 94 | #[test] 95 | fn test_read_write_ff() { 96 | use franklin_crypto::bellman::pairing::bn256::Fr; 97 | 98 | let bytes = [ 99 | 101u8, 121, 238, 208, 145, 118, 73, 126, 4, 129, 129, 133, 67, 167, 1, 64, 164, 189, 107, 100 | 239, 228, 126, 238, 70, 205, 50, 174, 80, 238, 181, 137, 47, 101 | ]; 102 | let point = read_field_element_le::(&bytes).unwrap(); 103 | assert_eq!( 104 | format!("{:?}", point), 105 | "Fr(0x2f89b5ee50ae32cd46ee7ee4ef6bbda44001a743858181047e497691d0ee7965)" 106 | ); 107 | 108 | let recovered_bytes = write_field_element_le(&point); 109 | assert_eq!(recovered_bytes, bytes); 110 | } 111 | 112 | pub fn generate_random_points( 113 | num_points: usize, 114 | ) -> anyhow::Result> 115 | where 116 | ::Base: PrimeField, 117 | { 118 | let mut hasher = Sha256::new(); 119 | hasher.update(b"eth_verkle_oct_2021"); // In case it changes or needs updating, we can use eth_verkle_month_year. 120 | let digest = hasher.finalize(); 121 | let u = read_field_element_le::<::Base>(digest.as_ref())?; 122 | 123 | // flag to indicate whether we choose the lexicographically larger 124 | // element of `x` out of it and it's negative (?) 125 | let is_largest = false; 126 | 127 | let mut points = vec![]; 128 | 129 | let mut increment = 0usize; 130 | 131 | while points.len() != num_points { 132 | let mut x = u; 133 | x.add_assign(&read_field_element_le(&increment.to_le_bytes()).unwrap()); // y = u + increment 134 | increment += 1; 135 | 136 | let mut rhs = x; 137 | rhs.square(); 138 | rhs.mul_assign(&x); 139 | rhs.add_assign(&G::Affine::b_coeff()); 140 | 141 | if let Some(y) = rhs.sqrt() { 142 | let y_repr = y.into_repr(); 143 | let mut neg_y = y; 144 | neg_y.negate(); 145 | let neg_y_repr = neg_y.into_repr(); 146 | let is_positive = is_largest ^ (neg_y_repr < y_repr); // XOR 147 | let selected_y = if is_positive { y } else { neg_y }; 148 | 149 | let point_found = G::Affine::from_xy_checked(x, selected_y).unwrap(); 150 | points.push(point_found); 151 | } 152 | } 153 | 154 | Ok(points) 155 | } 156 | 157 | /// Computes vector c satisfying `c[i] = a[i] + b[i] * x`. 158 | /// Errors will occur if vectors `a`, `b` have different lengths. 159 | pub fn fold_scalars(a: &[F], b: &[F], x: &F) -> anyhow::Result> { 160 | if a.len() != b.len() { 161 | anyhow::bail!( 162 | "two vectors must have the same lengths, {} != {}", 163 | a.len(), 164 | b.len() 165 | ); 166 | } 167 | 168 | let mut result = b.to_vec(); 169 | for i in 0..result.len() { 170 | result[i].mul_assign(x); 171 | result[i].add_assign(&a[i]); 172 | } 173 | 174 | Ok(result) 175 | } 176 | 177 | /// Computes vector c satisfying `c[i] = a[i] + b[i] * x`. 178 | /// Errors will occur if vectors `a`, `b` have different lengths. 179 | pub fn fold_points(a: &[G], b: &[G], x: G::Scalar) -> anyhow::Result> 180 | where 181 | G: CurveProjective, 182 | { 183 | if a.len() != b.len() { 184 | anyhow::bail!( 185 | "two vectors must have the same lengths, {} != {}", 186 | a.len(), 187 | b.len() 188 | ); 189 | } 190 | 191 | let mut result = b.to_vec(); 192 | for i in 0..b.len() { 193 | result[i].mul_assign(x); 194 | result[i].add_assign(&a[i]); 195 | } 196 | 197 | Ok(result) 198 | } 199 | 200 | /// Computes the inner product of vectors `a` and `b`. 201 | /// Errors will occur if the two vectors have different lengths. 202 | pub fn inner_prod(a: &[F], b: &[F]) -> anyhow::Result { 203 | if a.len() != b.len() { 204 | anyhow::bail!( 205 | "two vectors must have the same lengths, {} != {}", 206 | a.len(), 207 | b.len() 208 | ); 209 | } 210 | 211 | let mut result = F::zero(); 212 | for i in 0..a.len() { 213 | let mut tmp = a[i]; 214 | tmp.mul_assign(&b[i]); 215 | result.add_assign(&tmp); 216 | } 217 | 218 | Ok(result) 219 | } 220 | 221 | /// Multiply `points[i]` by `scalars[i]` for each `i`, and sums up these values. 222 | /// Errors will occur if the two vectors have different lengths. 223 | pub fn multi_scalar(points: &[G], scalars: &[G::Scalar]) -> anyhow::Result 224 | where 225 | G: CurveProjective, 226 | { 227 | if points.len() != scalars.len() { 228 | anyhow::bail!( 229 | "the number of points does not equal the number of scalars, {} != {}", 230 | points.len(), 231 | scalars.len() 232 | ); 233 | } 234 | 235 | let mut result = G::zero(); 236 | for i in 0..points.len() { 237 | let mut tmp = points[i]; 238 | tmp.mul_assign(scalars[i]); // tmp = points[i] * scalars[i] 239 | result.add_assign(&tmp); // result += tmp 240 | } 241 | 242 | Ok(result) 243 | } 244 | 245 | /// Commits to a polynomial using the input group elements. 246 | /// Errors will occur if the number of group elements does not equal the number of polynomial 247 | /// coefficients. 248 | pub fn commit(group_elements: &[G], polynomial: &[G::Scalar]) -> anyhow::Result 249 | where 250 | G: CurveProjective, 251 | { 252 | let result = multi_scalar(group_elements, polynomial)?; 253 | 254 | Ok(result) 255 | } 256 | 257 | pub fn test_poly(polynomial: &[u64], domain_size: usize) -> Vec { 258 | let n = polynomial.len(); 259 | assert!( 260 | n <= domain_size, 261 | "polynomial cannot exceed {} coefficients", 262 | domain_size 263 | ); 264 | 265 | let mut polynomial_fr = Vec::with_capacity(domain_size); 266 | for polynomial_i in polynomial { 267 | polynomial_fr.push(read_field_element_le(&polynomial_i.to_le_bytes()).unwrap()); 268 | } 269 | 270 | polynomial_fr.resize(domain_size, F::zero()); 271 | 272 | polynomial_fr 273 | } 274 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Verkle Tree 2 | 3 | Rust implementation of Verkle tree verifiable by PlonK. 4 | The circuit implementation of Verkle tree verification is [here](https://github.com/InternetMaximalism/verkle-tree-circuit). 5 | 6 | Original Golang implementation is in 7 | [crate-crypto/go-ipa](https://github.com/crate-crypto/go-ipa/tree/fe21866d2ad5c732d1529cc8c4ebcc715edcc4e1) and [gballet/go-verkle](https://github.com/gballet/go-verkle/tree/8cf71b342fb237a48fafba9fcb2f68240a0c9f43). 8 | 9 | This library uses alt-BabyJubjub BN128 instead Bandersnatch as the elliptic curve for commitments. 10 | 11 | ## What this is, and is not 12 | 13 | This is not an attempt to further speed up the creation or verification of Verkle tree proofs. The project is positioned as a groundwork for constructing Verkle tree proofs verifiable by PlonK and for making verification of Layer 2 transactions more efficient. 14 | 15 | ## Environment 16 | 17 | ```sh 18 | rustup override set nightly 19 | cargo --version # >= 1.56.0 20 | ``` 21 | 22 | ## API 23 | 24 | `VerkleTreeWith32BytesKeyValue` is the 32 bytes key-value storage with `G1Affine`-valued commitments. 25 | See also [sample code](./src/main.rs) about how to use this library. 26 | 27 | ```rust 28 | use franklin_crypto::bellman::bn256::G1Affine; 29 | use verkle_tree::bn256_verkle_tree::proof::VerkleProof; 30 | use verkle_tree::bn256_verkle_tree::VerkleTreeWith32BytesKeyValue; 31 | ``` 32 | 33 | ### Create an empty Verkle tree 34 | 35 | `VerkleTreeWith32BytesKeyValue::new()` returns a tree consisting of only one root node with no children. 36 | 37 | ```rust 38 | let domain_size = 256; 39 | let committer = IpaConfig::new(domain_size); 40 | let mut tree = VerkleTreeWith32BytesKeyValue::new(committer); 41 | ``` 42 | 43 | ### Insert an entry in a Verkle tree 44 | 45 | `VerkleTreeWith32BytesKeyValue::insert()` inserts `(key, value)` entry in given Verkle tree. 46 | This method updates the entry to the new value and returns the old value, 47 | even if the tree already has a value corresponding to the key. 48 | 49 | ```rust 50 | let old_value: Option<[u8; 32]> = tree.insert(key, value); 51 | ``` 52 | 53 | ### Remove an entry from a Verkle tree 54 | 55 | `VerkleTreeWith32BytesKeyValue::remove()` remove the entry corresponding to `key` in given Verkle tree. 56 | If the tree does not have a value corresponding to the key, this method does not change the tree state. 57 | 58 | ```rust 59 | let old_value: Option<[u8; 32]> = tree.remove(&key); 60 | ``` 61 | 62 | ### Get the value from a Verkle tree 63 | 64 | `VerkleTreeWith32BytesKeyValue::get()` fetch the value corresponding to `key` in given Verkle tree. 65 | The maximum time it takes to search entries depends on the depth of given Verkle tree. 66 | 67 | ```rust 68 | let stored_value: Option<&[u8; 32]> = tree.get(&key); 69 | ``` 70 | 71 | ### Compute the commitment of a Verkle root 72 | 73 | `VerkleTreeWith32BytesKeyValue::compute_digest()` computes the digest of given Verkle tree. 74 | 75 | ```rust 76 | let digest: Fr = tree.compute_digest()?; 77 | ``` 78 | 79 | ### Compute the inclusion/exclusion proof of a Verkle tree (Verkle proof) 80 | 81 | `VerkleProof::create()` returns the inclusion/exclusion proof and its auxiliary data. 82 | If `keys` includes one key, `elements.zs[i]` is a child index of the internal node 83 | corresponding the key prefix of length `i`, and `elements.ys[i]` is the value of that child. 84 | If `keys` includes two or more keys, compute `elements.zs` and `elements.ys` for each key, 85 | and concatenate them. 86 | 87 | ```rust 88 | let (proof, elements) = VerkleProof::create(&mut tree, &keys)?; 89 | let zs = elements.zs; 90 | let ys = elements.ys; 91 | ``` 92 | 93 | ### Encode Verkle proof 94 | 95 | **under development** 96 | 97 | `EncodedVerkleProof::encode()` returns a Verkle proof in an serializable form. 98 | It omits duplications and elements that can be calculated from other elements. 99 | 100 | ```rust 101 | let encoded_proof = EncodedVerkleProof::encode(&proof); 102 | ``` 103 | 104 | ### Decode Verkle proof 105 | 106 | **under development** 107 | 108 | `EncodedVerkleProof::decode()` returns a Verkle proof in an easy-to-calculate form. 109 | `zs` and `ys` can be restored from `proof`. 110 | 111 | ```rust 112 | let (proof, zs, ys) = encoded_proof.decode()?; 113 | ``` 114 | 115 | ### Validate an inclusion/exclusion proof 116 | 117 | `VerkleProof::check()` returns the validity of given inclusion/exclusion proof. 118 | The verification does not use `elements.fs`, which has information on all child nodes. 119 | 120 | ```rust 121 | let domain_size = 256; 122 | let committer = IpaConfig::new(domain_size); 123 | let is_valid: bool = VerkleProof::check(&proof, &zs, &ys, &committer)?; 124 | ``` 125 | 126 | ## Details 127 | 128 | ### Transcript 129 | 130 | The **transcript** is the object storing all commitments which a prover should submits to a verifier and 131 | generating challenges (= pseudo-random variables) on behalf of the verifier. 132 | Generating challenges uses [Poseidon hash function](https://github.com/filecoin-project/neptune) for low-cost PlonK proofs. 133 | 134 | ### Elliptic Curve 135 | 136 | We choose Alt-BN128 (a.k.a. BN254) curve in our implementation for use with Ethereum Solidity. 137 | We need this elliptic curve to do the [inner product proof](https://eprint.iacr.org/2019/1177). 138 | 139 | ### Verkle Tree 140 | 141 | A **tree** data structure consists of the set called **nodes**. 142 | Each node consist of a value and a list of reference to other nodes called **children**. 143 | No reference is duplicated. 144 | There is only one node in a tree that is not referenced by any other node. This is called the **root**. 145 | 146 | **Verkle tree** is a type of prefix tree, where each node correspond to a key prefix, i.e. the first few bytes of the key, and refers to nodes corresponding to a prefix that is one character longer than its own prefix. 147 | There are two types of nodes in the case of Verkle trees: **internal** and **leaf**. 148 | Each internal node has 256 children and a digest of its subtree. 149 | Each leaf node has no children and a digest of the **suffix tree**, which is a data structure storing multiple entries corresponding to a key prefix. 150 | 151 | A similar data structure is **Merkle tree**, but the difference between these is in the way their commitments are computed. 152 | 153 | If you would like to know more, please refer to [Vitalik Buterin's post](https://vitalik.ca/general/2021/06/18/verkle.html). 154 | 155 | ### Encoded Verkle Proof 156 | 157 | Example: 158 | 159 | ```sh 160 | cargo test -- test_encode_verkle_proof --nocapture 161 | cat test_cases/case1/proof.json 162 | ``` 163 | 164 | ```json 165 | { 166 | "multi_proof": { 167 | "ipa": { 168 | "l": [ 169 | "0x373ae8f856e37542cda7561dc507ddf3a7ac666fb163e908d093fda016bd328a", 170 | "0x1d764657384e62b0e9b70d00d140cc13d885b8831355e7f3fb708f2b47be2604", 171 | "0x47ed7f94b6263630d585b4bb8070bb066aa74e9b1ee068d28c6b0dfef61b4d01", 172 | "0x363cf2f487193e12d57f5034b64a46dd7ce360b157b8c69cb39d5e9cde553714", 173 | "0xcab992777bd368c4fbb0372127f623dd803bf2830d69c620a6042b153e2d9727", 174 | "0xa9f01ce3441b121dc8bb75860eebac6a49b96001462a92a18e511c151501c6a8", 175 | "0xaddbaffbf6a28fad5f8d050be6d884aa68705421fdd345bb83296adc5ee2d602", 176 | "0x0d57a8821d9771380ef72b743304f3b0b960b59b7683f95a0434bf95d4cc6093" 177 | ], 178 | "r": [ 179 | "0x2ff4547fface585e095bf1eae305fa07b5e2b6b1692d17c1d7f964b2b1794181", 180 | "0x447165ae6c16b23540c07d3f0a93d92be37e90030c3b80e7fce16f9671890aa8", 181 | "0x39625eb44c1b211eced15ba93f2c901eadb1a32e0b5a0d0c4987b8d7d60c9b2f", 182 | "0x572729372ccd211f3073a3535e5c5590e38173ce0071d9ce55f67fccbedb4415", 183 | "0x5ebcd74626a3923034ec66bd0b7f7908fb6a6ff3fb1aa9dde6273684ec13bb16", 184 | "0x8e859d69cc0e4cb297acf8ac8b3af292d3d9e1de3ddc5734400769565ce3d088", 185 | "0x0b474fd0dc097920ec9642f1dbcfa3f840b7da6fe25c496c05aa181fad2632aa", 186 | "0xd8f52ca54bf344b80d7b5268b46a49fa3b633b51ed1277d49da429d4176dd41e" 187 | ], 188 | "a": "0x1e7caca7461a0200b57594e57db4a4bc33526f80a2757a6f6d93bb2e54364059" 189 | }, 190 | "d": "0x406cbde73c39a688977004d833d80105f19c058698f4e69c8b7427af1858e1a4" 191 | }, 192 | "keys": [ 193 | "0xfea400000000000000000000000000000000000000000000000000000000650d", 194 | "0x11a400000000000000000000000000000000000000000000000000000000670d", 195 | "0xfda400000000000000000000000000000000000000000000000000000000670d", 196 | "0xfea400000000000000000000000000000000000000000000000000000000670d", 197 | "0xff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 198 | ], 199 | "values": [ 200 | "0x0000000000000000000000000000000000000000000000000000000000000000", 201 | "0x0000000000000000000000000000000000000000000000000000000000000000", 202 | "0x0000000000000000000000000000000000000000000000000000000000000000", 203 | "0x8800000000000000000000000000003cc10000000000000000000000000000eb", 204 | "0x0000000000000000000000000000000000000000000000000000000000000000" 205 | ], 206 | "extra_data_list": [ 207 | "0x1000000000000000000000000000000000000000000000000000000000000000", 208 | "0x1200000000000000000000000000000000000000000000000000000000000000", 209 | "0x1300000000000000000000000000000000000000000000000000000000000000", 210 | "0x1400000000000000000000000000000000000000000000000000000000000000", 211 | "0x09ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 212 | ], 213 | "commitments": [ 214 | "0x548597525b0dcb2c046411b7f4d7ce5a2f89a5c2b74fd25de157034296e30ca2", 215 | "0x522a1a4b4989ba0d40f3087753aa85c29dce891816215036855c11b77362199c", 216 | "0x8d6606735e3b17c30992ec1646dbe6c01e37ed37b60cedfc19cb773d1c14890a", 217 | "0x421e3f1467b697029ce8b8ab9b50667233fa198d6df465364345b444feb12889", 218 | "0x421e3f1467b697029ce8b8ab9b50667233fa198d6df465364345b444feb12889", 219 | "0x9b9704755f28a84eca03566db4dbdf43f0a045e95df2fe400eee6cdcf9eaf227" 220 | ] 221 | } 222 | ``` 223 | 224 | NOTE: This Verkle proof has 5 keys, but a capacity of about 32 keys 225 | (to be precise, it can contain 256 commitments before encoding). 226 | The size of `multi_proof` is constant within that capacity. 227 | -------------------------------------------------------------------------------- /src/ipa_fr/config.rs: -------------------------------------------------------------------------------- 1 | use franklin_crypto::bellman::{CurveAffine, CurveProjective, Field, PrimeField}; 2 | 3 | use super::utils::{commit, generate_random_points, read_field_element_le}; 4 | 5 | /// `num_ipa_rounds` is a integer. 6 | /// `domain_size` is equal to 2^`num_ipa_rounds`. 7 | /// 8 | /// `barycentric_weights` stores A'(x_i) and 1 / A'(x_i). 9 | /// 10 | /// `inverted_domain` stores 1/k and -1/k for k in [0, `domain_size`). 11 | #[derive(Clone, Debug, PartialEq, Eq)] 12 | pub struct PrecomputedWeights { 13 | barycentric_weights: Vec, 14 | inverted_domain: Vec, 15 | domain_size: usize, 16 | } 17 | 18 | impl PrecomputedWeights { 19 | pub fn new(domain_size: usize) -> Self { 20 | // Note there are `domain_size` number of weights, but we are also storing their inverses 21 | // so we need double the amount of space. 22 | let mut barycentric_weights = vec![::zero(); domain_size * 2]; 23 | for i in 0..domain_size { 24 | let weight: F = compute_barycentric_weight_for_element(i, domain_size); 25 | let inv_weight = weight.inverse().unwrap(); 26 | 27 | barycentric_weights[i] = weight; 28 | barycentric_weights[i + domain_size] = inv_weight; 29 | } 30 | 31 | // Computing 1/k and -1/k for k in [0, domain_size - 1]. 32 | // Note that since we cannot do 1/0, we have one less element. 33 | let midpoint = domain_size - 1; 34 | let mut inverted_domain = vec![::zero(); midpoint * 2]; 35 | for i in 1..domain_size { 36 | let k = read_field_element_le::(&i.to_le_bytes()).unwrap(); 37 | let k = k.inverse().unwrap(); 38 | 39 | let mut negative_k = ::zero(); 40 | negative_k.sub_assign(&k); 41 | 42 | inverted_domain[i - 1] = k; 43 | inverted_domain[(i - 1) + midpoint] = negative_k; 44 | } 45 | 46 | Self { 47 | barycentric_weights, 48 | inverted_domain, 49 | domain_size, 50 | } 51 | } 52 | 53 | pub fn get_domain_size(&self) -> usize { 54 | self.domain_size 55 | } 56 | 57 | pub fn get_barycentric_weights(&self) -> &Vec { 58 | &self.barycentric_weights 59 | } 60 | 61 | pub fn get_inverted_domain(&self) -> &Vec { 62 | &self.inverted_domain 63 | } 64 | 65 | /// Computes the coefficients `barycentric_coeffs` for a point `z` such that 66 | /// when we have a polynomial `p` in lagrange basis, the inner product of `p` and `barycentric_coeffs` 67 | /// is equal to p(z). 68 | /// Note that `z` should not be in the domain. 69 | pub fn compute_barycentric_coefficients(&self, point: &F) -> anyhow::Result> { 70 | let domain_size = self.get_domain_size(); 71 | 72 | // Compute A(x_i) * point - x_i 73 | let mut lagrange_evals: Vec = Vec::with_capacity(domain_size); 74 | let mut total_prod = F::one(); 75 | for i in 0..domain_size { 76 | let weight = self.barycentric_weights[i]; 77 | let mut tmp = read_field_element_le::(&i.to_le_bytes())?; 78 | tmp.sub_assign(point); 79 | tmp.negate(); 80 | total_prod.mul_assign(&tmp); // total_prod *= (point - i) 81 | 82 | tmp.mul_assign(&weight); // lagrange_evals[i] = (point - i) * weight 83 | lagrange_evals.push(tmp); 84 | } 85 | 86 | // TODO: Calculate the inverses of all elements together. 87 | let mut lagrange_evals = { 88 | let mut tmp = vec![]; 89 | for eval in lagrange_evals { 90 | let inverse_of_eval = eval.inverse().ok_or(anyhow::anyhow!( 91 | "cannot find inverse of `lagrange_evals[i]`" 92 | ))?; // lagrange_evals[i] = 1 / ((point - i) * weight) 93 | tmp.push(inverse_of_eval); 94 | } 95 | 96 | tmp 97 | }; 98 | 99 | for eval in lagrange_evals.iter_mut() { 100 | eval.mul_assign(&total_prod); // lagrange_evals[i] = total_prod / ((point - i) * weight) 101 | } 102 | 103 | Ok(lagrange_evals) 104 | } 105 | 106 | pub fn get_inverted_element(&self, element: usize, is_neg: bool) -> F { 107 | assert!(element != 0, "cannot compute the inverse of zero"); 108 | let mut index = element - 1; 109 | 110 | if is_neg { 111 | let midpoint = self.inverted_domain.len() / 2; 112 | index += midpoint; 113 | } 114 | 115 | self.inverted_domain[index] 116 | } 117 | 118 | pub fn get_ratio_of_weights(&self, numerator: usize, denominator: usize) -> F { 119 | let a = self.barycentric_weights[numerator]; 120 | let midpoint = self.barycentric_weights.len() / 2; 121 | let b = self.barycentric_weights[denominator + midpoint]; 122 | 123 | let mut result = a; 124 | result.mul_assign(&b); 125 | result 126 | } 127 | 128 | /// Computes (f(x) - f(x_i)) / (x - x_i) where x_i is an element in the domain. 129 | pub fn divide_on_domain(&self, index: usize, f: &[F]) -> Vec { 130 | let domain_size = self.get_domain_size(); 131 | 132 | let mut quotient = vec![::zero(); domain_size]; 133 | 134 | let y = f[index]; 135 | 136 | for i in 0..domain_size { 137 | if i != index { 138 | // den = i - index 139 | let (abs_den, is_neg) = sub_abs(i, index); // den = i - index 140 | 141 | let den_inv = self.get_inverted_element(abs_den, is_neg); 142 | 143 | // compute q_i 144 | quotient[i] = f[i]; 145 | quotient[i].sub_assign(&y); 146 | quotient[i].mul_assign(&den_inv); // quotient[i] = (f[i] - f[index]) / (i - index) 147 | 148 | let weight_ratio = self.get_ratio_of_weights(index, i); 149 | let mut tmp = weight_ratio; 150 | tmp.mul_assign("ient[i]); // tmp = weight_ratio * quotient[i] 151 | quotient[index].sub_assign(&tmp); // quotient[index] -= tmp 152 | } 153 | } 154 | 155 | quotient 156 | } 157 | } 158 | 159 | /// Computes A'(x_j) where x_j is an element in [0, domain_size). 160 | /// This is computed as the product of x_j - x_i where x_i is an element in the domain 161 | /// and x_i is not equal to x_j. 162 | pub fn compute_barycentric_weight_for_element( 163 | element: usize, 164 | domain_size: usize, 165 | ) -> F { 166 | assert!( 167 | element < domain_size, 168 | "The domain is [0, {}], {} is not in the domain.", 169 | domain_size - 1, 170 | element 171 | ); 172 | 173 | let domain_element_fr = read_field_element_le::(&element.to_le_bytes()).unwrap(); 174 | 175 | let mut total = F::one(); 176 | 177 | for i in 0..domain_size { 178 | if i == element { 179 | continue; 180 | } 181 | 182 | let i_fr = read_field_element_le::(&i.to_le_bytes()).unwrap(); 183 | 184 | let mut tmp = domain_element_fr; 185 | tmp.sub_assign(&i_fr); 186 | total.mul_assign(&tmp); 187 | } 188 | 189 | total 190 | } 191 | 192 | /// Return (|a - b|, a < b). 193 | fn sub_abs + std::cmp::PartialOrd>(a: N, b: N) -> (N, bool) { 194 | if a < b { 195 | (b - a, true) 196 | } else { 197 | (a - b, false) 198 | } 199 | } 200 | 201 | /// `srs` is a structured reference string. 202 | /// 203 | /// `q` is a point on the elliptic curve `G`. 204 | /// 205 | /// `precomputed_weights` is a instance of `PrecomputedWeights`. 206 | #[derive(Clone, Debug, PartialEq, Eq)] 207 | pub struct IpaConfig { 208 | srs: Vec, 209 | q: GA, 210 | precomputed_weights: PrecomputedWeights, 211 | } 212 | 213 | impl IpaConfig 214 | where 215 | GA::Base: PrimeField, 216 | { 217 | pub fn new(domain_size: usize) -> Self { 218 | #[cfg(debug_assertions)] 219 | let start = std::time::Instant::now(); 220 | 221 | let srs = generate_random_points::(domain_size).unwrap(); 222 | 223 | #[cfg(debug_assertions)] 224 | println!( 225 | "generate srs: {} s", 226 | start.elapsed().as_micros() as f64 / 1000000.0 227 | ); 228 | 229 | let q = GA::one(); 230 | let precomputed_weights = PrecomputedWeights::new(domain_size); 231 | 232 | Self { 233 | srs, 234 | q, 235 | precomputed_weights, 236 | } 237 | } 238 | 239 | pub fn get_srs(&self) -> &Vec { 240 | &self.srs 241 | } 242 | 243 | pub fn get_q(&self) -> GA { 244 | self.q 245 | } 246 | 247 | pub fn get_precomputed_weights(&self) -> &PrecomputedWeights { 248 | &self.precomputed_weights 249 | } 250 | } 251 | 252 | #[test] 253 | fn test_ensure_length_of_srs_is_valid() { 254 | use franklin_crypto::bellman::bn256::G1Affine; 255 | 256 | let domain_size = 256; 257 | let ipa_conf = IpaConfig::::new(domain_size); 258 | 259 | assert_eq!(ipa_conf.get_srs().len(), domain_size); 260 | } 261 | 262 | pub trait Committer { 263 | type Err: Send + Sync + 'static; 264 | 265 | fn get_domain_size(&self) -> usize; 266 | 267 | fn commit(&self, polynomial: &[GA::Scalar]) -> Result; 268 | } 269 | 270 | impl Committer for IpaConfig { 271 | type Err = anyhow::Error; 272 | 273 | fn get_domain_size(&self) -> usize { 274 | self.precomputed_weights.get_domain_size() 275 | } 276 | 277 | fn commit(&self, polynomial: &[GA::Scalar]) -> anyhow::Result { 278 | let result = commit::( 279 | &self 280 | .srs 281 | .iter() 282 | .map(|x| x.into_projective()) 283 | .collect::>(), 284 | polynomial, 285 | ) 286 | .unwrap() 287 | .into_affine(); 288 | 289 | Ok(result) 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /src/ipa_fs/utils.rs: -------------------------------------------------------------------------------- 1 | // use ff_utils::{Bn256Fr, FromBytes, ToBytes}; 2 | use franklin_crypto::babyjubjub::edwards::Point; 3 | use franklin_crypto::babyjubjub::{JubjubEngine, Unknown}; 4 | use franklin_crypto::bellman::{Field, PrimeField, PrimeFieldRepr}; 5 | use sha2::{Digest, Sha256}; 6 | 7 | pub fn log2_ceil(value: usize) -> usize { 8 | assert!(value != 0, "The first argument must be a positive number."); 9 | 10 | if value == 1 { 11 | return 0; 12 | } 13 | 14 | let mut log_value = 1; 15 | let mut tmp_value = value - 1; 16 | while tmp_value > 1 { 17 | tmp_value /= 2; 18 | log_value += 1; 19 | } 20 | 21 | log_value 22 | } 23 | 24 | #[test] 25 | #[should_panic] 26 | pub fn test_error_log2_ceil() { 27 | log2_ceil(0); 28 | } 29 | 30 | #[test] 31 | pub fn test_log2_ceil() { 32 | let res0 = log2_ceil(1); 33 | assert_eq!(res0, 0); 34 | 35 | let res1 = log2_ceil(2); 36 | assert_eq!(res1, 1); 37 | 38 | let res2 = log2_ceil(3); 39 | assert_eq!(res2, 2); 40 | 41 | let res3 = log2_ceil(4); 42 | assert_eq!(res3, 2); 43 | 44 | let res4 = log2_ceil(5); 45 | assert_eq!(res4, 3); 46 | 47 | let res5 = log2_ceil(127); 48 | assert_eq!(res5, 7); 49 | } 50 | 51 | pub fn read_field_element_le(bytes: &[u8]) -> anyhow::Result { 52 | let mut repr = F::Repr::default(); 53 | let mut padded_bytes = bytes.to_vec(); 54 | let num_bits = F::NUM_BITS as usize; 55 | // assert!(bytes.len() <= (num_bits + 7) / 8); 56 | // for _ in bytes.len()..num_bits { 57 | // padded_bytes.push(0); 58 | // } 59 | padded_bytes.resize((num_bits + 7) / 8, 0); 60 | repr.read_le::<&[u8]>(padded_bytes.as_ref())?; 61 | let value = F::from_repr(repr)?; 62 | 63 | Ok(value) 64 | } 65 | 66 | pub fn read_field_element_be(bytes: &[u8]) -> anyhow::Result { 67 | let mut padded_bytes = bytes.to_vec(); 68 | padded_bytes.reverse(); 69 | read_field_element_le(&padded_bytes) 70 | } 71 | 72 | pub fn write_field_element_le(scalar: &F) -> Vec { 73 | let scalar_u64_vec = scalar.into_repr().as_ref().to_vec(); 74 | let mut result = vec![0; scalar_u64_vec.len() * 8]; 75 | for (bytes, tmp) in scalar_u64_vec 76 | .iter() 77 | .map(|x| x.to_le_bytes()) 78 | .zip(result.chunks_mut(8)) 79 | { 80 | // for i in 0..bytes.len() { 81 | // tmp[i] = bytes[i]; 82 | // } 83 | tmp[..bytes.len()].clone_from_slice(&bytes[..]); 84 | } 85 | 86 | result 87 | } 88 | 89 | pub fn write_field_element_be(scalar: &F) -> Vec { 90 | let mut result = write_field_element_le(scalar); 91 | result.reverse(); 92 | 93 | result 94 | } 95 | 96 | const FS_REPR_3_MASK: u64 = 0x03FFFFFFFFFFFFFF; // (250 - 192) bits 97 | 98 | pub fn convert_fr_to_fs(value: &E::Fr) -> anyhow::Result { 99 | let raw_value = value.into_repr(); 100 | let mut raw_result = ::Repr::default(); 101 | raw_result.as_mut()[0] = raw_value.as_ref()[0]; 102 | raw_result.as_mut()[1] = raw_value.as_ref()[1]; 103 | raw_result.as_mut()[2] = raw_value.as_ref()[2]; 104 | raw_result.as_mut()[3] = raw_value.as_ref()[3] & FS_REPR_3_MASK; 105 | let result = E::Fs::from_repr(raw_result)?; 106 | 107 | Ok(result) 108 | } 109 | 110 | pub fn convert_fs_to_fr(value: &E::Fs) -> anyhow::Result { 111 | let raw_value = value.into_repr(); 112 | let raw_result = convert_fs_repr_to_fr_repr::(&raw_value)?; 113 | let result = E::Fr::from_repr(raw_result)?; 114 | 115 | Ok(result) 116 | } 117 | 118 | pub fn convert_fs_repr_to_fr_repr( 119 | raw_value: &::Repr, 120 | ) -> anyhow::Result<::Repr> { 121 | let mut raw_result = ::Repr::default(); 122 | for (r, &v) in raw_result.as_mut().iter_mut().zip(raw_value.as_ref()) { 123 | let _ = std::mem::replace(r, v); 124 | } 125 | 126 | Ok(raw_result) 127 | } 128 | 129 | #[test] 130 | fn test_read_write_ff() { 131 | use franklin_crypto::bellman::pairing::bn256::Fr; 132 | 133 | let bytes = [ 134 | 101u8, 121, 238, 208, 145, 118, 73, 126, 4, 129, 129, 133, 67, 167, 1, 64, 164, 189, 107, 135 | 239, 228, 126, 238, 70, 205, 50, 174, 80, 238, 181, 137, 47, 136 | ]; 137 | let point = read_field_element_le::(&bytes).unwrap(); 138 | assert_eq!( 139 | format!("{:?}", point), 140 | "Fr(0x2f89b5ee50ae32cd46ee7ee4ef6bbda44001a743858181047e497691d0ee7965)" 141 | ); 142 | 143 | let recovered_bytes = write_field_element_le(&point); 144 | assert_eq!(recovered_bytes, bytes); 145 | } 146 | 147 | // pub fn fr_to_fs_repr( 148 | // value: &E::Fr, 149 | // ) -> anyhow::Result<::Repr> { 150 | // let bytes = write_field_element_le(value); 151 | // let mut fs_repr = ::Repr::default(); 152 | // fs_repr.read_le::<&[u8]>(bytes.as_ref())?; 153 | 154 | // Ok(fs_repr) 155 | // } 156 | 157 | // pub fn fr_to_fs(value: &E::Fr) -> anyhow::Result { 158 | // read_field_element_le(&write_field_element_le(value)) 159 | // } 160 | 161 | pub fn generate_random_points( 162 | num_points: usize, 163 | jubjub_params: &E::Params, 164 | ) -> anyhow::Result>> { 165 | let mut hasher = Sha256::new(); 166 | hasher.update(b"eth_verkle_oct_2021"); // In case it changes or needs updating, we can use eth_verkle_month_year. 167 | let digest = hasher.finalize(); 168 | let u = read_field_element_le::(digest.as_ref())?; 169 | 170 | // flag to indicate whether we choose the lexicographically larger 171 | // element of `x` out of it and it's negative (?) 172 | let choose_largest = false; 173 | 174 | let mut points = vec![]; 175 | 176 | let mut increment = 0usize; 177 | 178 | // TODO: It takes too long to find some random points with the specific order. 179 | while points.len() != num_points { 180 | let mut y = u; 181 | y.add_assign(&read_field_element_le(&increment.to_le_bytes()).unwrap()); // y = u + increment 182 | increment += 1; 183 | 184 | let point_found = Point::::get_for_y(y, choose_largest, jubjub_params); 185 | if point_found.is_none() { 186 | continue; 187 | } 188 | 189 | let point_found = point_found.unwrap(); 190 | let result = point_found.as_prime_order(jubjub_params); 191 | if let Some(_p) = result { 192 | points.push(point_found); 193 | } 194 | } 195 | 196 | Ok(points) 197 | } 198 | 199 | // pub fn is_in_prime_subgroup( 200 | // p: &Point, 201 | // jubjub_params: &E::Params, 202 | // ) -> bool { 203 | // let order = jubjub_params.order(); 204 | 205 | // let mut res_proj = Point::::zero(); // identity 206 | 207 | // let bit_len = order.bit_len(); 208 | 209 | // for i in 0..(bit_len + 1) { 210 | // res_proj = res_proj.double(jubjub_params); 211 | // if order.bit(bit_len - i) == 1 { 212 | // res_proj = res_proj.add(p, jubjub_params); 213 | // } 214 | // } 215 | 216 | // let identity = Point::::zero(); // identity 217 | 218 | // identity.eq(&res_proj) 219 | // } 220 | 221 | // Computes vector c satisfying c[i] = a[i] + b[i] * x. 222 | // Error if vectors a, b have different lengths. 223 | pub fn fold_scalars(a: &[F], b: &[F], x: &F) -> anyhow::Result> { 224 | if a.len() != b.len() { 225 | anyhow::bail!( 226 | "two vectors must have the same lengths, {} != {}", 227 | a.len(), 228 | b.len() 229 | ); 230 | } 231 | 232 | let mut result = b.to_vec(); 233 | for (result_i, a_i) in result.iter_mut().zip(a) { 234 | result_i.mul_assign(x); 235 | result_i.add_assign(a_i); 236 | } 237 | 238 | Ok(result) 239 | } 240 | 241 | // Computes vector c satisfying c[i] = a[i] + b[i] * x. 242 | // Error if vectors a, b have different lengths. 243 | pub fn fold_points( 244 | a: &[Point], 245 | b: &[Point], 246 | x: &E::Fs, 247 | jubjub_params: &E::Params, 248 | ) -> anyhow::Result>> { 249 | if a.len() != b.len() { 250 | anyhow::bail!( 251 | "two vectors must have the same lengths, {} != {}", 252 | a.len(), 253 | b.len() 254 | ); 255 | } 256 | 257 | let mut result = b.to_vec(); 258 | for i in 0..b.len() { 259 | result[i] = result[i].mul(*x, jubjub_params); 260 | result[i] = result[i].add(&a[i], jubjub_params); 261 | } 262 | 263 | Ok(result) 264 | } 265 | 266 | // Computes the inner product of vectors a and b. 267 | // Error if the two vectors have different lengths. 268 | pub fn inner_prod(a: &[F], b: &[F]) -> anyhow::Result { 269 | if a.len() != b.len() { 270 | anyhow::bail!( 271 | "two vectors must have the same lengths, {} != {}", 272 | a.len(), 273 | b.len() 274 | ); 275 | } 276 | 277 | let mut result = F::zero(); 278 | for i in 0..a.len() { 279 | let mut tmp = a[i]; 280 | tmp.mul_assign(&b[i]); 281 | result.add_assign(&tmp); 282 | } 283 | 284 | Ok(result) 285 | } 286 | 287 | // Computes the inner product of vectors a and b. 288 | // Error if the two vectors have different lengths. 289 | pub fn multi_scalar( 290 | points: &[Point], 291 | scalars: &[E::Fs], 292 | jubjub_params: &E::Params, 293 | ) -> anyhow::Result> { 294 | if points.len() != scalars.len() { 295 | anyhow::bail!( 296 | "the number of points does not equal the number of scalars, {} != {}", 297 | points.len(), 298 | scalars.len() 299 | ); 300 | } 301 | 302 | let mut result = Point::::zero(); 303 | for i in 0..points.len() { 304 | let mut tmp = points[i].clone(); 305 | tmp = tmp.mul(scalars[i], jubjub_params); // tmp = points[i] * scalars[i] 306 | result = result.add(&tmp, jubjub_params); // result += tmp 307 | } 308 | 309 | Ok(result) 310 | } 311 | 312 | // Commits to a polynomial using the input group elements. 313 | // Error if the number of group elements does not equal the number of polynomial coefficients. 314 | pub fn commit( 315 | group_elements: &[Point], 316 | polynomial: &[E::Fs], 317 | jubjub_params: &E::Params, 318 | ) -> anyhow::Result> { 319 | // let scalars = polynomial 320 | // .iter() 321 | // .map(fr_to_fs::) 322 | // .collect::>>()?; 323 | let result = multi_scalar::(group_elements, polynomial, jubjub_params)?; 324 | 325 | Ok(result) 326 | } 327 | -------------------------------------------------------------------------------- /src/batch_proof_fs/mod.rs: -------------------------------------------------------------------------------- 1 | use franklin_crypto::babyjubjub::edwards::Point; 2 | use franklin_crypto::babyjubjub::fs::Fs; 3 | use franklin_crypto::babyjubjub::{JubjubEngine, Unknown}; 4 | use franklin_crypto::bellman::pairing::bn256::{Bn256, Fr}; 5 | use franklin_crypto::bellman::Field; 6 | 7 | use crate::ipa_fs::config::{Committer, IpaConfig}; 8 | use crate::ipa_fs::proof::IpaProof; 9 | use crate::ipa_fs::transcript::{Bn256Transcript, PoseidonBn256Transcript}; 10 | use crate::ipa_fs::utils::read_field_element_le; 11 | 12 | #[derive(Clone)] 13 | pub struct BatchProof { 14 | pub ipa: IpaProof, 15 | pub d: Point, 16 | } 17 | 18 | #[cfg(test)] 19 | mod tests { 20 | use franklin_crypto::babyjubjub::fs::Fs; 21 | use franklin_crypto::babyjubjub::JubjubBn256; 22 | use franklin_crypto::bellman::pairing::bn256::Bn256; 23 | 24 | use crate::{ 25 | ipa_fr::utils::test_poly, 26 | ipa_fs::{ 27 | config::{Committer, IpaConfig}, 28 | transcript::{Bn256Transcript, PoseidonBn256Transcript}, 29 | }, 30 | }; 31 | 32 | use super::BatchProof; 33 | 34 | #[test] 35 | fn test_multi_proof_create_verify() -> Result<(), Box> { 36 | // Shared View 37 | let domain_size = 128; 38 | let jubjub_params = &JubjubBn256::new(); 39 | println!("create ipa_conf"); 40 | let ipa_conf = &IpaConfig::::new(domain_size, jubjub_params); 41 | 42 | // Prover view 43 | let poly_1 = test_poly::(&[12, 97, 37, 0, 1, 208, 132, 3], domain_size); 44 | let prover_transcript = PoseidonBn256Transcript::with_bytes(b"multi_proof"); 45 | let prover_commitment_1 = ipa_conf.commit(&poly_1)?; 46 | 47 | let commitments = vec![prover_commitment_1.clone(), prover_commitment_1]; 48 | let fs = vec![poly_1.clone(), poly_1]; 49 | let index_1 = 36; 50 | let index_2 = 103; 51 | let zs = vec![index_1, index_2]; 52 | // let mut ys = vec![]; 53 | // for i in 0..zs.len() { 54 | // let y_i = fs[i][zs[i]]; 55 | // ys.push(y_i); 56 | // } 57 | let (proof, ys) = BatchProof::create( 58 | &commitments, 59 | &fs, 60 | &zs, 61 | prover_transcript.into_params(), 62 | ipa_conf, 63 | )?; 64 | 65 | // test_serialize_deserialize_proof(proof); 66 | 67 | // Verifier view 68 | let verifier_transcript = PoseidonBn256Transcript::with_bytes(b"multi_proof"); 69 | let success = proof.check( 70 | &commitments, 71 | &ys, 72 | &zs, 73 | verifier_transcript.into_params(), 74 | ipa_conf, 75 | )?; 76 | 77 | assert!(success, "inner product proof failed"); 78 | 79 | Ok(()) 80 | } 81 | } 82 | 83 | impl BatchProof { 84 | pub fn create( 85 | commitments: &[Point], 86 | fs: &[Vec], 87 | zs: &[usize], 88 | transcript_params: Fr, 89 | ipa_conf: &IpaConfig, 90 | ) -> anyhow::Result<(Self, Vec)> { 91 | let jubjub_params = ipa_conf.jubjub_params; 92 | let mut transcript = PoseidonBn256Transcript::new(&transcript_params); 93 | 94 | // transcript.DomainSep("multiproof"); 95 | 96 | if commitments.len() != fs.len() { 97 | anyhow::anyhow!( 98 | "number of commitments = {}, while number of functions = {}", 99 | commitments.len(), 100 | fs.len() 101 | ); 102 | } 103 | if commitments.len() != zs.len() { 104 | anyhow::anyhow!( 105 | "number of commitments = {}, while number of points = {}", 106 | commitments.len(), 107 | zs.len() 108 | ); 109 | } 110 | 111 | let num_queries = commitments.len(); 112 | if num_queries == 0 { 113 | anyhow::anyhow!("cannot create a batch proof with no data"); 114 | } 115 | 116 | let domain_size = ipa_conf.get_domain_size(); 117 | let mut ys = vec![]; 118 | for i in 0..num_queries { 119 | transcript.commit_point(&commitments[i])?; // C 120 | 121 | assert!(zs[i] < domain_size); 122 | transcript.commit_bytes(&zs[i].to_le_bytes())?; 123 | 124 | // get the `y` value 125 | 126 | let f_i = fs[i].clone(); 127 | let y_i = f_i[zs[i]]; 128 | transcript.commit_field_element(&y_i)?; // y 129 | ys.push(y_i); 130 | } 131 | let r = transcript.get_challenge(); // r 132 | 133 | // println!("r: {:?}", r); 134 | 135 | // Compute g(X) 136 | let mut g_x = vec![Fs::zero(); domain_size]; 137 | let mut powers_of_r = Fs::one(); // powers_of_r = 1 138 | for i in 0..num_queries { 139 | let quotient = ipa_conf.precomputed_weights.divide_on_domain(zs[i], &fs[i]); // quotient[j] = (f_i(j) - f_i(zs[i])) / (j - zs[i]) 140 | 141 | for j in 0..domain_size { 142 | let mut tmp = quotient[j]; 143 | tmp.mul_assign(&powers_of_r); 144 | g_x[j].add_assign(&tmp); // g_x[j] += r^i * quotient[j] 145 | } 146 | 147 | powers_of_r.mul_assign(&r); 148 | } 149 | 150 | let d = ipa_conf.commit(&g_x)?; 151 | 152 | transcript.commit_point(&d)?; // D 153 | 154 | let t = transcript.get_challenge(); // t 155 | // println!("t: {:?}", t); 156 | 157 | // Compute h(X) = g_1(X) 158 | let mut h_x = vec![Fs::zero(); domain_size]; 159 | let mut powers_of_r = Fs::one(); 160 | for i in 0..num_queries { 161 | let z_i = read_field_element_le::(&zs[i].to_le_bytes()).unwrap(); 162 | let mut den = t; // den_inv = t 163 | den.sub_assign(&z_i); // den_inv = t - z_i 164 | let den_inv = den 165 | .inverse() 166 | .ok_or(anyhow::anyhow!("cannot find inverse of `t - z_i`"))?; // den_inv = 1 / (t - z_i) 167 | 168 | for (k, h_x_k) in h_x.iter_mut().enumerate() { 169 | let mut tmp = powers_of_r; 170 | tmp.mul_assign(&fs[i][k]); 171 | tmp.mul_assign(&den_inv); 172 | h_x_k.add_assign(&tmp); // h_x[k] += r^i * f[i][k] / (t - z_i) 173 | } 174 | 175 | powers_of_r.mul_assign(&r); // powers_of_r *= r 176 | } 177 | 178 | let mut h_minus_g = vec![Fs::zero(); domain_size]; 179 | for i in 0..domain_size { 180 | h_minus_g[i] = h_x[i]; 181 | h_minus_g[i].sub_assign(&g_x[i]); 182 | } 183 | 184 | let start = std::time::Instant::now(); 185 | let e = ipa_conf.commit(&h_x)?; 186 | println!( 187 | "commit h_x: {} s", 188 | start.elapsed().as_micros() as f64 / 1000000.0 189 | ); 190 | transcript.commit_point(&e)?; // E 191 | 192 | let minus_d = d.negate(); 193 | 194 | let e_minus_d = e.add(&minus_d, jubjub_params); 195 | 196 | let transcript_params = transcript.into_params(); 197 | 198 | let (ipa_proof, _) = 199 | IpaProof::create(e_minus_d, &h_minus_g, t, transcript_params, ipa_conf)?; 200 | 201 | Ok((BatchProof { ipa: ipa_proof, d }, ys)) 202 | } 203 | 204 | pub fn check( 205 | &self, 206 | commitments: &[Point], 207 | ys: &[Fs], 208 | zs: &[usize], 209 | transcript_params: Fr, 210 | ipa_conf: &IpaConfig, 211 | ) -> anyhow::Result { 212 | let proof = self; 213 | let jubjub_params = ipa_conf.jubjub_params; 214 | let mut transcript = PoseidonBn256Transcript::new(&transcript_params); 215 | 216 | if commitments.len() != ys.len() { 217 | anyhow::anyhow!( 218 | "number of commitments = {}, while number of output points = {}", 219 | commitments.len(), 220 | ys.len() 221 | ); 222 | } 223 | if commitments.len() != zs.len() { 224 | anyhow::anyhow!( 225 | "number of commitments = {}, while number of input points = {}", 226 | commitments.len(), 227 | zs.len() 228 | ); 229 | } 230 | 231 | let num_queries = commitments.len(); 232 | if num_queries == 0 { 233 | anyhow::anyhow!("cannot create a batch proof with no data"); 234 | } 235 | 236 | let domain_size = ipa_conf.get_domain_size(); 237 | 238 | println!("update transcript"); 239 | for i in 0..num_queries { 240 | assert!(zs[i] < domain_size); 241 | let start = std::time::Instant::now(); 242 | transcript.commit_point(&commitments[i])?; 243 | println!( 244 | "updated transcript {}/{}: {} s", 245 | 3 * i, 246 | 3 * num_queries, 247 | start.elapsed().as_micros() as f64 / 1000000.0 248 | ); 249 | let start = std::time::Instant::now(); 250 | transcript.commit_bytes(&zs[i].to_le_bytes())?; 251 | println!( 252 | "updated transcript {}/{}: {} s", 253 | 3 * i + 1, 254 | 3 * num_queries, 255 | start.elapsed().as_micros() as f64 / 1000000.0 256 | ); 257 | let start = std::time::Instant::now(); 258 | transcript.commit_field_element(&ys[i])?; 259 | println!( 260 | "updated transcript {}/{}: {} s", 261 | 3 * i + 2, 262 | 3 * num_queries, 263 | start.elapsed().as_micros() as f64 / 1000000.0 264 | ); 265 | } 266 | 267 | let r = transcript.get_challenge(); 268 | // println!("r: {:?}", r); 269 | 270 | transcript.commit_point(&proof.d)?; 271 | 272 | let t = transcript.get_challenge(); 273 | // println!("t: {:?}", t); 274 | 275 | // Compute helper_scalars. This is r^i / t - z_i 276 | // There are more optimal ways to do this, but 277 | // this is more readable, so will leave for now 278 | let mut helper_scalars: Vec = Vec::with_capacity(num_queries); 279 | let mut powers_of_r = Fs::one(); 280 | for z_i in zs.iter() { 281 | // helper_scalars[i] = r^i / (t - z_i) 282 | let mut t_minus_z_i = t; 283 | t_minus_z_i.sub_assign(&read_field_element_le::(&z_i.to_le_bytes()).unwrap()); // t - z_i 284 | 285 | let mut helper_scalars_i = t_minus_z_i 286 | .inverse() 287 | .ok_or(anyhow::anyhow!("cannot find inverse of `t - z_i`"))?; // 1 / (t - z_i) 288 | helper_scalars_i.mul_assign(&powers_of_r); // r^i / (t - z_i) 289 | helper_scalars.push(helper_scalars_i); // helper_scalars[i] = r^i / (t - z_i) 290 | 291 | powers_of_r.mul_assign(&r); // powers_of_r *= r 292 | } 293 | 294 | // Compute g_2(t) = SUM y_i * (r^i / t - z_i) = SUM y_i * helper_scalars 295 | let mut g_2_t = Fs::zero(); 296 | for i in 0..num_queries { 297 | let mut tmp = ys[i]; 298 | tmp.mul_assign(&helper_scalars[i]); 299 | g_2_t.add_assign(&tmp); // g_2_t += ys[i] * helper_scalars[i] 300 | } 301 | 302 | // Compute E = \sum_{i = 0}^{num_queries - 1} C_i * (r^i / t - z_i) 303 | let mut e = Point::zero(); 304 | for (i, c_i) in commitments.iter().enumerate() { 305 | let tmp = c_i.mul(helper_scalars[i], jubjub_params); // tmp = c_i * helper_scalars_i 306 | e = e.add(&tmp, jubjub_params); // e += c_i * helper_scalars_i 307 | } 308 | 309 | transcript.commit_point(&e)?; 310 | 311 | let minus_d = proof.d.negate(); 312 | let e_minus_d = e.add(&minus_d, jubjub_params); 313 | 314 | let transcript_params = transcript.into_params(); 315 | proof 316 | .ipa 317 | .check(e_minus_d, t, g_2_t, transcript_params, ipa_conf) 318 | } 319 | } 320 | -------------------------------------------------------------------------------- /src/batch_proof_fr/mod.rs: -------------------------------------------------------------------------------- 1 | use franklin_crypto::bellman::pairing::bn256::{Bn256, Fr, G1Affine, G1}; 2 | use franklin_crypto::bellman::{CurveAffine, CurveProjective, Field}; 3 | 4 | use crate::ipa_fr::config::{Committer, IpaConfig}; 5 | use crate::ipa_fr::proof::IpaProof; 6 | use crate::ipa_fr::rns::BaseRnsParameters; 7 | use crate::ipa_fr::transcript::{Bn256Transcript, PoseidonBn256Transcript}; 8 | use crate::ipa_fr::utils::read_field_element_le; 9 | 10 | #[derive(Clone, Debug)] 11 | pub struct BatchProof { 12 | pub ipa: IpaProof, 13 | pub d: GA, 14 | } 15 | 16 | #[cfg(test)] 17 | mod tests { 18 | use franklin_crypto::bellman::pairing::bn256::{Bn256, Fr, G1Affine}; 19 | 20 | use super::BatchProof; 21 | use crate::ipa_fr::config::Committer; 22 | use crate::ipa_fr::rns::BaseRnsParameters; 23 | use crate::ipa_fr::transcript::Bn256Transcript; 24 | use crate::ipa_fr::{config::IpaConfig, transcript::PoseidonBn256Transcript, utils::test_poly}; 25 | 26 | #[test] 27 | fn test_multi_proof_create_verify() -> Result<(), Box> { 28 | // Shared View 29 | println!("create ipa_conf"); 30 | let domain_size = 256; 31 | let ipa_conf = &IpaConfig::::new(domain_size); 32 | let rns_params = &BaseRnsParameters::::new_for_field(68, 110, 4); 33 | 34 | // Prover view 35 | let poly_1 = test_poly::(&[12, 97, 37, 0, 1, 208, 132, 3], domain_size); 36 | let prover_transcript = PoseidonBn256Transcript::with_bytes(b"multi_proof"); 37 | let prover_commitment_1 = ipa_conf.commit(&poly_1)?; 38 | 39 | let commitments = vec![prover_commitment_1]; 40 | let fs = vec![poly_1]; 41 | let index_1 = 36; 42 | let zs = vec![index_1]; 43 | let mut ys = vec![]; 44 | for i in 0..zs.len() { 45 | let y_i = fs[i][zs[i]]; 46 | ys.push(y_i); 47 | } 48 | let proof = BatchProof::::create( 49 | &commitments, 50 | &fs, 51 | &zs, 52 | prover_transcript.into_params(), 53 | rns_params, 54 | ipa_conf, 55 | )?; 56 | 57 | // test_serialize_deserialize_proof(proof); 58 | 59 | // Verifier view 60 | let verifier_transcript = PoseidonBn256Transcript::with_bytes(b"multi_proof"); 61 | let success = proof.check( 62 | &commitments, 63 | &ys, 64 | &zs, 65 | verifier_transcript.into_params(), 66 | rns_params, 67 | ipa_conf, 68 | )?; 69 | 70 | assert!(success, "inner product proof failed"); 71 | 72 | Ok(()) 73 | } 74 | } 75 | 76 | impl BatchProof { 77 | pub fn create( 78 | commitments: &[G1Affine], 79 | fs: &[Vec], 80 | zs: &[usize], 81 | transcript_params: Fr, 82 | rns_params: &BaseRnsParameters, 83 | ipa_conf: &IpaConfig, 84 | ) -> anyhow::Result { 85 | let mut transcript = PoseidonBn256Transcript::new(&transcript_params); 86 | 87 | if commitments.len() != fs.len() { 88 | anyhow::anyhow!( 89 | "number of commitments = {}, while number of functions = {}", 90 | commitments.len(), 91 | fs.len() 92 | ); 93 | } 94 | if commitments.len() != zs.len() { 95 | anyhow::anyhow!( 96 | "number of commitments = {}, while number of points = {}", 97 | commitments.len(), 98 | zs.len() 99 | ); 100 | } 101 | 102 | let num_queries = commitments.len(); 103 | if num_queries == 0 { 104 | anyhow::anyhow!("cannot create a batch proof with no data"); 105 | } 106 | 107 | let domain_size = ipa_conf.get_domain_size(); 108 | for i in 0..num_queries { 109 | transcript.commit_point(&commitments[i], rns_params)?; // C 110 | 111 | assert!( 112 | zs[i] < domain_size, 113 | "{:?} must be less than {:?}.", 114 | zs[i], 115 | domain_size 116 | ); 117 | transcript.commit_bytes(&zs[i].to_le_bytes())?; 118 | 119 | // get the `y` value 120 | let f_i = fs[i].clone(); 121 | let y_i = f_i[zs[i]]; 122 | transcript.commit_field_element(&y_i)?; // y 123 | } 124 | let r = transcript.get_challenge(); // r 125 | 126 | // println!("r: {:?}", r); 127 | 128 | // Compute g(X) 129 | let mut g_x = vec![Fr::zero(); domain_size]; 130 | let mut powers_of_r = Fr::one(); // powers_of_r = 1 131 | for i in 0..num_queries { 132 | let quotient = ipa_conf 133 | .get_precomputed_weights() 134 | .divide_on_domain(zs[i], &fs[i]); // quotient[j] = (f_i(j) - f_i(zs[i])) / (j - zs[i]) 135 | 136 | for j in 0..domain_size { 137 | let mut tmp = quotient[j]; 138 | tmp.mul_assign(&powers_of_r); 139 | g_x[j].add_assign(&tmp); // g_x[j] += r^i * quotient[j] 140 | } 141 | 142 | powers_of_r.mul_assign(&r); 143 | } 144 | 145 | let d = ipa_conf.commit(&g_x)?; 146 | 147 | transcript.commit_point(&d, rns_params)?; // D 148 | 149 | let t = transcript.get_challenge(); // t 150 | 151 | // println!("t: {:?}", t); 152 | 153 | // Compute h(X) = g_1(X) 154 | let mut h_x = vec![Fr::zero(); domain_size]; 155 | let mut powers_of_r = Fr::one(); // powers_of_r = 1 156 | for i in 0..num_queries { 157 | let z_i = read_field_element_le::(&zs[i].to_le_bytes()).unwrap(); 158 | let mut den = t; // den_inv = t 159 | den.sub_assign(&z_i); // den_inv = t - z_i 160 | let den_inv = den 161 | .inverse() 162 | .ok_or(anyhow::anyhow!("cannot find inverse of `t - z_i`"))?; // den_inv = 1 / (t - z_i) 163 | 164 | for (k, h_x_k) in h_x.iter_mut().enumerate() { 165 | let mut tmp = powers_of_r; 166 | tmp.mul_assign(&fs[i][k]); 167 | tmp.mul_assign(&den_inv); 168 | h_x_k.add_assign(&tmp); // h_x[k] += r^i * f[i][k] / (t - z_i) 169 | } 170 | 171 | powers_of_r.mul_assign(&r); // powers_of_r *= r 172 | } 173 | 174 | let mut h_minus_g = vec![Fr::zero(); domain_size]; 175 | for i in 0..domain_size { 176 | h_minus_g[i] = h_x[i]; 177 | h_minus_g[i].sub_assign(&g_x[i]); 178 | } 179 | 180 | let start = std::time::Instant::now(); 181 | let e = ipa_conf.commit(&h_x)?; 182 | println!( 183 | "commit h_x: {} s", 184 | start.elapsed().as_micros() as f64 / 1000000.0 185 | ); 186 | transcript.commit_point(&e, rns_params)?; // E 187 | 188 | let mut minus_d = G1::zero(); 189 | minus_d.sub_assign(&d.into_projective()); 190 | 191 | let mut e_minus_d = e.into_projective(); 192 | e_minus_d.add_assign(&minus_d); 193 | 194 | let transcript_params = transcript.get_challenge(); 195 | 196 | let (ipa_proof, _) = IpaProof::::create( 197 | e_minus_d.into_affine(), 198 | &h_minus_g, 199 | t, 200 | transcript_params, 201 | rns_params, 202 | ipa_conf, 203 | )?; 204 | 205 | Ok(BatchProof { ipa: ipa_proof, d }) 206 | } 207 | 208 | pub fn check( 209 | &self, 210 | commitments: &[G1Affine], 211 | ys: &[Fr], 212 | zs: &[usize], 213 | transcript_params: Fr, 214 | rns_params: &BaseRnsParameters, 215 | ipa_conf: &IpaConfig, 216 | ) -> anyhow::Result { 217 | let proof = self; 218 | let mut transcript = PoseidonBn256Transcript::new(&transcript_params); 219 | 220 | if commitments.len() != ys.len() { 221 | anyhow::anyhow!( 222 | "number of commitments = {}, while number of output points = {}", 223 | commitments.len(), 224 | ys.len() 225 | ); 226 | } 227 | if commitments.len() != zs.len() { 228 | anyhow::anyhow!( 229 | "number of commitments = {}, while number of input points = {}", 230 | commitments.len(), 231 | zs.len() 232 | ); 233 | } 234 | 235 | let num_queries = commitments.len(); 236 | if num_queries == 0 { 237 | anyhow::anyhow!("cannot create a batch proof with no data"); 238 | } 239 | 240 | let domain_size = ipa_conf.get_domain_size(); 241 | for i in 0..num_queries { 242 | assert!(zs[i] < domain_size); 243 | let start = std::time::Instant::now(); 244 | transcript.commit_point(&commitments[i], rns_params)?; 245 | println!( 246 | "updated transcript {}/{}: {} s", 247 | 3 * i + 1, 248 | 3 * num_queries, 249 | start.elapsed().as_micros() as f64 / 1000000.0 250 | ); 251 | let start = std::time::Instant::now(); 252 | transcript.commit_bytes(&zs[i].to_le_bytes())?; 253 | println!( 254 | "updated transcript {}/{}: {} s", 255 | 3 * i + 2, 256 | 3 * num_queries, 257 | start.elapsed().as_micros() as f64 / 1000000.0 258 | ); 259 | let start = std::time::Instant::now(); 260 | transcript.commit_field_element(&ys[i])?; 261 | println!( 262 | "updated transcript {}/{}: {} s", 263 | 3 * i + 3, 264 | 3 * num_queries, 265 | start.elapsed().as_micros() as f64 / 1000000.0 266 | ); 267 | } 268 | 269 | let r = transcript.get_challenge(); 270 | // println!("r: {:?}", r); 271 | 272 | transcript.commit_point(&proof.d, rns_params)?; 273 | 274 | let t = transcript.get_challenge(); 275 | // println!("t: {:?}", t); 276 | 277 | let mut helper_scalars: Vec = Vec::with_capacity(num_queries); 278 | let mut powers_of_r = Fr::one(); // powers_of_r = 1 279 | for z_i in zs.iter() { 280 | // helper_scalars[i] = r^i / (t - z_i) 281 | let mut t_minus_z_i = t; 282 | t_minus_z_i.sub_assign(&read_field_element_le::(&z_i.to_le_bytes()).unwrap()); // t - z_i 283 | 284 | let mut helper_scalars_i = t_minus_z_i 285 | .inverse() 286 | .ok_or(anyhow::anyhow!("cannot find inverse of `t - z_i`"))?; // 1 / (t - z_i) 287 | helper_scalars_i.mul_assign(&powers_of_r); // r^i / (t - z_i) 288 | helper_scalars.push(helper_scalars_i); // helper_scalars[i] = r^i / (t - z_i) 289 | 290 | powers_of_r.mul_assign(&r); // powers_of_r *= r 291 | } 292 | 293 | // Compute g_2(t) = \sum_{i = 0}^{num_queries - 1} y_i * (r^i / t - z_i). 294 | let mut g_2_t = Fr::zero(); 295 | for i in 0..num_queries { 296 | let mut tmp = ys[i]; 297 | tmp.mul_assign(&helper_scalars[i]); 298 | g_2_t.add_assign(&tmp); // g_2_t += ys[i] * helper_scalars[i] 299 | } 300 | 301 | // Compute E = \sum_{i = 0}^{num_queries - 1} C_i * (r^i / t - z_i). 302 | let mut e = G1::zero(); 303 | for (i, c_i) in commitments.iter().enumerate() { 304 | let tmp = c_i.mul(helper_scalars[i]); // tmp = c_i * helper_scalars_i 305 | e.add_assign(&tmp); // e += c_i * helper_scalars_i 306 | } 307 | 308 | transcript.commit_point(&e.into_affine(), rns_params)?; 309 | 310 | let mut e_minus_d = e; 311 | e_minus_d.sub_assign(&proof.d.into_projective()); 312 | 313 | let transcript_params = transcript.get_challenge(); 314 | proof.ipa.check( 315 | e_minus_d.into_affine(), 316 | t, 317 | g_2_t, 318 | transcript_params, 319 | rns_params, 320 | ipa_conf, 321 | ) 322 | } 323 | } 324 | -------------------------------------------------------------------------------- /src/ipa_fs/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod config; 2 | pub mod proof; 3 | pub mod transcript; 4 | pub mod utils; 5 | 6 | use franklin_crypto::babyjubjub::fs::Fs; 7 | use franklin_crypto::babyjubjub::{edwards, JubjubEngine, Unknown}; 8 | use franklin_crypto::bellman::pairing::bn256::{Bn256, Fr}; 9 | use franklin_crypto::bellman::{Field, PrimeField}; 10 | 11 | use crate::ipa_fr::utils::log2_ceil; 12 | use crate::ipa_fs::config::Committer; 13 | 14 | use self::config::IpaConfig; 15 | use self::proof::{generate_challenges, IpaProof}; 16 | use self::transcript::{Bn256Transcript, PoseidonBn256Transcript}; 17 | use self::utils::{commit, fold_points, fold_scalars, inner_prod}; 18 | 19 | #[cfg(test)] 20 | mod tests { 21 | use franklin_crypto::babyjubjub::fs::Fs; 22 | use franklin_crypto::babyjubjub::JubjubBn256; 23 | use franklin_crypto::bellman::pairing::bn256::Bn256; 24 | 25 | use crate::ipa_fr::utils::test_poly; 26 | 27 | use super::config::{Committer, IpaConfig}; 28 | use super::proof::IpaProof; 29 | use super::transcript::{Bn256Transcript, PoseidonBn256Transcript}; 30 | use super::utils::read_field_element_le; 31 | 32 | #[test] 33 | fn test_ipa_fs_proof_create_verify() -> Result<(), Box> { 34 | let domain_size = 256; 35 | let point: Fs = read_field_element_le(&123456789u64.to_le_bytes()).unwrap(); 36 | let jubjub_params = &JubjubBn256::new(); 37 | let ipa_conf = &IpaConfig::::new(domain_size, jubjub_params); 38 | 39 | // Prover view 40 | let poly = test_poly::(&[12, 97, 37, 0, 1, 208, 132, 3], domain_size); 41 | let prover_commitment = ipa_conf.commit(&poly).unwrap(); 42 | 43 | let prover_transcript = PoseidonBn256Transcript::with_bytes(b"ipa"); 44 | 45 | let (proof, inner_product) = IpaProof::create( 46 | prover_commitment.clone(), 47 | &poly, 48 | point, 49 | prover_transcript.into_params(), 50 | ipa_conf, 51 | )?; 52 | 53 | // test_serialize_deserialize_proof(proof); 54 | 55 | // Verifier view 56 | let verifier_commitment = prover_commitment; // In reality, the verifier will rebuild this themselves 57 | let verifier_transcript = PoseidonBn256Transcript::with_bytes(b"ipa"); 58 | 59 | let success = proof 60 | .check( 61 | verifier_commitment, 62 | point, 63 | inner_product, 64 | verifier_transcript.into_params(), 65 | ipa_conf, 66 | ) 67 | .unwrap(); 68 | assert!(success, "inner product proof failed"); 69 | 70 | Ok(()) 71 | } 72 | } 73 | 74 | impl IpaProof { 75 | pub fn create( 76 | commitment: edwards::Point, 77 | lagrange_poly: &[Fs], 78 | eval_point: Fs, 79 | transcript_params: Fr, 80 | ipa_conf: &IpaConfig, 81 | ) -> anyhow::Result<(Self, ::Fs)> { 82 | let jubjub_params = ipa_conf.jubjub_params; 83 | let mut transcript = PoseidonBn256Transcript::new(&transcript_params); 84 | let mut current_basis = ipa_conf.srs.clone(); 85 | // let _commitment = commit(¤t_basis.clone(), lagrange_poly, jubjub_params)?; 86 | // assert!(commitment.eq(&_commitment)); 87 | 88 | let mut lagrange_poly = lagrange_poly.to_vec(); 89 | let start = std::time::Instant::now(); 90 | let mut b = ipa_conf 91 | .precomputed_weights 92 | .compute_barycentric_coefficients(&eval_point)?; 93 | println!( 94 | "compute barycentric coefficients of eval_point: {} s", 95 | start.elapsed().as_micros() as f64 / 1000000.0 96 | ); 97 | if b.len() != ipa_conf.srs.len() { 98 | anyhow::bail!("`barycentric_coefficients` had incorrect length"); 99 | } 100 | 101 | let ip = inner_prod(&lagrange_poly, &b)?; 102 | 103 | let start = std::time::Instant::now(); 104 | transcript.commit_point(&commitment)?; // C 105 | transcript.commit_field_element(&eval_point)?; // input point 106 | transcript.commit_field_element(&ip)?; // output point 107 | let w = transcript.get_challenge(); // w 108 | 109 | println!( 110 | "update transcript: {} s", 111 | start.elapsed().as_micros() as f64 / 1000000.0 112 | ); 113 | 114 | let q = ipa_conf.q.clone(); 115 | let qw = q.mul(w, jubjub_params); 116 | 117 | let num_ipa_rounds = log2_ceil(ipa_conf.get_domain_size()) as usize; 118 | 119 | let mut ls = Vec::with_capacity(num_ipa_rounds); 120 | let mut rs = Vec::with_capacity(num_ipa_rounds); 121 | 122 | for _ in 0..num_ipa_rounds { 123 | let lap_start = std::time::Instant::now(); 124 | 125 | let a_lr = lagrange_poly 126 | .chunks(lagrange_poly.len() / 2) 127 | .collect::>(); 128 | let a_l = a_lr[0]; 129 | let a_r = a_lr[1]; 130 | let b_lr = b.chunks(b.len() / 2).collect::>(); 131 | let b_l = b_lr[0]; 132 | let b_r = b_lr[1]; 133 | let g_lr = current_basis 134 | .chunks(current_basis.len() / 2) 135 | .collect::>(); 136 | let g_l = g_lr[0]; 137 | let g_r = g_lr[1]; 138 | 139 | let z_l = inner_prod(a_r, b_l)?; 140 | let z_r = inner_prod(a_l, b_r)?; 141 | 142 | let start = std::time::Instant::now(); 143 | let c_l_1 = commit(g_l, a_r, jubjub_params)?; 144 | let c_l = qw.mul(z_l, jubjub_params).add(&c_l_1, jubjub_params); 145 | // let c_l = commit(&[c_l_1, qw.clone()], &[one.clone(), z_l], jubjub_params)?; 146 | 147 | let c_r_1 = commit(g_r, a_l, jubjub_params)?; 148 | let c_r = qw.mul(z_r, jubjub_params).add(&c_r_1, jubjub_params); 149 | // let c_r = commit(&[c_r_1, qw.clone()], &[one.clone(), z_r], jubjub_params)?; 150 | println!( 151 | "commit: {} s", 152 | start.elapsed().as_micros() as f64 / 1000000.0 153 | ); 154 | 155 | ls.push(c_l.clone()); 156 | rs.push(c_r.clone()); 157 | 158 | let start = std::time::Instant::now(); 159 | transcript.commit_point(&c_l)?; // L 160 | transcript.commit_point(&c_r)?; // R 161 | println!( 162 | "update transcript: {} s", 163 | start.elapsed().as_micros() as f64 / 1000000.0 164 | ); 165 | 166 | let x = transcript.get_challenge(); // x 167 | 168 | let x_inv = x 169 | .inverse() 170 | .ok_or(anyhow::anyhow!("cannot find inverse of `x`"))?; 171 | 172 | lagrange_poly = fold_scalars(a_l, a_r, &x)?; 173 | b = fold_scalars(b_l, b_r, &x_inv)?; 174 | current_basis = fold_points(g_l, g_r, &x_inv, jubjub_params)?; 175 | 176 | println!( 177 | "lap: {} s", 178 | lap_start.elapsed().as_micros() as f64 / 1000000.0 179 | ); 180 | } 181 | 182 | if lagrange_poly.len() != 1 { 183 | anyhow::bail!( 184 | "`lagrange_poly`, `b` and `current_basis` should be 1 at the end of the reduction" 185 | ); 186 | } 187 | 188 | let ipa_proof = IpaProof { 189 | l: ls, 190 | r: rs, 191 | a: lagrange_poly[0], 192 | }; 193 | 194 | Ok((ipa_proof, ip)) 195 | } 196 | 197 | pub fn check( 198 | &self, 199 | commitment: edwards::Point, 200 | eval_point: Fs, 201 | ip: Fs, // inner_prod 202 | transcript_params: Fr, 203 | ipa_conf: &IpaConfig, 204 | ) -> anyhow::Result { 205 | dbg!(transcript_params); 206 | 207 | let proof = self; 208 | let jubjub_params = ipa_conf.jubjub_params; 209 | let mut transcript = PoseidonBn256Transcript::new(&transcript_params); 210 | 211 | // println!("{:?}", proof); 212 | if proof.l.len() != proof.r.len() { 213 | anyhow::bail!("L and R should be the same size"); 214 | } 215 | 216 | let num_ipa_rounds = log2_ceil(ipa_conf.get_domain_size()) as usize; 217 | if proof.l.len() != num_ipa_rounds { 218 | anyhow::bail!( 219 | "The number of points for L or R should be equal to the number of rounds" 220 | ); 221 | } 222 | 223 | // let bit_limit = None; // Some(256usize); 224 | let mut b = ipa_conf 225 | .precomputed_weights 226 | .compute_barycentric_coefficients(&eval_point)?; 227 | 228 | if b.len() != ipa_conf.srs.len() { 229 | anyhow::bail!("`barycentric_coefficients` had incorrect length"); 230 | } 231 | 232 | dbg!(commitment.into_xy()); 233 | transcript.commit_point(&commitment)?; // C 234 | transcript.commit_field_element(&eval_point)?; // input point 235 | transcript.commit_field_element(&ip)?; // output point 236 | 237 | let w = transcript.get_challenge(); 238 | dbg!(w.into_repr()); 239 | 240 | let q = ipa_conf.q.clone(); 241 | let qw = q.mul(w, jubjub_params); 242 | let qy = qw.mul(ip, jubjub_params); 243 | dbg!(qy.into_xy()); 244 | 245 | let mut result_c = commitment.add(&qy, jubjub_params); 246 | dbg!(result_c.into_xy()); 247 | 248 | let challenges = generate_challenges(proof, &mut transcript).unwrap(); 249 | 250 | let mut challenges_inv: Vec = Vec::with_capacity(challenges.len()); 251 | 252 | // Compute expected commitment 253 | for (i, x) in challenges.iter().enumerate() { 254 | dbg!(x.into_repr()); 255 | 256 | // println!("challenges_inv: {}/{}", i, challenges.len()); 257 | let l = proof.l[i].clone(); 258 | let r = proof.r[i].clone(); 259 | 260 | let x_inv = x 261 | .inverse() 262 | .ok_or(anyhow::anyhow!("cannot find inverse of `x`"))?; 263 | challenges_inv.push(x_inv); 264 | 265 | let result_c_l = l.mul(*x, jubjub_params); 266 | let result_c_r = r.mul(x_inv, jubjub_params); 267 | result_c = result_c 268 | .add(&result_c_l, jubjub_params) 269 | .add(&result_c_r, jubjub_params); 270 | dbg!(result_c.into_xy()); 271 | } 272 | 273 | // println!("challenges_inv: {}/{}", challenges.len(), challenges.len()); 274 | 275 | let mut current_basis = ipa_conf.srs.clone(); 276 | 277 | println!("reduction starts"); 278 | let start = std::time::Instant::now(); 279 | 280 | for (_i, x_inv) in challenges_inv.iter().enumerate() { 281 | // println!("x_inv: {}/{}", _i, challenges_inv.len()); 282 | assert_eq!( 283 | current_basis.len() % 2, 284 | 0, 285 | "cannot split `current_basis` in half" 286 | ); 287 | let mut g_chunks = current_basis.chunks(current_basis.len() / 2); 288 | let g_l = g_chunks.next().unwrap().to_vec(); 289 | let g_r = g_chunks.next().unwrap().to_vec(); 290 | 291 | let mut b_chunks = b.chunks(b.len() / 2); 292 | let b_l = b_chunks.next().unwrap().to_vec(); 293 | let b_r = b_chunks.next().unwrap().to_vec(); 294 | 295 | dbg!(x_inv.into_repr()); 296 | b = fold_scalars::(&b_l, &b_r, x_inv)?; 297 | current_basis = fold_points(&g_l, &g_r, x_inv, jubjub_params)?; 298 | } 299 | 300 | // println!("x_inv: {}/{}", challenges_inv.len(), challenges_inv.len()); 301 | 302 | if b.len() != 1 { 303 | anyhow::bail!("`b` and `current_basis` should be 1 at the end of the reduction"); 304 | } 305 | 306 | println!( 307 | "reduction ends: {} s", 308 | start.elapsed().as_micros() as f64 / 1000000.0 309 | ); 310 | 311 | println!("verification check starts"); 312 | let start = std::time::Instant::now(); 313 | 314 | dbg!(current_basis[0].into_xy()); 315 | dbg!(b[0].into_repr()); 316 | 317 | // Compute `result = a[0] * G[0] + (a[0] * b[0] * w) * Q`. 318 | let result1 = current_basis[0].mul(proof.a, jubjub_params); // result1 = a[0] * G[0] 319 | dbg!(result1.into_xy()); 320 | let mut part_2a = b[0]; // part_2a = b[0] 321 | dbg!(proof.a.into_repr()); 322 | part_2a.mul_assign(&proof.a); // part_2a = a[0] * b[0] 323 | dbg!(part_2a.into_repr()); 324 | let result2 = qw.mul(part_2a, jubjub_params); // result2 = a[0] * b[0] * w * Q 325 | dbg!(result2.into_xy()); 326 | let result = result1.add(&result2, jubjub_params); // result = result1 + result2 327 | dbg!(result.into_xy()); 328 | 329 | // Ensure `commitment` is equal to `result`. 330 | let is_ok = result_c.eq(&result); 331 | 332 | println!( 333 | "verification check ends: {} s", 334 | start.elapsed().as_micros() as f64 / 1000000.0 335 | ); 336 | 337 | Ok(is_ok) 338 | } 339 | } 340 | -------------------------------------------------------------------------------- /src/ipa_fr/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod config; 2 | pub mod proof; 3 | pub mod rns; 4 | pub mod transcript; 5 | pub mod utils; 6 | 7 | use franklin_crypto::bellman::pairing::bn256::{Bn256, Fr, G1Affine}; 8 | use franklin_crypto::bellman::{CurveAffine, CurveProjective, Field}; 9 | 10 | use crate::ipa_fr::config::Committer; 11 | use crate::ipa_fr::utils::log2_ceil; 12 | 13 | use self::config::IpaConfig; 14 | use self::proof::{generate_challenges, IpaProof}; 15 | use self::rns::BaseRnsParameters; 16 | use self::transcript::{Bn256Transcript, PoseidonBn256Transcript}; 17 | use self::utils::{commit, fold_points, fold_scalars, inner_prod}; 18 | 19 | #[cfg(test)] 20 | mod tests { 21 | use franklin_crypto::bellman::pairing::bn256::{Bn256, Fr, G1Affine}; 22 | 23 | use crate::ipa_fr::proof::IpaProof; 24 | use crate::ipa_fr::rns::BaseRnsParameters; 25 | 26 | use super::config::{Committer, IpaConfig}; 27 | use super::transcript::{Bn256Transcript, PoseidonBn256Transcript}; 28 | use super::utils::{read_field_element_le, test_poly}; 29 | 30 | #[test] 31 | fn test_ipa_fr_proof_create_verify() -> Result<(), Box> { 32 | let point: Fr = read_field_element_le(&123456789u64.to_le_bytes()).unwrap(); 33 | 34 | // Prover view 35 | 36 | let poly = vec![12, 97]; 37 | // let poly = vec![12, 97, 37, 0, 1, 208, 132, 3]; 38 | let domain_size = poly.len(); 39 | let ipa_conf = &IpaConfig::::new(domain_size); 40 | let rns_params = &BaseRnsParameters::::new_for_field(68, 110, 4); 41 | 42 | let padded_poly = test_poly::(&poly, domain_size); 43 | let prover_commitment = ipa_conf.commit(&padded_poly).unwrap(); 44 | 45 | let prover_transcript = PoseidonBn256Transcript::with_bytes(b"ipa"); 46 | 47 | let (proof, inner_product) = IpaProof::::create( 48 | prover_commitment, 49 | &padded_poly, 50 | point, 51 | prover_transcript.into_params(), 52 | rns_params, 53 | ipa_conf, 54 | )?; 55 | 56 | // Verifier view 57 | 58 | let verifier_commitment = prover_commitment; // In reality, the verifier will rebuild this themselves. 59 | let verifier_transcript = PoseidonBn256Transcript::with_bytes(b"ipa"); 60 | 61 | let success = proof 62 | .check( 63 | verifier_commitment, 64 | point, 65 | inner_product, 66 | verifier_transcript.into_params(), 67 | rns_params, 68 | ipa_conf, 69 | ) 70 | .unwrap(); 71 | assert!(success, "inner product proof failed"); 72 | 73 | Ok(()) 74 | } 75 | } 76 | 77 | /// Create a proof which shows `inner_prod = f(eval_point)` and verify it. 78 | /// Here, f(z) is a `G::Scalar`-polynomial of degree at most `domain_size - 1`, 79 | /// 80 | /// `lagrange_poly` is a `G::Scalar`-array which satisfies 81 | /// `lagrange_poly[z] = f(z)` for any integer z in [0, `domain_size`). 82 | /// 83 | /// `commitment` must be equal to `ipa_conf.commit(&lagrange_poly)`. 84 | /// 85 | /// `eval_point` and `inner_prod` are elements in `G::Scalar`. 86 | /// 87 | /// `transcript_params` is a initialization parameter of the transcript `T`. 88 | impl IpaProof { 89 | /// Create a proof which shows `inner_prod = f(eval_point)`. 90 | pub fn create( 91 | commitment: G1Affine, 92 | lagrange_poly: &[Fr], 93 | eval_point: Fr, 94 | transcript_params: Fr, 95 | rns_params: &BaseRnsParameters, 96 | ipa_conf: &IpaConfig, 97 | ) -> anyhow::Result<(Self, Fr)> { 98 | let mut transcript = PoseidonBn256Transcript::new(&transcript_params); 99 | let mut current_basis = ipa_conf 100 | .get_srs() 101 | .iter() 102 | .map(|x| x.into_projective()) 103 | .collect::>(); 104 | if cfg!(debug_assertions) { 105 | assert!(commitment.eq(&ipa_conf.commit(lagrange_poly).unwrap())); 106 | } 107 | 108 | let mut a = lagrange_poly.to_vec(); 109 | let start = std::time::Instant::now(); 110 | let mut b = ipa_conf 111 | .get_precomputed_weights() 112 | .compute_barycentric_coefficients(&eval_point)?; 113 | println!( 114 | "compute barycentric coefficients of eval_point: {} s", 115 | start.elapsed().as_micros() as f64 / 1000000.0 116 | ); 117 | if b.len() != current_basis.len() { 118 | anyhow::bail!("`barycentric_coefficients` had incorrect length"); 119 | } 120 | 121 | let ip = inner_prod(&a, &b)?; 122 | 123 | let start = std::time::Instant::now(); 124 | transcript.commit_point(&commitment, rns_params)?; // C 125 | transcript.commit_field_element(&eval_point)?; // input point 126 | transcript.commit_field_element(&ip)?; // output point 127 | let w = transcript.get_challenge(); // w 128 | println!( 129 | "update transcript: {} s", 130 | start.elapsed().as_micros() as f64 / 1000000.0 131 | ); 132 | 133 | let q = ipa_conf.get_q().into_projective(); 134 | let mut qw = q; 135 | qw.mul_assign(w); 136 | 137 | let domain_size = ipa_conf.get_precomputed_weights().get_domain_size(); 138 | let num_rounds = log2_ceil(domain_size) as usize; 139 | 140 | let mut ls = Vec::with_capacity(num_rounds); 141 | let mut rs = Vec::with_capacity(num_rounds); 142 | 143 | for _ in 0..num_rounds { 144 | let lap_start = std::time::Instant::now(); 145 | 146 | let a_lr = a.chunks(a.len() / 2).collect::>(); 147 | let a_l = a_lr[0]; 148 | let a_r = a_lr[1]; 149 | let b_lr = b.chunks(b.len() / 2).collect::>(); 150 | let b_l = b_lr[0]; 151 | let b_r = b_lr[1]; 152 | let g_lr = current_basis 153 | .chunks(current_basis.len() / 2) 154 | .collect::>(); 155 | let g_l = g_lr[0]; 156 | let g_r = g_lr[1]; 157 | 158 | let z_l = inner_prod(a_r, b_l)?; 159 | let z_r = inner_prod(a_l, b_r)?; 160 | 161 | let start = std::time::Instant::now(); 162 | let c_l_1 = commit(g_l, a_r)?; 163 | let c_l = commit(&[c_l_1, qw], &[Fr::one(), z_l])?.into_affine(); 164 | 165 | let c_r_1 = commit(g_r, a_l)?; 166 | let c_r = commit(&[c_r_1, qw], &[Fr::one(), z_r])?.into_affine(); 167 | println!( 168 | "commit: {} s", 169 | start.elapsed().as_micros() as f64 / 1000000.0 170 | ); 171 | 172 | ls.push(c_l); 173 | rs.push(c_r); 174 | 175 | let start = std::time::Instant::now(); 176 | transcript.commit_point(&c_l, rns_params)?; // L 177 | transcript.commit_point(&c_r, rns_params)?; // R 178 | println!( 179 | "update transcript: {} s", 180 | start.elapsed().as_micros() as f64 / 1000000.0 181 | ); 182 | 183 | let x = transcript.get_challenge(); // x 184 | 185 | let x_inv = x 186 | .inverse() 187 | .ok_or(anyhow::anyhow!("cannot find inverse of `x`"))?; 188 | 189 | a = fold_scalars(a_l, a_r, &x)?; 190 | b = fold_scalars(b_l, b_r, &x_inv)?; 191 | current_basis = fold_points(g_l, g_r, x_inv)?; 192 | 193 | println!( 194 | "lap: {} s", 195 | lap_start.elapsed().as_micros() as f64 / 1000000.0 196 | ); 197 | } 198 | 199 | if a.len() != 1 { 200 | anyhow::bail!("`a`, `b` and `current_basis` should be 1 at the end of the reduction"); 201 | } 202 | 203 | Ok(( 204 | IpaProof { 205 | l: ls, 206 | r: rs, 207 | a: a[0], 208 | }, 209 | ip, 210 | )) 211 | } 212 | 213 | /// Verify given `proof`. 214 | pub fn check( 215 | &self, 216 | commitment: G1Affine, 217 | eval_point: Fr, 218 | ip: Fr, // inner_prod 219 | transcript_params: Fr, 220 | rns_params: &BaseRnsParameters, 221 | ipa_conf: &IpaConfig, 222 | ) -> anyhow::Result { 223 | let proof = self; 224 | let mut transcript = PoseidonBn256Transcript::new(&transcript_params); 225 | 226 | // println!("{:?}", proof); 227 | if proof.l.len() != proof.r.len() { 228 | anyhow::bail!("L and R should be the same size"); 229 | } 230 | 231 | let domain_size = ipa_conf.get_domain_size(); 232 | let num_rounds = log2_ceil(domain_size) as usize; 233 | if proof.l.len() != num_rounds { 234 | anyhow::bail!( 235 | "The number of points for L or R should be equal to the number of rounds" 236 | ); 237 | } 238 | 239 | let mut b = ipa_conf 240 | .get_precomputed_weights() 241 | .compute_barycentric_coefficients(&eval_point)?; 242 | 243 | if b.len() != ipa_conf.get_srs().len() { 244 | anyhow::bail!("`barycentric_coefficients` had incorrect length"); 245 | } 246 | 247 | transcript.commit_point(&commitment, rns_params)?; // C 248 | transcript.commit_field_element(&eval_point)?; // input point 249 | transcript.commit_field_element(&ip)?; // output point 250 | 251 | let w = transcript.get_challenge(); 252 | 253 | let q = ipa_conf.get_q().into_projective(); 254 | let mut qw = q; 255 | qw.mul_assign(w); 256 | let mut qy = qw; 257 | qy.mul_assign(ip); 258 | let mut result_c = commitment.into_projective(); 259 | result_c.add_assign(&qy); 260 | 261 | let challenges = generate_challenges(proof, rns_params, &mut transcript).unwrap(); 262 | 263 | let mut challenges_inv: Vec = Vec::with_capacity(challenges.len()); 264 | 265 | // Compute expected commitment 266 | for (i, x) in challenges.iter().enumerate() { 267 | // println!("challenges_inv: {}/{}", i, challenges.len()); 268 | let l = proof.l[i].into_projective(); 269 | let r = proof.r[i].into_projective(); 270 | 271 | let x_inv = x 272 | .inverse() 273 | .ok_or(anyhow::anyhow!("cannot find inverse of `x`"))?; 274 | challenges_inv.push(x_inv); 275 | 276 | let one = Fr::one(); 277 | result_c = commit(&[result_c, l, r], &[one, *x, x_inv])?; 278 | } 279 | 280 | // println!("challenges_inv: {}/{}", challenges.len(), challenges.len()); 281 | 282 | let mut current_basis = ipa_conf 283 | .get_srs() 284 | .iter() 285 | .map(|x| x.into_projective()) 286 | .collect::>(); 287 | 288 | println!("reduction starts"); 289 | let start = std::time::Instant::now(); 290 | 291 | for (_i, x_inv) in challenges_inv.iter().enumerate() { 292 | // println!("x_inv: {}/{}", _i, challenges_inv.len()); 293 | assert_eq!( 294 | current_basis.len() % 2, 295 | 0, 296 | "cannot split `current_basis` in half" 297 | ); 298 | 299 | // Split the vector G into 2 parts. 300 | let mut g_chunks = current_basis.chunks(current_basis.len() / 2); 301 | let g_l = g_chunks.next().unwrap().to_vec(); 302 | let g_r = g_chunks.next().unwrap().to_vec(); 303 | 304 | // Split the vector b into 2 parts. 305 | let mut b_chunks = b.chunks(b.len() / 2); 306 | let b_l = b_chunks.next().unwrap().to_vec(); 307 | let b_r = b_chunks.next().unwrap().to_vec(); 308 | 309 | b = fold_scalars(&b_l, &b_r, &x_inv.clone())?; 310 | current_basis = fold_points(&g_l, &g_r, *x_inv)?; 311 | } 312 | 313 | // println!("x_inv: {}/{}", challenges_inv.len(), challenges_inv.len()); 314 | 315 | if b.len() != 1 { 316 | anyhow::bail!("`b` and `current_basis` should be 1 at the end of the reduction"); 317 | } 318 | 319 | println!( 320 | "reduction ends: {} s", 321 | start.elapsed().as_micros() as f64 / 1000000.0 322 | ); 323 | 324 | println!("verification check starts"); 325 | let start = std::time::Instant::now(); 326 | 327 | // Compute `result = a[0] * G[0] + (a[0] * b[0] * w) * Q`. 328 | let mut result1 = current_basis[0]; 329 | result1.mul_assign(proof.a); // result1 = a[0] * G[0] 330 | let mut part_2a = b[0]; // part_2a = b[0] 331 | part_2a.mul_assign(&proof.a); // part_2a = a[0] * b[0] 332 | let mut result2 = qw; 333 | result2.mul_assign(part_2a); // result2 = a[0] * b[0] * w * Q 334 | let mut result = result1; 335 | result.add_assign(&result2); // result = result1 + result2 336 | 337 | // Ensure `result_c` is equal to `result`. 338 | let is_ok = result_c.eq(&result); 339 | 340 | println!( 341 | "verification check ends: {} s", 342 | start.elapsed().as_micros() as f64 / 1000000.0 343 | ); 344 | 345 | Ok(is_ok) 346 | } 347 | } 348 | -------------------------------------------------------------------------------- /src/bn256_verkle_tree/mod.rs: -------------------------------------------------------------------------------- 1 | use franklin_crypto::bellman::bn256::G1Affine; 2 | 3 | use crate::ipa_fr::config::IpaConfig; 4 | use crate::verkle_tree::trie::VerkleTree; 5 | 6 | use self::leaf::LeafNodeWith32BytesValue; 7 | 8 | pub mod leaf; 9 | pub mod path; 10 | pub mod proof; 11 | 12 | pub type VerkleTreeWith32BytesKeyValue = 13 | VerkleTree<[u8; 32], LeafNodeWith32BytesValue, G1Affine, IpaConfig>; 14 | 15 | #[cfg(test)] 16 | mod bn256_verkle_tree_tests { 17 | use std::fs::OpenOptions; 18 | use std::path::Path; 19 | 20 | use crate::bn256_verkle_tree::proof::{ 21 | EncodedCommitmentElements, EncodedEcPoint, EncodedVerkleProof, VerkleProof, 22 | }; 23 | use crate::ipa_fr::config::IpaConfig; 24 | use crate::verkle_tree::trie::{AbstractKey, ExtStatus}; 25 | use crate::verkle_tree::witness::CommitmentElements; 26 | 27 | use super::VerkleTreeWith32BytesKeyValue; 28 | 29 | #[test] 30 | fn test_verkle_verification_with_one_entry() { 31 | // prover's view 32 | 33 | let domain_size = 256; 34 | let committer = IpaConfig::new(domain_size); 35 | let mut tree = VerkleTreeWith32BytesKeyValue::new(committer); 36 | let mut key = [0u8; 32]; 37 | key[0] = 13; 38 | let mut value = [0u8; 32]; 39 | value[0] = 27; 40 | tree.insert(key, value); 41 | tree.compute_digest().unwrap(); 42 | 43 | let result = tree.get_witnesses(&[key]).unwrap(); 44 | println!("commitments: {:?}", result.commitment_elements.commitments); 45 | println!("zs: {:?}", result.commitment_elements.elements.zs); 46 | println!("ys: {:?}", result.commitment_elements.elements.ys); 47 | 48 | let (proof, elements) = VerkleProof::create(&mut tree, &[key]).unwrap(); 49 | 50 | // verifier's view 51 | 52 | let domain_size = 256; 53 | let committer = IpaConfig::new(domain_size); 54 | let success = proof.check(&elements.zs, &elements.ys, &committer).unwrap(); 55 | 56 | assert!( 57 | success, 58 | "Fail to pass the verification of verkle proof circuit." 59 | ); 60 | } 61 | 62 | #[test] 63 | fn test_verkle_tree_with_some_entries() { 64 | let domain_size = 256; 65 | let committer = IpaConfig::new(domain_size); 66 | let mut tree = VerkleTreeWith32BytesKeyValue::new(committer); 67 | let mut keys = vec![]; 68 | { 69 | let mut key = [0u8; 32]; 70 | key[0] = 13; 71 | key[1] = 102; 72 | key[2] = 32; 73 | key[30] = 164; 74 | key[31] = 254; 75 | let value = [255u8; 32]; 76 | tree.insert(key, value); 77 | keys.push(key); 78 | } 79 | { 80 | let key = [255u8; 32]; 81 | let mut value = [0u8; 32]; 82 | value[0] = 28; 83 | value[15] = 193; 84 | value[16] = 60; 85 | value[31] = 27; 86 | tree.insert(key, value); 87 | keys.push(key); 88 | } 89 | { 90 | let mut key = [0u8; 32]; 91 | key[0] = 13; 92 | key[1] = 103; 93 | key[30] = 164; 94 | key[31] = 255; 95 | let value = [0u8; 32]; 96 | tree.insert(key, value); 97 | keys.push(key); 98 | } 99 | { 100 | let mut key = [0u8; 32]; 101 | key[0] = 13; 102 | key[1] = 103; 103 | key[30] = 164; 104 | key[31] = 254; 105 | let mut value = [0u8; 32]; 106 | value[0] = 235; 107 | value[15] = 193; 108 | value[16] = 60; 109 | value[31] = 136; 110 | tree.insert(key, value); 111 | keys.push(key); 112 | } 113 | 114 | tree.compute_digest().unwrap(); 115 | 116 | let result = tree.get_witnesses(&[keys[0]]).unwrap(); 117 | println!("commitments: {:?}", result.commitment_elements.commitments); 118 | println!("zs: {:?}", result.commitment_elements.elements.zs); 119 | println!("ys: {:?}", result.commitment_elements.elements.ys); 120 | println!("extra_data_list: {:?}", result.extra_data_list); 121 | assert_eq!( 122 | result.commitment_elements.elements.zs, 123 | [13, 102, 0, 1, 3, 252, 253] 124 | ); 125 | assert_eq!( 126 | result.commitment_elements.elements.ys.len(), 127 | result.commitment_elements.elements.zs.len() 128 | ); 129 | assert_eq!( 130 | result.commitment_elements.commitments.len(), 131 | result.commitment_elements.elements.zs.len() 132 | ); 133 | assert_eq!(result.extra_data_list.len(), 1); 134 | assert_eq!(result.extra_data_list[0].status, ExtStatus::Present); 135 | assert_eq!(result.extra_data_list[0].depth, 2); 136 | assert!(result.extra_data_list[0].poa_stem.is_none()); 137 | 138 | tree.remove(&keys[0]); 139 | 140 | tree.compute_digest().unwrap(); 141 | 142 | let key_empty_leaf = { 143 | let mut key = [0u8; 32]; 144 | key[0] = 13; 145 | key[1] = 101; 146 | key[30] = 164; 147 | key[31] = 254; 148 | 149 | key 150 | }; 151 | 152 | let result = tree.get_witnesses(&[key_empty_leaf]).unwrap(); 153 | println!("commitments: {:?}", result.commitment_elements.commitments); 154 | println!("ys: {:?}", result.commitment_elements.elements.ys); 155 | assert_eq!(result.commitment_elements.elements.zs, [13, 101]); 156 | assert_eq!( 157 | result.commitment_elements.elements.ys.len(), 158 | result.commitment_elements.elements.zs.len() 159 | ); 160 | assert_eq!( 161 | result.commitment_elements.commitments.len(), 162 | result.commitment_elements.elements.zs.len() 163 | ); 164 | assert_eq!(result.extra_data_list.len(), 1); 165 | assert_eq!(result.extra_data_list[0].status, ExtStatus::Empty); 166 | assert_eq!(result.extra_data_list[0].depth, 2); 167 | assert!(result.extra_data_list[0].poa_stem.is_none()); 168 | 169 | let key_other_stem = { 170 | let mut key = [255u8; 32]; 171 | key[30] = 0; 172 | 173 | key 174 | }; 175 | 176 | let result = tree.get_witnesses(&[key_other_stem]).unwrap(); 177 | println!("commitments: {:?}", result.commitment_elements.commitments); 178 | println!("ys: {:?}", result.commitment_elements.elements.ys); 179 | assert_eq!(result.commitment_elements.elements.zs, [255, 0, 1]); 180 | assert_eq!( 181 | result.commitment_elements.elements.ys.len(), 182 | result.commitment_elements.elements.zs.len() 183 | ); 184 | assert_eq!( 185 | result.commitment_elements.commitments.len(), 186 | result.commitment_elements.elements.zs.len() 187 | ); 188 | assert_eq!(result.extra_data_list[0].poa_stem, keys[1].get_stem()); 189 | assert_eq!(result.extra_data_list.len(), 1); 190 | assert_eq!(result.extra_data_list[0].status, ExtStatus::OtherStem); 191 | assert_eq!(result.extra_data_list[0].depth, 1); 192 | assert!(result.extra_data_list[0].poa_stem.is_some()); 193 | 194 | let key_other_key = { 195 | let mut key = [0u8; 32]; 196 | key[0] = 13; 197 | key[1] = 103; 198 | key[30] = 164; 199 | key[31] = 253; 200 | 201 | key 202 | }; 203 | 204 | let result = tree.get_witnesses(&[key_other_key]).unwrap(); 205 | println!("commitments: {:?}", result.commitment_elements.commitments); 206 | assert_eq!( 207 | result.commitment_elements.elements.zs, 208 | [13, 103, 0, 1, 3, 250] 209 | ); 210 | assert_eq!( 211 | result.commitment_elements.elements.ys.len(), 212 | result.commitment_elements.elements.zs.len() 213 | ); 214 | assert_eq!( 215 | result.commitment_elements.commitments.len(), 216 | result.commitment_elements.elements.zs.len() 217 | ); 218 | assert_eq!(result.extra_data_list.len(), 1); 219 | assert_eq!(result.extra_data_list[0].status, ExtStatus::OtherKey); 220 | assert_eq!(result.extra_data_list[0].depth, 2); 221 | assert!(result.extra_data_list[0].poa_stem.is_none()); 222 | 223 | let key_empty_suffix_tree = { 224 | let mut key = [0u8; 32]; 225 | key[0] = 13; 226 | key[1] = 103; 227 | key[30] = 164; 228 | key[31] = 17; 229 | 230 | key 231 | }; 232 | 233 | let result = tree.get_witnesses(&[key_empty_suffix_tree]).unwrap(); 234 | println!("commitments: {:?}", result.commitment_elements.commitments); 235 | assert_eq!(result.commitment_elements.elements.zs, [13, 103, 0, 1, 2]); 236 | assert_eq!( 237 | result.commitment_elements.elements.ys.len(), 238 | result.commitment_elements.elements.zs.len() 239 | ); 240 | assert_eq!( 241 | result.commitment_elements.commitments.len(), 242 | result.commitment_elements.elements.zs.len() 243 | ); 244 | assert_eq!(result.extra_data_list.len(), 1); 245 | assert_eq!(result.extra_data_list[0].status, ExtStatus::EmptySuffixTree); 246 | assert_eq!(result.extra_data_list[0].depth, 2); 247 | assert!(result.extra_data_list[0].poa_stem.is_none()); 248 | } 249 | 250 | #[test] 251 | fn test_encode_verkle_proof() { 252 | let domain_size = 256; 253 | let committer = IpaConfig::new(domain_size); 254 | let mut tree = VerkleTreeWith32BytesKeyValue::new(committer); 255 | let mut keys = vec![]; 256 | { 257 | let mut key = [0u8; 32]; 258 | key[0] = 13; 259 | key[1] = 102; 260 | key[2] = 32; 261 | key[30] = 164; 262 | key[31] = 254; 263 | let value = [255u8; 32]; 264 | tree.insert(key, value); 265 | keys.push(key); 266 | } 267 | { 268 | let key = [255u8; 32]; 269 | let mut value = [0u8; 32]; 270 | value[0] = 28; 271 | value[15] = 193; 272 | value[16] = 60; 273 | value[31] = 27; 274 | tree.insert(key, value); 275 | keys.push(key); 276 | } 277 | { 278 | let mut key = [0u8; 32]; 279 | key[0] = 13; 280 | key[1] = 103; 281 | key[30] = 164; 282 | key[31] = 255; 283 | let value = [0u8; 32]; 284 | tree.insert(key, value); 285 | keys.push(key); 286 | } 287 | { 288 | let mut key = [0u8; 32]; 289 | key[0] = 13; 290 | key[1] = 103; 291 | key[30] = 164; 292 | key[31] = 254; 293 | let mut value = [0u8; 32]; 294 | value[0] = 235; 295 | value[15] = 193; 296 | value[16] = 60; 297 | value[31] = 136; 298 | tree.insert(key, value); 299 | keys.push(key); 300 | } 301 | 302 | let key_empty_leaf = { 303 | let mut key = [0u8; 32]; 304 | key[0] = 13; 305 | key[1] = 101; 306 | key[30] = 164; 307 | key[31] = 254; 308 | 309 | key 310 | }; 311 | 312 | let key_other_stem = { 313 | let mut key = [255u8; 32]; 314 | key[30] = 0; 315 | 316 | key 317 | }; 318 | 319 | let key_other_key = { 320 | let mut key = [0u8; 32]; 321 | key[0] = 13; 322 | key[1] = 103; 323 | key[30] = 164; 324 | key[31] = 253; 325 | 326 | key 327 | }; 328 | 329 | let key_empty_suffix_tree = { 330 | let mut key = [0u8; 32]; 331 | key[0] = 13; 332 | key[1] = 103; 333 | key[30] = 164; 334 | key[31] = 17; 335 | 336 | key 337 | }; 338 | 339 | tree.compute_digest().unwrap(); 340 | 341 | let mut sorted_keys = [ 342 | key_empty_leaf, 343 | keys[3], 344 | key_other_stem, 345 | key_other_key, 346 | key_empty_suffix_tree, 347 | ]; 348 | sorted_keys.sort(); 349 | let (proof, elements) = VerkleProof::create(&mut tree, &sorted_keys).unwrap(); 350 | let encoded_proof = EncodedVerkleProof::encode(&proof); 351 | let proof_path = Path::new("./test_cases") 352 | .join("fr_case1") 353 | .join("proof.json"); 354 | let file = OpenOptions::new() 355 | .write(true) 356 | .create(true) 357 | .truncate(true) 358 | .open(proof_path) 359 | .unwrap(); 360 | serde_json::to_writer(file, &encoded_proof).unwrap(); 361 | let elements_path = Path::new("./test_cases") 362 | .join("fr_case1") 363 | .join("elements.json"); 364 | let file = OpenOptions::new() 365 | .write(true) 366 | .create(true) 367 | .truncate(true) 368 | .open(elements_path) 369 | .unwrap(); 370 | let commitment_elements = CommitmentElements { 371 | elements, 372 | commitments: proof.commitments, 373 | }; 374 | serde_json::to_writer( 375 | file, 376 | &EncodedCommitmentElements::encode(&commitment_elements), 377 | ) 378 | .unwrap(); 379 | 380 | let proof_path = Path::new("./test_cases") 381 | .join("fr_case1") 382 | .join("proof.json"); 383 | let file = OpenOptions::new().read(true).open(proof_path).unwrap(); 384 | let encoded_proof: EncodedVerkleProof = serde_json::from_reader(file).unwrap(); 385 | let (decoded_proof, decoded_zs, decoded_ys) = 386 | encoded_proof.decode(&tree.committer).unwrap(); 387 | let elements_path = Path::new("./test_cases") 388 | .join("fr_case1") 389 | .join("elements.json"); 390 | let file = OpenOptions::new().read(true).open(elements_path).unwrap(); 391 | let commitment_elements: EncodedCommitmentElements = serde_json::from_reader(file).unwrap(); 392 | let commitment_elements = commitment_elements.decode().unwrap(); 393 | assert_eq!(decoded_zs, commitment_elements.elements.zs); 394 | assert_eq!(decoded_ys, commitment_elements.elements.ys); 395 | assert_eq!( 396 | decoded_proof 397 | .commitments 398 | .iter() 399 | .map(EncodedEcPoint::encode) 400 | .collect::>(), 401 | commitment_elements 402 | .commitments 403 | .iter() 404 | .map(EncodedEcPoint::encode) 405 | .collect::>() 406 | ); 407 | 408 | let domain_size = 256; 409 | let committer = IpaConfig::new(domain_size); 410 | let success = decoded_proof 411 | .check(&decoded_zs, &decoded_ys, &committer) 412 | .unwrap(); 413 | 414 | assert!(success, "Fail to pass the verification of verkle proof."); 415 | } 416 | } 417 | -------------------------------------------------------------------------------- /src/bn256_verkle_tree_fs/mod.rs: -------------------------------------------------------------------------------- 1 | use franklin_crypto::bellman::bn256::Bn256; 2 | 3 | use crate::ipa_fs::config::IpaConfig; 4 | use crate::verkle_tree_fs::trie::VerkleTree; 5 | 6 | use self::leaf::LeafNodeWith32BytesValue; 7 | 8 | pub mod leaf; 9 | pub mod proof; 10 | 11 | pub type VerkleTreeWith32BytesKeyValue<'a, 'b> = 12 | VerkleTree<'b, [u8; 32], LeafNodeWith32BytesValue, Bn256, IpaConfig<'a, Bn256>>; 13 | 14 | #[cfg(test)] 15 | mod bn256_verkle_tree_fs_tests { 16 | use std::fs::OpenOptions; 17 | use std::path::Path; 18 | 19 | use franklin_crypto::babyjubjub::JubjubBn256; 20 | use franklin_crypto::bellman::PrimeField; 21 | 22 | use crate::bn256_verkle_tree_fs::proof::{ 23 | EncodedCommitmentElements, EncodedEcPoint, EncodedVerkleProof, VerkleProof, 24 | }; 25 | use crate::ipa_fr::transcript::{Bn256Transcript, PoseidonBn256Transcript}; 26 | use crate::ipa_fs::config::IpaConfig; 27 | use crate::verkle_tree::trie::{AbstractKey, ExtStatus}; 28 | use crate::verkle_tree_fs::witness::CommitmentElements; 29 | 30 | use super::VerkleTreeWith32BytesKeyValue; 31 | 32 | #[test] 33 | fn test_verkle_fs_verification_with_one_entry() { 34 | let domain_size = 256; 35 | let jubjub_params = &JubjubBn256::new(); 36 | let committer = &IpaConfig::new(domain_size, jubjub_params); 37 | 38 | // prover's view 39 | let mut tree = VerkleTreeWith32BytesKeyValue::new(committer); 40 | let mut key = [0u8; 32]; 41 | key[0] = 13; 42 | let mut value = [0u8; 32]; 43 | value[0] = 27; 44 | tree.insert(key, value); 45 | tree.compute_digest().unwrap(); 46 | 47 | let result = tree.get_witnesses(&[key]).unwrap(); 48 | // println!("commitments: {:?}", result.commitment_elements.commitments); 49 | println!("zs: {:?}", result.commitment_elements.elements.zs); 50 | println!("ys: {:?}", result.commitment_elements.elements.ys); 51 | 52 | let prover_transcript = PoseidonBn256Transcript::with_bytes(b"verkle_tree"); 53 | let (proof, elements) = 54 | VerkleProof::create(&mut tree, &[key], prover_transcript.into_params()).unwrap(); 55 | 56 | // verifier's view 57 | 58 | let verifier_transcript = PoseidonBn256Transcript::with_bytes(b"verkle_tree"); 59 | let success = proof 60 | .check( 61 | &elements.zs, 62 | &elements.ys, 63 | verifier_transcript.into_params(), 64 | &committer, 65 | ) 66 | .unwrap(); 67 | 68 | assert!( 69 | success, 70 | "Fail to pass the verification of verkle proof circuit." 71 | ); 72 | } 73 | 74 | #[test] 75 | fn test_verkle_tree_fs_with_some_entries() { 76 | let domain_size = 256; 77 | let jubjub_params = &JubjubBn256::new(); 78 | let committer = &IpaConfig::new(domain_size, jubjub_params); 79 | let mut tree = VerkleTreeWith32BytesKeyValue::new(committer); 80 | let mut keys = vec![]; 81 | { 82 | let mut key = [0u8; 32]; 83 | key[0] = 13; 84 | key[1] = 102; 85 | key[2] = 32; 86 | key[30] = 164; 87 | key[31] = 254; 88 | let value = [255u8; 32]; 89 | tree.insert(key, value); 90 | keys.push(key); 91 | } 92 | { 93 | let key = [255u8; 32]; 94 | let mut value = [0u8; 32]; 95 | value[0] = 28; 96 | value[15] = 193; 97 | value[16] = 60; 98 | value[31] = 27; 99 | tree.insert(key, value); 100 | keys.push(key); 101 | } 102 | { 103 | let mut key = [0u8; 32]; 104 | key[0] = 13; 105 | key[1] = 103; 106 | key[30] = 164; 107 | key[31] = 255; 108 | let value = [0u8; 32]; 109 | tree.insert(key, value); 110 | keys.push(key); 111 | } 112 | { 113 | let mut key = [0u8; 32]; 114 | key[0] = 13; 115 | key[1] = 103; 116 | key[30] = 164; 117 | key[31] = 254; 118 | let mut value = [0u8; 32]; 119 | value[0] = 235; 120 | value[15] = 193; 121 | value[16] = 60; 122 | value[31] = 136; 123 | tree.insert(key, value); 124 | keys.push(key); 125 | } 126 | 127 | tree.compute_digest().unwrap(); 128 | 129 | let result = tree.get_witnesses(&[keys[0]]).unwrap(); 130 | // println!("commitments: {:?}", result.commitment_elements.commitments); 131 | println!("zs: {:?}", result.commitment_elements.elements.zs); 132 | println!("ys: {:?}", result.commitment_elements.elements.ys); 133 | println!("extra_data_list: {:?}", result.extra_data_list); 134 | assert_eq!( 135 | result.commitment_elements.elements.zs, 136 | [13, 102, 0, 1, 3, 252, 253] 137 | ); 138 | assert_eq!( 139 | result.commitment_elements.elements.ys.len(), 140 | result.commitment_elements.elements.zs.len() 141 | ); 142 | assert_eq!( 143 | result.commitment_elements.commitments.len(), 144 | result.commitment_elements.elements.zs.len() 145 | ); 146 | assert_eq!(result.extra_data_list.len(), 1); 147 | assert_eq!(result.extra_data_list[0].status, ExtStatus::Present); 148 | assert_eq!(result.extra_data_list[0].depth, 2); 149 | assert!(result.extra_data_list[0].poa_stem.is_none()); 150 | 151 | tree.remove(&keys[0]); 152 | 153 | tree.compute_digest().unwrap(); 154 | 155 | let key_empty_leaf = { 156 | let mut key = [0u8; 32]; 157 | key[0] = 13; 158 | key[1] = 101; 159 | key[30] = 164; 160 | key[31] = 254; 161 | 162 | key 163 | }; 164 | 165 | let result = tree.get_witnesses(&[key_empty_leaf]).unwrap(); 166 | // println!("commitments: {:?}", result.commitment_elements.commitments); 167 | println!("ys: {:?}", result.commitment_elements.elements.ys); 168 | assert_eq!(result.commitment_elements.elements.zs, [13, 101]); 169 | assert_eq!( 170 | result.commitment_elements.elements.ys.len(), 171 | result.commitment_elements.elements.zs.len() 172 | ); 173 | assert_eq!( 174 | result.commitment_elements.commitments.len(), 175 | result.commitment_elements.elements.zs.len() 176 | ); 177 | assert_eq!(result.extra_data_list.len(), 1); 178 | assert_eq!(result.extra_data_list[0].status, ExtStatus::Empty); 179 | assert_eq!(result.extra_data_list[0].depth, 2); 180 | assert!(result.extra_data_list[0].poa_stem.is_none()); 181 | 182 | let key_other_stem = { 183 | let mut key = [255u8; 32]; 184 | key[30] = 0; 185 | 186 | key 187 | }; 188 | 189 | let result = tree.get_witnesses(&[key_other_stem]).unwrap(); 190 | // println!("commitments: {:?}", result.commitment_elements.commitments); 191 | println!("ys: {:?}", result.commitment_elements.elements.ys); 192 | assert_eq!(result.commitment_elements.elements.zs, [255, 0, 1]); 193 | assert_eq!( 194 | result.commitment_elements.elements.ys.len(), 195 | result.commitment_elements.elements.zs.len() 196 | ); 197 | assert_eq!( 198 | result.commitment_elements.commitments.len(), 199 | result.commitment_elements.elements.zs.len() 200 | ); 201 | assert_eq!(result.extra_data_list[0].poa_stem, keys[1].get_stem()); 202 | assert_eq!(result.extra_data_list.len(), 1); 203 | assert_eq!(result.extra_data_list[0].status, ExtStatus::OtherStem); 204 | assert_eq!(result.extra_data_list[0].depth, 1); 205 | assert!(result.extra_data_list[0].poa_stem.is_some()); 206 | 207 | let key_other_key = { 208 | let mut key = [0u8; 32]; 209 | key[0] = 13; 210 | key[1] = 103; 211 | key[30] = 164; 212 | key[31] = 253; 213 | 214 | key 215 | }; 216 | 217 | let result = tree.get_witnesses(&[key_other_key]).unwrap(); 218 | // println!("commitments: {:?}", result.commitment_elements.commitments); 219 | assert_eq!( 220 | result.commitment_elements.elements.zs, 221 | [13, 103, 0, 1, 3, 250] 222 | ); 223 | assert_eq!( 224 | result.commitment_elements.elements.ys.len(), 225 | result.commitment_elements.elements.zs.len() 226 | ); 227 | assert_eq!( 228 | result.commitment_elements.commitments.len(), 229 | result.commitment_elements.elements.zs.len() 230 | ); 231 | assert_eq!(result.extra_data_list.len(), 1); 232 | assert_eq!(result.extra_data_list[0].status, ExtStatus::OtherKey); 233 | assert_eq!(result.extra_data_list[0].depth, 2); 234 | assert!(result.extra_data_list[0].poa_stem.is_none()); 235 | 236 | let key_empty_suffix_tree = { 237 | let mut key = [0u8; 32]; 238 | key[0] = 13; 239 | key[1] = 103; 240 | key[30] = 164; 241 | key[31] = 17; 242 | 243 | key 244 | }; 245 | 246 | let result = tree.get_witnesses(&[key_empty_suffix_tree]).unwrap(); 247 | // println!("commitments: {:?}", result.commitment_elements.commitments); 248 | assert_eq!(result.commitment_elements.elements.zs, [13, 103, 0, 1, 2]); 249 | assert_eq!( 250 | result.commitment_elements.elements.ys.len(), 251 | result.commitment_elements.elements.zs.len() 252 | ); 253 | assert_eq!( 254 | result.commitment_elements.commitments.len(), 255 | result.commitment_elements.elements.zs.len() 256 | ); 257 | assert_eq!(result.extra_data_list.len(), 1); 258 | assert_eq!(result.extra_data_list[0].status, ExtStatus::EmptySuffixTree); 259 | assert_eq!(result.extra_data_list[0].depth, 2); 260 | assert!(result.extra_data_list[0].poa_stem.is_none()); 261 | } 262 | 263 | #[test] 264 | fn test_encode_verkle_fs_proof() { 265 | let domain_size = 256; 266 | let jubjub_params = &JubjubBn256::new(); 267 | let committer = &IpaConfig::new(domain_size, jubjub_params); 268 | let mut tree = VerkleTreeWith32BytesKeyValue::new(committer); 269 | let mut keys = vec![]; 270 | { 271 | let mut key = [0u8; 32]; 272 | key[0] = 13; 273 | key[1] = 102; 274 | key[2] = 32; 275 | key[30] = 164; 276 | key[31] = 254; 277 | let value = [255u8; 32]; 278 | tree.insert(key, value); 279 | keys.push(key); 280 | } 281 | { 282 | let key = [255u8; 32]; 283 | let mut value = [0u8; 32]; 284 | value[0] = 28; 285 | value[15] = 193; 286 | value[16] = 60; 287 | value[31] = 27; 288 | tree.insert(key, value); 289 | keys.push(key); 290 | } 291 | { 292 | let mut key = [0u8; 32]; 293 | key[0] = 13; 294 | key[1] = 103; 295 | key[30] = 164; 296 | key[31] = 255; 297 | let value = [0u8; 32]; 298 | tree.insert(key, value); 299 | keys.push(key); 300 | } 301 | { 302 | let mut key = [0u8; 32]; 303 | key[0] = 13; 304 | key[1] = 103; 305 | key[30] = 164; 306 | key[31] = 254; 307 | let mut value = [0u8; 32]; 308 | value[0] = 235; 309 | value[15] = 193; 310 | value[16] = 60; 311 | value[31] = 136; 312 | tree.insert(key, value); 313 | keys.push(key); 314 | } 315 | 316 | let key_empty_leaf = { 317 | let mut key = [0u8; 32]; 318 | key[0] = 13; 319 | key[1] = 101; 320 | key[30] = 164; 321 | key[31] = 254; 322 | 323 | key 324 | }; 325 | 326 | let key_other_stem = { 327 | let mut key = [255u8; 32]; 328 | key[30] = 0; 329 | 330 | key 331 | }; 332 | 333 | let key_other_key = { 334 | let mut key = [0u8; 32]; 335 | key[0] = 13; 336 | key[1] = 103; 337 | key[30] = 164; 338 | key[31] = 253; 339 | 340 | key 341 | }; 342 | 343 | let key_empty_suffix_tree = { 344 | let mut key = [0u8; 32]; 345 | key[0] = 13; 346 | key[1] = 103; 347 | key[30] = 164; 348 | key[31] = 17; 349 | 350 | key 351 | }; 352 | 353 | tree.compute_digest().unwrap(); 354 | 355 | let mut sorted_keys = [ 356 | key_empty_leaf, 357 | keys[3], 358 | key_other_stem, 359 | key_other_key, 360 | key_empty_suffix_tree, 361 | ]; 362 | sorted_keys.sort(); 363 | 364 | let prover_transcript = PoseidonBn256Transcript::with_bytes(b"verkle_tree"); 365 | let (proof, elements) = 366 | VerkleProof::create(&mut tree, &sorted_keys, prover_transcript.into_params()).unwrap(); 367 | let encoded_proof = EncodedVerkleProof::encode(&proof); 368 | let proof_path = Path::new("./test_cases") 369 | .join("fs_case1") 370 | .join("proof.json"); 371 | let file = OpenOptions::new() 372 | .write(true) 373 | .create(true) 374 | .truncate(true) 375 | .open(proof_path) 376 | .unwrap(); 377 | serde_json::to_writer(file, &encoded_proof).unwrap(); 378 | let elements_path = Path::new("./test_cases") 379 | .join("fs_case1") 380 | .join("elements.json"); 381 | let file = OpenOptions::new() 382 | .write(true) 383 | .create(true) 384 | .truncate(true) 385 | .open(elements_path) 386 | .unwrap(); 387 | let commitment_elements = CommitmentElements { 388 | elements, 389 | commitments: proof.commitments, 390 | }; 391 | serde_json::to_writer( 392 | file, 393 | &EncodedCommitmentElements::encode(&commitment_elements), 394 | ) 395 | .unwrap(); 396 | 397 | let proof_path = Path::new("./test_cases") 398 | .join("fs_case1") 399 | .join("proof.json"); 400 | let file = OpenOptions::new().read(true).open(proof_path).unwrap(); 401 | let encoded_proof: EncodedVerkleProof = serde_json::from_reader(file).unwrap(); 402 | let (decoded_proof, decoded_zs, decoded_ys) = encoded_proof.decode(tree.committer).unwrap(); 403 | let elements_path = Path::new("./test_cases") 404 | .join("fs_case1") 405 | .join("elements.json"); 406 | let file = OpenOptions::new().read(true).open(elements_path).unwrap(); 407 | let commitment_elements: EncodedCommitmentElements = serde_json::from_reader(file).unwrap(); 408 | let commitment_elements = commitment_elements.decode().unwrap(); 409 | assert_eq!(decoded_zs, commitment_elements.elements.zs); 410 | for (i, (_y, y)) in decoded_ys 411 | .iter() 412 | .zip(&commitment_elements.elements.ys) 413 | .enumerate() 414 | { 415 | if _y != y { 416 | println!( 417 | "{}-th commitment is invalid: {:?} != {:?}", 418 | i, 419 | _y.into_repr(), 420 | y.into_repr() 421 | ); 422 | } 423 | } 424 | assert_eq!(decoded_ys, commitment_elements.elements.ys); 425 | assert_eq!( 426 | decoded_proof 427 | .commitments 428 | .iter() 429 | .map(|v| EncodedEcPoint::encode(v)) 430 | .collect::>(), 431 | commitment_elements 432 | .commitments 433 | .iter() 434 | .map(|v| EncodedEcPoint::encode(v)) 435 | .collect::>() 436 | ); 437 | 438 | let domain_size = 256; 439 | let jubjub_params = &JubjubBn256::new(); 440 | let committer = IpaConfig::new(domain_size, jubjub_params); 441 | let verifier_transcript = PoseidonBn256Transcript::with_bytes(b"verkle_tree"); 442 | let success = decoded_proof 443 | .check( 444 | &decoded_zs, 445 | &decoded_ys, 446 | verifier_transcript.into_params(), 447 | &committer, 448 | ) 449 | .unwrap(); 450 | 451 | assert!(success, "Fail to pass the verification of verkle proof."); 452 | } 453 | } 454 | -------------------------------------------------------------------------------- /packages/ff_utils/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addchain" 7 | version = "0.2.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "3b2e69442aa5628ea6951fa33e24efe8313f4321a91bd729fc2f75bdfc858570" 10 | dependencies = [ 11 | "num-bigint 0.3.3", 12 | "num-integer", 13 | "num-traits", 14 | ] 15 | 16 | [[package]] 17 | name = "autocfg" 18 | version = "1.0.1" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 21 | 22 | [[package]] 23 | name = "bitvec" 24 | version = "0.22.3" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | checksum = "5237f00a8c86130a0cc317830e558b966dd7850d48a953d998c813f01a41b527" 27 | dependencies = [ 28 | "funty", 29 | "radium", 30 | "tap", 31 | "wyz", 32 | ] 33 | 34 | [[package]] 35 | name = "byteorder" 36 | version = "1.4.3" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 39 | 40 | [[package]] 41 | name = "cfg-if" 42 | version = "0.1.10" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 45 | 46 | [[package]] 47 | name = "cfg-if" 48 | version = "1.0.0" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 51 | 52 | [[package]] 53 | name = "crossbeam" 54 | version = "0.7.3" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" 57 | dependencies = [ 58 | "cfg-if 0.1.10", 59 | "crossbeam-channel", 60 | "crossbeam-deque", 61 | "crossbeam-epoch", 62 | "crossbeam-queue", 63 | "crossbeam-utils", 64 | ] 65 | 66 | [[package]] 67 | name = "crossbeam-channel" 68 | version = "0.4.4" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" 71 | dependencies = [ 72 | "crossbeam-utils", 73 | "maybe-uninit", 74 | ] 75 | 76 | [[package]] 77 | name = "crossbeam-deque" 78 | version = "0.7.4" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" 81 | dependencies = [ 82 | "crossbeam-epoch", 83 | "crossbeam-utils", 84 | "maybe-uninit", 85 | ] 86 | 87 | [[package]] 88 | name = "crossbeam-epoch" 89 | version = "0.8.2" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" 92 | dependencies = [ 93 | "autocfg", 94 | "cfg-if 0.1.10", 95 | "crossbeam-utils", 96 | "lazy_static", 97 | "maybe-uninit", 98 | "memoffset", 99 | "scopeguard", 100 | ] 101 | 102 | [[package]] 103 | name = "crossbeam-queue" 104 | version = "0.2.3" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" 107 | dependencies = [ 108 | "cfg-if 0.1.10", 109 | "crossbeam-utils", 110 | "maybe-uninit", 111 | ] 112 | 113 | [[package]] 114 | name = "crossbeam-utils" 115 | version = "0.7.2" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" 118 | dependencies = [ 119 | "autocfg", 120 | "cfg-if 0.1.10", 121 | "lazy_static", 122 | ] 123 | 124 | [[package]] 125 | name = "ff" 126 | version = "0.10.1" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" 129 | dependencies = [ 130 | "rand_core 0.6.3", 131 | "subtle", 132 | ] 133 | 134 | [[package]] 135 | name = "ff" 136 | version = "0.11.0" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "b2958d04124b9f27f175eaeb9a9f383d026098aa837eadd8ba22c11f13a05b9e" 139 | dependencies = [ 140 | "bitvec", 141 | "byteorder", 142 | "ff_derive", 143 | "rand_core 0.6.3", 144 | "subtle", 145 | ] 146 | 147 | [[package]] 148 | name = "ff_ce" 149 | version = "0.12.0" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "38107cbd8bac0d907d7e7513c9f68c95adbda9e6f6f6bdf3f5111c6ecac4fe47" 152 | dependencies = [ 153 | "byteorder", 154 | "ff_derive_ce", 155 | "hex", 156 | "rand", 157 | ] 158 | 159 | [[package]] 160 | name = "ff_derive" 161 | version = "0.11.0" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "a923972863adcef93ac7092c9bf6543a26e922c1bd6c925518156411e05bf85c" 164 | dependencies = [ 165 | "addchain", 166 | "num-bigint 0.3.3", 167 | "num-integer", 168 | "num-traits", 169 | "proc-macro2", 170 | "quote", 171 | "syn", 172 | ] 173 | 174 | [[package]] 175 | name = "ff_derive_ce" 176 | version = "0.9.3" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "dde5a00073374b4d7aa2d3a8359a5709f9c0bfac8393f254655d16b4acdfe823" 179 | dependencies = [ 180 | "num-bigint 0.4.3", 181 | "num-integer", 182 | "num-traits", 183 | "proc-macro2", 184 | "quote", 185 | "syn", 186 | ] 187 | 188 | [[package]] 189 | name = "ff_utils" 190 | version = "1.0.0" 191 | dependencies = [ 192 | "bitvec", 193 | "byteorder", 194 | "crossbeam", 195 | "ff 0.11.0", 196 | "futures", 197 | "group", 198 | "hex", 199 | "num", 200 | "num_cpus", 201 | "pairing_ce", 202 | "rand_core 0.6.3", 203 | "serde", 204 | "subtle", 205 | ] 206 | 207 | [[package]] 208 | name = "fuchsia-cprng" 209 | version = "0.1.1" 210 | source = "registry+https://github.com/rust-lang/crates.io-index" 211 | checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 212 | 213 | [[package]] 214 | name = "funty" 215 | version = "1.2.0" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e" 218 | 219 | [[package]] 220 | name = "futures" 221 | version = "0.3.19" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4" 224 | dependencies = [ 225 | "futures-channel", 226 | "futures-core", 227 | "futures-executor", 228 | "futures-io", 229 | "futures-sink", 230 | "futures-task", 231 | "futures-util", 232 | ] 233 | 234 | [[package]] 235 | name = "futures-channel" 236 | version = "0.3.19" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" 239 | dependencies = [ 240 | "futures-core", 241 | "futures-sink", 242 | ] 243 | 244 | [[package]] 245 | name = "futures-core" 246 | version = "0.3.19" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" 249 | 250 | [[package]] 251 | name = "futures-executor" 252 | version = "0.3.19" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a" 255 | dependencies = [ 256 | "futures-core", 257 | "futures-task", 258 | "futures-util", 259 | "num_cpus", 260 | ] 261 | 262 | [[package]] 263 | name = "futures-io" 264 | version = "0.3.19" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" 267 | 268 | [[package]] 269 | name = "futures-sink" 270 | version = "0.3.19" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" 273 | 274 | [[package]] 275 | name = "futures-task" 276 | version = "0.3.19" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" 279 | 280 | [[package]] 281 | name = "futures-util" 282 | version = "0.3.19" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" 285 | dependencies = [ 286 | "futures-channel", 287 | "futures-core", 288 | "futures-io", 289 | "futures-sink", 290 | "futures-task", 291 | "memchr", 292 | "pin-project-lite", 293 | "pin-utils", 294 | "slab", 295 | ] 296 | 297 | [[package]] 298 | name = "group" 299 | version = "0.10.0" 300 | source = "registry+https://github.com/rust-lang/crates.io-index" 301 | checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" 302 | dependencies = [ 303 | "byteorder", 304 | "ff 0.10.1", 305 | "rand_core 0.6.3", 306 | "subtle", 307 | ] 308 | 309 | [[package]] 310 | name = "hermit-abi" 311 | version = "0.1.19" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 314 | dependencies = [ 315 | "libc", 316 | ] 317 | 318 | [[package]] 319 | name = "hex" 320 | version = "0.4.3" 321 | source = "registry+https://github.com/rust-lang/crates.io-index" 322 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 323 | 324 | [[package]] 325 | name = "lazy_static" 326 | version = "1.4.0" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 329 | 330 | [[package]] 331 | name = "libc" 332 | version = "0.2.112" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" 335 | 336 | [[package]] 337 | name = "maybe-uninit" 338 | version = "2.0.0" 339 | source = "registry+https://github.com/rust-lang/crates.io-index" 340 | checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" 341 | 342 | [[package]] 343 | name = "memchr" 344 | version = "2.4.1" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 347 | 348 | [[package]] 349 | name = "memoffset" 350 | version = "0.5.6" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" 353 | dependencies = [ 354 | "autocfg", 355 | ] 356 | 357 | [[package]] 358 | name = "num" 359 | version = "0.4.0" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" 362 | dependencies = [ 363 | "num-bigint 0.4.3", 364 | "num-complex", 365 | "num-integer", 366 | "num-iter", 367 | "num-rational", 368 | "num-traits", 369 | ] 370 | 371 | [[package]] 372 | name = "num-bigint" 373 | version = "0.3.3" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" 376 | dependencies = [ 377 | "autocfg", 378 | "num-integer", 379 | "num-traits", 380 | ] 381 | 382 | [[package]] 383 | name = "num-bigint" 384 | version = "0.4.3" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" 387 | dependencies = [ 388 | "autocfg", 389 | "num-integer", 390 | "num-traits", 391 | ] 392 | 393 | [[package]] 394 | name = "num-complex" 395 | version = "0.4.0" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085" 398 | dependencies = [ 399 | "num-traits", 400 | ] 401 | 402 | [[package]] 403 | name = "num-integer" 404 | version = "0.1.44" 405 | source = "registry+https://github.com/rust-lang/crates.io-index" 406 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 407 | dependencies = [ 408 | "autocfg", 409 | "num-traits", 410 | ] 411 | 412 | [[package]] 413 | name = "num-iter" 414 | version = "0.1.42" 415 | source = "registry+https://github.com/rust-lang/crates.io-index" 416 | checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" 417 | dependencies = [ 418 | "autocfg", 419 | "num-integer", 420 | "num-traits", 421 | ] 422 | 423 | [[package]] 424 | name = "num-rational" 425 | version = "0.4.0" 426 | source = "registry+https://github.com/rust-lang/crates.io-index" 427 | checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" 428 | dependencies = [ 429 | "autocfg", 430 | "num-bigint 0.4.3", 431 | "num-integer", 432 | "num-traits", 433 | ] 434 | 435 | [[package]] 436 | name = "num-traits" 437 | version = "0.2.14" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 440 | dependencies = [ 441 | "autocfg", 442 | ] 443 | 444 | [[package]] 445 | name = "num_cpus" 446 | version = "1.13.1" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" 449 | dependencies = [ 450 | "hermit-abi", 451 | "libc", 452 | ] 453 | 454 | [[package]] 455 | name = "pairing_ce" 456 | version = "0.24.2" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "1e753515675eaaa98071d814bea0148ae8c9d7995fa0531bf222e7857e3f1759" 459 | dependencies = [ 460 | "byteorder", 461 | "cfg-if 1.0.0", 462 | "ff_ce", 463 | "rand", 464 | ] 465 | 466 | [[package]] 467 | name = "pin-project-lite" 468 | version = "0.2.8" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" 471 | 472 | [[package]] 473 | name = "pin-utils" 474 | version = "0.1.0" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 477 | 478 | [[package]] 479 | name = "proc-macro2" 480 | version = "1.0.36" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" 483 | dependencies = [ 484 | "unicode-xid", 485 | ] 486 | 487 | [[package]] 488 | name = "quote" 489 | version = "1.0.14" 490 | source = "registry+https://github.com/rust-lang/crates.io-index" 491 | checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" 492 | dependencies = [ 493 | "proc-macro2", 494 | ] 495 | 496 | [[package]] 497 | name = "radium" 498 | version = "0.6.2" 499 | source = "registry+https://github.com/rust-lang/crates.io-index" 500 | checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" 501 | 502 | [[package]] 503 | name = "rand" 504 | version = "0.4.6" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" 507 | dependencies = [ 508 | "fuchsia-cprng", 509 | "libc", 510 | "rand_core 0.3.1", 511 | "rdrand", 512 | "winapi", 513 | ] 514 | 515 | [[package]] 516 | name = "rand_core" 517 | version = "0.3.1" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 520 | dependencies = [ 521 | "rand_core 0.4.2", 522 | ] 523 | 524 | [[package]] 525 | name = "rand_core" 526 | version = "0.4.2" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" 529 | 530 | [[package]] 531 | name = "rand_core" 532 | version = "0.6.3" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" 535 | 536 | [[package]] 537 | name = "rdrand" 538 | version = "0.4.0" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 541 | dependencies = [ 542 | "rand_core 0.3.1", 543 | ] 544 | 545 | [[package]] 546 | name = "scopeguard" 547 | version = "1.1.0" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 550 | 551 | [[package]] 552 | name = "serde" 553 | version = "1.0.133" 554 | source = "registry+https://github.com/rust-lang/crates.io-index" 555 | checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a" 556 | dependencies = [ 557 | "serde_derive", 558 | ] 559 | 560 | [[package]] 561 | name = "serde_derive" 562 | version = "1.0.133" 563 | source = "registry+https://github.com/rust-lang/crates.io-index" 564 | checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537" 565 | dependencies = [ 566 | "proc-macro2", 567 | "quote", 568 | "syn", 569 | ] 570 | 571 | [[package]] 572 | name = "slab" 573 | version = "0.4.5" 574 | source = "registry+https://github.com/rust-lang/crates.io-index" 575 | checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" 576 | 577 | [[package]] 578 | name = "subtle" 579 | version = "2.4.1" 580 | source = "registry+https://github.com/rust-lang/crates.io-index" 581 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 582 | 583 | [[package]] 584 | name = "syn" 585 | version = "1.0.85" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7" 588 | dependencies = [ 589 | "proc-macro2", 590 | "quote", 591 | "unicode-xid", 592 | ] 593 | 594 | [[package]] 595 | name = "tap" 596 | version = "1.0.1" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" 599 | 600 | [[package]] 601 | name = "unicode-xid" 602 | version = "0.2.2" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 605 | 606 | [[package]] 607 | name = "winapi" 608 | version = "0.3.9" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 611 | dependencies = [ 612 | "winapi-i686-pc-windows-gnu", 613 | "winapi-x86_64-pc-windows-gnu", 614 | ] 615 | 616 | [[package]] 617 | name = "winapi-i686-pc-windows-gnu" 618 | version = "0.4.0" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 621 | 622 | [[package]] 623 | name = "winapi-x86_64-pc-windows-gnu" 624 | version = "0.4.0" 625 | source = "registry+https://github.com/rust-lang/crates.io-index" 626 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 627 | 628 | [[package]] 629 | name = "wyz" 630 | version = "0.4.0" 631 | source = "registry+https://github.com/rust-lang/crates.io-index" 632 | checksum = "129e027ad65ce1453680623c3fb5163cbf7107bfe1aa32257e7d0e63f9ced188" 633 | dependencies = [ 634 | "tap", 635 | ] 636 | -------------------------------------------------------------------------------- /src/verkle_tree_fs/trie.rs: -------------------------------------------------------------------------------- 1 | use franklin_crypto::babyjubjub::{edwards, JubjubEngine, Unknown}; 2 | use franklin_crypto::bellman::Field; 3 | use std::borrow::Borrow; 4 | use std::collections::HashMap; 5 | 6 | use crate::ipa_fs::config::Committer; 7 | use crate::verkle_tree::trie::{ 8 | AbstractKey, AbstractPath, AbstractStem, AbstractValue, IntoFieldElement, 9 | }; 10 | 11 | use super::utils::point_to_field_element; 12 | 13 | #[derive(PartialEq)] 14 | pub struct VerkleTree<'a, K, L, E, C> 15 | where 16 | K: AbstractKey, 17 | L: LeafNodeValue, 18 | E: JubjubEngine, 19 | C: Committer, 20 | { 21 | pub root: VerkleNode, 22 | pub(crate) committer: &'a C, 23 | } 24 | 25 | // impl Default for VerkleTree 26 | // where 27 | // K: AbstractKey, 28 | // L: LeafNodeValue, 29 | // GA: CurveAffine, 30 | // GA::Base: PrimeField, 31 | // { 32 | // fn default() -> Self { 33 | // Self { 34 | // root: VerkleNode::default(), 35 | // committer: IpaConfig::new(WIDTH), 36 | // } 37 | // } 38 | // } 39 | 40 | impl<'a, K, L, E, C> VerkleTree<'a, K, L, E, C> 41 | where 42 | C: Committer, 43 | K: AbstractKey, 44 | L: LeafNodeValue, 45 | E: JubjubEngine, 46 | { 47 | pub fn new(committer: &'a C) -> Self { 48 | let num_limbs = L::num_limbs(); 49 | assert!( 50 | committer.get_domain_size() >= num_limbs + 2, 51 | "domain size must be larger than or equal to {}", 52 | num_limbs + 2 53 | ); 54 | Self { 55 | root: VerkleNode::default(), 56 | committer, 57 | } 58 | } 59 | 60 | pub fn get_width(&mut self) -> usize { 61 | self.committer.get_domain_size() 62 | } 63 | } 64 | 65 | impl<'a, P, K, L, E, C> VerkleTree<'a, K, L, E, C> 66 | where 67 | C: Committer, 68 | P: Default + AbstractPath, 69 | K: AbstractKey, 70 | K::Stem: AbstractStem + IntoFieldElement, 71 | L: LeafNodeValue, 72 | E: JubjubEngine, 73 | { 74 | /// Inserts `(key, value)` entry in given Verkle tree. 75 | /// This method updates the entry to the new value and returns the old value, 76 | /// even if the tree already has a value corresponding to the key. 77 | pub fn insert(&mut self, key: K, value: L::Value) -> Option { 78 | self.root.insert(key.to_path(), key, value) 79 | } 80 | 81 | /// Remove the entry corresponding to `key` in given Verkle tree. 82 | /// If the tree does not have a value corresponding to the key, this method does not change the tree state. 83 | pub fn remove(&mut self, key: &K) -> Option { 84 | self.root.remove(key.to_path(), key) 85 | } 86 | 87 | /// Fetch the value corresponding to `key` in given Verkle tree. 88 | /// The maximum time it takes to search entries depends on the depth of given Verkle tree. 89 | pub fn get(&self, key: &K) -> Option<&L::Value> { 90 | self.root.get(key.to_path(), key) 91 | } 92 | } 93 | 94 | // pub trait AbstractMerkleTree 95 | // where 96 | // K: AbstractKey, 97 | // V: AbstractValue, 98 | // { 99 | // type Err: Send + Sync + 'static; 100 | // type Digest: PartialEq + Eq; 101 | // type ProofCommitments: PartialEq + Eq; 102 | 103 | // fn compute_digest(&mut self) -> Result; 104 | // } 105 | 106 | impl<'a, P, K, L, E, C> VerkleTree<'a, K, L, E, C> 107 | where 108 | C: Committer, 109 | P: Default + AbstractPath, 110 | K: AbstractKey, 111 | K::Stem: AbstractStem + IntoFieldElement, 112 | L: LeafNodeValue, 113 | E: JubjubEngine, 114 | { 115 | /// Computes the digest of given Verkle tree. 116 | pub fn compute_digest(&mut self) -> anyhow::Result { 117 | self.root.compute_digest(self.committer) 118 | } 119 | } 120 | 121 | // pub trait IntoFieldElement { 122 | // type Err: Send + Sync + 'static; 123 | 124 | // fn into_field_element(self) -> Result; 125 | // } 126 | 127 | pub trait NodeValue 128 | where 129 | E: JubjubEngine, 130 | { 131 | fn len(&self) -> usize; 132 | 133 | fn is_empty(&self) -> bool { 134 | self.len() == 0 135 | } 136 | 137 | fn get_digest_mut(&mut self) -> &mut Option; 138 | 139 | fn get_digest(&self) -> Option<&E::Fs>; 140 | } 141 | 142 | pub trait LeafNodeValue: Clone + Default + NodeValue 143 | where 144 | K: AbstractKey, 145 | E: JubjubEngine, 146 | { 147 | type Value: AbstractValue; 148 | 149 | fn new() -> Self; 150 | 151 | fn insert(&mut self, key: usize, value: Self::Value) -> Option; 152 | 153 | fn get(&self, key: &usize) -> Option<&Self::Value>; 154 | 155 | fn remove(&mut self, key: &usize) -> Option; 156 | 157 | fn compute_digest>( 158 | &mut self, 159 | stem: &mut K::Stem, 160 | committer: &C, 161 | ) -> anyhow::Result; 162 | 163 | // fn get_witnesses>( 164 | // &self, 165 | // keys: &[K], 166 | // stem: K::Stem, 167 | // depth: usize, 168 | // committer: &C, 169 | // ) -> anyhow::Result>; 170 | 171 | fn bits_of_value() -> usize; 172 | 173 | fn num_limbs() -> usize; 174 | } 175 | 176 | #[derive(Clone, PartialEq)] 177 | pub struct InternalNodeValue 178 | where 179 | E: JubjubEngine, 180 | { 181 | /// The number of children which are `Some` rather than `None`. 182 | num_nonempty_children: usize, 183 | 184 | /// The commitment of this node. 185 | /// If it has not computed yet, `commitment` set `None`. 186 | commitment: Option>, 187 | 188 | /// The digest of `commitment`. 189 | /// If it has not computed yet, `digest` set `None`. 190 | digest: Option, 191 | } 192 | 193 | impl NodeValue for InternalNodeValue 194 | where 195 | E: JubjubEngine, 196 | { 197 | fn len(&self) -> usize { 198 | self.num_nonempty_children 199 | } 200 | 201 | fn get_digest_mut(&mut self) -> &mut Option { 202 | &mut self.digest 203 | } 204 | 205 | fn get_digest(&self) -> Option<&E::Fs> { 206 | let digest = &self.digest; 207 | 208 | digest.into() 209 | } 210 | } 211 | 212 | impl InternalNodeValue 213 | where 214 | E: JubjubEngine, 215 | { 216 | pub fn get_commitment_mut(&mut self) -> &mut Option> { 217 | &mut self.commitment 218 | } 219 | 220 | pub fn get_commitment(&self) -> Option<&edwards::Point> { 221 | let commitment = &self.commitment; 222 | 223 | commitment.into() 224 | } 225 | } 226 | 227 | #[derive(PartialEq)] 228 | pub enum VerkleNode 229 | where 230 | K: AbstractKey, 231 | L: LeafNodeValue, 232 | E: JubjubEngine, 233 | { 234 | Leaf { 235 | path: K::Path, 236 | stem: K::Stem, 237 | info: L, 238 | }, 239 | Internal { 240 | path: K::Path, 241 | children: HashMap>, // HashMap> 242 | info: InternalNodeValue, 243 | }, 244 | } 245 | 246 | impl VerkleNode 247 | where 248 | K: AbstractKey, 249 | L: LeafNodeValue, 250 | E: JubjubEngine, 251 | { 252 | pub fn new_leaf_node_with_entry(path: K::Path, key: K, value: L::Value) -> Self { 253 | // let mut leaves = HashMap::new(); 254 | // leaves.insert(key.get_suffix(), value); 255 | let mut info = L::new(); 256 | info.insert(key.get_suffix(), value); 257 | Self::Leaf { 258 | stem: key.get_stem(), 259 | path, 260 | info, 261 | } 262 | } 263 | 264 | pub fn new_internal_node_with_children( 265 | path: K::Path, 266 | children: HashMap>, 267 | ) -> Self { 268 | let num_nonempty_children = children.len(); 269 | Self::Internal { 270 | path, 271 | children, 272 | info: InternalNodeValue { 273 | num_nonempty_children, 274 | commitment: None, 275 | digest: None, 276 | }, 277 | } 278 | } 279 | 280 | pub fn get_path(&self) -> &K::Path { 281 | match self { 282 | Self::Leaf { path, .. } => path, 283 | Self::Internal { path, .. } => path, 284 | } 285 | } 286 | 287 | pub fn is_empty(&self) -> bool { 288 | match self { 289 | Self::Leaf { info, .. } => info.is_empty(), 290 | Self::Internal { info, .. } => info.is_empty(), 291 | } 292 | } 293 | 294 | // pub fn get_commitment(&self) -> Option<&GA> { 295 | // match self { 296 | // Self::Leaf { info, .. } => info.get_commitment(), 297 | // Self::Internal { info, .. } => info.get_commitment(), 298 | // } 299 | // } 300 | 301 | pub fn get_digest(&self) -> Option<&E::Fs> { 302 | match self { 303 | Self::Leaf { info, .. } => info.get_digest(), 304 | Self::Internal { info, .. } => info.get_digest(), 305 | } 306 | } 307 | } 308 | 309 | impl Default for VerkleNode 310 | where 311 | K: AbstractKey, 312 | L: LeafNodeValue, 313 | E: JubjubEngine, 314 | { 315 | fn default() -> Self { 316 | Self::new_internal_node_with_children(K::Path::default(), HashMap::new()) 317 | } 318 | } 319 | 320 | impl VerkleNode 321 | where 322 | P: Default + AbstractPath, 323 | K: AbstractKey, 324 | K::Stem: AbstractStem + IntoFieldElement, 325 | L: LeafNodeValue, 326 | E: JubjubEngine, 327 | { 328 | pub fn insert(&mut self, relative_path: K::Path, key: K, value: L::Value) -> Option { 329 | if relative_path.is_empty() { 330 | panic!("`relative_path` must be non-empty."); 331 | } 332 | 333 | match self { 334 | VerkleNode::Leaf { 335 | stem, path, info, .. 336 | } => { 337 | let stem_relative_path = stem 338 | .to_path() 339 | .remove_prefix(path) 340 | .expect("unreachable code"); 341 | if stem_relative_path.is_empty() { 342 | panic!("`relative_path` must be non-empty."); 343 | } 344 | if key.get_stem().eq(stem) { 345 | return info.insert(key.get_suffix(), value); 346 | } 347 | 348 | // A new branch node has to be inserted. Depending 349 | // on the next branch in both keys, a recursion into 350 | // the moved leaf node can occur. 351 | let (_, next_branch_of_existing_key) = 352 | stem_relative_path.get_next_path_and_branch(); 353 | // assert!(next_branch_of_existing_key < WIDTH); 354 | 355 | let mut new_branch = { 356 | let mut children = HashMap::new(); 357 | let mut new_path = path.clone(); 358 | new_path.push(next_branch_of_existing_key); 359 | let moving_child = VerkleNode::Leaf { 360 | stem: stem.clone(), 361 | path: new_path, 362 | info: info.clone(), 363 | }; 364 | children.insert(next_branch_of_existing_key, moving_child); 365 | 366 | VerkleNode::new_internal_node_with_children(path.clone(), children) 367 | }; 368 | 369 | let (_, next_branch_of_inserting_key) = relative_path.get_next_path_and_branch(); 370 | // assert!(next_branch_of_inserting_key < WIDTH); 371 | 372 | if next_branch_of_inserting_key != next_branch_of_existing_key { 373 | // Next branch differs, so this was the last level. 374 | // Insert it directly into its suffix. 375 | let mut info = L::new(); 376 | info.insert(key.get_suffix(), value); 377 | let mut new_path = path.clone(); 378 | new_path.push(next_branch_of_inserting_key); 379 | let leaf_node = VerkleNode::Leaf { 380 | stem: key.get_stem(), 381 | path: new_path, 382 | info, 383 | }; 384 | 385 | match &mut new_branch { 386 | VerkleNode::Internal { children, info, .. } => { 387 | children.insert(next_branch_of_inserting_key, leaf_node); 388 | info.num_nonempty_children += 1; 389 | } 390 | VerkleNode::Leaf { .. } => { 391 | panic!("unreachable code"); 392 | } 393 | } 394 | let _ = std::mem::replace(self, new_branch); 395 | 396 | return None; 397 | } 398 | 399 | let _ = std::mem::replace(self, new_branch); 400 | 401 | self.insert(relative_path, key, value) 402 | } 403 | VerkleNode::Internal { 404 | path, 405 | children, 406 | info, 407 | .. 408 | } => { 409 | let _ = info.commitment.take(); 410 | let _ = info.digest.take(); 411 | 412 | let (next_relative_path, next_branch_of_inserting_key) = 413 | relative_path.get_next_path_and_branch(); 414 | // assert!(next_branch_of_inserting_key < WIDTH); 415 | 416 | if let Some(child) = children.get_mut(&next_branch_of_inserting_key) { 417 | child.insert(next_relative_path, key, value) 418 | } else { 419 | let mut new_path = path.clone(); 420 | new_path.push(next_branch_of_inserting_key); 421 | children.insert( 422 | next_branch_of_inserting_key, 423 | VerkleNode::new_leaf_node_with_entry(new_path, key, value), 424 | ); 425 | 426 | None 427 | } 428 | } 429 | } 430 | } 431 | 432 | pub fn remove(&mut self, relative_path: K::Path, key: &K) -> Option { 433 | match self { 434 | Self::Leaf { info, .. } => info.remove(&key.borrow().get_suffix()), 435 | Self::Internal { 436 | children, 437 | info: 438 | InternalNodeValue { 439 | commitment, digest, .. 440 | }, 441 | .. 442 | } => { 443 | let _ = commitment.take(); 444 | let _ = digest.take(); 445 | 446 | let (next_path, next_branch) = relative_path.get_next_path_and_branch(); 447 | // assert!(next_branch < WIDTH); 448 | 449 | if let Some(child) = children.get_mut(&next_branch) { 450 | let old_value = child.remove(next_path, key); 451 | 452 | // Remove a empty node if any. 453 | if child.is_empty() { 454 | let _ = children.remove(&next_branch); 455 | } 456 | 457 | old_value 458 | } else { 459 | None 460 | } 461 | } 462 | } 463 | } 464 | 465 | /// Get a value from this tree. 466 | pub fn get(&self, relative_path: K::Path, key: &K) -> Option<&L::Value> { 467 | match &self { 468 | Self::Leaf { stem, info, .. } => { 469 | if key.get_stem() != stem.clone() { 470 | None 471 | } else { 472 | info.get(&key.get_suffix()) 473 | } 474 | } 475 | Self::Internal { children, .. } => { 476 | let (next_path, next_branch) = relative_path.get_next_path_and_branch(); 477 | // assert!(next_branch < WIDTH); 478 | 479 | children 480 | .get(&next_branch) 481 | .and_then(|child| child.get(next_path, key)) 482 | } 483 | } 484 | } 485 | 486 | // Returns witness of the existence or non-existence of 487 | // an entry corresponding to the given key. 488 | // If the entry exists, `witness` is the entry. 489 | // If the entry does not exist, 490 | // `witness` is an entry corresponding "the nearest" key to the given one. 491 | // pub fn get_witness( 492 | // &self, 493 | // relative_path: K::Path, 494 | // key: K, 495 | // ) -> anyhow::Result<(K::Path, L::Value)> { 496 | // match &self { 497 | // Self::Leaf { .. } => { 498 | // todo!(); 499 | // // if key.get_stem() != stem.clone() { 500 | // // todo!(); 501 | // // } 502 | 503 | // // match leaves.get(&key.get_suffix()) { 504 | // // Some(&value) => Ok((key.to_path(), value)), 505 | // // None => { 506 | // // todo!() 507 | // // } 508 | // // } 509 | // } 510 | // Self::Internal { children, .. } => { 511 | // let (next_path, next_branch) = relative_path.get_next_path_and_branch(); 512 | // // assert!(next_branch < WIDTH); 513 | 514 | // if let Some(child) = children.get(&next_branch) { 515 | // child.get_witness(next_path, key) 516 | // } else { 517 | // todo!() 518 | // } 519 | // } 520 | // } 521 | // } 522 | } 523 | 524 | pub fn compute_commitment_of_internal_node>( 525 | committer: &C, 526 | children_digests: Vec, 527 | ) -> anyhow::Result> { 528 | committer 529 | .commit(&children_digests) 530 | .or_else(|_| anyhow::bail!("Fail to make a commitment of given polynomial.")) 531 | } 532 | 533 | impl VerkleNode 534 | where 535 | P: Default + AbstractPath, 536 | K: AbstractKey, 537 | K::Stem: AbstractStem + IntoFieldElement, 538 | L: LeafNodeValue, 539 | E: JubjubEngine, 540 | { 541 | pub fn compute_digest>(&mut self, committer: &C) -> anyhow::Result { 542 | if let Some(d) = self.get_digest() { 543 | return Ok(*d); 544 | } 545 | 546 | match self { 547 | VerkleNode::Leaf { stem, info, .. } => info.compute_digest::(stem, committer), 548 | VerkleNode::Internal { children, info, .. } => { 549 | // TODO: info.compute_digest::(children, committer) 550 | let width = committer.get_domain_size(); 551 | let mut children_digests = vec![E::Fs::zero(); width]; 552 | for (&i, child) in children.iter_mut() { 553 | children_digests[i] = child.compute_digest(committer)?; 554 | } 555 | 556 | let tmp_commitment = 557 | compute_commitment_of_internal_node(committer, children_digests)?; 558 | let tmp_digest = point_to_field_element(&tmp_commitment)?; 559 | 560 | let _ = std::mem::replace(&mut info.commitment, Some(tmp_commitment)); 561 | let _ = std::mem::replace(&mut info.digest, Some(tmp_digest)); 562 | 563 | Ok(tmp_digest) 564 | } 565 | } 566 | } 567 | } 568 | --------------------------------------------------------------------------------