From 175ab763b574d9154fbe05cbc801b9795edcc7a3 Mon Sep 17 00:00:00 2001 From: 0xhhh <52317293+cyl19970726@users.noreply.github.com> Date: Sat, 15 Jun 2024 19:57:35 +0800 Subject: [PATCH 01/25] decouple mmcs (#2) * refactor * decouple mmcs within fri * fix test bug * Reduce the computational effort of testing --------- Co-authored-by: wangyao --- Cargo.lock | 17 +- Cargo.toml | 5 +- fri/Cargo.toml | 5 +- fri/benches/fold_even_odd.rs | 2 +- fri/src/error.rs | 19 +- fri/src/fold_even_odd.rs | 6 +- fri/src/fri_scripts/fiat_shamir_subtree.rs | 32 +- fri/src/fri_scripts/leaf.rs | 186 +------ fri/src/fri_scripts/mod.rs | 4 +- fri/src/fri_scripts/verify_folding.rs | 15 +- fri/src/lib.rs | 6 +- fri/src/proof.rs | 26 +- fri/src/prover.rs | 46 +- fri/src/script_verifier.rs | 33 +- fri/src/verifier.rs | 21 +- primitives/Cargo.toml | 10 +- primitives/src/bit_comm/bc_assign.rs | 3 +- primitives/src/bit_comm/mod.rs | 9 +- primitives/src/challenger/chan_field.rs | 1 - primitives/src/challenger/mod.rs | 10 +- primitives/src/lib.rs | 4 +- primitives/src/mmcs/bf_mmcs.rs | 44 ++ primitives/src/mmcs/error.rs | 18 + primitives/src/mmcs/mod.rs | 8 + primitives/src/mmcs/point.rs | 249 +++++++++ primitives/src/mmcs/tapleaf.rs | 41 ++ primitives/src/mmcs/taptree.rs | 617 +++++++++++++++++++++ primitives/src/mmcs/taptree_mmcs.rs | 94 ++++ scripts/Cargo.toml | 2 +- scripts/src/bit_comm/bit_comm_u32.rs | 12 +- scripts/src/bit_comm/mod.rs | 6 - scripts/src/u31/babybear.rs | 1 - scripts/src/u31/mod.rs | 2 +- scripts/src/u31_ext/mod.rs | 106 ---- segment/Cargo.toml | 10 + segment/src/lib.rs | 16 + 36 files changed, 1241 insertions(+), 445 deletions(-) create mode 100644 primitives/src/mmcs/bf_mmcs.rs create mode 100644 primitives/src/mmcs/error.rs create mode 100644 primitives/src/mmcs/mod.rs create mode 100644 primitives/src/mmcs/point.rs create mode 100644 primitives/src/mmcs/tapleaf.rs create mode 100644 primitives/src/mmcs/taptree.rs create mode 100644 primitives/src/mmcs/taptree_mmcs.rs create mode 100644 segment/Cargo.toml create mode 100644 segment/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 44fe11f..f66cc7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "bitcoin-scriptexec" version = "0.0.0" -source = "git+https://github.com/cyl19970726/rust-bitcoin-scriptexec?rev=09c601e#09c601e9dc48f3ffec795177855677275e3633c7" +source = "git+https://github.com/cyl19970726/rust-bitcoin-scriptexec?rev=205b90c#205b90c19009342bc8e2249bd222cdebe7947342" dependencies = [ "bitcoin", "clap", @@ -411,6 +411,7 @@ dependencies = [ "rand", "rand_chacha", "scripts", + "segment", "serde", "tracing", "tracing-subscriber", @@ -903,13 +904,17 @@ dependencies = [ "lazy_static", "p3-baby-bear", "p3-challenger", + "p3-dft", "p3-field", + "p3-interpolation", + "p3-matrix", "p3-maybe-rayon", "p3-symmetric", "p3-util", "rand", "rand_chacha", "scripts", + "segment", "serde", "tracing", "tracing-subscriber", @@ -1114,6 +1119,16 @@ dependencies = [ "cc", ] +[[package]] +name = "segment" +version = "0.1.0" +dependencies = [ + "bitcoin", + "bitcoin-script", + "bitcoin-scriptexec", + "scripts", +] + [[package]] name = "serde" version = "1.0.203" diff --git a/Cargo.toml b/Cargo.toml index 09fe24e..9d62a1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "fri", "primitives", "p3", - "scripts" -] + "scripts", + "segment" + ] diff --git a/fri/Cargo.toml b/fri/Cargo.toml index ab7aabf..c4e166c 100644 --- a/fri/Cargo.toml +++ b/fri/Cargo.toml @@ -7,8 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] bitcoin-script = { git = "https://github.com/cyl19970726/rust-bitcoin-script", rev = "eda97c5" } bitcoin = { git = "https://github.com/cyl19970726/rust-bitcoin", rev = "ffad6f3" } -bitcoin-scriptexec = { git = "https://github.com/cyl19970726/rust-bitcoin-scriptexec",rev = "09c601e" } - +bitcoin-scriptexec = { git = "https://github.com/cyl19970726/rust-bitcoin-scriptexec",rev = "205b90c"} p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git" } p3-dft = { git = "https://github.com/Plonky3/Plonky3.git" } @@ -28,11 +27,11 @@ rand = "0.8.5" scripts = { path = "../scripts"} primitives = {path = "../primitives"} +segment ={ path = "../segment"} p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } p3-symmetric = { git = "https://github.com/Plonky3/Plonky3.git" } [dev-dependencies] p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } -p3-dft = { git = "https://github.com/Plonky3/Plonky3.git" } p3-goldilocks = { git = "https://github.com/Plonky3/Plonky3.git" } p3-mersenne-31 = { git = "https://github.com/Plonky3/Plonky3.git" } p3-mds = { git = "https://github.com/Plonky3/Plonky3.git" } diff --git a/fri/benches/fold_even_odd.rs b/fri/benches/fold_even_odd.rs index d17f4fd..e8ffd4f 100644 --- a/fri/benches/fold_even_odd.rs +++ b/fri/benches/fold_even_odd.rs @@ -1,7 +1,7 @@ use std::any::type_name; -use fri::fold_even_odd; use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; +use fri::fold_even_odd; use itertools::Itertools; use p3_baby_bear::BabyBear; use p3_field::extension::Complex; diff --git a/fri/src/error.rs b/fri/src/error.rs index d4d95a6..858c84c 100644 --- a/fri/src/error.rs +++ b/fri/src/error.rs @@ -1,16 +1,5 @@ use bitcoin::taproot::TaprootBuilderError; -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum BfError { - TaprootBuilderError(TaprootBuilderError), - TaprootError, - TapLeafError, - TapTreeError, - EvaluationLeafError, - ExecuteScriptError, - InvalidMerkleProof, - IndexWithEmptyLeaf(u32, u32), -} - +use primitives::mmcs::error::BfError; #[derive(Debug, PartialEq, Eq, Clone)] pub enum SVError { VerifyCalNegXScriptError, @@ -23,12 +12,6 @@ pub enum SVError { InvalidWitness, } -impl From for BfError { - fn from(error: TaprootBuilderError) -> Self { - BfError::TaprootBuilderError(error) - } -} - impl From for FriError { fn from(error: BfError) -> Self { FriError::::BFError(error) diff --git a/fri/src/fold_even_odd.rs b/fri/src/fold_even_odd.rs index e776a96..ecd1117 100644 --- a/fri/src/fold_even_odd.rs +++ b/fri/src/fold_even_odd.rs @@ -54,17 +54,17 @@ pub fn fold_even_odd(poly: Vec, beta: F) -> Vec { #[cfg(test)] mod tests { - use crate::fri_scripts::verify_folding::fold_degree; - use scripts::{execute_script, ext_fold_degree1, BabyBear4}; - use primitives::field::BfField; use itertools::izip; use p3_baby_bear::BabyBear; use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; use p3_field::extension::BinomialExtensionField; use p3_field::AbstractExtensionField; + use primitives::field::BfField; use rand::{thread_rng, Rng}; + use scripts::execute_script; use super::*; + use crate::fri_scripts::verify_folding::fold_degree; #[test] fn test_fold_even_odd() { diff --git a/fri/src/fri_scripts/fiat_shamir_subtree.rs b/fri/src/fri_scripts/fiat_shamir_subtree.rs index 6b75279..e826389 100644 --- a/fri/src/fri_scripts/fiat_shamir_subtree.rs +++ b/fri/src/fri_scripts/fiat_shamir_subtree.rs @@ -9,19 +9,16 @@ use bitcoin::script::{self, scriptint_vec}; use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; use itertools::Itertools; -use primitives::challenger::{BfChallenger, BitExtractor, Blake3Permutation}; -use primitives::challenger::chan_field::{PermutationField, U32}; use p3_field::PrimeField32; - +use primitives::bit_comm::{BCAssignment, BitCommitment}; +use primitives::challenger::chan_field::{PermutationField, U32}; +use primitives::challenger::{BfChallenger, BitExtractor, Blake3Permutation}; +use primitives::field::BfField; use scripts::bit_comm_u32::*; -use primitives::bit_comm::BitCommitment; -use scripts::blake3; use scripts::pseudo::{OP_4DROP, OP_4FROMALTSTACK, OP_4TOALTSTACK}; use scripts::u32_rrot::{u32_rrot, u8_extract_hbit}; use scripts::u32_std::{u32_compress, u32_equal, u32_equalverify, u32_push}; -use primitives::bit_comm::BCAssignment; -use primitives::field::BfField; -use scripts::BabyBearU31; +use scripts::{blake3, BabyBearU31}; /// fiat shamir subtree contains a series script leafs and coressponding trait SubTree { @@ -409,20 +406,17 @@ mod test { use bitcoin_script::{define_pushable, script}; use itertools::Itertools; use p3_baby_bear::BabyBear; - use p3_challenger::{ - CanObserve, CanSample, CanSampleBits, - }; - use primitives::challenger::{BfChallenger, BfGrindingChallenger, Blake3Permutation}; + use p3_challenger::{CanObserve, CanSample, CanSampleBits}; use p3_field::extension::BinomialExtensionField; - use p3_field::{AbstractField, PrimeField32, }; - use primitives::challenger::chan_field::{PermutationField,U32}; - - use super::{new_u32_bit_commit, Commit, FiatShamirSubTree, SubTree}; - use scripts::bit_comm::pushable; - use super::new_challenge_commit; + use p3_field::{AbstractField, PrimeField32}; use primitives::bit_comm::BCAssignment; + use primitives::challenger::chan_field::{PermutationField, U32}; + use primitives::challenger::{BfChallenger, BfGrindingChallenger, Blake3Permutation}; + use scripts::bit_comm::pushable; use scripts::{execute_script, execute_script_with_inputs, to_digits, BabyBear4}; - + + use super::{new_challenge_commit, new_u32_bit_commit, Commit, FiatShamirSubTree, SubTree}; + fn verify_u32_4bytes_script(value: u32) -> Script { let message = to_digits(value, 8); let mut commit_message = vec![0u8; 8 / 2]; diff --git a/fri/src/fri_scripts/leaf.rs b/fri/src/fri_scripts/leaf.rs index b82ccf7..e53e1e2 100644 --- a/fri/src/fri_scripts/leaf.rs +++ b/fri/src/fri_scripts/leaf.rs @@ -11,38 +11,22 @@ use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; use itertools::rev; use p3_field::TwoAdicField; - -use primitives::bit_comm::*; - -use primitives::{bit_comm::BitCommitment, field::BfField}; -use primitives::bit_comm::BCAssignment; +use primitives::bit_comm::{BCAssignment, BitCommitment, *}; +use primitives::field::BfField; +use scripts::bit_comm::winternitz; use scripts::bit_comm_u32::BitCommitmentU32; -use super::verify_folding::cal_neg_x_with_input; -use scripts::{u31_add, u31_equalverify}; -use super::verify_folding::{fold_degree,fold_degree_with_input,index_to_rou,reverse_bits_len_script_with_input,value_square_with_input}; use scripts::{ - execute_script, execute_script_with_inputs, - u31ext_add, u31ext_equalverify, - BabyBear4, BabyBearU31,bit_comm::winternitz + execute_script, execute_script_with_inputs, u31_add, u31_equalverify, u31ext_add, + u31ext_equalverify, BabyBear4, BabyBearU31, }; +use segment::SegmentLeaf; -define_pushable!(); - -pub trait SegmentLeaf { - fn input(&self) -> Vec>; - fn check_input(&self) -> Script; - fn leaf_script(&self) -> Script; - - fn execute_leaf_script(&self) -> bool { - let result = execute_script_with_inputs(self.leaf_script(), self.input()); - result.success - } - - fn leaf_script_witn_noeuqal(&self) -> Script { - self.leaf_script() - } -} +use super::verify_folding::{ + cal_neg_x_with_input, fold_degree, fold_degree_with_input, index_to_rou, + reverse_bits_len_script_with_input, value_square_with_input, +}; +define_pushable!(); pub struct RevIndexLeaf { sub_group_bits: u32, index: u32, @@ -476,75 +460,6 @@ impl<'a, const NUM_POLY: usize, F: BfField> SegmentLeaf for VerifyFoldingLeaf { - leaf_index: usize, - x: F, - x_commitment: BitCommitment, - neg_x_commitment: BitCommitment, - evaluations: Vec, - evaluations_commitments: Vec>, -} - -impl EvaluationLeaf { - pub fn new(leaf_index: usize, x: F, evaluations: Vec) -> Self { - assert_eq!(evaluations.len(), NUM_POLY); - - let x_commitment = BitCommitment::new("b138982ce17ac813d505b5b40b665d404e9528e8", x); - let neg_x_commitment = BitCommitment::new( - "b138982ce17ac813d505b5b40b665d404e9528e8", - F::field_mod() - x, - ); - let mut evaluations_commitments = Vec::new(); - for i in 0..NUM_POLY { - evaluations_commitments.push(BitCommitment::new( - "b138982ce17ac813d505b5b40b665d404e9528e9", - evaluations[i], - )); - } - - Self { - leaf_index, - x, - x_commitment, - neg_x_commitment, - evaluations, - evaluations_commitments, - } - } - - pub fn leaf_script(&self) -> Script { - // equal to x script - let scripts = script! { - { self.x_commitment.commitments[0].checksig_verify_script() } - { self.x_commitment.commitments[0].commit_u32_as_4bytes_script() } - // todo: calculate to equal to -x - for i in 0..NUM_POLY{ - { self.evaluations_commitments[NUM_POLY-1-i].commitments[0].checksig_verify_script() } - { self.evaluations_commitments[NUM_POLY-1-i].commitments[0].commit_u32_as_4bytes_script() } - } - OP_1 - }; - - scripts - } - - pub fn two_point_leaf_script(&self) -> Script { - // equal to x script - let scripts = script! { - { self.x_commitment.commitments[0].checksig_verify_script() } - { self.x_commitment.commitments[0].commit_u32_as_4bytes_script() } - { self.neg_x_commitment.commitments[0].checksig_verify_script() } - { self.neg_x_commitment.commitments[0].commit_u32_as_4bytes_script() } - for i in 0..NUM_POLY{ - { self.evaluations_commitments[NUM_POLY-1-i].commitments[0].checksig_verify_script() } - { self.evaluations_commitments[NUM_POLY-1-i].commitments[0].commit_u32_as_4bytes_script() } - } - OP_1 - }; - scripts - } -} - pub fn u8_to_hex_str(byte: &u8) -> String { format!("{:02X}", byte) } @@ -556,13 +471,15 @@ mod test { use p3_field::extension::BinomialExtensionField; use p3_field::AbstractField; use p3_util::reverse_bits_len; + use primitives::mmcs::taptree::EvaluationLeaf; use rand::Rng; type AF = BabyBear; type F = BinomialExtensionField; - use super::*; use scripts::execute_script_with_inputs; + use super::*; + #[test] fn test_rev_index_leaf() { let mut assign = BCAssignment::new(); @@ -778,81 +695,6 @@ mod test { } } - #[test] - fn test_check_x_neg_x_equal_script() { - const num_polys: usize = 1; - let x = BabyBear::from_u32(0x11654321); - let neg_x = BabyBear::field_mod() - x; // 669ABCE0 - let expect_neg_x = BabyBear::from_u32(0x669ABCE0); - assert_eq!(neg_x, expect_neg_x); - let leaf = - EvaluationLeaf::::new(0, x, vec![BabyBear::from_u32(0x11654321)]); - - // check signature and verify the value - let signature = leaf.x_commitment.commitments[0].signature(); - // check equal to r - let exec_scripts = script! { - { leaf.x_commitment.commitments[0].checksig_verify_script() } - { leaf.x_commitment.commitments[0].check_equal_x_or_neg_x_script(&leaf.neg_x_commitment.commitments[0]) } - OP_1 - }; - let exec_result = execute_script_with_inputs(exec_scripts, signature); - assert!(exec_result.success); - - // check equal to -r - let signature = leaf.x_commitment.commitments[0].signature(); - let exec_scripts = script! { - { leaf.x_commitment.commitments[0].checksig_verify_script() } - { leaf.neg_x_commitment.commitments[0].check_equal_x_or_neg_x_script(&leaf.x_commitment.commitments[0]) } - OP_1 - }; - let exec_result = execute_script_with_inputs(exec_scripts, signature); - assert!(exec_result.success); - - for _ in 0..30 { - let mut rng = rand::thread_rng(); - let random_number: u32 = rng.gen(); - let x = random_number % BabyBear::MOD; - let x = BabyBear::from_u32(x); - let neg_x = BabyBear::field_mod() - x; - let leaf = EvaluationLeaf::::new( - 0, - x, - vec![BabyBear::from_u32(0x11654321)], - ); - - // check signature and verify the value - let signature = leaf.x_commitment.commitments[0].signature(); - // check equal to r - let exec_scripts = script! { - { leaf.x_commitment.commitments[0].checksig_verify_script() } - { leaf.x_commitment.commitments[0].check_equal_x_or_neg_x_script(&leaf.neg_x_commitment.commitments[0]) } - OP_1 - }; - let exec_result = execute_script_with_inputs(exec_scripts, signature); - assert!(exec_result.success); - - // check equal to -r - let signature = leaf.x_commitment.commitments[0].signature(); - let exec_scripts = script! { - { leaf.x_commitment.commitments[0].checksig_verify_script() } - { leaf.neg_x_commitment.commitments[0].check_equal_x_or_neg_x_script(&leaf.x_commitment.commitments[0]) } - OP_1 - }; - let exec_result = execute_script_with_inputs(exec_scripts, signature); - assert!(exec_result.success); - - let signature = leaf.neg_x_commitment.commitments[0].signature(); - let exec_scripts = script! { - { leaf.neg_x_commitment.commitments[0].checksig_verify_script() } - { leaf.x_commitment.commitments[0].check_equal_x_or_neg_x_script(&leaf.neg_x_commitment.commitments[0]) } - OP_1 - }; - let exec_result = execute_script_with_inputs(exec_scripts, signature); - assert!(exec_result.success); - } - } - #[test] fn test_push_bytes() { let scripts1 = script! { diff --git a/fri/src/fri_scripts/mod.rs b/fri/src/fri_scripts/mod.rs index bb7def3..da09dd1 100644 --- a/fri/src/fri_scripts/mod.rs +++ b/fri/src/fri_scripts/mod.rs @@ -1,5 +1,3 @@ - pub mod fiat_shamir_subtree; pub mod leaf; -pub mod point; -pub mod verify_folding; \ No newline at end of file +pub mod verify_folding; diff --git a/fri/src/fri_scripts/verify_folding.rs b/fri/src/fri_scripts/verify_folding.rs index 1e28d6a..3f397e3 100644 --- a/fri/src/fri_scripts/verify_folding.rs +++ b/fri/src/fri_scripts/verify_folding.rs @@ -5,21 +5,19 @@ use bitcoin::opcodes::{ use bitcoin::secp256k1::ellswift; use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; +use p3_baby_bear::BabyBear; use p3_field::{AbstractField, TwoAdicField}; use p3_util::{log2_ceil_u64, log2_ceil_usize, log2_strict_usize, reverse_bits_len}; - -use p3_baby_bear::BabyBear; +use primitives::field::BfField; use scripts::pseudo::{ OP_4DUP, OP_4FROMALTSTACK, OP_4MUL, OP_4PICK, OP_4ROLL, OP_4TOALTSTACK, OP_NDUP, }; -use scripts::{BabyBearU31, U31Config}; use scripts::u32_rrot::u8_extract_hbit; use scripts::u32_std::{u32_compress, u32_push}; use scripts::{ u31_add, u31_double, u31_equalverify, u31_mul, u31_sub, u31ext_add, u31ext_double, - u31ext_equalverify, u31ext_mul, u31ext_sub, BabyBear4, + u31ext_equalverify, u31ext_mul, u31ext_sub, BabyBear4, BabyBearU31, U31Config, }; -use primitives::field::BfField; define_pushable!(); @@ -296,9 +294,10 @@ mod tests { use rand::{random, Rng}; type AF = BabyBear; type F = BinomialExtensionField; - use super::*; use scripts::{execute_script, execute_script_with_inputs}; + use super::*; + #[test] fn test_get_generator() { for i in 0..27 { @@ -1042,12 +1041,12 @@ mod tests2 { use bitcoin::opcodes::{OP_DROP, OP_EQUAL, OP_EQUALVERIFY, OP_FROMALTSTACK, OP_TOALTSTACK}; use bitcoin::Script; use p3_baby_bear::BabyBear; + use primitives::field::BfField; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; + use scripts::execute_script; use super::*; - use scripts::{execute_script}; - use primitives::field::BfField; #[test] fn test_op4_op() { diff --git a/fri/src/lib.rs b/fri/src/lib.rs index 559e1ed..eed31ea 100644 --- a/fri/src/lib.rs +++ b/fri/src/lib.rs @@ -3,19 +3,15 @@ extern crate alloc; mod config; +pub mod error; mod fold_even_odd; -pub mod mmcs; mod proof; pub mod prover; -// mod two_adic_pcs; -pub mod error; pub mod script_verifier; pub mod verifier; pub use config::*; pub use fold_even_odd::*; -pub use mmcs::*; pub use proof::*; pub use script_verifier::*; pub mod fri_scripts; -// pub use two_adic_pcs::*; diff --git a/fri/src/proof.rs b/fri/src/proof.rs index 8bf0430..0c2b025 100644 --- a/fri/src/proof.rs +++ b/fri/src/proof.rs @@ -1,12 +1,11 @@ use alloc::vec::Vec; -use crate::fri_scripts::point::PointsLeaf; -use primitives::field::BfField; use bitcoin::taproot::LeafNode; - +use primitives::field::BfField; // use serde::{Deserialize, Serialize}; -use crate::bf_mmcs::BFMmcs; - +use primitives::mmcs::bf_mmcs::BFMmcs; +use primitives::mmcs::point::PointsLeaf; +use primitives::mmcs::taptree_mmcs::CommitProof; // #[derive(Serialize, Deserialize)] // #[serde(bound( // serialize = "Witness: Serialize", @@ -26,22 +25,7 @@ pub struct FriProof, Witness> { pub struct BfQueryProof { /// For each commit phase commitment, this contains openings of a commit phase codeword at the /// queried location, along with an opening proof. - pub(crate) commit_phase_openings: Vec>, -} - -// #[derive(Serialize, Deserialize, Clone)] -#[derive(Clone)] -// #[serde(bound(serialize = "F: Serialize"))] -// #[serde(bound = "")] -pub struct BfCommitPhaseProofStep { - /// The opening of the commit phase codeword at the sibling location. - // This may change to Vec if the library is generalized to support other FRI - // folding arities besides 2, meaning that there can be multiple siblings. - pub(crate) points_leaf: PointsLeaf, - // pub(crate) leaf_node: TapLeaf, - - // pub(crate) merkle_branch: TaprootMerkleBranch, - pub leaf_node: LeafNode, + pub(crate) commit_phase_openings: Vec>, } pub fn get_leaf_index_by_query_index(query_index: usize) -> (usize, usize, usize) { diff --git a/fri/src/prover.rs b/fri/src/prover.rs index 1faaaf1..6503f7c 100644 --- a/fri/src/prover.rs +++ b/fri/src/prover.rs @@ -1,19 +1,20 @@ use alloc::vec; use alloc::vec::Vec; -use primitives::field::BfField; use itertools::Itertools; -use primitives::challenger::BfGrindingChallenger; -use p3_challenger::{ CanObserve, CanSample}; +use p3_challenger::{CanObserve, CanSample}; use p3_field::TwoAdicField; use p3_matrix::dense::RowMajorMatrix; +use primitives::challenger::BfGrindingChallenger; +use primitives::field::BfField; +use primitives::mmcs::bf_mmcs::BFMmcs; +use primitives::mmcs::taptree_mmcs::{CommitProof, DEFAULT_MATRIX_WIDTH}; use tracing::{info_span, instrument}; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; -use crate::bf_mmcs::BFMmcs; use crate::fold_even_odd::fold_even_odd; -use crate::{BfCommitPhaseProofStep, BfQueryProof, FriConfig, FriProof}; +use crate::{BfQueryProof, FriConfig, FriProof}; #[instrument(name = "FRI prover", skip_all)] pub fn bf_prove( @@ -23,7 +24,7 @@ pub fn bf_prove( ) -> (FriProof, Vec) where F: BfField, - M: BFMmcs>, + M: BFMmcs>, Challenger: BfGrindingChallenger + CanObserve + CanSample, { // 1. rposition start iterator from the end and calculate the valid leagth of the polynomial want commit @@ -62,7 +63,7 @@ fn bf_answer_query( ) -> BfQueryProof where F: BfField, - M: BFMmcs>, + M: BFMmcs>, { let commit_phase_openings = commit_phase_commits .iter() @@ -79,9 +80,6 @@ where commit_phase_openings, } } -// Commit two adjacent points to a leaf node -pub const DEFAULT_MATRIX_WIDTH: usize = 2; -pub const LOG_DEFAULT_MATRIX_WIDTH: usize = 1; #[instrument(name = "commit phase", skip_all)] fn bf_commit_phase( @@ -138,26 +136,26 @@ struct CommitPhaseResult> { #[cfg(test)] mod tests { - use primitives::bit_comm::BCAssignment; - use p3_baby_bear::BabyBear; use itertools::Itertools; - use primitives::challenger::{BfChallenger, Blake3Permutation,chan_field::U32}; + use p3_baby_bear::BabyBear; use p3_challenger::CanSampleBits; use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; use p3_field::extension::BinomialExtensionField; - use p3_field::{AbstractField}; + use p3_field::AbstractField; use p3_matrix::util::reverse_matrix_index_bits; use p3_matrix::Matrix; use p3_symmetric::{CryptographicPermutation, Permutation}; use p3_util::log2_strict_usize; + use primitives::bit_comm::BCAssignment; + use primitives::challenger::chan_field::U32; + use primitives::challenger::{BfChallenger, Blake3Permutation}; + use primitives::mmcs::taptree_mmcs::TapTreeMmcs; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; use tracing_subscriber::fmt; use super::*; - use crate::mmcs::taptree_mmcs::ROOT_WIDTH; use crate::script_verifier::bf_verify_challenges; - use crate::taptree_mmcs::TapTreeMmcs; use crate::verifier; type PF = U32; @@ -293,7 +291,7 @@ mod tests { let shift = Val::generator(); let mut rng = ChaCha20Rng::seed_from_u64(0); - let ldes: Vec> = (1..10) + let ldes: Vec> = (4..5) .map(|deg_bits| { let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); let mut lde = dft.coset_lde_batch(evals, 1, shift); @@ -460,25 +458,25 @@ mod tests { #[cfg(test)] mod tests2 { - use primitives::bit_comm::BCAssignment; - use p3_baby_bear::BabyBear; use itertools::Itertools; - use primitives::challenger::{BfChallenger, Blake3Permutation,chan_field::U32}; + use p3_baby_bear::BabyBear; use p3_challenger::CanSampleBits; use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; use p3_field::extension::BinomialExtensionField; - use p3_field::{AbstractField}; + use p3_field::AbstractField; use p3_matrix::util::reverse_matrix_index_bits; use p3_matrix::Matrix; use p3_symmetric::{CryptographicPermutation, Permutation}; use p3_util::log2_strict_usize; + use primitives::bit_comm::BCAssignment; + use primitives::challenger::chan_field::U32; + use primitives::challenger::{BfChallenger, Blake3Permutation}; + use primitives::mmcs::taptree_mmcs::{TapTreeMmcs, ROOT_WIDTH}; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; use tracing_subscriber::fmt; use super::*; - use crate::mmcs::taptree_mmcs::ROOT_WIDTH; - use crate::taptree_mmcs::TapTreeMmcs; use crate::{bf_verify_challenges, verifier}; type PF = U32; @@ -614,7 +612,7 @@ mod tests2 { let shift = Val::generator(); let mut rng = ChaCha20Rng::seed_from_u64(0); - let ldes: Vec> = (10..17) + let ldes: Vec> = (2..3) .map(|deg_bits| { let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); let mut lde = dft.coset_lde_batch(evals, 1, shift); diff --git a/fri/src/script_verifier.rs b/fri/src/script_verifier.rs index e658a18..cc0173b 100644 --- a/fri/src/script_verifier.rs +++ b/fri/src/script_verifier.rs @@ -2,24 +2,25 @@ use alloc::vec; use alloc::vec::Vec; use core::panic; -use scripts::{ - execute_script_with_inputs -}; -use crate::fri_scripts::leaf::{CalNegXLeaf, IndexToROULeaf,SegmentLeaf,SquareFLeaf,ReductionLeaf, RevIndexLeaf, VerifyFoldingLeaf }; -use crate::fri_scripts::point::{ Point, - PointsLeaf}; -use primitives::bit_comm::BCAssignment; -use primitives::field::BfField; use bitcoin::taproot::TapLeaf; use itertools::izip; -use primitives::challenger::{BfGrindingChallenger}; -use p3_challenger::{ CanObserve, CanSample}; +use p3_challenger::{CanObserve, CanSample}; use p3_util::reverse_bits_len; - -use crate::bf_mmcs::BFMmcs; -use crate::error::{BfError, FriError, SVError}; +use primitives::bit_comm::BCAssignment; +use primitives::challenger::BfGrindingChallenger; +use primitives::field::BfField; +use primitives::mmcs::bf_mmcs::BFMmcs; +use primitives::mmcs::point::{Point, PointsLeaf}; +use primitives::mmcs::taptree_mmcs::CommitProof; +use scripts::execute_script_with_inputs; +use segment::SegmentLeaf; + +use crate::error::{FriError, SVError}; +use crate::fri_scripts::leaf::{ + CalNegXLeaf, IndexToROULeaf, ReductionLeaf, RevIndexLeaf, SquareFLeaf, VerifyFoldingLeaf, +}; use crate::verifier::*; -use crate::{BfCommitPhaseProofStep, BfQueryProof, FriConfig, FriProof}; +use crate::{BfQueryProof, FriConfig, FriProof}; pub fn bf_verify_challenges( assign: &mut BCAssignment, @@ -30,7 +31,7 @@ pub fn bf_verify_challenges( ) -> Result<(), FriError> where F: BfField, - M: BFMmcs>, + M: BFMmcs>, { let log_max_height = proof.commit_phase_commits.len() + config.log_blowup; for (&index, query_proof, ro) in izip!( @@ -69,7 +70,7 @@ fn bf_verify_query( ) -> Result> where F: BfField, - M: BFMmcs>, + M: BFMmcs>, { let mut folded_eval = F::zero(); diff --git a/fri/src/verifier.rs b/fri/src/verifier.rs index 9d07145..1b3ce07 100644 --- a/fri/src/verifier.rs +++ b/fri/src/verifier.rs @@ -1,19 +1,20 @@ use alloc::vec; use alloc::vec::Vec; -use scripts::{execute_script_with_inputs}; -use crate::fri_scripts::point::{Point, PointsLeaf}; -use primitives::field::{BfField}; use bitcoin::taproot::TapLeaf; use bitcoin::Script; use itertools::izip; -use primitives::challenger::BfGrindingChallenger; use p3_challenger::{CanObserve, CanSample}; use p3_util::reverse_bits_len; +use primitives::challenger::BfGrindingChallenger; +use primitives::field::BfField; +use primitives::mmcs::bf_mmcs::BFMmcs; +use primitives::mmcs::point::{Point, PointsLeaf}; +use primitives::mmcs::taptree_mmcs::CommitProof; +use scripts::execute_script_with_inputs; -use crate::bf_mmcs::BFMmcs; -use crate::error::{BfError, FriError}; -use crate::{BfCommitPhaseProofStep, BfQueryProof, FriConfig, FriProof}; +use crate::error::FriError; +use crate::{BfQueryProof, FriConfig, FriProof}; #[derive(Debug)] pub struct FriChallenges { @@ -28,7 +29,7 @@ pub fn verify_shape_and_sample_challenges( ) -> Result, FriError> where F: BfField, - M: BFMmcs>, + M: BFMmcs>, Challenger: BfGrindingChallenger + CanObserve + CanSample, { let betas: Vec = proof @@ -69,7 +70,7 @@ pub fn verify_challenges( ) -> Result<(), FriError> where F: BfField, - M: BFMmcs>, + M: BFMmcs>, { let log_max_height = proof.commit_phase_commits.len() + config.log_blowup; for (&index, query_proof, ro) in izip!( @@ -106,7 +107,7 @@ fn verify_query( ) -> Result> where F: BfField, - M: BFMmcs>, + M: BFMmcs>, { let mut folded_eval = F::zero(); diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 313a142..1945526 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] bitcoin-script = { git = "https://github.com/cyl19970726/rust-bitcoin-script", rev = "eda97c5" } bitcoin = { git = "https://github.com/cyl19970726/rust-bitcoin", rev = "ffad6f3" } -bitcoin-scriptexec = { git = "https://github.com/cyl19970726/rust-bitcoin-scriptexec",rev = "09c601e" } +bitcoin-scriptexec = { git = "https://github.com/cyl19970726/rust-bitcoin-scriptexec",rev = "205b90c"} lazy_static = "1.4.0" itertools = "0.12.0" tracing = "0.1.37" @@ -23,5 +23,11 @@ p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git" } p3-util = { git = "https://github.com/Plonky3/Plonky3.git" } p3-maybe-rayon ={ git = "https://github.com/Plonky3/Plonky3.git" } +p3-matrix = { git = "https://github.com/Plonky3/Plonky3.git" } -scripts ={ path = "../scripts" } \ No newline at end of file +scripts ={ path = "../scripts" } +segment ={ path = "../segment" } + +[dev-dependencies] +p3-interpolation = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-dft = { git = "https://github.com/Plonky3/Plonky3.git" } diff --git a/primitives/src/bit_comm/bc_assign.rs b/primitives/src/bit_comm/bc_assign.rs index ff9d4e6..6acf35a 100644 --- a/primitives/src/bit_comm/bc_assign.rs +++ b/primitives/src/bit_comm/bc_assign.rs @@ -1,9 +1,8 @@ use std::collections::HashMap; use itertools::Itertools; - -use super::BitCommitment; use scripts::bit_comm_u32::BitCommitmentU32; +use super::BitCommitment; use crate::field::BfField; #[derive(Debug, Clone, Default, PartialEq, Eq)] diff --git a/primitives/src/bit_comm/mod.rs b/primitives/src/bit_comm/mod.rs index 6e470b3..0513b73 100644 --- a/primitives/src/bit_comm/mod.rs +++ b/primitives/src/bit_comm/mod.rs @@ -1,14 +1,13 @@ pub mod bc_assign; pub use bc_assign::*; - use bitcoin::opcodes::OP_EQUALVERIFY; use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; use itertools::Itertools; - use scripts::bit_comm_u32::*; -use crate::field::*; use scripts::{u31_equalverify, u31ext_equalverify, BabyBear4}; + +use crate::field::*; define_pushable!(); #[derive(Clone, Debug, Default, PartialEq, Eq)] @@ -130,13 +129,13 @@ mod test { use p3_field::{AbstractExtensionField, AbstractField, PrimeField32}; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; - - use super::*; use scripts::{ execute_script, execute_script_with_inputs, u31ext_add, u31ext_double, u31ext_equalverify, BabyBear4, }; + use super::*; + type F = BabyBear; type EF = p3_field::extension::BinomialExtensionField; diff --git a/primitives/src/challenger/chan_field.rs b/primitives/src/challenger/chan_field.rs index 39aff6c..68a999d 100644 --- a/primitives/src/challenger/chan_field.rs +++ b/primitives/src/challenger/chan_field.rs @@ -1,4 +1,3 @@ - use core::array; use p3_baby_bear::BabyBear; diff --git a/primitives/src/challenger/mod.rs b/primitives/src/challenger/mod.rs index 8d5be76..29a4cd4 100644 --- a/primitives/src/challenger/mod.rs +++ b/primitives/src/challenger/mod.rs @@ -1,23 +1,21 @@ - use core::array; use core::marker::PhantomData; use std::any::{Any, TypeId}; use bitcoin::hashes::serde::Serializer; +use chan_field::{ChallengeField, PermutationField, U32}; use p3_baby_bear::BabyBear; +use p3_challenger::{CanObserve, CanSample, CanSampleBits}; use p3_field::extension::BinomialExtensionField; use p3_field::{ - AbstractExtensionField, AbstractField,ExtensionField, Field, PackedValue, - PrimeField, PrimeField32, + AbstractExtensionField, AbstractField, ExtensionField, Field, PackedValue, PrimeField, + PrimeField32, }; -use chan_field::{PermutationField,ChallengeField,U32}; use p3_maybe_rayon::prelude::*; use p3_symmetric::{CryptographicPermutation, Hash, Permutation}; use tracing; use tracing::instrument; -use p3_challenger::{CanObserve, CanSample, CanSampleBits}; - pub mod chan_field; /// A challenger that operates natively on PF but produces challenges of F: Field + BitExtractor,. diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index d6649b8..cda6fb5 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -1,4 +1,4 @@ - +pub mod bit_comm; pub mod challenger; pub mod field; -pub mod bit_comm; \ No newline at end of file +pub mod mmcs; diff --git a/primitives/src/mmcs/bf_mmcs.rs b/primitives/src/mmcs/bf_mmcs.rs new file mode 100644 index 0000000..af32757 --- /dev/null +++ b/primitives/src/mmcs/bf_mmcs.rs @@ -0,0 +1,44 @@ +// use alloc::vec; +// use alloc::vec::Vec; +use core::fmt::Debug; + +use p3_matrix::dense::RowMajorMatrix; +// use serde::de::DeserializeOwned; +// use serde::Serialize; + +/// A "Mixed Matrix Commitment Scheme" (MMCS) is a generalization of a vector commitment scheme; it +/// supports committing to matrices and then opening rows. It is also batch-oriented; one can commit +/// to a batch of matrices at once even if their widths and heights differ. +/// +/// When a particular row index is opened, it is interpreted directly as a row index for matrices +/// with the largest height. For matrices with smaller heights, some bits of the row index are +/// removed (from the least-significant side) to get the effective row index. These semantics are +/// useful in the FRI protocol. See the documentation for `open_batch` for more details. +pub trait BFMmcs: Clone { + type ProverData; + // type Commitment: Clone + Serialize + DeserializeOwned; + // type Proof: Clone + Serialize + DeserializeOwned; + type Commitment: Clone; + type Proof: Clone; + type Error: Debug; + + fn commit(&self, inputs: Vec>) -> (Self::Commitment, Self::ProverData); + + fn commit_matrix(&self, input: RowMajorMatrix) -> (Self::Commitment, Self::ProverData) { + self.commit(vec![input]) + } + + fn commit_vec(&self, input: Vec) -> (Self::Commitment, Self::ProverData) + where + T: Clone + Send + Sync, + { + self.commit_matrix(RowMajorMatrix::new_col(input)) + } + + fn open_taptree(&self, index: usize, prover_data: &Self::ProverData) -> Self::Proof; + fn verify_taptree( + &self, + proof: &Self::Proof, + root: &Self::Commitment, + ) -> Result<(), Self::Error>; +} diff --git a/primitives/src/mmcs/error.rs b/primitives/src/mmcs/error.rs new file mode 100644 index 0000000..ff2c0b1 --- /dev/null +++ b/primitives/src/mmcs/error.rs @@ -0,0 +1,18 @@ +use bitcoin::taproot::TaprootBuilderError; +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum BfError { + TaprootBuilderError(TaprootBuilderError), + TaprootError, + TapLeafError, + TapTreeError, + EvaluationLeafError, + ExecuteScriptError, + InvalidMerkleProof, + IndexWithEmptyLeaf(u32, u32), +} + +impl From for BfError { + fn from(error: TaprootBuilderError) -> Self { + BfError::TaprootBuilderError(error) + } +} diff --git a/primitives/src/mmcs/mod.rs b/primitives/src/mmcs/mod.rs new file mode 100644 index 0000000..3579e4f --- /dev/null +++ b/primitives/src/mmcs/mod.rs @@ -0,0 +1,8 @@ +#![feature(slice_pattern)] + +pub mod bf_mmcs; +pub mod error; +pub mod point; +pub mod tapleaf; +pub mod taptree; +pub mod taptree_mmcs; diff --git a/primitives/src/mmcs/point.rs b/primitives/src/mmcs/point.rs new file mode 100644 index 0000000..81905b7 --- /dev/null +++ b/primitives/src/mmcs/point.rs @@ -0,0 +1,249 @@ +use std::usize; + +use bitcoin::ScriptBuf as Script; +use bitcoin_script::{define_pushable, script}; + +use crate::bit_comm::{BCAssignment, BitCommitment}; +use crate::field::BfField; +define_pushable!(); + +#[derive(Debug, Clone)] +pub struct PointsLeaf { + leaf_index_1: usize, + leaf_index_2: usize, + points: Points, +} + +impl PointsLeaf { + pub fn new( + leaf_index_1: usize, + leaf_index_2: usize, + x: F, + y: F, + x2: F, + y2: F, + ) -> PointsLeaf { + let points = Points::::new(x, y, x2, y2); + Self { + leaf_index_1, + leaf_index_2, + points, + } + } + + pub fn recover_points_euqal_to_commited_point(&self) -> Script { + let scripts = script! { + {self.points.p1.recover_point_euqal_to_commited_point()} + {self.points.p2.recover_point_euqal_to_commited_point()} + OP_1 + }; + scripts + } + + pub fn signature(&self) -> Vec> { + let mut p1_sigs = self.points.p1.signature(); + let mut p2_sigs = self.points.p2.signature(); + p2_sigs.append(p1_sigs.as_mut()); + p2_sigs + } + + pub fn get_point_by_index(&self, index: usize) -> Option<&Point> { + if index == self.leaf_index_1 { + Some(&self.points.p1) + } else if self.leaf_index_2 == index { + Some(&self.points.p2) + } else { + None + } + } +} + +#[derive(Debug, Clone)] +pub struct Points { + p1: Point, + p2: Point, +} + +impl Points { + pub fn new(x1: F, y1: F, x2: F, y2: F) -> Points { + let p1 = Point::::new(x1, y1); + let p2 = Point::::new(x2, y2); + Self { p1, p2 } + } + + pub fn recover_points_euqal_to_commited_points(&self) -> Script { + let scripts = script! { + {self.p1.recover_point_euqal_to_commited_point()} + {self.p2.recover_point_euqal_to_commited_point()} + }; + scripts + } + + pub fn signature(&self) -> Vec> { + let mut p1_sigs = self.p1.signature(); + let mut p2_sigs = self.p2.signature(); + p2_sigs.append(p1_sigs.as_mut()); + p2_sigs + } +} + +#[derive(Debug, Clone)] +pub struct Point { + pub x: F, + pub y: F, + pub x_commit: BitCommitment, + pub y_commit: BitCommitment, +} + +impl Point { + pub fn new_from_assign(x: F, y: F, bc_assign: &mut BCAssignment) -> Point { + let x_commit = bc_assign.assign_field(x); + let y_commit = bc_assign.assign_field(y); + Self { + x, + y, + x_commit, + y_commit, + } + } + + pub fn new(x: F, y: F) -> Point { + let x_commit = BitCommitment::::new("b138982ce17ac813d505b5b40b665d404e9528e8", x); + let y_commit = BitCommitment::::new("b138982ce17ac813d505b5b40b665d404e9528e8", y); + Self { + x: x, + y: y, + x_commit: x_commit, + y_commit: y_commit, + } + } + + pub fn recover_point_euqal_to_commited_point(&self) -> Script { + let scripts = script! { + { self.x_commit.recover_message_euqal_to_commit_message() } + { self.y_commit.recover_message_euqal_to_commit_message() } + }; + + scripts + } + + pub fn recover_point_x_at_altstack_y_at_stack(&self) -> Script { + let scripts = script! { + { self.x_commit.recover_message_at_altstack() } + { self.y_commit.recover_message_at_stack() } + }; + + scripts + } + + pub fn recover_point_at_altstack(&self) -> Script { + let scripts = script! { + { self.x_commit.recover_message_at_altstack() } + { self.y_commit.recover_message_at_altstack() } + }; + + scripts + } + + pub fn recover_point_at_stack(&self) -> Script { + let scripts = script! { + { self.x_commit.recover_message_at_stack() } + { self.y_commit.recover_message_at_stack() } + }; + + scripts + } + + pub fn signature(&self) -> Vec> { + let mut x_sigs = self.x_commit.signature(); + let mut y_sigs = self.y_commit.signature(); + y_sigs.append(x_sigs.as_mut()); + y_sigs + } +} + +#[cfg(test)] +mod test { + use p3_baby_bear::BabyBear; + use p3_field::{AbstractExtensionField, AbstractField, PrimeField32}; + use rand::{Rng, SeedableRng}; + use rand_chacha::ChaCha20Rng; + use scripts::execute_script_with_inputs; + + use super::*; + use crate::field::BfField; + + type F = BabyBear; + type EF = p3_field::extension::BinomialExtensionField; + + #[test] + fn test_point_babybear() { + use p3_baby_bear::BabyBear; + let p = Point::::new(BabyBear::from_u32(1), BabyBear::from_u32(2)); + + let script = script! { + {p.recover_point_euqal_to_commited_point()} + OP_1 + }; + let inputs = p.signature(); + let res = execute_script_with_inputs(script, inputs); + assert!(res.success); + } + + #[test] + fn test_point_Babybear4() { + use super::*; + let mut rng = ChaCha20Rng::seed_from_u64(0u64); + let a = rng.gen::(); + let b = rng.gen::(); + + let p = Point::new(a, b); + + let script = script! { + {p.recover_point_euqal_to_commited_point()} + OP_1 + }; + let inputs = p.signature(); + let res = execute_script_with_inputs(script, inputs); + assert!(res.success); + } + + #[test] + fn test_points_Babybear() { + use p3_baby_bear::BabyBear; + let p = Points::::new( + BabyBear::from_u32(1), + BabyBear::from_u32(2), + BabyBear::from_u32(3), + BabyBear::from_u32(4), + ); + + let script = script! { + {p.recover_points_euqal_to_commited_points()} + OP_1 + }; + let inputs = p.signature(); + let res = execute_script_with_inputs(script, inputs); + assert!(res.success); + } + + #[test] + fn test_extension_points_Babybear4() { + use super::*; + let mut rng = ChaCha20Rng::seed_from_u64(0u64); + let a = rng.gen::(); + let b = rng.gen::(); + let c = rng.gen::(); + let d = rng.gen::(); + + let p = Points::new(a, b, c, d); + + let script = script! { + {p.recover_points_euqal_to_commited_points()} + OP_1 + }; + let inputs = p.signature(); + let res = execute_script_with_inputs(script, inputs); + assert!(res.success); + } +} diff --git a/primitives/src/mmcs/tapleaf.rs b/primitives/src/mmcs/tapleaf.rs new file mode 100644 index 0000000..706c359 --- /dev/null +++ b/primitives/src/mmcs/tapleaf.rs @@ -0,0 +1,41 @@ +use bitcoin::ScriptBuf as Script; +use segment::SegmentLeaf; +pub trait Tapleaf { + fn unlock_witness(&self) -> Vec>; + fn script(&self) -> Script; +} + +pub struct VerifierLeaf { + pub witness: Vec>, + pub script: Script, +} + +impl VerifierLeaf { + fn new(witness: Vec>, script: Script) -> Self { + Self { witness, script } + } + + fn new_from_segment_leaf(leaf: L) -> Self { + let script = leaf.leaf_script_witn_noeuqal(); + let witness = leaf.input(); + Self::new(witness, script) + } +} + +impl From for VerifierLeaf { + fn from(leaf: L) -> Self { + let script = leaf.leaf_script_witn_noeuqal(); + let witness = leaf.input(); + Self { witness, script } + } +} + +impl Tapleaf for VerifierLeaf { + fn unlock_witness(&self) -> Vec> { + self.witness.clone() + } + + fn script(&self) -> Script { + self.script.clone() + } +} diff --git a/primitives/src/mmcs/taptree.rs b/primitives/src/mmcs/taptree.rs new file mode 100644 index 0000000..a473cd2 --- /dev/null +++ b/primitives/src/mmcs/taptree.rs @@ -0,0 +1,617 @@ +use core::ops::{Deref, DerefMut}; +use core::{mem, usize}; + +use bitcoin::taproot::LeafVersion::TapScript; +use bitcoin::taproot::{LeafNode, LeafNodes, NodeInfo, TaprootMerkleBranch}; +use bitcoin::{ScriptBuf, TapNodeHash}; +use itertools::{Chunk, Itertools}; +use p3_util::{log2_strict_usize, reverse_slice_index_bits}; + +use super::error::BfError; +use super::point::PointsLeaf; +use crate::field::BfField; + +pub fn combine_two_nodes(a: NodeInfo, b: NodeInfo) -> Result<(NodeInfo, bool), BfError> { + let parent = NodeInfo::combine_with_order(a, b)?; + Ok(parent) +} +use bitcoin::ScriptBuf as Script; +use bitcoin_script::{define_pushable, script}; + +use crate::bit_comm::BitCommitment; +define_pushable!(); + +pub struct EvaluationLeaf { + leaf_index: usize, + x: F, + x_commitment: BitCommitment, + neg_x_commitment: BitCommitment, + evaluations: Vec, + evaluations_commitments: Vec>, +} + +impl EvaluationLeaf { + pub fn new(leaf_index: usize, x: F, evaluations: Vec) -> Self { + assert_eq!(evaluations.len(), NUM_POLY); + + let x_commitment = BitCommitment::new("b138982ce17ac813d505b5b40b665d404e9528e8", x); + let neg_x_commitment = BitCommitment::new( + "b138982ce17ac813d505b5b40b665d404e9528e8", + F::field_mod() - x, + ); + let mut evaluations_commitments = Vec::new(); + for i in 0..NUM_POLY { + evaluations_commitments.push(BitCommitment::new( + "b138982ce17ac813d505b5b40b665d404e9528e9", + evaluations[i], + )); + } + + Self { + leaf_index, + x, + x_commitment, + neg_x_commitment, + evaluations, + evaluations_commitments, + } + } + + pub fn leaf_script(&self) -> Script { + // equal to x script + let scripts = script! { + { self.x_commitment.commitments[0].checksig_verify_script() } + { self.x_commitment.commitments[0].commit_u32_as_4bytes_script() } + // todo: calculate to equal to -x + for i in 0..NUM_POLY{ + { self.evaluations_commitments[NUM_POLY-1-i].commitments[0].checksig_verify_script() } + { self.evaluations_commitments[NUM_POLY-1-i].commitments[0].commit_u32_as_4bytes_script() } + } + OP_1 + }; + + scripts + } + + pub fn two_point_leaf_script(&self) -> Script { + // equal to x script + let scripts = script! { + { self.x_commitment.commitments[0].checksig_verify_script() } + { self.x_commitment.commitments[0].commit_u32_as_4bytes_script() } + { self.neg_x_commitment.commitments[0].checksig_verify_script() } + { self.neg_x_commitment.commitments[0].commit_u32_as_4bytes_script() } + for i in 0..NUM_POLY{ + { self.evaluations_commitments[NUM_POLY-1-i].commitments[0].checksig_verify_script() } + { self.evaluations_commitments[NUM_POLY-1-i].commitments[0].commit_u32_as_4bytes_script() } + } + OP_1 + }; + scripts + } +} + +// Todo: use &[F] to replace Vec +pub fn construct_evaluation_leaf_script( + leaf_index: usize, + x: F, + y_s: Vec, +) -> Result { + let leaf_script: EvaluationLeaf = EvaluationLeaf::new(leaf_index, x, y_s); + let script = leaf_script.leaf_script(); + Ok(script) +} + +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +pub struct GlobalTree {} + +// =============== Polycommitment Tree =============== + +#[derive(Clone, Debug)] +pub struct PolyCommitTree { + pub tree: BasicTree, + pub points_leafs: Vec>, +} + +impl PolyCommitTree { + pub fn new(log_poly_points: usize) -> Self { + Self { + tree: BasicTree::::new(log_poly_points), + points_leafs: Vec::new(), + } + } + + pub fn commit_points(&mut self, evaluations: Vec) { + let poly_points = evaluations.len(); + let evas = Polynomials::new_eva_poly( + evaluations, + F::sub_group(log2_strict_usize(poly_points)), + PolynomialType::Eva, + ); + let mut builder = TreeBuilder::::new(); + for i in 0..evas.values.len() { + let leaf_script = construct_evaluation_leaf_script::<1, F>( + i, + evas.points[i], + vec![evas.values[i].clone()], + ) + .unwrap(); + } + self.tree = builder.build_tree(); + } + + pub fn commit_rev_points(&mut self, evaluations: Vec, width: usize) { + let poly_points = evaluations.len(); + let mut subgroup = F::sub_group(log2_strict_usize(poly_points)); + let leaf_indexs: Vec = (0..poly_points).into_iter().collect(); + reverse_slice_index_bits(&mut subgroup); + let mut tree_builder = TreeBuilder::::new(); + for i in (0..poly_points).into_iter().step_by(width) { + let leaf = PointsLeaf::new( + leaf_indexs[i], + leaf_indexs[i + 1], + subgroup[i], + evaluations[i], + subgroup[i + 1], + evaluations[i + 1], + ); + self.add_leaf(&mut tree_builder, &leaf) + } + + self.tree = tree_builder.build_tree(); + } + + pub fn root(&self) -> &NodeInfo { + self.tree.root() + } + + pub fn get_tapleaf(&self, index: usize) -> Option<&LeafNode> { + self.tree.get_tapleaf(index) + } + + // pub fn combine_tree() + + pub fn verify_inclusion_by_index(&self, index: usize) -> bool { + self.tree.verify_inclusion_by_index(index) + } + + pub fn add_leaf(&mut self, builder: &mut TreeBuilder, leaf: &PointsLeaf) { + self.points_leafs.push(leaf.clone()); + + builder.add_leaf(leaf.recover_points_euqal_to_commited_point()); + } + + pub fn get_points_leafs(&self) -> &[PointsLeaf] { + &self.points_leafs + } + + pub fn get_points_leaf(&self, index: usize) -> &PointsLeaf { + &self.points_leafs[index] + } +} + +#[derive(Clone, Debug, PartialEq, PartialOrd)] +pub struct BasicTree { + pub root_node: Option, + leaf_count: usize, + leaf_indices: Vec, +} + +pub struct TreeBuilder { + leaf_count: usize, + leaf_indices: Vec, + to_add_leaves: Vec, +} + +impl TreeBuilder { + pub fn new() -> Self { + Self { + leaf_count: 0, + leaf_indices: Vec::new(), + to_add_leaves: Vec::new(), + } + } + + pub fn add_leaf(&mut self, leaf_script: ScriptBuf) { + self.leaf_count += 1; + let leaf = NodeInfo::new_leaf_with_ver(leaf_script, TapScript); + self.leaf_indices.push(self.leaf_count - 1); + self.to_add_leaves.push(leaf); + } + + /* + The leaves_indices are postion info of merkle tree leaves in the taptree. + When we building the taptree, it is much easier to work with a dict where the index is + the taptree position and the element is the merkle tree postion. + We flip the dict and save it to the leaf_indices. + + */ + pub fn build_tree(&mut self) -> BasicTree { + let mut working_nodes = self.to_add_leaves.clone(); + let mut t_idx_to_m_idx = self.leaf_indices.clone(); + + while working_nodes.len() > 1 { + //the tuple() method in itertool will drop the elements in Iter if the size is not enough to + //generate a tuple, so we have to save the last node if the size of working node is odd. + let mut reminder_node: Option = None; + if working_nodes.len() % 2 == 1 { + reminder_node = working_nodes.pop(); + } + + let mut node_tuples = working_nodes.into_iter().tuples(); + let mut todo: Vec = Vec::new(); + let mut a_start_idx = 0usize; // will be updated after finishing combining two nodes. + + for (a, b) in node_tuples { + let a_leaf_size = a.leaf_nodes().len(); + let a_end_idx = a_start_idx + a_leaf_size; + let b_start_idx = a_end_idx; + let b_leaf_size = b.leaf_nodes().len(); + let b_end_idx = b_start_idx + b_leaf_size; + let (ret_node, left_first) = NodeInfo::combine_with_order(a, b).unwrap(); + + todo.push(ret_node); + + if !left_first { + let mut temp_a_leaf_indices = vec![0usize; a_leaf_size]; + temp_a_leaf_indices + .as_mut_slice() + .copy_from_slice(&t_idx_to_m_idx[a_start_idx..a_end_idx]); + + let mut temp_b_leaf_indices = vec![0usize; b_leaf_size]; + temp_b_leaf_indices + .as_mut_slice() + .copy_from_slice(&t_idx_to_m_idx[b_start_idx..b_end_idx]); + temp_b_leaf_indices.append(&mut temp_a_leaf_indices); + t_idx_to_m_idx[a_start_idx..b_end_idx] + .copy_from_slice(&temp_b_leaf_indices.as_slice()); + } + a_start_idx += a_leaf_size + b_leaf_size; + } + working_nodes = todo; + todo = Vec::new(); + } + BasicTree { + root_node: Some(working_nodes.into_iter().next().unwrap()), + leaf_count: self.leaf_count, + leaf_indices: reverse_idx_dict(&t_idx_to_m_idx), + } + } +} + +fn reverse_idx_dict(idx_dict: &Vec) -> Vec { + let mut ret_vec = vec![0usize; idx_dict.len()]; + for (idx, pos) in idx_dict.iter().enumerate() { + ret_vec[*pos] = idx; + } + ret_vec +} + +impl BasicTree { + pub fn new(log_poly_points: usize) -> Self { + Self { + root_node: None, + leaf_count: 0, + leaf_indices: Vec::new(), + } + } + + pub fn root(&self) -> &NodeInfo { + let root = self.root_node.as_ref().unwrap(); + root + } + + // This function only support combine trees with same depth + pub fn combine_tree(a: Self, b: Self) -> Self { + // perserve indices map before combining two trees. + let mut a_leaf_indices = a.leaf_indices.clone(); + let mut b_leaf_indices = b.leaf_indices.clone(); + + let (combined_tree, noswap) = + combine_two_nodes(a.root_node.unwrap(), b.root_node.unwrap()).unwrap(); + + let mut a_t_idx_to_m_idx = reverse_idx_dict(&a_leaf_indices); + let mut b_t_idx_to_m_idx = reverse_idx_dict(&b_leaf_indices); + + let t_idx_to_m_idx = match noswap { + true => { + for b_m_idx in b_t_idx_to_m_idx.iter() { + a_t_idx_to_m_idx.push(*b_m_idx); + } + a_t_idx_to_m_idx + } + false => { + for a_m_idx in a_t_idx_to_m_idx.iter() { + b_t_idx_to_m_idx.push(*a_m_idx); + } + b_t_idx_to_m_idx + } + }; + + Self { + root_node: Some(combined_tree), + leaf_count: t_idx_to_m_idx.len(), + leaf_indices: reverse_idx_dict(&t_idx_to_m_idx), + } + } + + pub fn leaf_count(&self) -> usize { + self.leaf_count + } + + pub fn leaves(&self) -> LeafNodes { + let nodes = self.root_node.as_ref().unwrap().leaf_nodes(); + nodes + } + + pub fn get_leaf_merkle_path(&self, index: usize) -> Option<&TaprootMerkleBranch> { + let index = self.index_map(index); + if let Some(leaf) = self.leaves().nth(index) { + Some(leaf.merkle_branch()) + } else { + None + } + } + + fn index_map(&self, index: usize) -> usize { + self.leaf_indices[index] as usize + } + + pub fn get_tapleaf(&self, index: usize) -> Option<&LeafNode> { + let index = self.index_map(index); + self.leaves().nth(index) + } + + pub fn verify_inclusion_by_index(&self, index: usize) -> bool { + let index = self.index_map(index); + let leaf = self.get_tapleaf(index).unwrap(); + let path = self.get_leaf_merkle_path(index).unwrap(); + let mut first_node_hash = TapNodeHash::from_node_hashes(leaf.node_hash(), path[0]); + path[1..].into_iter().for_each(|sibling_node| { + first_node_hash = TapNodeHash::from_node_hashes(first_node_hash, *sibling_node); + }); + + first_node_hash == self.root().node_hash() + } +} + +impl From for BasicTree { + fn from(value: NodeInfo) -> Self { + Self { + root_node: Some(value), + leaf_count: 0, + leaf_indices: Vec::new(), + } + } +} + +pub fn verify_inclusion(root: TapNodeHash, leaf: &LeafNode) -> bool { + let path = leaf.merkle_branch(); + let mut first_node_hash = TapNodeHash::from_node_hashes(leaf.node_hash(), path[0]); + path[1..].into_iter().for_each(|sibling_node| { + first_node_hash = TapNodeHash::from_node_hashes(first_node_hash, *sibling_node); + }); + + first_node_hash == root +} + +#[derive(Clone, Debug, PartialEq, PartialOrd)] +enum PolynomialType { + Eva, + Coeff, +} +struct Polynomials { + values: Vec, + points: Vec, // only for evaluations + style: PolynomialType, +} + +impl Polynomials { + pub fn new(values: Vec, style: PolynomialType) -> Self { + Self { + values, + points: Vec::new(), + style, + } + } + + pub fn new_eva_poly(values: Vec, points: Vec, style: PolynomialType) -> Self { + Self { + values, + points, + style, + } + } + + fn convert_to_evals_at_subgroup(&self) -> Self { + assert!(self.style == PolynomialType::Coeff); + let subgroup_bits = log2_strict_usize(self.values.len()); + let subgroup = F::sub_group(subgroup_bits); + let mut evals = Vec::new(); + for i in 0..subgroup.len() { + let point = subgroup[i]; + let result = self + .values + .iter() + .fold(F::zero(), |acc, item| acc + *item * point.exp_u64(i as u64)); + evals.push(result); + } + assert_eq!(subgroup.len(), evals.len()); + Self::new_eva_poly(evals, subgroup, PolynomialType::Eva) + } + + fn values(&self) -> &Vec { + &self.values + } + + fn points(&self) -> &Vec { + assert!(self.style == PolynomialType::Eva); + &self.points + } +} + +#[cfg(test)] +mod tests { + + use p3_baby_bear::BabyBear; + use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; + use p3_field::extension::BinomialExtensionField; + use p3_field::{AbstractExtensionField, AbstractField}; + use p3_interpolation::interpolate_subgroup; + use p3_matrix::dense::RowMajorMatrix; + use rand::distributions::Standard; + use rand::prelude::Distribution; + use rand::{thread_rng, Rng}; + use scripts::execute_script_with_inputs; + + use super::*; + + #[test] + fn test_check_x_neg_x_equal_script() { + const num_polys: usize = 1; + let x = BabyBear::from_u32(0x11654321); + let neg_x = BabyBear::field_mod() - x; // 669ABCE0 + let expect_neg_x = BabyBear::from_u32(0x669ABCE0); + assert_eq!(neg_x, expect_neg_x); + let leaf = + EvaluationLeaf::::new(0, x, vec![BabyBear::from_u32(0x11654321)]); + + // check signature and verify the value + let signature = leaf.x_commitment.commitments[0].signature(); + // check equal to r + let exec_scripts = script! { + { leaf.x_commitment.commitments[0].checksig_verify_script() } + { leaf.x_commitment.commitments[0].check_equal_x_or_neg_x_script(&leaf.neg_x_commitment.commitments[0]) } + OP_1 + }; + let exec_result = execute_script_with_inputs(exec_scripts, signature); + assert!(exec_result.success); + + // check equal to -r + let signature = leaf.x_commitment.commitments[0].signature(); + let exec_scripts = script! { + { leaf.x_commitment.commitments[0].checksig_verify_script() } + { leaf.neg_x_commitment.commitments[0].check_equal_x_or_neg_x_script(&leaf.x_commitment.commitments[0]) } + OP_1 + }; + let exec_result = execute_script_with_inputs(exec_scripts, signature); + assert!(exec_result.success); + + for _ in 0..30 { + let mut rng = rand::thread_rng(); + let random_number: u32 = rng.gen(); + let x = random_number % BabyBear::MOD; + let x = BabyBear::from_u32(x); + let neg_x = BabyBear::field_mod() - x; + let leaf = EvaluationLeaf::::new( + 0, + x, + vec![BabyBear::from_u32(0x11654321)], + ); + + // check signature and verify the value + let signature = leaf.x_commitment.commitments[0].signature(); + // check equal to r + let exec_scripts = script! { + { leaf.x_commitment.commitments[0].checksig_verify_script() } + { leaf.x_commitment.commitments[0].check_equal_x_or_neg_x_script(&leaf.neg_x_commitment.commitments[0]) } + OP_1 + }; + let exec_result = execute_script_with_inputs(exec_scripts, signature); + assert!(exec_result.success); + + // check equal to -r + let signature = leaf.x_commitment.commitments[0].signature(); + let exec_scripts = script! { + { leaf.x_commitment.commitments[0].checksig_verify_script() } + { leaf.neg_x_commitment.commitments[0].check_equal_x_or_neg_x_script(&leaf.x_commitment.commitments[0]) } + OP_1 + }; + let exec_result = execute_script_with_inputs(exec_scripts, signature); + assert!(exec_result.success); + + let signature = leaf.neg_x_commitment.commitments[0].signature(); + let exec_scripts = script! { + { leaf.neg_x_commitment.commitments[0].checksig_verify_script() } + { leaf.x_commitment.commitments[0].check_equal_x_or_neg_x_script(&leaf.neg_x_commitment.commitments[0]) } + OP_1 + }; + let exec_result = execute_script_with_inputs(exec_scripts, signature); + assert!(exec_result.success); + } + } + + #[test] + fn test_tree_builder() { + type F = BabyBear; + let depth = 3; + let mut coeffs1: Vec = Vec::with_capacity(2u32.pow(depth as u32) as usize); + for i in 0..2u32.pow(depth as u32) { + coeffs1.push(F::from_canonical_u32(i)); + } + let poly1 = Polynomials::new(coeffs1, PolynomialType::Coeff); + let eva_poly1 = poly1.convert_to_evals_at_subgroup(); + let evas1 = eva_poly1.values(); + + let mut tb = TreeBuilder::<3>::new(); + + for i in 0..evas1.len() { + let leaf_script = construct_evaluation_leaf_script::<1, F>( + i, + eva_poly1.points[i], + vec![evas1[i].clone()], + ) + .unwrap(); + tb.add_leaf(leaf_script); + } + + let tree = tb.build_tree(); + // assert!(root_node.leaf_nodes().len()==8); + } + + fn commit_with_poly_tree(degree: usize) -> PolyCommitTree + where + Standard: Distribution, + { + let mut rng = thread_rng(); + let coeffs = (0..degree).map(|_| rng.gen::()).collect::>(); + + let poly = Polynomials::new(coeffs, PolynomialType::Coeff); + let eva_poly = poly.convert_to_evals_at_subgroup(); + let evas = eva_poly.values(); + let mut poly_taptree = PolyCommitTree::::new(2); + poly_taptree.commit_rev_points(evas.clone(), 2); + poly_taptree + } + + #[test] + fn test_poly_commit_tree() { + // x^2 + 2 x + 3 + type F = BabyBear; + let poly_taptree = commit_with_poly_tree::(8); + + (0..4).into_iter().for_each(|index| { + let leaf = poly_taptree.get_tapleaf(index).unwrap(); + let script = leaf.leaf().as_script().unwrap(); + let points_leaf = poly_taptree.get_points_leaf(index); + assert_eq!( + points_leaf.recover_points_euqal_to_commited_point(), + *script.0 + ); + let success = verify_inclusion(poly_taptree.root().node_hash(), leaf); + assert_eq!(success, true); + }); + } + + #[test] + fn test_swap_slice() { + let mut values = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + + let temp1 = values[2..4].to_vec(); + let temp2 = values[6..8].to_vec(); + + values[2..4].clone_from_slice(&temp2); + values[6..8].clone_from_slice(&temp1); + + println!("{:?}", values); + } +} diff --git a/primitives/src/mmcs/taptree_mmcs.rs b/primitives/src/mmcs/taptree_mmcs.rs new file mode 100644 index 0000000..5f5e43d --- /dev/null +++ b/primitives/src/mmcs/taptree_mmcs.rs @@ -0,0 +1,94 @@ +use core::marker::PhantomData; +use core::{panic, usize}; + +use bitcoin::hashes::Hash as Bitcoin_HASH; +use bitcoin::taproot::LeafNode; +use bitcoin::TapNodeHash; +use p3_matrix::dense::RowMajorMatrix; +use p3_matrix::Matrix; +use p3_util::log2_strict_usize; + +use super::bf_mmcs::BFMmcs; +use super::error::BfError; +use super::point::PointsLeaf; +use super::taptree::{verify_inclusion, PolyCommitTree}; +use crate::challenger::chan_field::{u256_to_u32, u32_to_u256, U256, U32}; +use crate::field::BfField; + +pub type TreeRoot = [U32; ROOT_WIDTH]; +// Commit two adjacent points to a leaf node +pub const DEFAULT_MATRIX_WIDTH: usize = 2; +pub const LOG_DEFAULT_MATRIX_WIDTH: usize = 1; + +pub const ROOT_WIDTH: usize = 8; +#[derive(Clone, Debug, PartialEq, PartialOrd)] +pub struct TapTreeMmcs { + _marker: PhantomData, +} + +impl TapTreeMmcs { + pub fn new() -> Self { + Self { + _marker: PhantomData, + } + } +} + +#[derive(Clone)] +pub struct CommitProof { + pub points_leaf: PointsLeaf, + pub leaf_node: LeafNode, +} + +impl BFMmcs for TapTreeMmcs { + type ProverData = PolyCommitTree; + type Proof = CommitProof; + type Commitment = TreeRoot; + type Error = BfError; + + fn open_taptree(&self, index: usize, prover_data: &PolyCommitTree) -> Self::Proof { + // The matrix with width-2 lead to the index need to right shift 1-bit + let leaf_index = index >> LOG_DEFAULT_MATRIX_WIDTH; + let leaf = prover_data.get_tapleaf(leaf_index); + let opening_leaf = match leaf { + Some(v) => v, + None => { + // println!( + // "leaf index:{:?}, leaf count:{:?}", + // index, + // prover_data.leaf_count() + // ); + panic!("invalid leaf index") + } + }; + let open_leaf = prover_data.get_points_leaf(leaf_index).clone(); + CommitProof { + points_leaf: open_leaf, + leaf_node: opening_leaf.clone(), + } + } + + fn verify_taptree( + &self, + proof: &Self::Proof, + root: &Self::Commitment, + ) -> Result<(), Self::Error> { + let root_node = TapNodeHash::from_byte_array(u32_to_u256(root.clone())); + let success = verify_inclusion(root_node, &proof.leaf_node); + if success { + Ok(()) + } else { + Err(BfError::InvalidMerkleProof) + } + } + + fn commit(&self, inputs: Vec>) -> (Self::Commitment, Self::ProverData) { + let log_leaves = log2_strict_usize(inputs[0].height()); + let mut tree = PolyCommitTree::::new(log_leaves); + + tree.commit_rev_points(inputs[0].values.clone(), inputs[0].width); + let root: U256 = tree.root().node_hash().as_byte_array().clone(); + + (u256_to_u32(root), tree) + } +} diff --git a/scripts/Cargo.toml b/scripts/Cargo.toml index 530bb8f..3d7b8fa 100644 --- a/scripts/Cargo.toml +++ b/scripts/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] bitcoin-script = { git = "https://github.com/cyl19970726/rust-bitcoin-script", rev = "eda97c5" } bitcoin = { git = "https://github.com/cyl19970726/rust-bitcoin", rev = "ffad6f3" } -bitcoin-scriptexec = { git = "https://github.com/cyl19970726/rust-bitcoin-scriptexec",rev = "09c601e" } +bitcoin-scriptexec = { git = "https://github.com/cyl19970726/rust-bitcoin-scriptexec",rev = "205b90c"} lazy_static = "1.4.0" rand_chacha = "0.3.1" diff --git a/scripts/src/bit_comm/bit_comm_u32.rs b/scripts/src/bit_comm/bit_comm_u32.rs index fdaf6bd..6ca1091 100644 --- a/scripts/src/bit_comm/bit_comm_u32.rs +++ b/scripts/src/bit_comm/bit_comm_u32.rs @@ -8,7 +8,7 @@ use crate::winternitz; define_pushable!(); #[derive(Clone, Debug, PartialEq, Eq)] -pub struct BitCommitmentU32 { +pub struct BitCommitmentU32 { pub value: u32, pub winternitz: Winternitz, pub message: Vec, // every u8 only available for 4-bits @@ -65,14 +65,14 @@ impl BitCommitmentU32 { self.winternitz.sign_script(&self.message) } - pub fn recover_message_at_stack(&self) -> Script { + pub fn recover_message_at_stack(&self) -> Script { script! { {self.checksig_verify_script()} {u32_compress()} } } - pub fn recover_message_at_altstack(&self) -> Script { + pub fn recover_message_at_altstack(&self) -> Script { script! { {self.checksig_verify_script()} {u32_compress()} @@ -80,14 +80,14 @@ impl BitCommitmentU32 { } } - pub fn message_from_altstack(&self) -> Script { + pub fn message_from_altstack(&self) -> Script { script! { OP_FROMALTSTACK } } // signuture is the input of this script - pub fn recover_message_euqal_to_commit_message(&self) -> Script { + pub fn recover_message_euqal_to_commit_message(&self) -> Script { script! { {self.recover_message_at_stack()} {self.value } @@ -95,7 +95,7 @@ impl BitCommitmentU32 { } } - pub fn signature(&self) -> Vec> { + pub fn signature(&self) -> Vec> { let mut sig = self.winternitz.sign(&self.message); for i in 0..sig.len() { if sig[i].len() == 1 && sig[i][0] == 0 { diff --git a/scripts/src/bit_comm/mod.rs b/scripts/src/bit_comm/mod.rs index 969c893..b720e32 100644 --- a/scripts/src/bit_comm/mod.rs +++ b/scripts/src/bit_comm/mod.rs @@ -1,11 +1,5 @@ - pub mod winternitz; pub use winternitz::*; pub mod bit_comm_u32; - - - - - diff --git a/scripts/src/u31/babybear.rs b/scripts/src/u31/babybear.rs index f85e197..a971137 100644 --- a/scripts/src/u31/babybear.rs +++ b/scripts/src/u31/babybear.rs @@ -4,7 +4,6 @@ use bitcoin_script::{define_pushable, script}; use p3_field::{AbstractField, TwoAdicField}; use p3_util::{log2_ceil_u64, log2_ceil_usize, log2_strict_usize, reverse_bits_len}; - use crate::u31::{babybear, U31Config}; use crate::{u31_double, u31_mul}; diff --git a/scripts/src/u31/mod.rs b/scripts/src/u31/mod.rs index 94316eb..f56ef5b 100644 --- a/scripts/src/u31/mod.rs +++ b/scripts/src/u31/mod.rs @@ -137,7 +137,7 @@ mod test { use rand_chacha::ChaCha20Rng; use super::*; - use crate::{execute_script}; + use crate::execute_script; #[test] fn test_rot() { let scripts = script! { diff --git a/scripts/src/u31_ext/mod.rs b/scripts/src/u31_ext/mod.rs index ea2925b..fa9b781 100644 --- a/scripts/src/u31_ext/mod.rs +++ b/scripts/src/u31_ext/mod.rs @@ -80,109 +80,3 @@ pub fn u31ext_double() -> Script { pub fn u31ext_mul() -> Script { C::mul_impl() } - -pub fn ext_fold_degree1( - degree: u32, - x: &[F], - y_0_x: &[F], - y_0_neg_x: &[F], - beta: &[F], - y_1_x_quare: &[F], -) -> Script { - let x_vec: Vec = x.into_iter().map(|v| v.as_canonical_u32()).collect(); - let y_0_x_vec: Vec = y_0_x.into_iter().map(|v| v.as_canonical_u32()).collect(); - let y_0_neg_x_vec: Vec = y_0_neg_x - .into_iter() - .map(|v| v.as_canonical_u32()) - .collect(); - let beta_vec: Vec = beta.into_iter().map(|v| v.as_canonical_u32()).collect(); - let y_1_x_quare_vec: Vec = y_1_x_quare - .into_iter() - .map(|v| v.as_canonical_u32()) - .collect(); - ext_fold_degree::( - degree, - &x_vec, - &y_0_x_vec, - &y_0_neg_x_vec, - &beta_vec, - &y_1_x_quare_vec, - ) -} - -// y_0(r)= g_0,1(r^2) + r g_0,2(r^2) -// y_0(-r)= g_0,1(r^2) -r g_0,2(r^2) -// y_1(r^2) = g_0,1(r^2) + v_0 g_0,2(r^2) -pub fn ext_fold_degree( - _degree: u32, - x: &[u32], - y_0_x: &[u32], - y_0_neg_x: &[u32], - beta: &[u32], - y_1_x_quare: &[u32], -) -> Script { - script! { - - // calculate 2 * g_0,1(r^2) - for i in (0..M::DEGREE).rev(){ - {y_0_x[i as usize]} - } - for i in (0..M::DEGREE).rev(){ - {y_0_neg_x[i as usize]} - } - { u31ext_add::() } - // calculate 2 * x * g_0,1(r^2) - for i in (0..M::DEGREE).rev(){ - {x[i as usize]} - } - { u31ext_mul::()} - - for _ in 0..M::DEGREE{ - OP_TOALTSTACK - } - - // calculate 2 * x * g_0,2(r^2) - for i in (0..M::DEGREE).rev(){ - {y_0_x[i as usize]} - } - for i in (0..M::DEGREE).rev(){ - {y_0_neg_x[i as usize]} - } - { u31ext_sub::() } - // calculate 2 * r * beta * g_0,2(r^2) - for i in (0..M::DEGREE).rev(){ - {beta[i as usize]} - } - {u31ext_mul::()} - // calaulate (2 * r * beta * g_0,2(r^2)) + (2 * r * g_0,1(r^2)) - for _ in 0..M::DEGREE{ - OP_FROMALTSTACK - } - - { u31ext_add::() } - for _ in 0..M::DEGREE{ - OP_TOALTSTACK - } - - - // calculate 2*r*y_1(r^2) - for i in (0..M::DEGREE).rev(){ - {y_1_x_quare[i as usize]} - } - {u31ext_double::()} - for i in (0..M::DEGREE).rev(){ - {x[i as usize]} - } - {u31ext_mul::()} - - // Check Equal - // y_1(r^2) = g_0,1(r^2) + beta g_0,2(r^2) - // 2r y_1(r^2) = 2r g_0,1(r^2) + 2r beta g_0,2(r^2) - for _ in 0..M::DEGREE{ - OP_FROMALTSTACK - } - - { u31ext_equalverify::() } - OP_1 - } -} diff --git a/segment/Cargo.toml b/segment/Cargo.toml new file mode 100644 index 0000000..96cadb8 --- /dev/null +++ b/segment/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "segment" +version = "0.1.0" +edition = "2021" + +[dependencies] +bitcoin-script = { git = "https://github.com/cyl19970726/rust-bitcoin-script", rev = "eda97c5" } +bitcoin = { git = "https://github.com/cyl19970726/rust-bitcoin", rev = "ffad6f3" } +bitcoin-scriptexec = { git = "https://github.com/cyl19970726/rust-bitcoin-scriptexec",rev = "205b90c"} +scripts ={ path = "../scripts"} \ No newline at end of file diff --git a/segment/src/lib.rs b/segment/src/lib.rs new file mode 100644 index 0000000..ebff921 --- /dev/null +++ b/segment/src/lib.rs @@ -0,0 +1,16 @@ +use bitcoin::ScriptBuf as Script; +use scripts::execute_script_with_inputs; +pub trait SegmentLeaf { + fn input(&self) -> Vec>; + fn check_input(&self) -> Script; + fn leaf_script(&self) -> Script; + + fn execute_leaf_script(&self) -> bool { + let result = execute_script_with_inputs(self.leaf_script(), self.input()); + result.success + } + + fn leaf_script_witn_noeuqal(&self) -> Script { + self.leaf_script() + } +} From e09e5c959efe64817dbbec83e3f25865d36f8562 Mon Sep 17 00:00:00 2001 From: 0xhhh <52317293+cyl19970726@users.noreply.github.com> Date: Mon, 17 Jun 2024 13:05:39 +0800 Subject: [PATCH 02/25] decouple u31 (#5) * refactor * decouple mmcs within fri * fix test bug * update rust-bitcoin replated dependency * use u31_lib * add **/Cargo.lock into .gitignore * delete mmcs within fri --------- Co-authored-by: wangyao --- .gitignore | 2 +- Cargo.lock | 61 ++- fri/Cargo.toml | 6 +- fri/src/fold_even_odd.rs | 27 +- fri/src/fri_scripts/fiat_shamir_subtree.rs | 5 +- fri/src/fri_scripts/leaf.rs | 14 +- fri/src/fri_scripts/verify_folding.rs | 25 +- fri/src/mmcs/bf_mmcs.rs | 44 -- fri/src/mmcs/mod.rs | 6 - fri/src/mmcs/tapleaf.rs | 43 -- fri/src/mmcs/taptree.rs | 471 --------------------- fri/src/mmcs/taptree_mmcs.rs | 84 ---- fri/src/prover.rs | 2 +- primitives/Cargo.toml | 6 +- primitives/src/bit_comm/bc_assign.rs | 1 + primitives/src/bit_comm/mod.rs | 8 +- scripts/Cargo.toml | 7 +- scripts/src/lib.rs | 22 +- scripts/src/u31/m31.rs | 6 - scripts/src/u31_ext/babybear.rs | 215 ---------- scripts/src/u31_ext/karatsuba.rs | 193 --------- scripts/src/u31_ext/karatsuba_complex.rs | 193 --------- scripts/src/u31_ext/m31.rs | 181 -------- segment/Cargo.toml | 6 +- 24 files changed, 105 insertions(+), 1523 deletions(-) delete mode 100644 fri/src/mmcs/bf_mmcs.rs delete mode 100644 fri/src/mmcs/mod.rs delete mode 100644 fri/src/mmcs/tapleaf.rs delete mode 100644 fri/src/mmcs/taptree.rs delete mode 100644 fri/src/mmcs/taptree_mmcs.rs delete mode 100644 scripts/src/u31/m31.rs delete mode 100644 scripts/src/u31_ext/babybear.rs delete mode 100644 scripts/src/u31_ext/karatsuba.rs delete mode 100644 scripts/src/u31_ext/karatsuba_complex.rs delete mode 100644 scripts/src/u31_ext/m31.rs diff --git a/.gitignore b/.gitignore index 606f7a0..b06f1f2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ target/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html Cargo.lock +**/Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk - diff --git a/Cargo.lock b/Cargo.lock index f66cc7f..143f489 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,7 +103,7 @@ checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" [[package]] name = "bitcoin" version = "0.31.0" -source = "git+https://github.com/cyl19970726/rust-bitcoin?rev=ffad6f3#ffad6f309054e62aacc36311fc0cc08492f81848" +source = "git+https://github.com/bitlayer-org/rust-bitcoin?branch=bf-stark#ffad6f309054e62aacc36311fc0cc08492f81848" dependencies = [ "base58ck", "bech32", @@ -135,7 +135,7 @@ checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" [[package]] name = "bitcoin-script" version = "0.2.0" -source = "git+https://github.com/cyl19970726/rust-bitcoin-script?rev=eda97c5#eda97c5c919908ae28c87b6f2a78318c0f6a5817" +source = "git+https://github.com/bitlayer-org/rust-bitcoin-script#b7144e931d5e9f1e9a07df100a3dbff3210c4ab0" dependencies = [ "bitcoin", "hex", @@ -148,13 +148,12 @@ dependencies = [ [[package]] name = "bitcoin-scriptexec" version = "0.0.0" -source = "git+https://github.com/cyl19970726/rust-bitcoin-scriptexec?rev=205b90c#205b90c19009342bc8e2249bd222cdebe7947342" +source = "git+https://github.com/bitlayer-org/rust-bitcoin-scriptexec#eabf1a9c1ba4153dc3f5042be0b21891c4355c8c" dependencies = [ "bitcoin", "clap", "console_error_panic_hook", "getrandom", - "hex", "lazy_static", "serde", "serde-wasm-bindgen", @@ -567,9 +566,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "nu-ansi-term" @@ -647,7 +646,7 @@ version = "0.1.0" [[package]] name = "p3-baby-bear" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#fde81db95b8eeb39e07890f4099a7d59daeec52f" +source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" dependencies = [ "num-bigint", "p3-field", @@ -661,7 +660,7 @@ dependencies = [ [[package]] name = "p3-blake3" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#fde81db95b8eeb39e07890f4099a7d59daeec52f" +source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" dependencies = [ "blake3", "p3-symmetric", @@ -670,7 +669,7 @@ dependencies = [ [[package]] name = "p3-challenger" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#fde81db95b8eeb39e07890f4099a7d59daeec52f" +source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" dependencies = [ "p3-field", "p3-maybe-rayon", @@ -682,7 +681,7 @@ dependencies = [ [[package]] name = "p3-commit" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#fde81db95b8eeb39e07890f4099a7d59daeec52f" +source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" dependencies = [ "itertools 0.13.0", "p3-challenger", @@ -695,7 +694,7 @@ dependencies = [ [[package]] name = "p3-dft" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#fde81db95b8eeb39e07890f4099a7d59daeec52f" +source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" dependencies = [ "p3-field", "p3-matrix", @@ -707,7 +706,7 @@ dependencies = [ [[package]] name = "p3-field" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#fde81db95b8eeb39e07890f4099a7d59daeec52f" +source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" dependencies = [ "itertools 0.13.0", "num-bigint", @@ -722,7 +721,7 @@ dependencies = [ [[package]] name = "p3-goldilocks" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#fde81db95b8eeb39e07890f4099a7d59daeec52f" +source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" dependencies = [ "num-bigint", "p3-dft", @@ -738,7 +737,7 @@ dependencies = [ [[package]] name = "p3-interpolation" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#fde81db95b8eeb39e07890f4099a7d59daeec52f" +source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" dependencies = [ "p3-field", "p3-matrix", @@ -748,7 +747,7 @@ dependencies = [ [[package]] name = "p3-keccak" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#fde81db95b8eeb39e07890f4099a7d59daeec52f" +source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" dependencies = [ "p3-symmetric", "tiny-keccak", @@ -757,7 +756,7 @@ dependencies = [ [[package]] name = "p3-matrix" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#fde81db95b8eeb39e07890f4099a7d59daeec52f" +source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" dependencies = [ "itertools 0.13.0", "p3-field", @@ -771,12 +770,12 @@ dependencies = [ [[package]] name = "p3-maybe-rayon" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#fde81db95b8eeb39e07890f4099a7d59daeec52f" +source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" [[package]] name = "p3-mds" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#fde81db95b8eeb39e07890f4099a7d59daeec52f" +source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" dependencies = [ "itertools 0.12.1", "p3-dft", @@ -790,7 +789,7 @@ dependencies = [ [[package]] name = "p3-merkle-tree" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#fde81db95b8eeb39e07890f4099a7d59daeec52f" +source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" dependencies = [ "itertools 0.13.0", "p3-commit", @@ -806,7 +805,7 @@ dependencies = [ [[package]] name = "p3-mersenne-31" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#fde81db95b8eeb39e07890f4099a7d59daeec52f" +source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" dependencies = [ "itertools 0.13.0", "num-bigint", @@ -825,7 +824,7 @@ dependencies = [ [[package]] name = "p3-poseidon2" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#fde81db95b8eeb39e07890f4099a7d59daeec52f" +source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" dependencies = [ "gcd", "p3-field", @@ -837,7 +836,7 @@ dependencies = [ [[package]] name = "p3-symmetric" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#fde81db95b8eeb39e07890f4099a7d59daeec52f" +source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" dependencies = [ "itertools 0.13.0", "p3-field", @@ -847,7 +846,7 @@ dependencies = [ [[package]] name = "p3-util" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#fde81db95b8eeb39e07890f4099a7d59daeec52f" +source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" dependencies = [ "serde", ] @@ -1056,6 +1055,21 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +[[package]] +name = "rust-bitcoin-u31-or-u30" +version = "0.1.0" +source = "git+https://github.com/bitlayer-org/rust-bitcoin-m31-or-babybear.git?branch=bf-stark#5d28e196d7306d6f3094a8f02ad04dfdff370f30" +dependencies = [ + "bitcoin", + "bitcoin-script", + "bitcoin-scriptexec", + "p3-baby-bear", + "p3-field", + "p3-mersenne-31", + "rand", + "rand_chacha", +] + [[package]] name = "ryu" version = "1.0.18" @@ -1097,6 +1111,7 @@ dependencies = [ "p3-util", "rand", "rand_chacha", + "rust-bitcoin-u31-or-u30", ] [[package]] diff --git a/fri/Cargo.toml b/fri/Cargo.toml index c4e166c..7efbf9e 100644 --- a/fri/Cargo.toml +++ b/fri/Cargo.toml @@ -5,9 +5,9 @@ edition = "2021" license = "MIT OR Apache-2.0" [dependencies] -bitcoin-script = { git = "https://github.com/cyl19970726/rust-bitcoin-script", rev = "eda97c5" } -bitcoin = { git = "https://github.com/cyl19970726/rust-bitcoin", rev = "ffad6f3" } -bitcoin-scriptexec = { git = "https://github.com/cyl19970726/rust-bitcoin-scriptexec",rev = "205b90c"} +bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } +bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } +bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git" } p3-dft = { git = "https://github.com/Plonky3/Plonky3.git" } diff --git a/fri/src/fold_even_odd.rs b/fri/src/fold_even_odd.rs index ecd1117..de0f3e0 100644 --- a/fri/src/fold_even_odd.rs +++ b/fri/src/fold_even_odd.rs @@ -159,9 +159,9 @@ mod tests { .map(|(even, odd)| even + beta * odd) .collect::>(); - // println!("{:?}", evals); - // println!("------- folding -------"); - // println!("{:?}", expected); + println!("{:?}", evals); + println!("------- folding -------"); + println!("{:?}", expected); // fold_even_odd takes and returns in bitrev order. let mut folded = evals.clone(); @@ -195,18 +195,19 @@ mod tests { true, ); let result = execute_script(with_input_script); + println!("{:?}", result); assert!(result.success); - let script = fold_degree::( - x.as_u32_vec(), - y0_x.as_u32_vec(), - y0_neg_x.as_u32_vec(), - beta.as_u32_vec(), - y_1_x_quare.as_u32_vec(), - false, - ); - let result = execute_script(script); - assert!(result.success); + // let script = fold_degree::( + // x.as_u32_vec(), + // y0_x.as_u32_vec(), + // y0_neg_x.as_u32_vec(), + // beta.as_u32_vec(), + // y_1_x_quare.as_u32_vec(), + // false, + // ); + // let result = execute_script(script); + // assert!(result.success); } } } diff --git a/fri/src/fri_scripts/fiat_shamir_subtree.rs b/fri/src/fri_scripts/fiat_shamir_subtree.rs index e826389..42bb096 100644 --- a/fri/src/fri_scripts/fiat_shamir_subtree.rs +++ b/fri/src/fri_scripts/fiat_shamir_subtree.rs @@ -15,10 +15,10 @@ use primitives::challenger::chan_field::{PermutationField, U32}; use primitives::challenger::{BfChallenger, BitExtractor, Blake3Permutation}; use primitives::field::BfField; use scripts::bit_comm_u32::*; +use scripts::blake3; use scripts::pseudo::{OP_4DROP, OP_4FROMALTSTACK, OP_4TOALTSTACK}; use scripts::u32_rrot::{u32_rrot, u8_extract_hbit}; use scripts::u32_std::{u32_compress, u32_equal, u32_equalverify, u32_push}; -use scripts::{blake3, BabyBearU31}; /// fiat shamir subtree contains a series script leafs and coressponding trait SubTree { @@ -413,7 +413,8 @@ mod test { use primitives::challenger::chan_field::{PermutationField, U32}; use primitives::challenger::{BfChallenger, BfGrindingChallenger, Blake3Permutation}; use scripts::bit_comm::pushable; - use scripts::{execute_script, execute_script_with_inputs, to_digits, BabyBear4}; + use scripts::u31_lib::BabyBear4; + use scripts::{execute_script, execute_script_with_inputs, to_digits}; use super::{new_challenge_commit, new_u32_bit_commit, Commit, FiatShamirSubTree, SubTree}; diff --git a/fri/src/fri_scripts/leaf.rs b/fri/src/fri_scripts/leaf.rs index e53e1e2..22c2ee7 100644 --- a/fri/src/fri_scripts/leaf.rs +++ b/fri/src/fri_scripts/leaf.rs @@ -9,15 +9,12 @@ use std::usize; use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; -use itertools::rev; -use p3_field::TwoAdicField; use primitives::bit_comm::{BCAssignment, BitCommitment, *}; use primitives::field::BfField; -use scripts::bit_comm::winternitz; use scripts::bit_comm_u32::BitCommitmentU32; -use scripts::{ - execute_script, execute_script_with_inputs, u31_add, u31_equalverify, u31ext_add, - u31ext_equalverify, BabyBear4, BabyBearU31, +use scripts::execute_script_with_inputs; +use scripts::u31_lib::{ + u31_add, u31_equalverify, u31ext_add, u31ext_equalverify, BabyBear4, BabyBearU31, }; use segment::SegmentLeaf; @@ -466,13 +463,14 @@ pub fn u8_to_hex_str(byte: &u8) -> String { #[cfg(test)] mod test { - use itertools::equal; + use itertools::{equal, rev}; use p3_baby_bear::BabyBear; use p3_field::extension::BinomialExtensionField; - use p3_field::AbstractField; + use p3_field::{AbstractField, TwoAdicField}; use p3_util::reverse_bits_len; use primitives::mmcs::taptree::EvaluationLeaf; use rand::Rng; + use scripts::execute_script; type AF = BabyBear; type F = BinomialExtensionField; diff --git a/fri/src/fri_scripts/verify_folding.rs b/fri/src/fri_scripts/verify_folding.rs index 3f397e3..b319d38 100644 --- a/fri/src/fri_scripts/verify_folding.rs +++ b/fri/src/fri_scripts/verify_folding.rs @@ -1,22 +1,12 @@ -use bitcoin::opcodes::{ - OP_DEPTH, OP_DROP, OP_DUP, OP_ELSE, OP_ENDIF, OP_EQUAL, OP_EQUALVERIFY, OP_FROMALTSTACK, - OP_GREATERTHAN, OP_PICK, OP_SWAP, OP_TOALTSTACK, -}; -use bitcoin::secp256k1::ellswift; use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; -use p3_baby_bear::BabyBear; -use p3_field::{AbstractField, TwoAdicField}; -use p3_util::{log2_ceil_u64, log2_ceil_usize, log2_strict_usize, reverse_bits_len}; use primitives::field::BfField; use scripts::pseudo::{ OP_4DUP, OP_4FROMALTSTACK, OP_4MUL, OP_4PICK, OP_4ROLL, OP_4TOALTSTACK, OP_NDUP, }; -use scripts::u32_rrot::u8_extract_hbit; -use scripts::u32_std::{u32_compress, u32_push}; -use scripts::{ - u31_add, u31_double, u31_equalverify, u31_mul, u31_sub, u31ext_add, u31ext_double, - u31ext_equalverify, u31ext_mul, u31ext_sub, BabyBear4, BabyBearU31, U31Config, +use scripts::u31_lib::{ + u31_add, u31_double, u31_mul, u31_sub, u31ext_add, u31ext_double, u31ext_equalverify, + u31ext_mul, u31ext_sub, BabyBear4, BabyBearU31, }; define_pushable!(); @@ -71,7 +61,7 @@ pub fn reverse_bits_len_script_with_input(input_index: u32, bits: usize) -> Scri } {reverse_bits_len_script(bits)} OP_FROMALTSTACK - {OP_EQUAL} + OP_EQUAL } } @@ -286,11 +276,12 @@ pub fn value_square_with_input() -> Script { #[cfg(test)] mod tests { - use std::ops::MulAssign; use bitcoin::opcodes::{OP_DEPTH, OP_EQUAL}; - use bitcoin::script; + use p3_baby_bear::BabyBear; use p3_field::extension::BinomialExtensionField; + use p3_field::{AbstractField, TwoAdicField}; + use p3_util::reverse_bits_len; use rand::{random, Rng}; type AF = BabyBear; type F = BinomialExtensionField; @@ -628,7 +619,7 @@ mod tests { } {reverse_bits_len_script(bits)} {reverse_bits_len(x as usize, bits)} - {OP_EQUAL} + OP_EQUAL }; let res = execute_script(script); // println!("{:?}", res); diff --git a/fri/src/mmcs/bf_mmcs.rs b/fri/src/mmcs/bf_mmcs.rs deleted file mode 100644 index c56c76b..0000000 --- a/fri/src/mmcs/bf_mmcs.rs +++ /dev/null @@ -1,44 +0,0 @@ -use alloc::vec; -use alloc::vec::Vec; -use core::fmt::Debug; - -use p3_matrix::dense::RowMajorMatrix; -// use serde::de::DeserializeOwned; -// use serde::Serialize; - -/// A "Mixed Matrix Commitment Scheme" (MMCS) is a generalization of a vector commitment scheme; it -/// supports committing to matrices and then opening rows. It is also batch-oriented; one can commit -/// to a batch of matrices at once even if their widths and heights differ. -/// -/// When a particular row index is opened, it is interpreted directly as a row index for matrices -/// with the largest height. For matrices with smaller heights, some bits of the row index are -/// removed (from the least-significant side) to get the effective row index. These semantics are -/// useful in the FRI protocol. See the documentation for `open_batch` for more details. -pub trait BFMmcs: Clone { - type ProverData; - // type Commitment: Clone + Serialize + DeserializeOwned; - // type Proof: Clone + Serialize + DeserializeOwned; - type Commitment: Clone; - type Proof: Clone; - type Error: Debug; - - fn commit(&self, inputs: Vec>) -> (Self::Commitment, Self::ProverData); - - fn commit_matrix(&self, input: RowMajorMatrix) -> (Self::Commitment, Self::ProverData) { - self.commit(vec![input]) - } - - fn commit_vec(&self, input: Vec) -> (Self::Commitment, Self::ProverData) - where - T: Clone + Send + Sync, - { - self.commit_matrix(RowMajorMatrix::new_col(input)) - } - - fn open_taptree(&self, index: usize, prover_data: &Self::ProverData) -> Self::Proof; - fn verify_taptree( - &self, - proof: &Self::Proof, - root: &Self::Commitment, - ) -> Result<(), Self::Error>; -} diff --git a/fri/src/mmcs/mod.rs b/fri/src/mmcs/mod.rs deleted file mode 100644 index c0c563f..0000000 --- a/fri/src/mmcs/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![feature(slice_pattern)] - -pub mod bf_mmcs; -pub mod tapleaf; -pub mod taptree; -pub mod taptree_mmcs; diff --git a/fri/src/mmcs/tapleaf.rs b/fri/src/mmcs/tapleaf.rs deleted file mode 100644 index cab1c6f..0000000 --- a/fri/src/mmcs/tapleaf.rs +++ /dev/null @@ -1,43 +0,0 @@ -use alloc::vec::Vec; - -use crate::fri_scripts::leaf::SegmentLeaf; -use bitcoin::{witness, ScriptBuf as Script, TapNodeHash}; -pub trait Tapleaf { - fn unlock_witness(&self) -> Vec>; - fn script(&self) -> Script; -} - -pub struct VerifierLeaf { - pub witness: Vec>, - pub script: Script, -} - -impl VerifierLeaf { - fn new(witness: Vec>, script: Script) -> Self { - Self { witness, script } - } - - fn new_from_segment_leaf(leaf: L) -> Self { - let script = leaf.leaf_script_witn_noeuqal(); - let witness = leaf.input(); - Self::new(witness, script) - } -} - -impl From for VerifierLeaf { - fn from(leaf: L) -> Self { - let script = leaf.leaf_script_witn_noeuqal(); - let witness = leaf.input(); - Self { witness, script } - } -} - -impl Tapleaf for VerifierLeaf { - fn unlock_witness(&self) -> Vec> { - self.witness.clone() - } - - fn script(&self) -> Script { - self.script.clone() - } -} diff --git a/fri/src/mmcs/taptree.rs b/fri/src/mmcs/taptree.rs deleted file mode 100644 index 65d7b16..0000000 --- a/fri/src/mmcs/taptree.rs +++ /dev/null @@ -1,471 +0,0 @@ -use alloc::vec::Vec; -use alloc::{slice, vec}; -use core::ops::{Deref, DerefMut}; -use core::{mem, usize}; - - -use primitives::field::BfField; -use crate::fri_scripts::leaf::{EvaluationLeaf}; -use crate::fri_scripts::point::PointsLeaf; -use bitcoin::taproot::LeafVersion::TapScript; -use bitcoin::taproot::{LeafNode, LeafNodes, NodeInfo, TaprootMerkleBranch}; -use bitcoin::{ScriptBuf, TapNodeHash}; -use itertools::{Chunk, Itertools}; -use p3_util::{log2_strict_usize, reverse_slice_index_bits}; - -use crate::error::BfError; - -pub fn combine_two_nodes(a: NodeInfo, b: NodeInfo) -> Result<(NodeInfo, bool), BfError> { - let parent = NodeInfo::combine_with_order(a, b)?; - Ok(parent) -} - -// Todo: use &[F] to replace Vec -pub fn construct_evaluation_leaf_script( - leaf_index: usize, - x: F, - y_s: Vec, -) -> Result { - let leaf_script: EvaluationLeaf = EvaluationLeaf::new(leaf_index, x, y_s); - let script = leaf_script.leaf_script(); - Ok(script) -} - -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] -pub struct GlobalTree {} - -// =============== Polycommitment Tree =============== - -#[derive(Clone, Debug)] -pub struct PolyCommitTree { - pub tree: BasicTree, - pub points_leafs: Vec>, -} - -impl PolyCommitTree { - pub fn new(log_poly_points: usize) -> Self { - Self { - tree: BasicTree::::new(log_poly_points), - points_leafs: Vec::new(), - } - } - - pub fn commit_points(&mut self, evaluations: Vec) { - let poly_points = evaluations.len(); - let evas = Polynomials::new_eva_poly( - evaluations, - F::sub_group(log2_strict_usize(poly_points)), - PolynomialType::Eva, - ); - let mut builder = TreeBuilder::::new(); - for i in 0..evas.values.len() { - let leaf_script = construct_evaluation_leaf_script::<1, F>( - i, - evas.points[i], - vec![evas.values[i].clone()], - ) - .unwrap(); - } - self.tree = builder.build_tree(); - } - - pub fn commit_rev_points(&mut self, evaluations: Vec, width: usize) { - let poly_points = evaluations.len(); - let mut subgroup = F::sub_group(log2_strict_usize(poly_points)); - let leaf_indexs: Vec = (0..poly_points).into_iter().collect(); - reverse_slice_index_bits(&mut subgroup); - let mut tree_builder = TreeBuilder::::new(); - for i in (0..poly_points).into_iter().step_by(width) { - let leaf = PointsLeaf::new( - leaf_indexs[i], - leaf_indexs[i + 1], - subgroup[i], - evaluations[i], - subgroup[i + 1], - evaluations[i + 1], - ); - self.add_leaf(&mut tree_builder, &leaf) - } - - self.tree = tree_builder.build_tree(); - } - - pub fn root(&self) -> &NodeInfo { - self.tree.root() - } - - pub fn get_tapleaf(&self, index: usize) -> Option<&LeafNode> { - self.tree.get_tapleaf(index) - } - - // pub fn combine_tree() - - pub fn verify_inclusion_by_index(&self, index: usize) -> bool { - self.tree.verify_inclusion_by_index(index) - } - - pub fn add_leaf(&mut self, builder: &mut TreeBuilder, leaf: &PointsLeaf) { - self.points_leafs.push(leaf.clone()); - - builder.add_leaf(leaf.recover_points_euqal_to_commited_point()); - } - - pub fn get_points_leafs(&self) -> &[PointsLeaf] { - &self.points_leafs - } - - pub fn get_points_leaf(&self, index: usize) -> &PointsLeaf { - &self.points_leafs[index] - } -} - -#[derive(Clone, Debug, PartialEq, PartialOrd)] -pub struct BasicTree { - pub root_node: Option, - leaf_count: usize, - leaf_indices: Vec, -} - -pub struct TreeBuilder { - leaf_count: usize, - leaf_indices: Vec, - to_add_leaves: Vec, -} - -impl TreeBuilder { - pub fn new() -> Self { - Self { - leaf_count: 0, - leaf_indices: Vec::new(), - to_add_leaves: Vec::new(), - } - } - - pub fn add_leaf(&mut self, leaf_script: ScriptBuf) { - self.leaf_count += 1; - let leaf = NodeInfo::new_leaf_with_ver(leaf_script, TapScript); - self.leaf_indices.push(self.leaf_count - 1); - self.to_add_leaves.push(leaf); - } - - /* - The leaves_indices are postion info of merkle tree leaves in the taptree. - When we building the taptree, it is much easier to work with a dict where the index is - the taptree position and the element is the merkle tree postion. - We flip the dict and save it to the leaf_indices. - - */ - pub fn build_tree(&mut self) -> BasicTree { - let mut working_nodes = self.to_add_leaves.clone(); - let mut t_idx_to_m_idx = self.leaf_indices.clone(); - - while working_nodes.len() > 1 { - //the tuple() method in itertool will drop the elements in Iter if the size is not enough to - //generate a tuple, so we have to save the last node if the size of working node is odd. - let mut reminder_node: Option = None; - if working_nodes.len() % 2 == 1 { - reminder_node = working_nodes.pop(); - } - - let mut node_tuples = working_nodes.into_iter().tuples(); - let mut todo: Vec = Vec::new(); - let mut a_start_idx = 0usize; // will be updated after finishing combining two nodes. - - for (a, b) in node_tuples { - let a_leaf_size = a.leaf_nodes().len(); - let a_end_idx = a_start_idx + a_leaf_size; - let b_start_idx = a_end_idx; - let b_leaf_size = b.leaf_nodes().len(); - let b_end_idx = b_start_idx + b_leaf_size; - let (ret_node, left_first) = NodeInfo::combine_with_order(a, b).unwrap(); - - todo.push(ret_node); - - if !left_first { - let mut temp_a_leaf_indices = vec![0usize; a_leaf_size]; - temp_a_leaf_indices - .as_mut_slice() - .copy_from_slice(&t_idx_to_m_idx[a_start_idx..a_end_idx]); - - let mut temp_b_leaf_indices = vec![0usize; b_leaf_size]; - temp_b_leaf_indices - .as_mut_slice() - .copy_from_slice(&t_idx_to_m_idx[b_start_idx..b_end_idx]); - temp_b_leaf_indices.append(&mut temp_a_leaf_indices); - t_idx_to_m_idx[a_start_idx..b_end_idx] - .copy_from_slice(&temp_b_leaf_indices.as_slice()); - } - a_start_idx += a_leaf_size + b_leaf_size; - } - working_nodes = todo; - todo = Vec::new(); - } - BasicTree { - root_node: Some(working_nodes.into_iter().next().unwrap()), - leaf_count: self.leaf_count, - leaf_indices: reverse_idx_dict(&t_idx_to_m_idx), - } - } -} - -fn reverse_idx_dict(idx_dict: &Vec) -> Vec { - let mut ret_vec = vec![0usize; idx_dict.len()]; - for (idx, pos) in idx_dict.iter().enumerate() { - ret_vec[*pos] = idx; - } - ret_vec -} - -impl BasicTree { - pub fn new(log_poly_points: usize) -> Self { - Self { - root_node: None, - leaf_count: 0, - leaf_indices: Vec::new(), - } - } - - pub fn root(&self) -> &NodeInfo { - let root = self.root_node.as_ref().unwrap(); - root - } - - // This function only support combine trees with same depth - pub fn combine_tree(a: Self, b: Self) -> Self { - // perserve indices map before combining two trees. - let mut a_leaf_indices = a.leaf_indices.clone(); - let mut b_leaf_indices = b.leaf_indices.clone(); - - let (combined_tree, noswap) = - combine_two_nodes(a.root_node.unwrap(), b.root_node.unwrap()).unwrap(); - - let mut a_t_idx_to_m_idx = reverse_idx_dict(&a_leaf_indices); - let mut b_t_idx_to_m_idx = reverse_idx_dict(&b_leaf_indices); - - let t_idx_to_m_idx = match noswap { - true => { - for b_m_idx in b_t_idx_to_m_idx.iter() { - a_t_idx_to_m_idx.push(*b_m_idx); - } - a_t_idx_to_m_idx - } - false => { - for a_m_idx in a_t_idx_to_m_idx.iter() { - b_t_idx_to_m_idx.push(*a_m_idx); - } - b_t_idx_to_m_idx - } - }; - - Self { - root_node: Some(combined_tree), - leaf_count: t_idx_to_m_idx.len(), - leaf_indices: reverse_idx_dict(&t_idx_to_m_idx), - } - } - - pub fn leaf_count(&self) -> usize { - self.leaf_count - } - - pub fn leaves(&self) -> LeafNodes { - let nodes = self.root_node.as_ref().unwrap().leaf_nodes(); - nodes - } - - pub fn get_leaf_merkle_path(&self, index: usize) -> Option<&TaprootMerkleBranch> { - let index = self.index_map(index); - if let Some(leaf) = self.leaves().nth(index) { - Some(leaf.merkle_branch()) - } else { - None - } - } - - fn index_map(&self, index: usize) -> usize { - self.leaf_indices[index] as usize - } - - pub fn get_tapleaf(&self, index: usize) -> Option<&LeafNode> { - let index = self.index_map(index); - self.leaves().nth(index) - } - - pub fn verify_inclusion_by_index(&self, index: usize) -> bool { - let index = self.index_map(index); - let leaf = self.get_tapleaf(index).unwrap(); - let path = self.get_leaf_merkle_path(index).unwrap(); - let mut first_node_hash = TapNodeHash::from_node_hashes(leaf.node_hash(), path[0]); - path[1..].into_iter().for_each(|sibling_node| { - first_node_hash = TapNodeHash::from_node_hashes(first_node_hash, *sibling_node); - }); - - first_node_hash == self.root().node_hash() - } -} - -impl From for BasicTree { - fn from(value: NodeInfo) -> Self { - Self { - root_node: Some(value), - leaf_count: 0, - leaf_indices: Vec::new(), - } - } -} - -pub fn verify_inclusion(root: TapNodeHash, leaf: &LeafNode) -> bool { - let path = leaf.merkle_branch(); - let mut first_node_hash = TapNodeHash::from_node_hashes(leaf.node_hash(), path[0]); - path[1..].into_iter().for_each(|sibling_node| { - first_node_hash = TapNodeHash::from_node_hashes(first_node_hash, *sibling_node); - }); - - first_node_hash == root -} - -#[derive(Clone, Debug, PartialEq, PartialOrd)] -enum PolynomialType { - Eva, - Coeff, -} -struct Polynomials { - values: Vec, - points: Vec, // only for evaluations - style: PolynomialType, -} - -impl Polynomials { - pub fn new(values: Vec, style: PolynomialType) -> Self { - Self { - values, - points: Vec::new(), - style, - } - } - - pub fn new_eva_poly(values: Vec, points: Vec, style: PolynomialType) -> Self { - Self { - values, - points, - style, - } - } - - fn convert_to_evals_at_subgroup(&self) -> Self { - assert!(self.style == PolynomialType::Coeff); - let subgroup_bits = log2_strict_usize(self.values.len()); - let subgroup = F::sub_group(subgroup_bits); - let mut evals = Vec::new(); - for i in 0..subgroup.len() { - let point = subgroup[i]; - let result = self - .values - .iter() - .fold(F::zero(), |acc, item| acc + *item * point.exp_u64(i as u64)); - evals.push(result); - } - assert_eq!(subgroup.len(), evals.len()); - Self::new_eva_poly(evals, subgroup, PolynomialType::Eva) - } - - fn values(&self) -> &Vec { - &self.values - } - - fn points(&self) -> &Vec { - assert!(self.style == PolynomialType::Eva); - &self.points - } -} - -#[cfg(test)] -mod tests { - - use p3_baby_bear::BabyBear; - use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; - use p3_field::extension::BinomialExtensionField; - use p3_field::{AbstractExtensionField, AbstractField}; - use p3_interpolation::interpolate_subgroup; - use p3_matrix::dense::RowMajorMatrix; - use rand::distributions::Standard; - use rand::prelude::Distribution; - use rand::{thread_rng, Rng}; - - use super::*; - - #[test] - fn test_tree_builder() { - type F = BabyBear; - let depth = 3; - let mut coeffs1: Vec = Vec::with_capacity(2u32.pow(depth as u32) as usize); - for i in 0..2u32.pow(depth as u32) { - coeffs1.push(F::from_canonical_u32(i)); - } - let poly1 = Polynomials::new(coeffs1, PolynomialType::Coeff); - let eva_poly1 = poly1.convert_to_evals_at_subgroup(); - let evas1 = eva_poly1.values(); - - let mut tb = TreeBuilder::<3>::new(); - - for i in 0..evas1.len() { - let leaf_script = construct_evaluation_leaf_script::<1, F>( - i, - eva_poly1.points[i], - vec![evas1[i].clone()], - ) - .unwrap(); - tb.add_leaf(leaf_script); - } - - let tree = tb.build_tree(); - // assert!(root_node.leaf_nodes().len()==8); - } - - fn commit_with_poly_tree(degree: usize) -> PolyCommitTree - where - Standard: Distribution, - { - let mut rng = thread_rng(); - let coeffs = (0..degree).map(|_| rng.gen::()).collect::>(); - - let poly = Polynomials::new(coeffs, PolynomialType::Coeff); - let eva_poly = poly.convert_to_evals_at_subgroup(); - let evas = eva_poly.values(); - let mut poly_taptree = PolyCommitTree::::new(2); - poly_taptree.commit_rev_points(evas.clone(), 2); - poly_taptree - } - - #[test] - fn test_poly_commit_tree() { - // x^2 + 2 x + 3 - type F = BabyBear; - let poly_taptree = commit_with_poly_tree::(8); - - (0..4).into_iter().for_each(|index| { - let leaf = poly_taptree.get_tapleaf(index).unwrap(); - let script = leaf.leaf().as_script().unwrap(); - let points_leaf = poly_taptree.get_points_leaf(index); - assert_eq!( - points_leaf.recover_points_euqal_to_commited_point(), - *script.0 - ); - let success = verify_inclusion(poly_taptree.root().node_hash(), leaf); - assert_eq!(success, true); - }); - } - - #[test] - fn test_swap_slice() { - let mut values = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - - let temp1 = values[2..4].to_vec(); - let temp2 = values[6..8].to_vec(); - - values[2..4].clone_from_slice(&temp2); - values[6..8].clone_from_slice(&temp1); - - println!("{:?}", values); - } -} diff --git a/fri/src/mmcs/taptree_mmcs.rs b/fri/src/mmcs/taptree_mmcs.rs deleted file mode 100644 index 7614a72..0000000 --- a/fri/src/mmcs/taptree_mmcs.rs +++ /dev/null @@ -1,84 +0,0 @@ -use alloc::vec::Vec; -use core::marker::PhantomData; -use core::{panic, usize}; - -use primitives::field::BfField; -use bitcoin::hashes::Hash as Bitcoin_HASH; -use bitcoin::TapNodeHash; -use primitives::challenger::chan_field::{u256_to_u32, u32_to_u256, U256, U32}; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; -use p3_util::log2_strict_usize; - -use super::bf_mmcs::BFMmcs; -use crate::error::BfError; -use crate::prover::LOG_DEFAULT_MATRIX_WIDTH; -use crate::taptree::{verify_inclusion, PolyCommitTree}; -use crate::BfCommitPhaseProofStep; - -pub type TreeRoot = [U32; ROOT_WIDTH]; -pub const ROOT_WIDTH: usize = 8; -#[derive(Clone, Debug, PartialEq, PartialOrd)] -pub struct TapTreeMmcs { - _marker: PhantomData, -} - -impl TapTreeMmcs { - pub fn new() -> Self { - Self { - _marker: PhantomData, - } - } -} -impl BFMmcs for TapTreeMmcs { - type ProverData = PolyCommitTree; - type Proof = BfCommitPhaseProofStep; - type Commitment = TreeRoot; - type Error = BfError; - - fn open_taptree(&self, index: usize, prover_data: &PolyCommitTree) -> Self::Proof { - // The matrix with width-2 lead to the index need to right shift 1-bit - let leaf_index = index >> LOG_DEFAULT_MATRIX_WIDTH; - let leaf = prover_data.get_tapleaf(leaf_index); - let opening_leaf = match leaf { - Some(v) => v, - None => { - // println!( - // "leaf index:{:?}, leaf count:{:?}", - // index, - // prover_data.leaf_count() - // ); - panic!("invalid leaf index") - } - }; - let open_leaf = prover_data.get_points_leaf(leaf_index).clone(); - BfCommitPhaseProofStep { - points_leaf: open_leaf, - leaf_node: opening_leaf.clone(), - } - } - - fn verify_taptree( - &self, - proof: &Self::Proof, - root: &Self::Commitment, - ) -> Result<(), Self::Error> { - let root_node = TapNodeHash::from_byte_array(u32_to_u256(root.clone())); - let success = verify_inclusion(root_node, &proof.leaf_node); - if success { - Ok(()) - } else { - Err(BfError::InvalidMerkleProof) - } - } - - fn commit(&self, inputs: Vec>) -> (Self::Commitment, Self::ProverData) { - let log_leaves = log2_strict_usize(inputs[0].height()); - let mut tree = PolyCommitTree::::new(log_leaves); - - tree.commit_rev_points(inputs[0].values.clone(), inputs[0].width); - let root: U256 = tree.root().node_hash().as_byte_array().clone(); - - (u256_to_u32(root), tree) - } -} diff --git a/fri/src/prover.rs b/fri/src/prover.rs index 6503f7c..218e242 100644 --- a/fri/src/prover.rs +++ b/fri/src/prover.rs @@ -389,7 +389,7 @@ mod tests { let shift = Val::generator(); let mut rng = ChaCha20Rng::seed_from_u64(0); - let ldes: Vec> = (9..10) + let ldes: Vec> = (5..6) .map(|deg_bits| { let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); let mut lde = dft.coset_lde_batch(evals, 1, shift); diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 1945526..a1e5853 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -4,9 +4,9 @@ version = "0.1.0" edition = "2021" [dependencies] -bitcoin-script = { git = "https://github.com/cyl19970726/rust-bitcoin-script", rev = "eda97c5" } -bitcoin = { git = "https://github.com/cyl19970726/rust-bitcoin", rev = "ffad6f3" } -bitcoin-scriptexec = { git = "https://github.com/cyl19970726/rust-bitcoin-scriptexec",rev = "205b90c"} +bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } +bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } +bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } lazy_static = "1.4.0" itertools = "0.12.0" tracing = "0.1.37" diff --git a/primitives/src/bit_comm/bc_assign.rs b/primitives/src/bit_comm/bc_assign.rs index 6acf35a..e827b24 100644 --- a/primitives/src/bit_comm/bc_assign.rs +++ b/primitives/src/bit_comm/bc_assign.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use itertools::Itertools; use scripts::bit_comm_u32::BitCommitmentU32; + use super::BitCommitment; use crate::field::BfField; diff --git a/primitives/src/bit_comm/mod.rs b/primitives/src/bit_comm/mod.rs index 0513b73..0fb6041 100644 --- a/primitives/src/bit_comm/mod.rs +++ b/primitives/src/bit_comm/mod.rs @@ -5,7 +5,7 @@ use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; use itertools::Itertools; use scripts::bit_comm_u32::*; -use scripts::{u31_equalverify, u31ext_equalverify, BabyBear4}; +use scripts::u31_lib::{u31_equalverify, u31ext_equalverify, BabyBear4}; use crate::field::*; define_pushable!(); @@ -129,10 +129,8 @@ mod test { use p3_field::{AbstractExtensionField, AbstractField, PrimeField32}; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; - use scripts::{ - execute_script, execute_script_with_inputs, u31ext_add, u31ext_double, u31ext_equalverify, - BabyBear4, - }; + use scripts::u31_lib::{u31ext_add, u31ext_equalverify, BabyBear4}; + use scripts::{execute_script, execute_script_with_inputs}; use super::*; diff --git a/scripts/Cargo.toml b/scripts/Cargo.toml index 3d7b8fa..1848695 100644 --- a/scripts/Cargo.toml +++ b/scripts/Cargo.toml @@ -4,9 +4,10 @@ version = "0.1.0" edition = "2021" [dependencies] -bitcoin-script = { git = "https://github.com/cyl19970726/rust-bitcoin-script", rev = "eda97c5" } -bitcoin = { git = "https://github.com/cyl19970726/rust-bitcoin", rev = "ffad6f3" } -bitcoin-scriptexec = { git = "https://github.com/cyl19970726/rust-bitcoin-scriptexec",rev = "205b90c"} +bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } +bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } +bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } +rust-bitcoin-u31-or-u30 ={ git = "https://github.com/bitlayer-org/rust-bitcoin-m31-or-babybear.git", branch = "bf-stark" } lazy_static = "1.4.0" rand_chacha = "0.3.1" diff --git a/scripts/src/lib.rs b/scripts/src/lib.rs index 9911878..52e4dfa 100644 --- a/scripts/src/lib.rs +++ b/scripts/src/lib.rs @@ -6,11 +6,6 @@ use bitcoin::hashes::Hash; use bitcoin::taproot::TapLeafHash; use bitcoin_script::define_pushable; use bitcoin_scriptexec::{Exec, ExecCtx, ExecutionResult, Options, TxTemplate}; -mod u31; -pub use u31::*; - -mod u31_ext; -pub use u31_ext::*; pub mod bit_comm; pub use bit_comm::*; @@ -25,6 +20,23 @@ pub use hashes::*; define_pushable!(); +#[allow(dead_code)] +pub mod u31_lib { + pub use bitcoin::ScriptBuf as Script; + pub use bitcoin_script::{define_pushable, script}; + define_pushable!(); + + pub use rust_bitcoin_u31_or_u30::{ + u31_add, u31_double, u31_mul, u31_sub, u31ext_add, u31ext_double, u31ext_equalverify, + u31ext_mul, u31ext_sub, BabyBear as BabyBearU31, BabyBear4, + }; + + pub fn u31_equalverify() -> Script { + script! { + OP_EQUALVERIFY + } + } +} #[allow(dead_code)] // Re-export what is needed to write treepp scripts pub mod treepp { diff --git a/scripts/src/u31/m31.rs b/scripts/src/u31/m31.rs deleted file mode 100644 index 3639491..0000000 --- a/scripts/src/u31/m31.rs +++ /dev/null @@ -1,6 +0,0 @@ -use crate::u31::U31Config; - -pub struct M31; -impl U31Config for M31 { - const MOD: u32 = (1 << 31) - 1; -} diff --git a/scripts/src/u31_ext/babybear.rs b/scripts/src/u31_ext/babybear.rs deleted file mode 100644 index 8529d43..0000000 --- a/scripts/src/u31_ext/babybear.rs +++ /dev/null @@ -1,215 +0,0 @@ -use bitcoin::ScriptBuf as Script; -use bitcoin_script::script; - -use crate::u31::{u31_add, u31_double, BabyBearU31 as BabyBear}; -use crate::{karatsuba_big, pushable, U31ExtConfig}; - -pub struct BabyBear4; - -impl BabyBear4 { - fn mul_11() -> Script { - script! { - OP_DUP - { u31_double::() } - OP_DUP - { u31_double::() } - { u31_double::() } - { u31_add::() } - { u31_add::() } - } - } -} - -impl U31ExtConfig for BabyBear4 { - type BaseFieldConfig = BabyBear; - const DEGREE: u32 = 4; - - fn mul_impl() -> Script { - script! { - { karatsuba_big::() } - 6 OP_ROLL - 6 OP_ROLL - { u31_add::() } - { Self::mul_11() } - { u31_add::() } - 5 OP_ROLL - { Self::mul_11() } - 2 OP_ROLL - { u31_add::() } - 5 OP_ROLL - { Self::mul_11() } - 3 OP_ROLL - 4 OP_ROLL - { u31_add::() } - { u31_add::() } - OP_SWAP - OP_ROT - } - } -} - -#[cfg(test)] -mod test { - use core::ops::{Add, Mul, Neg}; - - use bitcoin::opcodes::OP_ROLL; - use p3_field::{AbstractExtensionField, AbstractField, PrimeField32}; - use rand::{Rng, SeedableRng}; - use rand_chacha::ChaCha20Rng; - - use super::*; - use crate::pseudo::{OP_4DUP, OP_4PICK, OP_4ROLL, OP_4TOALTSTACK, OP_NDUP}; - use crate::{ - execute_script, u31ext_add, u31ext_double, u31ext_equalverify, u31ext_mul, u31ext_sub, - }; - - type F = p3_field::extension::BinomialExtensionField; - - #[test] - fn test_u31ext_add() { - let mut rng = ChaCha20Rng::seed_from_u64(0u64); - eprintln!("babybear4 add: {}", u31ext_add::().len()); - - let a = rng.gen::(); - let b = rng.gen::(); - - let c = a.add(b); - - let a: &[p3_baby_bear::BabyBear] = a.as_base_slice(); - let b: &[p3_baby_bear::BabyBear] = b.as_base_slice(); - let c: &[p3_baby_bear::BabyBear] = c.as_base_slice(); - - let script = script! { - { a[3].as_canonical_u32() } { a[2].as_canonical_u32() } { a[1].as_canonical_u32() } { a[0].as_canonical_u32() } - { b[3].as_canonical_u32() } { b[2].as_canonical_u32() } { b[1].as_canonical_u32() } { b[0].as_canonical_u32() } - { b[3].as_canonical_u32() } { b[2].as_canonical_u32() } { b[1].as_canonical_u32() } { b[0].as_canonical_u32() } - 8 OP_4ROLL - - { u31ext_add::() } - - { c[3].as_canonical_u32() } { c[2].as_canonical_u32() } { c[1].as_canonical_u32() } { c[0].as_canonical_u32() } - { u31ext_equalverify::() } - - OP_4DUP - { u31ext_equalverify::() } - OP_PUSHNUM_1 - }; - - let exec_result = execute_script(script); - assert!(exec_result.success); - - let script = script! { - { a[3].as_canonical_u32() } { a[2].as_canonical_u32() } { a[1].as_canonical_u32() } { a[0].as_canonical_u32() } - { b[3].as_canonical_u32() } { b[2].as_canonical_u32() } { b[1].as_canonical_u32() } { b[0].as_canonical_u32() } - 4 OP_4PICK - - { u31ext_add::() } - - { c[3].as_canonical_u32() } { c[2].as_canonical_u32() } { c[1].as_canonical_u32() } { c[0].as_canonical_u32() } - { u31ext_equalverify::() } - - // {OP_NDUP(4)} - OP_4DUP - // { b[3].as_canonical_u32() } { b[2].as_canonical_u32() } { b[1].as_canonical_u32() } { b[0].as_canonical_u32() } - { u31ext_equalverify::() } - OP_PUSHNUM_1 - }; - let exec_result = execute_script(script); - assert!(exec_result.success); - - let script = script! { - for i in (0..4).rev(){ - {a[i].as_canonical_u32()} - } - for i in (0..4).rev(){ - {b[i].as_canonical_u32()} - } - - { u31ext_add::() } - - for i in (0..4).rev(){ - {c[i].as_canonical_u32()} - } - - { u31ext_equalverify::() } - OP_PUSHNUM_1 - }; - let exec_result = execute_script(script); - println!("{:?}", exec_result.error); - assert!(exec_result.success); - } - - #[test] - fn test_u31ext_double() { - let mut rng = ChaCha20Rng::seed_from_u64(0u64); - - let a = rng.gen::(); - let c = a.double(); - - let a: &[p3_baby_bear::BabyBear] = a.as_base_slice(); - let c: &[p3_baby_bear::BabyBear] = c.as_base_slice(); - - let script = script! { - { a[3].as_canonical_u32() } { a[2].as_canonical_u32() } { a[1].as_canonical_u32() } { a[0].as_canonical_u32() } - { u31ext_double::() } - { c[3].as_canonical_u32() } { c[2].as_canonical_u32() } { c[1].as_canonical_u32() } { c[0].as_canonical_u32() } - { u31ext_equalverify::() } - OP_PUSHNUM_1 - }; - let exec_result = execute_script(script); - assert!(exec_result.success); - } - - #[test] - fn test_u31ext_sub() { - let mut rng = ChaCha20Rng::seed_from_u64(0u64); - eprintln!("babybear4 sub: {}", u31ext_sub::().len()); - - let a = rng.gen::(); - let b = rng.gen::(); - let c = a.add(b.neg()); - - let a: &[p3_baby_bear::BabyBear] = a.as_base_slice(); - let b: &[p3_baby_bear::BabyBear] = b.as_base_slice(); - let c: &[p3_baby_bear::BabyBear] = c.as_base_slice(); - - let script = script! { - { a[3].as_canonical_u32() } { a[2].as_canonical_u32() } { a[1].as_canonical_u32() } { a[0].as_canonical_u32() } - { b[3].as_canonical_u32() } { b[2].as_canonical_u32() } { b[1].as_canonical_u32() } { b[0].as_canonical_u32() } - { u31ext_sub::() } - { c[3].as_canonical_u32() } { c[2].as_canonical_u32() } { c[1].as_canonical_u32() } { c[0].as_canonical_u32() } - { u31ext_equalverify::() } - OP_PUSHNUM_1 - }; - let exec_result = execute_script(script); - assert!(exec_result.success); - } - - #[test] - fn test_u31ext_mul() { - let mut rng = ChaCha20Rng::seed_from_u64(0u64); - eprintln!("babybear4 mul: {}", u31ext_mul::().len()); - - let a = rng.gen::(); - let b = rng.gen::(); - let c = a.mul(b); - - let a: &[p3_baby_bear::BabyBear] = a.as_base_slice(); - let b: &[p3_baby_bear::BabyBear] = b.as_base_slice(); - let c: &[p3_baby_bear::BabyBear] = c.as_base_slice(); - - let script = script! { - { a[3].as_canonical_u32() } { a[2].as_canonical_u32() } { a[1].as_canonical_u32() } { a[0].as_canonical_u32() } - { b[3].as_canonical_u32() } { b[2].as_canonical_u32() } { b[1].as_canonical_u32() } { b[0].as_canonical_u32() } - { u31ext_mul::() } - { c[3].as_canonical_u32() } { c[2].as_canonical_u32() } { c[1].as_canonical_u32() } { c[0].as_canonical_u32() } - { u31ext_equalverify::() } - OP_PUSHNUM_1 - }; - - let script_len = script.len(); - println!("script_len: {}", script_len); - let exec_result = execute_script(script); - assert!(exec_result.success); - } -} diff --git a/scripts/src/u31_ext/karatsuba.rs b/scripts/src/u31_ext/karatsuba.rs deleted file mode 100644 index d8e9827..0000000 --- a/scripts/src/u31_ext/karatsuba.rs +++ /dev/null @@ -1,193 +0,0 @@ -use bitcoin::ScriptBuf as Script; -use bitcoin_script::script; - -use crate::{pushable, u31_add, u31_mul, u31_sub, U31Config}; - -// Input: A1 B1 A2 B2 -// Output: -// A1A2 -// A1B2 + A2B1 -// B1B2 -pub fn karatsuba_small() -> Script { - script! { - OP_OVER 4 OP_PICK - { u31_mul::() } - OP_TOALTSTACK - OP_DUP - 3 OP_PICK - { u31_mul::() } - OP_TOALTSTACK - { u31_add::() } - OP_TOALTSTACK - { u31_add::() } - OP_FROMALTSTACK - { u31_mul::() } - OP_FROMALTSTACK - OP_FROMALTSTACK - OP_2DUP - { u31_add::() } - 3 OP_ROLL - OP_SWAP - { u31_sub::() } - OP_ROT - } -} - -// Input: -// A1 B1 C1 D1 -// A2 B2 C2 D2 -// Output: -// (A1, B1) * (A2, B2) - 3 elements -// (A1, B1) * (C2, D2) + (A2, B2) * (C1, D1) - 3 elements -// (C1, D1) * (C2, D2) - 3 elements -pub fn karatsuba_big() -> Script { - script! { - 7 OP_PICK - 7 OP_PICK - 5 OP_PICK - 5 OP_PICK - { karatsuba_small::() } - OP_TOALTSTACK - OP_TOALTSTACK - OP_TOALTSTACK - OP_2DUP - 7 OP_PICK - 7 OP_PICK - { karatsuba_small::() } - OP_TOALTSTACK - OP_TOALTSTACK - OP_TOALTSTACK - OP_ROT - { u31_add::() } - OP_TOALTSTACK - { u31_add::() } - OP_TOALTSTACK - OP_ROT - { u31_add::() } - OP_TOALTSTACK - { u31_add::() } - OP_FROMALTSTACK - OP_FROMALTSTACK - OP_FROMALTSTACK - { karatsuba_small::() } - OP_FROMALTSTACK - OP_FROMALTSTACK - OP_FROMALTSTACK - OP_FROMALTSTACK - OP_FROMALTSTACK - OP_FROMALTSTACK - 8 OP_ROLL - 3 OP_PICK - 7 OP_PICK - { u31_add::() } - { u31_sub::() } - 8 OP_ROLL - 3 OP_PICK - 7 OP_PICK - { u31_add::() } - { u31_sub::() } - 8 OP_ROLL - 3 OP_PICK - 7 OP_PICK - { u31_add::() } - { u31_sub::() } - 8 OP_ROLL - 8 OP_ROLL - 8 OP_ROLL - } -} - -#[cfg(test)] -mod test { - use core::ops::{Add, Mul}; - - use bitcoin_script::script; - use p3_baby_bear::BabyBear as P3BabyBear; - use p3_field::PrimeField32; - use rand::{Rng, SeedableRng}; - use rand_chacha::ChaCha20Rng; - - use crate::{ - execute_script, karatsuba_big, karatsuba_small, pushable, BabyBearU31 as BabyBear, - }; - - #[test] - fn test_small_karatsuba() { - let mut prng = ChaCha20Rng::seed_from_u64(0u64); - - let a1: P3BabyBear = prng.gen(); - let b1: P3BabyBear = prng.gen(); - let a2: P3BabyBear = prng.gen(); - let b2: P3BabyBear = prng.gen(); - - let first = a1.mul(a2); - let second = a1.mul(b2).add(a2.mul(b1)); - let third = b1.mul(b2); - - let script = script! { - { a1.as_canonical_u32() } { b1.as_canonical_u32() } { a2.as_canonical_u32() } { b2.as_canonical_u32() } - { karatsuba_small::() } - { third.as_canonical_u32() } - OP_EQUALVERIFY - { second.as_canonical_u32() } - OP_EQUALVERIFY - { first.as_canonical_u32() } - OP_EQUAL - }; - let exec_result = execute_script(script); - assert!(exec_result.success); - } - - #[test] - fn test_big_karatsuba() { - let mut prng = ChaCha20Rng::seed_from_u64(0u64); - - let a1: P3BabyBear = prng.gen(); - let b1: P3BabyBear = prng.gen(); - let c1: P3BabyBear = prng.gen(); - let d1: P3BabyBear = prng.gen(); - - let a2: P3BabyBear = prng.gen(); - let b2: P3BabyBear = prng.gen(); - let c2: P3BabyBear = prng.gen(); - let d2: P3BabyBear = prng.gen(); - - let group1_first = a1.mul(a2); - let group1_second = a1.mul(b2).add(a2.mul(b1)); - let group1_third = b1.mul(b2); - - let group3_first = c1.mul(c2); - let group3_second = c1.mul(d2).add(c2.mul(d1)); - let group3_third = d1.mul(d2); - - let group2_first = a1.mul(c2).add(a2.mul(c1)); - let group2_second = a1.mul(d2).add(b1.mul(c2)).add(a2.mul(d1)).add(b2.mul(c1)); - let group2_third = b1.mul(d2).add(b2.mul(d1)); - - let script = script! { - { a1.as_canonical_u32() } { b1.as_canonical_u32() } { c1.as_canonical_u32() } { d1.as_canonical_u32() } - { a2.as_canonical_u32() } { b2.as_canonical_u32() } { c2.as_canonical_u32() } { d2.as_canonical_u32() } - { karatsuba_big::() } - { group3_third.as_canonical_u32() } - OP_EQUALVERIFY - { group3_second.as_canonical_u32() } - OP_EQUALVERIFY - { group3_first.as_canonical_u32() } - OP_EQUALVERIFY - { group2_third.as_canonical_u32() } - OP_EQUALVERIFY - { group2_second.as_canonical_u32() } - OP_EQUALVERIFY - { group2_first.as_canonical_u32() } - OP_EQUALVERIFY - { group1_third.as_canonical_u32() } - OP_EQUALVERIFY - { group1_second.as_canonical_u32() } - OP_EQUALVERIFY - { group1_first.as_canonical_u32() } - OP_EQUAL - }; - let exec_result = execute_script(script); - assert!(exec_result.success); - } -} diff --git a/scripts/src/u31_ext/karatsuba_complex.rs b/scripts/src/u31_ext/karatsuba_complex.rs deleted file mode 100644 index 81bf423..0000000 --- a/scripts/src/u31_ext/karatsuba_complex.rs +++ /dev/null @@ -1,193 +0,0 @@ -use bitcoin::ScriptBuf as Script; -use bitcoin_script::script; - -use crate::{pushable, u31_add, u31_mul, u31_sub, U31Config}; - -// Input: A1 B1 A2 B2 -// Output: -// A1B2 + A2B1 -// B1B2 - A1A2 -pub fn karatsuba_complex_small() -> Script { - script! { - OP_OVER 4 OP_PICK - { u31_mul::() } - OP_TOALTSTACK - OP_DUP - 3 OP_PICK - { u31_mul::() } - OP_TOALTSTACK - { u31_add::() } - OP_TOALTSTACK - { u31_add::() } - OP_FROMALTSTACK - { u31_mul::() } - OP_FROMALTSTACK - OP_FROMALTSTACK - OP_2DUP - { u31_add::() } - 3 OP_ROLL - OP_SWAP - { u31_sub::() } - OP_TOALTSTACK - { u31_sub::() } - OP_FROMALTSTACK - OP_SWAP - } -} - -// Input: -// A1 B1 C1 D1 -// A2 B2 C2 D2 -// Output: -// (A1, B1) * (A2, B2) - 2 elements -// (A1, B1) * (C2, D2) + (A2, B2) * (C1, D1) - 2 elements -// (C1, D1) * (C2, D2) - 2 elements -pub fn karatsuba_complex_big() -> Script { - script! { - 7 OP_PICK - 7 OP_PICK - 5 OP_PICK - 5 OP_PICK - { karatsuba_complex_small::() } - OP_TOALTSTACK - OP_TOALTSTACK - OP_2DUP - 7 OP_PICK - 7 OP_PICK - { karatsuba_complex_small::() } - OP_TOALTSTACK - OP_TOALTSTACK - OP_ROT - { u31_add::() } - OP_TOALTSTACK - { u31_add::() } - OP_TOALTSTACK - OP_ROT - { u31_add::() } - OP_TOALTSTACK - { u31_add::() } - OP_FROMALTSTACK - OP_FROMALTSTACK - OP_FROMALTSTACK - { karatsuba_complex_small::() } - OP_FROMALTSTACK - OP_FROMALTSTACK - OP_FROMALTSTACK - OP_FROMALTSTACK - 5 OP_ROLL - 2 OP_PICK - 5 OP_PICK - { u31_add::() } - { u31_sub::() } - 5 OP_ROLL - 2 OP_PICK - 5 OP_PICK - { u31_add::() } - { u31_sub::() } - 5 OP_ROLL - 5 OP_ROLL - } -} - -#[cfg(test)] -mod test { - use core::ops::{Add, Mul, Sub}; - - use bitcoin_script::script; - use p3_field::extension::Complex; - use p3_field::PrimeField32; - use p3_mersenne_31::Mersenne31 as P3M31; - use rand::{Rng, SeedableRng}; - use rand_chacha::ChaCha20Rng; - - use crate::{execute_script, karatsuba_complex_big, karatsuba_complex_small, pushable, M31}; - - #[test] - fn test_small_karatsuba_complex() { - let mut prng = ChaCha20Rng::seed_from_u64(0u64); - - let a1: P3M31 = prng.gen(); - let b1: P3M31 = prng.gen(); - let a2: P3M31 = prng.gen(); - let b2: P3M31 = prng.gen(); - - let first = a1.mul(b2).add(a2.mul(b1)); - let second = b1.mul(b2).sub(a1.mul(a2)); - - let script = script! { - { a1.as_canonical_u32() } { b1.as_canonical_u32() } { a2.as_canonical_u32() } { b2.as_canonical_u32() } - { karatsuba_complex_small::() } - { second.as_canonical_u32() } - OP_EQUALVERIFY - { first.as_canonical_u32() } - OP_EQUAL - }; - let exec_result = execute_script(script); - assert!(exec_result.success); - } - - #[test] - fn test_big_karatsuba_complex() { - let mut prng = ChaCha20Rng::seed_from_u64(0u64); - - let a1: P3M31 = prng.gen(); - let b1: P3M31 = prng.gen(); - let c1: P3M31 = prng.gen(); - let d1: P3M31 = prng.gen(); - - let a2: P3M31 = prng.gen(); - let b2: P3M31 = prng.gen(); - let c2: P3M31 = prng.gen(); - let d2: P3M31 = prng.gen(); - - let group1_first = a1.mul(b2).add(a2.mul(b1)); - let group1_second = b1.mul(b2).sub(a1.mul(a2)); - - let group3_first = c1.mul(d2).add(c2.mul(d1)); - let group3_second = d1.mul(d2).sub(c1.mul(c2)); - - let group2_first = a1.mul(d2).add(b1.mul(c2)).add(a2.mul(d1)).add(b2.mul(c1)); - let group2_second = b1.mul(d2).add(b2.mul(d1)).sub(a1.mul(c2).add(a2.mul(c1))); - - let script = script! { - { a1.as_canonical_u32() } { b1.as_canonical_u32() } { c1.as_canonical_u32() } { d1.as_canonical_u32() } - { a2.as_canonical_u32() } { b2.as_canonical_u32() } { c2.as_canonical_u32() } { d2.as_canonical_u32() } - { karatsuba_complex_big::() } - { group3_second.as_canonical_u32() } - OP_EQUALVERIFY - { group3_first.as_canonical_u32() } - OP_EQUALVERIFY - { group2_second.as_canonical_u32() } - OP_EQUALVERIFY - { group2_first.as_canonical_u32() } - OP_EQUALVERIFY - { group1_second.as_canonical_u32() } - OP_EQUALVERIFY - { group1_first.as_canonical_u32() } - OP_EQUAL - }; - let exec_result = execute_script(script); - assert!(exec_result.success); - } - - #[test] - fn test_small_karatsuba_complex_consistency() { - let mut rng = ChaCha20Rng::seed_from_u64(0u64); - - let a: Complex = rng.gen(); - let b: Complex = rng.gen(); - let c = a.mul(b); - - let script = script! { - { a.imag().as_canonical_u32() } { a.real().as_canonical_u32() } - { b.imag().as_canonical_u32() } { b.real().as_canonical_u32() } - { karatsuba_complex_small::() } - { c.real().as_canonical_u32() } - OP_EQUALVERIFY - { c.imag().as_canonical_u32() } - OP_EQUAL - }; - let exec_result = execute_script(script); - assert!(exec_result.success); - } -} diff --git a/scripts/src/u31_ext/m31.rs b/scripts/src/u31_ext/m31.rs deleted file mode 100644 index 8e5b99f..0000000 --- a/scripts/src/u31_ext/m31.rs +++ /dev/null @@ -1,181 +0,0 @@ -use bitcoin::ScriptBuf as Script; -use bitcoin_script::script; - -use crate::{karatsuba_complex_big, pushable, u31_add, u31_double, u31_sub, U31ExtConfig, M31}; - -pub struct QM31; - -impl U31ExtConfig for QM31 { - type BaseFieldConfig = M31; - const DEGREE: u32 = 4; - - fn mul_impl() -> Script { - script! { - { karatsuba_complex_big::() } - 4 OP_ROLL - OP_DUP - { u31_double::() } - 6 OP_ROLL - OP_DUP - { u31_double::() } - OP_ROT - OP_ROT - { u31_sub::() } - 3 OP_ROLL - { u31_add::() } - OP_ROT - OP_ROT - { u31_add::() } - OP_ROT - { u31_add::() } - OP_SWAP - } - } -} - -#[cfg(test)] -mod test { - use core::ops::{Add, Mul, Neg}; - - use p3_field::extension::Complex; - use p3_field::{AbstractExtensionField, AbstractField, PrimeField32}; - use rand::{Rng, SeedableRng}; - use rand_chacha::ChaCha20Rng; - - use super::*; - use crate::{ - execute_script, u31ext_add, u31ext_double, u31ext_equalverify, u31ext_mul, u31ext_sub, - }; - - type F = p3_field::extension::BinomialExtensionField, 2>; - - #[test] - fn test_u31ext_add() { - let mut rng = ChaCha20Rng::seed_from_u64(0u64); - eprintln!("qm31 add: {}", u31ext_add::().len()); - - let a = rng.gen::(); - let b = rng.gen::(); - - let c = a.add(b); - - let a: &[Complex] = a.as_base_slice(); - let b: &[Complex] = b.as_base_slice(); - let c: &[Complex] = c.as_base_slice(); - - let script = script! { - { a[1].imag().as_canonical_u32() } - { a[1].real().as_canonical_u32() } - { a[0].imag().as_canonical_u32() } - { a[0].real().as_canonical_u32() } - { b[1].imag().as_canonical_u32() } - { b[1].real().as_canonical_u32() } - { b[0].imag().as_canonical_u32() } - { b[0].real().as_canonical_u32() } - { u31ext_add::() } - { c[1].imag().as_canonical_u32() } - { c[1].real().as_canonical_u32() } - { c[0].imag().as_canonical_u32() } - { c[0].real().as_canonical_u32() } - { u31ext_equalverify::() } - OP_PUSHNUM_1 - }; - let exec_result = execute_script(script); - assert!(exec_result.success); - } - - #[test] - fn test_u31ext_double() { - let mut rng = ChaCha20Rng::seed_from_u64(0u64); - - let a = rng.gen::(); - let c = a.double(); - - let a: &[Complex] = a.as_base_slice(); - let c: &[Complex] = c.as_base_slice(); - - let script = script! { - { a[1].imag().as_canonical_u32() } - { a[1].real().as_canonical_u32() } - { a[0].imag().as_canonical_u32() } - { a[0].real().as_canonical_u32() } - { u31ext_double::() } - { c[1].imag().as_canonical_u32() } - { c[1].real().as_canonical_u32() } - { c[0].imag().as_canonical_u32() } - { c[0].real().as_canonical_u32() } - { u31ext_equalverify::() } - OP_PUSHNUM_1 - }; - let exec_result = execute_script(script); - assert!(exec_result.success); - } - - #[test] - fn test_u31ext_sub() { - let mut rng = ChaCha20Rng::seed_from_u64(0u64); - eprintln!("qm31 sub: {}", u31ext_sub::().len()); - - let a = rng.gen::(); - let b = rng.gen::(); - let c = a.add(b.neg()); - - let a: &[Complex] = a.as_base_slice(); - let b: &[Complex] = b.as_base_slice(); - let c: &[Complex] = c.as_base_slice(); - - let script = script! { - { a[1].imag().as_canonical_u32() } - { a[1].real().as_canonical_u32() } - { a[0].imag().as_canonical_u32() } - { a[0].real().as_canonical_u32() } - { b[1].imag().as_canonical_u32() } - { b[1].real().as_canonical_u32() } - { b[0].imag().as_canonical_u32() } - { b[0].real().as_canonical_u32() } - { u31ext_sub::() } - { c[1].imag().as_canonical_u32() } - { c[1].real().as_canonical_u32() } - { c[0].imag().as_canonical_u32() } - { c[0].real().as_canonical_u32() } - { u31ext_equalverify::() } - OP_PUSHNUM_1 - }; - let exec_result = execute_script(script); - assert!(exec_result.success); - } - - #[test] - fn test_u31ext_mul() { - let mut rng = ChaCha20Rng::seed_from_u64(0u64); - eprintln!("qm31 mul: {}", u31ext_mul::().len()); - - let a = rng.gen::(); - let b = rng.gen::(); - let c = a.mul(b); - - let a: &[Complex] = a.as_base_slice(); - let b: &[Complex] = b.as_base_slice(); - let c: &[Complex] = c.as_base_slice(); - - let script = script! { - { a[1].imag().as_canonical_u32() } - { a[1].real().as_canonical_u32() } - { a[0].imag().as_canonical_u32() } - { a[0].real().as_canonical_u32() } - { b[1].imag().as_canonical_u32() } - { b[1].real().as_canonical_u32() } - { b[0].imag().as_canonical_u32() } - { b[0].real().as_canonical_u32() } - { u31ext_mul::() } - { c[1].imag().as_canonical_u32() } - { c[1].real().as_canonical_u32() } - { c[0].imag().as_canonical_u32() } - { c[0].real().as_canonical_u32() } - { u31ext_equalverify::() } - OP_PUSHNUM_1 - }; - let exec_result = execute_script(script); - assert!(exec_result.success); - } -} diff --git a/segment/Cargo.toml b/segment/Cargo.toml index 96cadb8..2fdd961 100644 --- a/segment/Cargo.toml +++ b/segment/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -bitcoin-script = { git = "https://github.com/cyl19970726/rust-bitcoin-script", rev = "eda97c5" } -bitcoin = { git = "https://github.com/cyl19970726/rust-bitcoin", rev = "ffad6f3" } -bitcoin-scriptexec = { git = "https://github.com/cyl19970726/rust-bitcoin-scriptexec",rev = "205b90c"} +bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } +bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } +bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } scripts ={ path = "../scripts"} \ No newline at end of file From a9986e043faa6684a1fb20009c423057de916cf4 Mon Sep 17 00:00:00 2001 From: AndreW0ng Date: Tue, 18 Jun 2024 15:46:27 +0800 Subject: [PATCH 03/25] Bitcommitment manager [Part 1] (#6) * refactor bit commitment * add secret_generator * rewrite bc_assignment * refactor some name * init script info structure * add script info structure * fix conflict * refactor script info * add bc assigner to script info --- .gitignore | 2 + Cargo.lock | 34 ++ Cargo.toml | 8 +- common/Cargo.toml | 8 + common/src/lib.rs | 29 ++ fri/Cargo.toml | 2 + fri/src/fold_even_odd.rs | 1 + fri/src/fri_scripts/fiat_shamir_subtree.rs | 53 +-- fri/src/fri_scripts/leaf.rs | 220 ++++++++---- fri/src/fri_scripts/point.rs | 59 +-- fri/src/prover.rs | 8 +- fri/src/script_verifier.rs | 8 +- fri/src/verifier.rs | 2 +- primitives/Cargo.toml | 5 +- primitives/src/bit_comm/bc_assign.rs | 98 ----- primitives/src/field/mod.rs | 9 +- primitives/src/lib.rs | 1 - primitives/src/mmcs/point.rs | 32 +- primitives/src/mmcs/tapleaf.rs | 1 + primitives/src/mmcs/taptree.rs | 16 +- script_manager/Cargo.toml | 48 +++ script_manager/src/bc_assignment.rs | 123 +++++++ script_manager/src/lib.rs | 3 + script_manager/src/planner.rs | 58 +++ script_manager/src/script_info.rs | 338 ++++++++++++++++++ scripts/Cargo.toml | 4 + .../src/bit_comm/bit_comm.rs | 210 +++++++---- scripts/src/bit_comm/bit_comm_u32.rs | 13 +- scripts/src/bit_comm/mod.rs | 8 +- scripts/src/bit_comm/secret_generator.rs | 34 ++ scripts/src/bit_comm/winternitz.rs | 3 +- 31 files changed, 1084 insertions(+), 354 deletions(-) create mode 100644 common/Cargo.toml create mode 100644 common/src/lib.rs delete mode 100644 primitives/src/bit_comm/bc_assign.rs create mode 100644 script_manager/Cargo.toml create mode 100644 script_manager/src/bc_assignment.rs create mode 100644 script_manager/src/lib.rs create mode 100644 script_manager/src/planner.rs create mode 100644 script_manager/src/script_info.rs rename primitives/src/bit_comm/mod.rs => scripts/src/bit_comm/bit_comm.rs (50%) create mode 100644 scripts/src/bit_comm/secret_generator.rs diff --git a/.gitignore b/.gitignore index b06f1f2..ba697ef 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk + +.DS_Store diff --git a/Cargo.lock b/Cargo.lock index 143f489..f52617f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -292,6 +292,14 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +[[package]] +name = "common" +version = "0.1.0" +dependencies = [ + "p3-baby-bear", + "p3-field", +] + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -409,6 +417,7 @@ dependencies = [ "primitives", "rand", "rand_chacha", + "script_manager", "scripts", "segment", "serde", @@ -899,6 +908,7 @@ dependencies = [ "bitcoin-script", "bitcoin-scriptexec", "blake3", + "common", "itertools 0.12.1", "lazy_static", "p3-baby-bear", @@ -912,6 +922,7 @@ dependencies = [ "p3-util", "rand", "rand_chacha", + "script_manager", "scripts", "segment", "serde", @@ -1085,6 +1096,27 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "script_manager" +version = "0.1.0" +dependencies = [ + "bitcoin", + "bitcoin-script", + "bitcoin-scriptexec", + "hex", + "itertools 0.12.1", + "lazy_static", + "once_cell", + "p3-baby-bear", + "p3-challenger", + "p3-field", + "p3-util", + "primitives", + "rand", + "rand_chacha", + "scripts", +] + [[package]] name = "scripts" version = "0.1.0" @@ -1093,6 +1125,7 @@ dependencies = [ "bitcoin-script", "bitcoin-scriptexec", "blake3", + "common", "criterion", "hex", "itertools 0.12.1", @@ -1109,6 +1142,7 @@ dependencies = [ "p3-poseidon2", "p3-symmetric", "p3-util", + "primitives", "rand", "rand_chacha", "rust-bitcoin-u31-or-u30", diff --git a/Cargo.toml b/Cargo.toml index 9d62a1a..ea9749e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,9 @@ members = [ "fri", "primitives", "p3", - "scripts", - "segment" - ] + "scripts", + "script_manager", + "segment", + "common" +] diff --git a/common/Cargo.toml b/common/Cargo.toml new file mode 100644 index 0000000..1603dd6 --- /dev/null +++ b/common/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "common" +version = "0.1.0" +edition = "2021" + +[dependencies] +p3-field = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } \ No newline at end of file diff --git a/common/src/lib.rs b/common/src/lib.rs new file mode 100644 index 0000000..1bcbf5f --- /dev/null +++ b/common/src/lib.rs @@ -0,0 +1,29 @@ +pub use p3_baby_bear::BabyBear; +pub use p3_field::extension::BinomialExtensionField; +pub use p3_field::{AbstractExtensionField, AbstractField, PrimeField32, TwoAdicField}; + +pub trait AsU32Vec { + fn bc_as_u32_vec(&self) -> Vec; + // fn u32_clone(&self) -> Self; +} + +impl AsU32Vec for u32 { + fn bc_as_u32_vec(&self) -> Vec { + vec![self.clone()] + } +} + +impl AsU32Vec for BinomialExtensionField { + fn bc_as_u32_vec(&self) -> Vec { + self.as_base_slice() + .iter() + .map(|babybear: &BabyBear| babybear.as_canonical_u32()) + .collect() + } +} + +impl AsU32Vec for BabyBear { + fn bc_as_u32_vec(&self) -> Vec { + vec![self.as_canonical_u32()] + } +} diff --git a/fri/Cargo.toml b/fri/Cargo.toml index 7efbf9e..0dc6e68 100644 --- a/fri/Cargo.toml +++ b/fri/Cargo.toml @@ -28,6 +28,8 @@ rand = "0.8.5" scripts = { path = "../scripts"} primitives = {path = "../primitives"} segment ={ path = "../segment"} +script_manager = {path = "../script_manager"} + p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } p3-symmetric = { git = "https://github.com/Plonky3/Plonky3.git" } [dev-dependencies] diff --git a/fri/src/fold_even_odd.rs b/fri/src/fold_even_odd.rs index de0f3e0..0814920 100644 --- a/fri/src/fold_even_odd.rs +++ b/fri/src/fold_even_odd.rs @@ -62,6 +62,7 @@ mod tests { use primitives::field::BfField; use rand::{thread_rng, Rng}; use scripts::execute_script; + use scripts::u31_lib::BabyBear4; use super::*; use crate::fri_scripts::verify_folding::fold_degree; diff --git a/fri/src/fri_scripts/fiat_shamir_subtree.rs b/fri/src/fri_scripts/fiat_shamir_subtree.rs index 42bb096..cc1a7ee 100644 --- a/fri/src/fri_scripts/fiat_shamir_subtree.rs +++ b/fri/src/fri_scripts/fiat_shamir_subtree.rs @@ -10,10 +10,11 @@ use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; use itertools::Itertools; use p3_field::PrimeField32; -use primitives::bit_comm::{BCAssignment, BitCommitment}; use primitives::challenger::chan_field::{PermutationField, U32}; use primitives::challenger::{BfChallenger, BitExtractor, Blake3Permutation}; use primitives::field::BfField; +use script_manager::bc_assignment::DefaultBCAssignment; +use scripts::bit_comm::bit_comm::BitCommitment; use scripts::bit_comm_u32::*; use scripts::blake3; use scripts::pseudo::{OP_4DROP, OP_4FROMALTSTACK, OP_4TOALTSTACK}; @@ -71,7 +72,7 @@ where /// currently just implement Blake3Permuation with U32;16 fn new_from_fri_challenger( challenger: &BfChallenger, - bc_assignment: &mut BCAssignment, + bc_assignment: &mut DefaultBCAssignment, ) -> FiatShamirSubTree { assert_eq!( challenger.permutation_input_records.len(), @@ -135,7 +136,7 @@ where fs_subtree } - fn commit(&mut self, bc_assignment: &mut BCAssignment) { + fn commit(&mut self, bc_assignment: &mut DefaultBCAssignment) { self.input_commits.clear(); self.output_commits.clear(); self.sample_input_commits.clear(); @@ -221,28 +222,28 @@ fn u32_to_compressed_babybear() -> Script { ) } -fn new_u32_bit_commit(bc_assignment: &mut BCAssignment, value: U32) -> Commit { - let bitcommit = bc_assignment.assign(U32_to_u32(value)); +fn new_u32_bit_commit(bc_assignment: &mut DefaultBCAssignment, value: U32) -> Commit { + let mut bitcommit = bc_assignment.assign(U32_to_u32(value)); let locking = script! { - { bitcommit.checksig_verify_script() } + { bitcommit.commitments.get(0).unwrap().checksig_verify_script() } }; Commit { locking_script: locking, - unlock_witness: bitcommit.signature(), + unlock_witness: bitcommit.witness(), } } -fn new_challenge_commit(bc_assignment: &mut BCAssignment, value: F) -> Commit +fn new_challenge_commit(bc_assignment: &mut DefaultBCAssignment, value: F) -> Commit where F: BfField, { - let bitcommit: BitCommitment = bc_assignment.assign_field(value); + let bitcommit: BitCommitment = bc_assignment.assign(value); let locking = script! { - { bitcommit.recover_message_at_stack() } + { bitcommit.check_and_recover() } }; Commit { locking_script: locking, - unlock_witness: bitcommit.signature(), + unlock_witness: bitcommit.witness(), } } @@ -409,12 +410,12 @@ mod test { use p3_challenger::{CanObserve, CanSample, CanSampleBits}; use p3_field::extension::BinomialExtensionField; use p3_field::{AbstractField, PrimeField32}; - use primitives::bit_comm::BCAssignment; use primitives::challenger::chan_field::{PermutationField, U32}; use primitives::challenger::{BfChallenger, BfGrindingChallenger, Blake3Permutation}; - use scripts::bit_comm::pushable; + use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; + use scripts::bit_comm::winternitz::{pushable, to_digits}; use scripts::u31_lib::BabyBear4; - use scripts::{execute_script, execute_script_with_inputs, to_digits}; + use scripts::{execute_script, execute_script_with_inputs}; use super::{new_challenge_commit, new_u32_bit_commit, Commit, FiatShamirSubTree, SubTree}; @@ -434,7 +435,7 @@ mod test { #[test] fn test_bitcommit() { - let mut bc_assignment = BCAssignment::new(); + let mut bc_assignment = DefaultBCAssignment::new(); let scripts = new_u32_bit_commit(&mut bc_assignment, U32::from_u64(0x28121614)); println!("verify scripts: {:?}", verify_u32_4bytes_script(0x28121614)); let exec_script = script! { @@ -453,7 +454,7 @@ mod test { let point = BabyBear::from_canonical_u64(value); let point_as_u32 = point.as_canonical_u32(); - let mut bc_assignment = BCAssignment::new(); + let mut bc_assignment = DefaultBCAssignment::new(); let scripts = new_challenge_commit(&mut bc_assignment, point); let exec_script = script! { {scripts.locking_script} @@ -489,7 +490,7 @@ mod test { #[test] fn test_mock_fs_subtree() { - let mut bc_assignment = BCAssignment::new(); + let mut bc_assignment = DefaultBCAssignment::new(); let mut fs_subtree: FiatShamirSubTree = Default::default(); fs_subtree.state_leafs_num = 1; @@ -536,7 +537,7 @@ mod test { #[test] fn test_fs_subtree_from_challenger() { - let mut bc_assignment = BCAssignment::new(); + let mut bc_assignment = DefaultBCAssignment::new(); let permutation = Blake3Permutation {}; let mut challenger: BfChallenger = @@ -571,7 +572,7 @@ mod test { #[test] fn test_fs_subtree_from_challenger_with_grind() { - let mut bc_assignment = BCAssignment::new(); + let mut bc_assignment = DefaultBCAssignment::new(); let permutation = Blake3Permutation {}; let mut challenger: BfChallenger = @@ -606,7 +607,7 @@ mod test { #[test] fn test_fs_subtree_from_challenger_with_grind8() { - let mut bc_assignment = BCAssignment::new(); + let mut bc_assignment = DefaultBCAssignment::new(); let permutation = Blake3Permutation {}; let mut challenger: BfChallenger = @@ -641,7 +642,7 @@ mod test { #[test] fn test_fs_subtree_from_challenger_with_grind10() { - let mut bc_assignment = BCAssignment::new(); + let mut bc_assignment = DefaultBCAssignment::new(); let permutation = Blake3Permutation {}; let mut challenger: BfChallenger = @@ -677,7 +678,7 @@ mod test { #[test] fn test_fs_subtree_from_challenger_with_grind_random() { for grind_i in 2..15 { - let mut bc_assignment = BCAssignment::new(); + let mut bc_assignment = DefaultBCAssignment::new(); let permutation = Blake3Permutation {}; let mut challenger: BfChallenger = @@ -709,7 +710,7 @@ mod test { #[test] fn test_fs_subtree_from_challenger_with_grind_random_and_sample() { - let mut bc_assignment = BCAssignment::new(); + let mut bc_assignment = DefaultBCAssignment::new(); let permutation = Blake3Permutation {}; let mut challenger: BfChallenger = @@ -749,7 +750,7 @@ mod test { #[test] fn test_fs_subtree_from_challenger_with_grind_random_and_sample2() { - let mut bc_assignment = BCAssignment::new(); + let mut bc_assignment = DefaultBCAssignment::new(); let permutation = Blake3Permutation {}; let mut challenger: BfChallenger = @@ -788,7 +789,7 @@ mod test { #[test] fn test_babybear4() { - let mut bc_assignment = BCAssignment::new(); + let mut bc_assignment = DefaultBCAssignment::new(); let permutation = Blake3Permutation {}; let mut challenger: BfChallenger< @@ -822,7 +823,7 @@ mod test { #[test] fn test_babybear4_more() { - let mut bc_assignment = BCAssignment::new(); + let mut bc_assignment = DefaultBCAssignment::new(); let permutation = Blake3Permutation {}; let mut challenger: BfChallenger< diff --git a/fri/src/fri_scripts/leaf.rs b/fri/src/fri_scripts/leaf.rs index 22c2ee7..b4fce21 100644 --- a/fri/src/fri_scripts/leaf.rs +++ b/fri/src/fri_scripts/leaf.rs @@ -9,10 +9,14 @@ use std::usize; use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; -use primitives::bit_comm::{BCAssignment, BitCommitment, *}; +use itertools::rev; +use p3_field::TwoAdicField; use primitives::field::BfField; +use script_manager::bc_assignment::DefaultBCAssignment; +use scripts::bit_comm::bit_comm::BitCommitment; use scripts::bit_comm_u32::BitCommitmentU32; use scripts::execute_script_with_inputs; +use scripts::secret_generator::ConstantSecretGen; use scripts::u31_lib::{ u31_add, u31_equalverify, u31ext_add, u31ext_equalverify, BabyBear4, BabyBearU31, }; @@ -27,16 +31,16 @@ define_pushable!(); pub struct RevIndexLeaf { sub_group_bits: u32, index: u32, - index_bc: BitCommitmentU32, + index_bc: BitCommitment, rev_index: u32, - rev_index_bc: BitCommitmentU32, + rev_index_bc: BitCommitment, } impl RevIndexLeaf { pub fn new_from_assign( sub_group_bits: u32, index: u32, rev_index: u32, - assign: &mut BCAssignment, + assign: &mut DefaultBCAssignment, ) -> Self { let index_bc = assign.assign(index); let rev_index_bc = assign.assign(rev_index); @@ -46,9 +50,9 @@ impl RevIndexLeaf { pub fn new( sub_group_bits: u32, index: u32, - index_bc: BitCommitmentU32, + index_bc: BitCommitment, rev_index: u32, - rev_index_bc: BitCommitmentU32, + rev_index_bc: BitCommitment, ) -> Self { Self { sub_group_bits, @@ -62,8 +66,8 @@ impl RevIndexLeaf { impl SegmentLeaf for RevIndexLeaf { fn input(&self) -> Vec> { - let mut sigs1 = self.index_bc.signature(); - let mut sigs0 = self.rev_index_bc.signature(); + let mut sigs1 = self.index_bc.witness(); + let mut sigs0 = self.rev_index_bc.witness(); sigs1.append(&mut sigs0); sigs1 } @@ -78,8 +82,8 @@ impl SegmentLeaf for RevIndexLeaf { fn leaf_script(&self) -> Script { script! { - {self.rev_index_bc.recover_message_at_altstack()} - {self.index_bc.recover_message_at_stack()} + {self.rev_index_bc.check_and_recover_to_altstack()} + {self.index_bc.check_and_recover()} {self.rev_index_bc.message_from_altstack()} {reverse_bits_len_script_with_input(self.index,self.sub_group_bits as usize )} } @@ -91,10 +95,10 @@ pub struct SquareFLeaf { value_square_bc: BitCommitment, } impl SquareFLeaf { - pub fn new_from_assign(value: F, value_suqare: F, assign: &mut BCAssignment) -> Self { + pub fn new_from_assign(value: F, value_suqare: F, assign: &mut DefaultBCAssignment) -> Self { assert_eq!(value * value, value_suqare); - let val_bc = assign.assign_field(value); - let val_square_bc = assign.assign_field(value_suqare); + let val_bc = assign.assign(value); + let val_square_bc = assign.assign(value_suqare); Self::new(val_bc, val_square_bc) } @@ -108,8 +112,8 @@ impl SquareFLeaf { impl SegmentLeaf for SquareFLeaf { fn input(&self) -> Vec> { - let mut sigs1 = self.value_square_bc.signature(); - let mut sigs0 = self.value_bc.signature(); + let mut sigs1 = self.value_square_bc.witness(); + let mut sigs0 = self.value_bc.witness(); sigs1.append(&mut sigs0); sigs1 } @@ -124,8 +128,8 @@ impl SegmentLeaf for SquareFLeaf fn leaf_script(&self) -> Script { script! { - {self.value_bc.recover_message_at_altstack()} - {self.value_square_bc.recover_message_at_stack()} + {self.value_bc.check_and_recover_to_altstack()} + {self.value_square_bc.check_and_recover()} {self.value_bc.message_from_altstack()} {value_square_with_input::()} } @@ -137,9 +141,9 @@ pub struct CalNegXLeaf { neg_x_bc: BitCommitment, } impl CalNegXLeaf { - pub fn new_from_assign(x: F, neg_x: F, assign: &mut BCAssignment) -> Self { - let x_bc = assign.assign_field(x); - let neg_x_bc = assign.assign_field(neg_x); + pub fn new_from_assign(x: F, neg_x: F, assign: &mut DefaultBCAssignment) -> Self { + let x_bc = assign.assign(x); + let neg_x_bc = assign.assign(neg_x); Self::new(x_bc, neg_x_bc) } @@ -150,8 +154,8 @@ impl CalNegXLeaf { impl SegmentLeaf for CalNegXLeaf { fn input(&self) -> Vec> { - let mut sigs1 = self.neg_x_bc.signature(); - let mut sigs0 = self.x_bc.signature(); + let mut sigs1 = self.neg_x_bc.witness(); + let mut sigs0 = self.x_bc.witness(); sigs1.append(&mut sigs0); sigs1 } @@ -166,8 +170,8 @@ impl SegmentLeaf for CalNegXLeaf fn leaf_script(&self) -> Script { script! { - {self.x_bc.recover_message_at_altstack()} - {self.neg_x_bc.recover_message_at_stack()} + {self.x_bc.check_and_recover_to_altstack()} + {self.neg_x_bc.check_and_recover()} {self.x_bc.message_from_altstack()} {cal_neg_x_with_input::()} } @@ -179,7 +183,7 @@ pub struct IndexToROULeaf { index: usize, subgroup_bit_size: usize, generator: F, - index_bc: BitCommitmentU32, + index_bc: BitCommitment, x_bc: BitCommitment, } impl IndexToROULeaf { @@ -187,9 +191,9 @@ impl IndexToROULeaf { index: usize, subgroup_bit_size: usize, x: F, - assign: &mut BCAssignment, + assign: &mut DefaultBCAssignment, ) -> Self { - let x_bc = assign.assign_field(x); + let x_bc = assign.assign(x); let index_bc = assign.assign(index as u32); let gen = F::two_adic_generator(subgroup_bit_size); Self::new(index, subgroup_bit_size, gen, index_bc, x_bc) @@ -199,7 +203,7 @@ impl IndexToROULeaf { index: usize, subgroup_bit_size: usize, generator: F, - index_bc: BitCommitmentU32, + index_bc: BitCommitment, x_bc: BitCommitment, ) -> Self { IndexToROULeaf { @@ -218,8 +222,8 @@ impl IndexToROULeaf { impl SegmentLeaf for IndexToROULeaf { fn input(&self) -> Vec> { - let mut sigs0 = self.x_bc.signature(); - let mut sigs1 = self.index_bc.signature(); + let mut sigs0 = self.x_bc.witness(); + let mut sigs1 = self.index_bc.witness(); sigs1.extend(sigs0); sigs1 } @@ -238,8 +242,8 @@ impl SegmentLeaf for IndexToROULeaf ReductionLeaf { prev_fold: F, opening: F, result: F, - assign: &'a mut BCAssignment, + assign: &'a mut DefaultBCAssignment, ) -> Self { - let prev_fold_bc = assign.assign_field(prev_fold); - let opening_bc = assign.assign_field(opening); - let result_bc = assign.assign_field(result); + let prev_fold_bc = assign.assign(prev_fold); + let opening_bc = assign.assign(opening); + let result_bc = assign.assign(result); Self::new(prev_fold_bc, opening_bc, result_bc) } @@ -285,9 +289,9 @@ impl ReductionLeaf { impl SegmentLeaf for ReductionLeaf { fn input(&self) -> Vec> { - let mut sigs0 = self.result_bc.signature(); - let sigs1 = self.opening_bc.signature(); - let sigs2 = self.prev_fold_bc.signature(); + let mut sigs0 = self.result_bc.witness(); + let sigs1 = self.opening_bc.witness(); + let sigs2 = self.prev_fold_bc.witness(); sigs0.extend(sigs1.iter().cloned()); sigs0.extend(sigs2.iter().cloned()); @@ -305,9 +309,9 @@ impl SegmentLeaf for ReductionLeaf Script { script! { - {self.prev_fold_bc.recover_message_at_altstack()} - {self.opening_bc.recover_message_at_altstack()} - {self.result_bc.recover_message_at_stack()} + {self.prev_fold_bc.check_and_recover_to_altstack()} + {self.opening_bc.check_and_recover_to_altstack()} + {self.result_bc.check_and_recover()} {self.opening_bc.message_from_altstack()} {self.prev_fold_bc.message_from_altstack()} if F::U32_SIZE == 1 { @@ -338,13 +342,13 @@ impl<'a, const NUM_POLY: usize, F: BfField> VerifyFoldingLeaf { x: F, beta: F, y_1_x_square: F, - assgin: &'a mut BCAssignment, + assgin: &'a mut DefaultBCAssignment, ) -> Self { - let x_bc = assgin.assign_field(x); - let beta_bc = assgin.assign_field(beta); - let y_0_x_bc = assgin.assign_field(y_0_x); - let y_0_neg_x_bc = assgin.assign_field(y_0_neg_x); - let y_1_x_square_bc = assgin.assign_field(y_1_x_square); + let x_bc = assgin.assign(x); + let beta_bc = assgin.assign(beta); + let y_0_x_bc = assgin.assign(y_0_x); + let y_0_neg_x_bc = assgin.assign(y_0_neg_x); + let y_1_x_square_bc = assgin.assign(y_1_x_square); Self::new(y_0_x_bc, y_0_neg_x_bc, x_bc, beta_bc, y_1_x_square_bc) } @@ -365,11 +369,11 @@ impl<'a, const NUM_POLY: usize, F: BfField> VerifyFoldingLeaf { } fn input(&self) -> Vec> { - let mut sigs0 = self.y_1_x_square_bc.signature(); - let sigs1 = self.beta_bc.signature(); - let sigs2 = self.x_bc.signature(); - let sigs3 = self.y_0_neg_x_bc.signature(); - let sigs4 = self.y_0_x_bc.signature(); + let mut sigs0 = self.y_1_x_square_bc.witness(); + let sigs1 = self.beta_bc.witness(); + let sigs2 = self.x_bc.witness(); + let sigs3 = self.y_0_neg_x_bc.witness(); + let sigs4 = self.y_0_x_bc.witness(); sigs0.extend(sigs1.iter().cloned()); sigs0.extend(sigs2.iter().cloned()); @@ -391,11 +395,11 @@ impl<'a, const NUM_POLY: usize, F: BfField> VerifyFoldingLeaf { fn leaf_script(&self) -> Script { script! { - {self.y_0_x_bc.recover_message_at_altstack()} - {self.y_0_neg_x_bc.recover_message_at_altstack()} - {self.x_bc.recover_message_at_altstack()} - {self.beta_bc.recover_message_at_altstack()} - {self.y_1_x_square_bc.recover_message_at_stack()} + {self.y_0_x_bc.check_and_recover_to_altstack()} + {self.y_0_neg_x_bc.check_and_recover_to_altstack()} + {self.x_bc.check_and_recover_to_altstack()} + {self.beta_bc.check_and_recover_to_altstack()} + {self.y_1_x_square_bc.check_and_recover()} {self.beta_bc.message_from_altstack()} {self.x_bc.message_from_altstack()} {self.y_0_neg_x_bc.message_from_altstack()} @@ -417,11 +421,11 @@ impl<'a, const NUM_POLY: usize, F: BfField> VerifyFoldingLeaf { impl<'a, const NUM_POLY: usize, F: BfField> SegmentLeaf for VerifyFoldingLeaf { fn input(&self) -> Vec> { - let mut sigs0 = self.y_1_x_square_bc.signature(); - let sigs1 = self.beta_bc.signature(); - let sigs2 = self.x_bc.signature(); - let sigs3 = self.y_0_neg_x_bc.signature(); - let sigs4 = self.y_0_x_bc.signature(); + let mut sigs0 = self.y_1_x_square_bc.witness(); + let sigs1 = self.beta_bc.witness(); + let sigs2 = self.x_bc.witness(); + let sigs3 = self.y_0_neg_x_bc.witness(); + let sigs4 = self.y_0_x_bc.witness(); sigs0.extend(sigs1.iter().cloned()); sigs0.extend(sigs2.iter().cloned()); @@ -443,11 +447,11 @@ impl<'a, const NUM_POLY: usize, F: BfField> SegmentLeaf for VerifyFoldingLeaf Script { script! { - {self.y_0_x_bc.recover_message_at_altstack()} - {self.y_0_neg_x_bc.recover_message_at_altstack()} - {self.x_bc.recover_message_at_altstack()} - {self.beta_bc.recover_message_at_altstack()} - {self.y_1_x_square_bc.recover_message_at_stack()} + {self.y_0_x_bc.check_and_recover_to_altstack()} + {self.y_0_neg_x_bc.check_and_recover_to_altstack()} + {self.x_bc.check_and_recover_to_altstack()} + {self.beta_bc.check_and_recover_to_altstack()} + {self.y_1_x_square_bc.check_and_recover()} {self.beta_bc.message_from_altstack()} {self.x_bc.message_from_altstack()} {self.y_0_neg_x_bc.message_from_altstack()} @@ -457,13 +461,75 @@ impl<'a, const NUM_POLY: usize, F: BfField> SegmentLeaf for VerifyFoldingLeaf { + leaf_index: usize, + x: F, + x_commitment: BitCommitment, + neg_x_commitment: BitCommitment, + evaluations: Vec, + evaluations_commitments: Vec>, +} + +impl EvaluationLeaf { + pub fn new(leaf_index: usize, x: F, evaluations: Vec) -> Self { + assert_eq!(evaluations.len(), NUM_POLY); + + let x_commitment = BitCommitment::new::(x); + let neg_x_commitment = BitCommitment::new::(F::field_mod() - x); + let mut evaluations_commitments = Vec::new(); + for i in 0..NUM_POLY { + evaluations_commitments.push(BitCommitment::new::(evaluations[i])); + } + + Self { + leaf_index, + x, + x_commitment, + neg_x_commitment, + evaluations, + evaluations_commitments, + } + } + + pub fn leaf_script(&self) -> Script { + // equal to x script + let scripts = script! { + { self.x_commitment.commitments[0].checksig_verify_script() } + { self.x_commitment.commitments[0].commit_u32_as_4bytes_script() } + // todo: calculate to equal to -x + for i in 0..NUM_POLY{ + { self.evaluations_commitments[NUM_POLY-1-i].commitments[0].checksig_verify_script() } + { self.evaluations_commitments[NUM_POLY-1-i].commitments[0].commit_u32_as_4bytes_script() } + } + OP_1 + }; + + scripts + } + + pub fn two_point_leaf_script(&self) -> Script { + // equal to x script + let scripts = script! { + { self.x_commitment.commitments[0].checksig_verify_script() } + { self.x_commitment.commitments[0].commit_u32_as_4bytes_script() } + { self.neg_x_commitment.commitments[0].checksig_verify_script() } + { self.neg_x_commitment.commitments[0].commit_u32_as_4bytes_script() } + for i in 0..NUM_POLY{ + { self.evaluations_commitments[NUM_POLY-1-i].commitments[0].checksig_verify_script() } + { self.evaluations_commitments[NUM_POLY-1-i].commitments[0].commit_u32_as_4bytes_script() } + } + OP_1 + }; + scripts + } +} + pub fn u8_to_hex_str(byte: &u8) -> String { format!("{:02X}", byte) } #[cfg(test)] mod test { - use itertools::{equal, rev}; use p3_baby_bear::BabyBear; use p3_field::extension::BinomialExtensionField; use p3_field::{AbstractField, TwoAdicField}; @@ -480,7 +546,7 @@ mod test { #[test] fn test_rev_index_leaf() { - let mut assign = BCAssignment::new(); + let mut assign = DefaultBCAssignment::new(); let bits = 10; @@ -499,7 +565,7 @@ mod test { #[test] fn test_value_square_leaf() { - let mut assign = BCAssignment::new(); + let mut assign = DefaultBCAssignment::new(); let index = 6; let subgroup_bit_size = 3; @@ -526,7 +592,7 @@ mod test { #[test] fn test_cal_neg_x_leaf() { - let mut assign = BCAssignment::new(); + let mut assign = DefaultBCAssignment::new(); let index = 6; let subgroup_bit_size = 3; @@ -553,7 +619,7 @@ mod test { #[test] fn test_index_to_root_of_unity_leaf() { - let mut assign = BCAssignment::new(); + let mut assign = DefaultBCAssignment::new(); let num: usize = 100; let subgroup_bit_size = 12; for index in 0..num { @@ -574,7 +640,7 @@ mod test { #[test] fn test_index_to_root_of_unity_leaf_over_extension() { - let mut assign = BCAssignment::new(); + let mut assign = DefaultBCAssignment::new(); let num: usize = 100; let subgroup_bit_size = 12; for index in 0..num { @@ -595,7 +661,7 @@ mod test { #[test] fn test_reduction_leaf() { - let mut assign = BCAssignment::new(); + let mut assign = DefaultBCAssignment::new(); let a = BabyBear::from_canonical_u32(133); let b = BabyBear::from_canonical_u32(2222); let c = a + b; @@ -610,7 +676,7 @@ mod test { let result = execute_script_with_inputs(reduction_script, input); assert!(result.success); - let mut assign = BCAssignment::new(); + let mut assign = DefaultBCAssignment::new(); let a = F::from_canonical_u32(133); let b = F::from_canonical_u32(2222); let c = a + b; @@ -661,7 +727,7 @@ mod test { let subgroup = BabyBear::sub_group(*log_n as usize); - let mut assign = BCAssignment::new(); + let mut assign = DefaultBCAssignment::new(); for j in 0..n as usize { let x_index = j; diff --git a/fri/src/fri_scripts/point.rs b/fri/src/fri_scripts/point.rs index a060678..4d5c518 100644 --- a/fri/src/fri_scripts/point.rs +++ b/fri/src/fri_scripts/point.rs @@ -2,9 +2,10 @@ use std::usize; use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; - -use scripts::bit_comm::*; -use primitives::{bit_comm::{BCAssignment, BitCommitment},field::BfField}; +use primitives::field::BfField; +use script_manager::bc_assignment::DefaultBCAssignment; +use scripts::bit_comm::bit_comm::BitCommitment; +use scripts::secret_generator::ConstantSecretGen; define_pushable!(); #[derive(Debug, Clone)] @@ -40,9 +41,9 @@ impl PointsLeaf { scripts } - pub fn signature(&self) -> Vec> { - let mut p1_sigs = self.points.p1.signature(); - let mut p2_sigs = self.points.p2.signature(); + pub fn witness(&self) -> Vec> { + let mut p1_sigs = self.points.p1.witness(); + let mut p2_sigs = self.points.p2.witness(); p2_sigs.append(p1_sigs.as_mut()); p2_sigs } @@ -79,9 +80,9 @@ impl Points { scripts } - pub fn signature(&self) -> Vec> { - let mut p1_sigs = self.p1.signature(); - let mut p2_sigs = self.p2.signature(); + pub fn witness(&self) -> Vec> { + let mut p1_sigs = self.p1.witness(); + let mut p2_sigs = self.p2.witness(); p2_sigs.append(p1_sigs.as_mut()); p2_sigs } @@ -96,9 +97,9 @@ pub struct Point { } impl Point { - pub fn new_from_assign(x: F, y: F, bc_assign: &mut BCAssignment) -> Point { - let x_commit = bc_assign.assign_field(x); - let y_commit = bc_assign.assign_field(y); + pub fn new_from_assign(x: F, y: F, bc_assign: &mut DefaultBCAssignment) -> Point { + let x_commit = bc_assign.assign(x); + let y_commit = bc_assign.assign(y); Self { x, y, @@ -108,8 +109,8 @@ impl Point { } pub fn new(x: F, y: F) -> Point { - let x_commit = BitCommitment::::new("b138982ce17ac813d505b5b40b665d404e9528e8", x); - let y_commit = BitCommitment::::new("b138982ce17ac813d505b5b40b665d404e9528e8", y); + let x_commit = BitCommitment::::new::(x); + let y_commit = BitCommitment::::new::(y); Self { x: x, y: y, @@ -129,8 +130,8 @@ impl Point { pub fn recover_point_x_at_altstack_y_at_stack(&self) -> Script { let scripts = script! { - { self.x_commit.recover_message_at_altstack() } - { self.y_commit.recover_message_at_stack() } + { self.x_commit.check_and_recover_to_altstack() } + { self.y_commit.check_and_recover() } }; scripts @@ -138,8 +139,8 @@ impl Point { pub fn recover_point_at_altstack(&self) -> Script { let scripts = script! { - { self.x_commit.recover_message_at_altstack() } - { self.y_commit.recover_message_at_altstack() } + { self.x_commit.check_and_recover_to_altstack() } + { self.y_commit.check_and_recover_to_altstack() } }; scripts @@ -147,16 +148,16 @@ impl Point { pub fn recover_point_at_stack(&self) -> Script { let scripts = script! { - { self.x_commit.recover_message_at_stack() } - { self.y_commit.recover_message_at_stack() } + { self.x_commit.check_and_recover() } + { self.y_commit.check_and_recover() } }; scripts } - pub fn signature(&self) -> Vec> { - let mut x_sigs = self.x_commit.signature(); - let mut y_sigs = self.y_commit.signature(); + pub fn witness(&self) -> Vec> { + let mut x_sigs = self.x_commit.witness(); + let mut y_sigs = self.y_commit.witness(); y_sigs.append(x_sigs.as_mut()); y_sigs } @@ -166,12 +167,12 @@ impl Point { mod test { use p3_baby_bear::BabyBear; use p3_field::{AbstractExtensionField, AbstractField, PrimeField32}; + use primitives::field::BfField; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; + use scripts::execute_script_with_inputs; use super::*; - use scripts::execute_script_with_inputs; - use primitives::field::BfField; type F = BabyBear; type EF = p3_field::extension::BinomialExtensionField; @@ -185,7 +186,7 @@ mod test { {p.recover_point_euqal_to_commited_point()} OP_1 }; - let inputs = p.signature(); + let inputs = p.witness(); let res = execute_script_with_inputs(script, inputs); assert!(res.success); } @@ -203,7 +204,7 @@ mod test { {p.recover_point_euqal_to_commited_point()} OP_1 }; - let inputs = p.signature(); + let inputs = p.witness(); let res = execute_script_with_inputs(script, inputs); assert!(res.success); } @@ -222,7 +223,7 @@ mod test { {p.recover_points_euqal_to_commited_points()} OP_1 }; - let inputs = p.signature(); + let inputs = p.witness(); let res = execute_script_with_inputs(script, inputs); assert!(res.success); } @@ -242,7 +243,7 @@ mod test { {p.recover_points_euqal_to_commited_points()} OP_1 }; - let inputs = p.signature(); + let inputs = p.witness(); let res = execute_script_with_inputs(script, inputs); assert!(res.success); } diff --git a/fri/src/prover.rs b/fri/src/prover.rs index 218e242..999e681 100644 --- a/fri/src/prover.rs +++ b/fri/src/prover.rs @@ -146,12 +146,12 @@ mod tests { use p3_matrix::Matrix; use p3_symmetric::{CryptographicPermutation, Permutation}; use p3_util::log2_strict_usize; - use primitives::bit_comm::BCAssignment; use primitives::challenger::chan_field::U32; use primitives::challenger::{BfChallenger, Blake3Permutation}; use primitives::mmcs::taptree_mmcs::TapTreeMmcs; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; + use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; use tracing_subscriber::fmt; use super::*; @@ -284,7 +284,7 @@ mod tests { mmcs, }; - let mut assign = BCAssignment::new(); + let mut assign = DefaultBCAssignment::new(); let dft = Radix2Dit::default(); @@ -468,12 +468,12 @@ mod tests2 { use p3_matrix::Matrix; use p3_symmetric::{CryptographicPermutation, Permutation}; use p3_util::log2_strict_usize; - use primitives::bit_comm::BCAssignment; use primitives::challenger::chan_field::U32; use primitives::challenger::{BfChallenger, Blake3Permutation}; use primitives::mmcs::taptree_mmcs::{TapTreeMmcs, ROOT_WIDTH}; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; + use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; use tracing_subscriber::fmt; use super::*; @@ -605,7 +605,7 @@ mod tests2 { mmcs, }; - let mut assign = BCAssignment::new(); + let mut assign = DefaultBCAssignment::new(); let dft = Radix2Dit::default(); diff --git a/fri/src/script_verifier.rs b/fri/src/script_verifier.rs index cc0173b..522c826 100644 --- a/fri/src/script_verifier.rs +++ b/fri/src/script_verifier.rs @@ -6,12 +6,12 @@ use bitcoin::taproot::TapLeaf; use itertools::izip; use p3_challenger::{CanObserve, CanSample}; use p3_util::reverse_bits_len; -use primitives::bit_comm::BCAssignment; use primitives::challenger::BfGrindingChallenger; use primitives::field::BfField; use primitives::mmcs::bf_mmcs::BFMmcs; use primitives::mmcs::point::{Point, PointsLeaf}; use primitives::mmcs::taptree_mmcs::CommitProof; +use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; use scripts::execute_script_with_inputs; use segment::SegmentLeaf; @@ -23,7 +23,7 @@ use crate::verifier::*; use crate::{BfQueryProof, FriConfig, FriProof}; pub fn bf_verify_challenges( - assign: &mut BCAssignment, + assign: &mut DefaultBCAssignment, config: &FriConfig, proof: &FriProof, challenges: &FriChallenges, @@ -59,7 +59,7 @@ where } fn bf_verify_query( - assign: &mut BCAssignment, + assign: &mut DefaultBCAssignment, config: &FriConfig, commit_phase_commits: &[M::Commitment], mut index: usize, @@ -148,7 +148,7 @@ where let mut xs = vec![x; 2]; xs[index_sibling % 2] = neg_x; - let input = poins_leaf.signature(); + let input = poins_leaf.witness(); if let TapLeaf::Script(script, _ver) = step.leaf_node.leaf().clone() { assert_eq!(script, poins_leaf.recover_points_euqal_to_commited_point()); let res = execute_script_with_inputs( diff --git a/fri/src/verifier.rs b/fri/src/verifier.rs index 1b3ce07..f6380f4 100644 --- a/fri/src/verifier.rs +++ b/fri/src/verifier.rs @@ -144,7 +144,7 @@ where let mut xs = vec![x; 2]; xs[index_sibling % 2] = neg_x; - let input = open_leaf.signature(); + let input = open_leaf.witness(); if let TapLeaf::Script(script, _ver) = step.leaf_node.leaf().clone() { assert_eq!(script, open_leaf.recover_points_euqal_to_commited_point()); diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index a1e5853..69ec34c 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -25,9 +25,12 @@ p3-util = { git = "https://github.com/Plonky3/Plonky3.git" } p3-maybe-rayon ={ git = "https://github.com/Plonky3/Plonky3.git" } p3-matrix = { git = "https://github.com/Plonky3/Plonky3.git" } -scripts ={ path = "../scripts" } segment ={ path = "../segment" } +common = { path = "../common"} +scripts = {path = "../scripts"} +script_manager = {path = "../script_manager"} [dev-dependencies] p3-interpolation = { git = "https://github.com/Plonky3/Plonky3.git" } p3-dft = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-maybe-rayon ={ git = "https://github.com/Plonky3/Plonky3.git" } diff --git a/primitives/src/bit_comm/bc_assign.rs b/primitives/src/bit_comm/bc_assign.rs deleted file mode 100644 index e827b24..0000000 --- a/primitives/src/bit_comm/bc_assign.rs +++ /dev/null @@ -1,98 +0,0 @@ -use std::collections::HashMap; - -use itertools::Itertools; -use scripts::bit_comm_u32::BitCommitmentU32; - -use super::BitCommitment; -use crate::field::BfField; - -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct BCAssignment { - pub bcs: HashMap, - secret_assign: SecretAssignment, -} - -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct SecretAssignment; - -impl SecretAssignment { - pub fn new() -> Self { - SecretAssignment - } - fn get_secret(&self) -> &str { - // temporary secret - "0000" - } -} - -impl BCAssignment { - pub fn new() -> Self { - Self { - bcs: HashMap::new(), - // ebcs: HashMap::new(), - secret_assign: SecretAssignment::new(), - } - } - - fn get_secret(&self) -> &str { - self.secret_assign.get_secret() - } - - pub fn force_insert(&mut self, value: u32) -> BitCommitmentU32 { - let bc = BitCommitmentU32::new(self.get_secret(), value); - self.bcs.insert(value, bc); - self.get(value).unwrap() - } - - pub fn get(&self, value: u32) -> Option { - self.bcs.get(&value).map(|bc| bc.clone()) - } - - pub fn assign(&mut self, value: u32) -> BitCommitmentU32 { - let secret = self.secret_assign.get_secret(); - self.bcs - .entry(value) - .or_insert_with(|| BitCommitmentU32::new(secret, value)) - .clone() - } - - pub fn assign_field(&mut self, value: F) -> BitCommitment { - let commitments = value - .as_u32_vec() - .iter() - .map(|u32_value| self.assign(*u32_value)) - .collect_vec(); - BitCommitment { value, commitments } - } -} - -#[cfg(test)] -mod tests { - use p3_baby_bear::BabyBear; - use p3_field::AbstractField; - use rand::{Rng, SeedableRng}; - use rand_chacha::ChaCha20Rng; - - use super::*; - type F = BabyBear; - type EF = p3_field::extension::BinomialExtensionField; - - #[test] - fn test_assign_bitcommits() { - use super::*; - let key = 123; - let bc_assign: &mut BCAssignment = &mut BCAssignment::new(); - let mut bc_temp: BitCommitmentU32 = BitCommitmentU32::new("1223", key); - { - bc_assign.force_insert(key); - let bc: BitCommitmentU32 = bc_assign.get(key).unwrap(); - assert_eq!(bc.value, key); - bc_temp = bc.clone(); - } - - { - let bc1: BitCommitmentU32 = bc_assign.assign(key); - assert_eq!(bc1, bc_temp); - } - } -} diff --git a/primitives/src/field/mod.rs b/primitives/src/field/mod.rs index 594db29..08d450a 100644 --- a/primitives/src/field/mod.rs +++ b/primitives/src/field/mod.rs @@ -1,8 +1,9 @@ -use p3_baby_bear::BabyBear; -use p3_field::extension::BinomialExtensionField; -use p3_field::{AbstractExtensionField, AbstractField, PrimeField32, TwoAdicField}; +use common::AsU32Vec; +pub use p3_baby_bear::BabyBear; +pub use p3_field::extension::BinomialExtensionField; +pub use p3_field::{AbstractExtensionField, AbstractField, PrimeField32, TwoAdicField}; -pub trait BfField: AbstractField + TwoAdicField + Clone + Copy { +pub trait BfField: AbstractField + TwoAdicField + Clone + Copy + AsU32Vec { const BIS_SIZE: usize; const MOD: u32; const U32_SIZE: usize; diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index cda6fb5..88373df 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -1,4 +1,3 @@ -pub mod bit_comm; pub mod challenger; pub mod field; pub mod mmcs; diff --git a/primitives/src/mmcs/point.rs b/primitives/src/mmcs/point.rs index 81905b7..e497842 100644 --- a/primitives/src/mmcs/point.rs +++ b/primitives/src/mmcs/point.rs @@ -2,8 +2,10 @@ use std::usize; use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; +use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; +use scripts::bit_comm::bit_comm::BitCommitment; +use scripts::secret_generator::ConstantSecretGen; -use crate::bit_comm::{BCAssignment, BitCommitment}; use crate::field::BfField; define_pushable!(); @@ -40,7 +42,7 @@ impl PointsLeaf { scripts } - pub fn signature(&self) -> Vec> { + pub fn witness(&self) -> Vec> { let mut p1_sigs = self.points.p1.signature(); let mut p2_sigs = self.points.p2.signature(); p2_sigs.append(p1_sigs.as_mut()); @@ -96,9 +98,9 @@ pub struct Point { } impl Point { - pub fn new_from_assign(x: F, y: F, bc_assign: &mut BCAssignment) -> Point { - let x_commit = bc_assign.assign_field(x); - let y_commit = bc_assign.assign_field(y); + pub fn new_from_assign(x: F, y: F, bc_assign: &mut DefaultBCAssignment) -> Point { + let x_commit = bc_assign.assign(x); + let y_commit = bc_assign.assign(y); Self { x, y, @@ -108,8 +110,8 @@ impl Point { } pub fn new(x: F, y: F) -> Point { - let x_commit = BitCommitment::::new("b138982ce17ac813d505b5b40b665d404e9528e8", x); - let y_commit = BitCommitment::::new("b138982ce17ac813d505b5b40b665d404e9528e8", y); + let x_commit = BitCommitment::::new::(x); + let y_commit = BitCommitment::::new::(y); Self { x: x, y: y, @@ -129,8 +131,8 @@ impl Point { pub fn recover_point_x_at_altstack_y_at_stack(&self) -> Script { let scripts = script! { - { self.x_commit.recover_message_at_altstack() } - { self.y_commit.recover_message_at_stack() } + { self.x_commit.check_and_recover_to_altstack() } + { self.y_commit.check_and_recover() } }; scripts @@ -138,8 +140,8 @@ impl Point { pub fn recover_point_at_altstack(&self) -> Script { let scripts = script! { - { self.x_commit.recover_message_at_altstack() } - { self.y_commit.recover_message_at_altstack() } + { self.x_commit.check_and_recover_to_altstack() } + { self.y_commit.check_and_recover() } }; scripts @@ -147,16 +149,16 @@ impl Point { pub fn recover_point_at_stack(&self) -> Script { let scripts = script! { - { self.x_commit.recover_message_at_stack() } - { self.y_commit.recover_message_at_stack() } + { self.x_commit.check_and_recover_to_altstack() } + { self.y_commit.check_and_recover() } }; scripts } pub fn signature(&self) -> Vec> { - let mut x_sigs = self.x_commit.signature(); - let mut y_sigs = self.y_commit.signature(); + let mut x_sigs = self.x_commit.witness(); + let mut y_sigs = self.y_commit.witness(); y_sigs.append(x_sigs.as_mut()); y_sigs } diff --git a/primitives/src/mmcs/tapleaf.rs b/primitives/src/mmcs/tapleaf.rs index 706c359..2e2bce6 100644 --- a/primitives/src/mmcs/tapleaf.rs +++ b/primitives/src/mmcs/tapleaf.rs @@ -1,5 +1,6 @@ use bitcoin::ScriptBuf as Script; use segment::SegmentLeaf; + pub trait Tapleaf { fn unlock_witness(&self) -> Vec>; fn script(&self) -> Script; diff --git a/primitives/src/mmcs/taptree.rs b/primitives/src/mmcs/taptree.rs index a473cd2..c2e7b06 100644 --- a/primitives/src/mmcs/taptree.rs +++ b/primitives/src/mmcs/taptree.rs @@ -6,6 +6,7 @@ use bitcoin::taproot::{LeafNode, LeafNodes, NodeInfo, TaprootMerkleBranch}; use bitcoin::{ScriptBuf, TapNodeHash}; use itertools::{Chunk, Itertools}; use p3_util::{log2_strict_usize, reverse_slice_index_bits}; +use scripts::secret_generator::ThreadSecretGen; use super::error::BfError; use super::point::PointsLeaf; @@ -17,8 +18,7 @@ pub fn combine_two_nodes(a: NodeInfo, b: NodeInfo) -> Result<(NodeInfo, bool), B } use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; - -use crate::bit_comm::BitCommitment; +use scripts::bit_comm::bit_comm::BitCommitment; define_pushable!(); pub struct EvaluationLeaf { @@ -34,17 +34,11 @@ impl EvaluationLeaf { pub fn new(leaf_index: usize, x: F, evaluations: Vec) -> Self { assert_eq!(evaluations.len(), NUM_POLY); - let x_commitment = BitCommitment::new("b138982ce17ac813d505b5b40b665d404e9528e8", x); - let neg_x_commitment = BitCommitment::new( - "b138982ce17ac813d505b5b40b665d404e9528e8", - F::field_mod() - x, - ); + let x_commitment = BitCommitment::new::(x); + let neg_x_commitment = BitCommitment::new::(F::field_mod() - x); let mut evaluations_commitments = Vec::new(); for i in 0..NUM_POLY { - evaluations_commitments.push(BitCommitment::new( - "b138982ce17ac813d505b5b40b665d404e9528e9", - evaluations[i], - )); + evaluations_commitments.push(BitCommitment::new::(evaluations[i])); } Self { diff --git a/script_manager/Cargo.toml b/script_manager/Cargo.toml new file mode 100644 index 0000000..47276af --- /dev/null +++ b/script_manager/Cargo.toml @@ -0,0 +1,48 @@ +[package] +name = "script_manager" +version = "0.1.0" +edition = "2021" + +[dependencies] +bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } +bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } +bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } +lazy_static = "1.4.0" +scripts = {path = "../scripts"} + +[dev-dependencies] +rand_chacha = "0.3.1" +rand = "0.8.5" +p3-field = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-util = { git = "https://github.com/Plonky3/Plonky3.git" } +once_cell = "1.8.0" +hex = "0.4.3" +itertools = "0.12.1" +primitives = {path = "../primitives"} + +[profile.release] +opt-level = 3 +lto = "thin" +incremental = true +panic = 'abort' + +[profile.bench] +opt-level = 3 +debug = false +rpath = false +lto = "thin" +incremental = true +debug-assertions = false + +[profile.dev] +opt-level = 3 +panic = 'abort' + +[profile.test] +opt-level = 3 +lto = "thin" +incremental = true +debug-assertions = true +debug = true diff --git a/script_manager/src/bc_assignment.rs b/script_manager/src/bc_assignment.rs new file mode 100644 index 0000000..0f38638 --- /dev/null +++ b/script_manager/src/bc_assignment.rs @@ -0,0 +1,123 @@ +use std::collections::HashMap; +use std::sync::Arc; + +use scripts::bit_comm::bit_comm::BitCommitment; +use scripts::bit_comm_u32::BitCommitmentU32; +use scripts::secret_generator::{SecretGen, ThreadSecretGen}; +use scripts::AsU32Vec; + +#[derive(Debug, Clone, Default, PartialEq, Eq)] +pub struct BCAssignment { + // from u32 value -> u32 bitcommitment + pub value_assigns: HashMap, + // from index -> u32 bitcommitment + pub varible_assigns: HashMap>, + pub indexer: u32, + pub secret_gen: S, +} + +pub type DefaultBCAssignment = BCAssignment; + +impl BCAssignment { + pub fn new() -> Self { + Self { + value_assigns: HashMap::new(), + varible_assigns: HashMap::new(), + indexer: 0, + secret_gen: S::default(), + } + } + + pub fn assign(&mut self, value: F) -> BitCommitment { + let x = BitCommitment::new::(value); + for i in x.commitments.clone() { + self.value_assigns.entry(i.value).or_insert_with(|| i); + } + x + } + + pub fn assign_arc( + &mut self, + value: &Arc>, + ) -> Box> { + let x = BitCommitment::new_with_box::(value); + for i in x.commitments.clone() { + self.value_assigns.entry(i.value).or_insert_with(|| i); + } + x + } + + // pre assign a commitment without value + pub fn pre_assign_var(&mut self) -> (BitCommitment, String) { + self.indexer += 1; + let x = BitCommitment::::new::(F::default()); + self.varible_assigns + .entry(self.indexer.to_string()) + .or_insert_with(|| x.commitments.clone()); + (x, self.indexer.to_string()) + } + + pub fn assign_var(&mut self, name: &str, value: F) -> Option> { + self.varible_assigns.remove(name).and_then(|commits| { + let x: BitCommitment = BitCommitment::new_with_commits(value, commits); + for i in x.commitments.clone() { + self.value_assigns.entry(i.value).or_insert_with(|| i); + } + Some(x) + }) + } +} + +#[cfg(test)] +mod tests { + use itertools::Itertools; + use p3_baby_bear::BabyBear; + use p3_field::{AbstractField, PackedValue}; + use primitives::field::BfField; + use rand::{Rng, SeedableRng}; + use rand_chacha::ChaCha20Rng; + use scripts::secret_generator::ThreadSecretGen; + + use super::*; + type F = BabyBear; + type EF = p3_field::extension::BinomialExtensionField; + + #[test] + fn test_value_assign_bitcommits() { + let mut bc_assign = BCAssignment::::new(); + // let mut bc_temp: BitCommitmentU32 = BitCommitmentU32::new("1223", key); + bc_assign.assign(10); + bc_assign.assign(10); + bc_assign.assign(10); + bc_assign.assign(10); + bc_assign.assign(10); + + assert_eq!(bc_assign.value_assigns.len(), 1); + assert_eq!(bc_assign.value_assigns.get(&10).unwrap().value, 10); + + bc_assign.assign(12); + bc_assign.assign(10); + bc_assign.assign(14); + bc_assign.assign(11); + + assert_eq!(bc_assign.value_assigns.len(), 4); + assert_eq!(bc_assign.value_assigns.get(&10).unwrap().value, 10); + assert_eq!(bc_assign.value_assigns.get(&11).unwrap().value, 11); + assert_eq!(bc_assign.value_assigns.get(&12).unwrap().value, 12); + assert_eq!(bc_assign.value_assigns.get(&14).unwrap().value, 14); + + bc_assign.assign(EF::default()); // 00, 00, 00, 00 + assert_eq!(bc_assign.value_assigns.len(), 5); + } + + #[test] + fn test_vars_assign_bitcommits() { + let mut bc_assign = BCAssignment::::new(); + let (old_bc, bc_id) = bc_assign.pre_assign_var::(); + let new_bc = bc_assign + .assign_var(&bc_id, F::from_canonical_u32(0x1234)) + .unwrap(); + assert_ne!(old_bc.value, new_bc.value); + assert_eq!(old_bc.check_and_recover(), new_bc.check_and_recover()); + } +} diff --git a/script_manager/src/lib.rs b/script_manager/src/lib.rs new file mode 100644 index 0000000..f99b9b9 --- /dev/null +++ b/script_manager/src/lib.rs @@ -0,0 +1,3 @@ +pub mod bc_assignment; +pub mod planner; +pub mod script_info; diff --git a/script_manager/src/planner.rs b/script_manager/src/planner.rs new file mode 100644 index 0000000..595c868 --- /dev/null +++ b/script_manager/src/planner.rs @@ -0,0 +1,58 @@ +use bitcoin::ScriptBuf; + +use crate::bc_assignment::DefaultBCAssignment; +use crate::script_info::ScriptInfo; + +struct TaprootLeaf { + script_buf: ScriptBuf, + witness: Vec>, + meta_info: Vec, // record name of combined scriptInfo + debug: bool, +} + +type DefaultPlanner = SimplePlanner; +const SCRIPT_LIMIT: usize = 350 * 1000; // 350kb + +trait Planner { + /// combine + fn combine(infos: Vec) -> Vec; + /// compile infos to a set of success taprootleafs in debug mode + fn compile_to_eq(infos: Vec) -> (Vec, DefaultBCAssignment) { + let mut acc = 0; + let mut combined_infos: Vec = vec![]; + let mut res = vec![]; + for mut info in infos { + let info_size = info.script_size() + info.witness_size(); + if acc + info_size < SCRIPT_LIMIT { + acc += info_size; + combined_infos.push(info); + } else { + res.push(Self::combine(combined_infos)); + + // clear status + combined_infos = vec![info]; + acc = info_size; + } + } + + // now process res infos + + todo!() + } + /// compile infos to a set of fail taprootleafs in release mode + fn compile_to_neq(infos: Vec) -> (Vec, DefaultBCAssignment); + /// check whether all infos can be linked with commitments + fn integrity_check(infos: Vec) -> bool; +} + +/// There no too much combine rules in the simple planner +/// 1. Simple planner just combine neighbouring script infos, so the order of vector is a important hint. +/// 2. Some small script infos will be combined to a big one, limited by the `SCRIPT_LIMIT`. +/// 3. For before script's output and after script's input, equivalent bitcommitment is eliminated. +/// 4. u32_add_1 or u32_dec_1 can be thinked of it as equivalent. +struct SimplePlanner {} +// impl Planner for SimplePlanner {} + +mod test { + // some tests +} diff --git a/script_manager/src/script_info.rs b/script_manager/src/script_info.rs new file mode 100644 index 0000000..92ed9d2 --- /dev/null +++ b/script_manager/src/script_info.rs @@ -0,0 +1,338 @@ +use std::collections::VecDeque; +use std::sync::Arc; + +use bitcoin::{Script, ScriptBuf}; +use bitcoin_script::{define_pushable, script}; +use scripts::bit_comm::bit_comm::BitCommitment; +use scripts::secret_generator::ThreadSecretGen; +use scripts::{pushable, unroll, AsU32Vec}; + +use crate::bc_assignment::{BCAssignment, DefaultBCAssignment}; + +// Implement basic script, and can be commpiled by planner +pub struct ScriptInfo { + name: String, + intput_values: Vec>>, + output_values: Vec>>, + script: ScriptBuf, + + final_script: Option<(ScriptBuf, Vec>)>, +} + +impl ScriptInfo { + pub fn new(name: &str, script: ScriptBuf) -> Self { + assert!(Self::is_valid_name(name)); + Self { + name: name.clone().into(), + intput_values: vec![], + output_values: vec![], + script, + final_script: None, + } + } + pub fn add_input(&mut self, input: F) -> &mut Self { + self.intput_values.push(Arc::new(Box::new(input))); + self + } + + pub fn add_output(&mut self, output: F) -> &mut Self { + self.output_values.push(Arc::new(Box::new(output))); + self + } + + /// After executing this script, the stacks will be like this. + /// stack: [..., input1, input0], altstack: [..., output1, ouput0] + fn check_witness(&mut self) -> ScriptBuf { + match self.final_script.clone() { + Some((script, _)) => script, + None => { + panic!("need gen first") + } + } + } + + // witness: [..., output1, output0, ..., input1, input0] + // success with eq_script, and fail in neq_script + pub fn witness(&mut self) -> Vec> { + match self.final_script.clone() { + Some((_, witness)) => witness, + None => { + panic!("need gen first") + } + } + } + + pub fn gen(&mut self, bc_assigner: &mut DefaultBCAssignment) -> &mut Self { + if !self.final_script.is_none() { + return self; + } + + let mut script_bytes = vec![]; + let mut move_back_bytes = vec![]; + let mut witness: VecDeque> = Default::default(); + + for value in &self.intput_values { + let value_commitment = bc_assigner.assign_arc(value); + script_bytes.extend_from_slice( + script! { + {value_commitment.as_ref().check_and_recover()} + {value_commitment.as_ref().message_to_altstack()} + } + .as_bytes(), + ); + + move_back_bytes.extend_from_slice( + script! { + {value_commitment.as_ref().message_from_altstack()} + } + .as_bytes(), + ); + + let _ = value_commitment + .witness() + .iter() + .rev() + .for_each(|x| witness.push_front(x.clone())); + } + + for value in &self.output_values { + let value_commitment = bc_assigner.assign_arc(value); + script_bytes.extend_from_slice( + script! { + {value_commitment.as_ref().check_and_recover()} + {value_commitment.as_ref().message_to_altstack()} + } + .as_bytes(), + ); + + move_back_bytes.extend_from_slice( + script! { + {value_commitment.as_ref().message_from_altstack()} + } + .as_bytes(), + ); + + // witness.extend(value_commitment.witness()); + value_commitment + .witness() + .iter() + .rev() + .for_each(|x| witness.push_front(x.clone())); + } + + script_bytes.extend(move_back_bytes); + + let final_script = (ScriptBuf::from(script_bytes), witness.into()); + self.final_script = Some(final_script); + self + } + + pub fn ext_equalverify(size: u32, eq: bool) -> ScriptBuf { + script! { + { unroll(size - 1, |i| { + let gap = size - i; + script!{ + { gap } OP_ROLL + if eq {OP_EQUALVERIFY} else {OP_EQUAL OP_FALSE OP_EQUALVERIFY} + }}) } + if eq {OP_EQUALVERIFY} else {OP_EQUAL OP_FALSE OP_EQUALVERIFY} + } + } + + fn get_output_total_size(&self) -> u32 { + self.output_values + .iter() + .fold(0, |sum, x| sum + x.bc_as_u32_vec().len()) as u32 + } + + // for debug and unit test + pub fn get_eq_script(&mut self) -> ScriptBuf { + script! { + {self.check_witness()} + {self.script.clone()} + // check equal + {Self::ext_equalverify(self.get_output_total_size(), true)} + OP_TRUE + } + } + + // for release + pub fn get_neq_script(&mut self) -> ScriptBuf { + script! { + {self.check_witness()} + {self.script.clone()} + // check no equal + {Self::ext_equalverify(self.get_output_total_size(), false)} + OP_TRUE + } + } + + pub fn is_valid_name(name: &str) -> bool { + true + } + + pub fn script_size(&mut self) -> usize { + self.get_neq_script().len() + } + + pub fn witness_size(&mut self) -> usize { + let mut res = 0; + self.witness().iter().for_each(|x| res += x.len()); + res + } +} + +// macro_rules! script_info { +// ($name:expr, $script:expr, {$($inputs:expr)*}, {$($outputs:expr)*}) => {{ +// let mut temp_script_info = ScriptInfo::new($name, $script); +// $(temp_script_info.add_input($inputs))* +// $(temp_script_info.add_output($outputs))* +// temp_script_info +// }}; +// } + +macro_rules! script_info { + ($name:expr, $script:expr, [$($inputs:expr),*], [$($outputs:expr),*]) => {{ + let mut temp_script_info = ScriptInfo::new($name, $script); + $(temp_script_info.add_input($inputs);)* + $(temp_script_info.add_output($outputs);)* + temp_script_info + }}; +} + +#[cfg(test)] +mod test { + use std::ops::Mul; + + use bitcoin::opcodes::{OP_FROMALTSTACK, OP_TOALTSTACK}; + use bitcoin_script::script; + use p3_baby_bear::BabyBear; + use p3_field::AbstractField; + use primitives::field::BinomialExtensionField; + use scripts::bit_comm::bit_comm::BitCommitment; + use scripts::bit_comm_u32::pushable; + use scripts::execute_script_with_inputs; + use scripts::secret_generator::ThreadSecretGen; + use scripts::u31_lib::{u31ext_mul, BabyBear4}; + + use super::ScriptInfo; + use crate::bc_assignment::DefaultBCAssignment; + + type B4 = BinomialExtensionField; + + #[test] + fn test_basic_script_info_norun() { + let script_info = ScriptInfo::new( + "add_{i}+{j}+{c}", + script! { + OP_ADD + OP_ADD + }, + ) + .add_input(1) + .add_input(2) + .add_input(3) + .add_output(BabyBear::from_canonical_u16(0x12)); + } + + #[test] + fn test_basic_script_info() { + let mut bc_assigner = DefaultBCAssignment::new(); + let mut x = script_info!( + "add", + script! { + OP_ADD + // OP_ADD + }, + [1, 2], + [3] + ); + x.gen(&mut bc_assigner); + + // let bc = BitCommitment::new_with_box::(&x.output_values[0].clone()); + // let res = execute_script_with_inputs(bc.check_and_recover(), bc.witness()); + let res = execute_script_with_inputs(x.get_eq_script(), x.witness()); + println!("res: {:?}", res); + assert!(res.success); + let res = execute_script_with_inputs(x.get_neq_script(), x.witness()); + assert!(!res.success); + } + + #[test] + fn test_basic_script_info2() { + let mut bc_assigner = DefaultBCAssignment::new(); + let mut x = script_info!( + "add", + script! { + OP_ADD + OP_ADD + }, + [9, 10, 11], + [30] + ); + x.gen(&mut bc_assigner); + + // let bc = BitCommitment::new_with_box::(&x.output_values[0].clone()); + // let res = execute_script_with_inputs(bc.check_and_recover(), bc.witness()); + let res = execute_script_with_inputs(x.get_eq_script(), x.witness()); + println!("res: {:?}", res); + assert!(res.success); + let res = execute_script_with_inputs(x.get_neq_script(), x.witness()); + assert!(!res.success); + } + + #[test] + fn test_basic_script_info3() { + assert_eq!( + B4::from_canonical_u32(10).mul(B4::from_canonical_u32(12)), + B4::from_canonical_u32(120) + ); + let mut bc_assigner = DefaultBCAssignment::new(); + let mut x = script_info!( + "add", + script! { + {u31ext_mul::()} + }, + [B4::from_canonical_u32(10), B4::from_canonical_u32(12)], + [B4::from_canonical_u32(10).mul(B4::from_canonical_u32(12))] + ); + x.gen(&mut bc_assigner); + + // let bc = BitCommitment::new_with_box::(&x.output_values[0].clone()); + // let res = execute_script_with_inputs(bc.check_and_recover(), bc.witness()); + let res = execute_script_with_inputs(x.get_eq_script(), x.witness()); + println!("res stack: {:?}", res); + assert!(res.success); + let res = execute_script_with_inputs(x.get_neq_script(), x.witness()); + assert!(!res.success); + } + + #[test] + fn test_basic_script_info4() { + assert_eq!( + B4::from_canonical_u32(10).mul(B4::from_canonical_u32(12)), + B4::from_canonical_u32(120) + ); + let mut bc_assigner = DefaultBCAssignment::new(); + let mut x = script_info!( + "add", + script! { + OP_ADD + OP_TOALTSTACK + {u31ext_mul::()} + OP_FROMALTSTACK + }, + [1, 2, B4::from_canonical_u32(10), B4::from_canonical_u32(12)], + [3, B4::from_canonical_u32(120)] + ); + x.gen(&mut bc_assigner); + + // let bc = BitCommitment::new_with_box::(&x.output_values[0].clone()); + // let res = execute_script_with_inputs(bc.check_and_recover(), bc.witness()); + let res = execute_script_with_inputs(x.get_eq_script(), x.witness()); + println!("res stack: {:?}", res); + assert!(res.success); + let res = execute_script_with_inputs(x.get_neq_script(), x.witness()); + assert!(!res.success); + } +} diff --git a/scripts/Cargo.toml b/scripts/Cargo.toml index 1848695..abd4cfe 100644 --- a/scripts/Cargo.toml +++ b/scripts/Cargo.toml @@ -19,6 +19,9 @@ p3-util = { git = "https://github.com/Plonky3/Plonky3.git" } once_cell = "1.8.0" hex = "0.4.3" itertools = "0.12.1" + +common = {path = "../common"} + [dev-dependencies] p3-dft = { git = "https://github.com/Plonky3/Plonky3.git" } p3-goldilocks = { git = "https://github.com/Plonky3/Plonky3.git" } @@ -31,6 +34,7 @@ criterion = "0.5.1" rand = "0.8.5" rand_chacha = "0.3.1" blake3 = "1.5" +primitives = {path = "../primitives"} [profile.release] opt-level = 3 diff --git a/primitives/src/bit_comm/mod.rs b/scripts/src/bit_comm/bit_comm.rs similarity index 50% rename from primitives/src/bit_comm/mod.rs rename to scripts/src/bit_comm/bit_comm.rs index 0fb6041..ea5541b 100644 --- a/primitives/src/bit_comm/mod.rs +++ b/scripts/src/bit_comm/bit_comm.rs @@ -1,34 +1,96 @@ -pub mod bc_assign; -pub use bc_assign::*; -use bitcoin::opcodes::OP_EQUALVERIFY; +use std::marker::PhantomData; +use std::sync::Arc; + use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; +use common::AsU32Vec; use itertools::Itertools; -use scripts::bit_comm_u32::*; -use scripts::u31_lib::{u31_equalverify, u31ext_equalverify, BabyBear4}; -use crate::field::*; -define_pushable!(); +use super::bit_comm_u32::BitCommitmentU32; +use super::secret_generator::{SecretGen, ThreadSecretGen}; +use super::Witness; +use crate::pushable; +use crate::u31_lib::{u31_equalverify, u31ext_equalverify, BabyBear4}; + +// BitCommitment +// 1. Create a new BitCommitment through BCAssignment is a better way. +// 2. after run this `execute_script_with_input(bc.check_and_recover(), bc.witness())`, +// the u32 values should be placed on the stack for any bc. #[derive(Clone, Debug, Default, PartialEq, Eq)] -pub struct BitCommitment { - pub value: F, +pub struct BitCommitment { + pub u32_values: Vec, pub commitments: Vec, + pub value: Arc>, } -impl BitCommitment { - pub fn new(secret_key: &str, value: F) -> Self { - let u32_values = value.as_u32_vec(); +impl BitCommitment { + pub fn new_with_box(value: &Arc>) -> Box { + let u32_values = value.bc_as_u32_vec(); + let commitments = u32_values + .iter() + .map(|v| BitCommitmentU32::new(&S::gen(), *v)) + .collect_vec(); + Box::new(Self { + u32_values, + commitments, + value: value.clone(), + }) + } +} + +impl BitCommitment { + pub fn new(value: F) -> Self { + let u32_values = value.bc_as_u32_vec(); + let commitments = u32_values + .iter() + .map(|v| BitCommitmentU32::new(&S::gen(), *v)) + .collect_vec(); + Self { + u32_values, + commitments, + value: Arc::new(Box::new(value)), + } + } + + pub fn new_with_commits(value: F, commits: Vec) -> Self { + let u32_values = value.bc_as_u32_vec(); + assert_eq!(u32_values.len(), commits.len()); let commitments = u32_values .iter() - .map(|v| BitCommitmentU32::new(secret_key, *v)) + .enumerate() + .map(|(idx, value)| commits.get(idx).unwrap().clone().change_value(value)) .collect_vec(); - Self { value, commitments } + Self { + u32_values, + commitments, + value: Arc::new(Box::new(value)), + } + } +} +impl BitCommitment { + // execute with witness + // check bitcommitment and left u32_values to alt stack + pub fn check_and_recover_to_altstack(&self) -> Script { + self.recover_message_at_altstack() + } + + // execute with witness + // check bitcommitment and left u32_values to stack + pub fn check_and_recover(&self) -> Script { + script! { + {self.recover_message_at_altstack()} + {self.message_from_altstack()} + } + } + + pub fn witness(&self) -> Witness { + self.signature() } pub fn message_to_altstack(&self) -> Script { script! { - for _ in 0..F::U32_SIZE{ + for _ in 0..self.u32_values.len(){ OP_TOALTSTACK } } @@ -36,52 +98,40 @@ impl BitCommitment { pub fn message_from_altstack(&self) -> Script { script! { - for _ in 0..F::U32_SIZE{ + for _ in 0..self.u32_values.len(){ OP_FROMALTSTACK } } } -} -impl BitCommitment { - pub fn recover_message_at_stack(&self) -> Script { - // we must confirm the stack state look like below after the inputs enter to match the complete_script: - // bit_commits[0].sig <- top - // bit_commits[1].sig - // ... - // bit_commits[N].sig - let script = script! { - for i in 0..(F::U32_SIZE-1){ - {self.commitments[i].recover_message_euqal_to_commit_message()} - {self.commitments[i].value} - OP_TOALTSTACK + // bad function, just for uint test, need to be removed + pub fn recover_message_euqal_to_commit_message(&self) -> Script { + // signuture is the input of this script + let u32_values = self.value.bc_as_u32_vec(); + script! { + {self.check_and_recover()} + for i in (0..self.u32_values.len()).rev(){ + // the value compare sequence: { u32_values[3] } { u32_values[2]} { u32_values[1] } { u32_values[0]} + {u32_values[i]} } - {self.commitments[F::U32_SIZE-1].recover_message_euqal_to_commit_message()} - {self.commitments[F::U32_SIZE-1].value} - - for _ in 0..(F::U32_SIZE-1){ - OP_FROMALTSTACK + if self.u32_values.len() == 1{ + {u31_equalverify()} + }else { + {u31ext_equalverify::()} } - // The stake state looks like below: - // EF.slice(0) <- top - // EF.slice(1) - // ... - // EF.slice(EF::D-1) - }; - script + } } - pub fn recover_message_at_altstack(&self) -> Script { + fn recover_message_at_altstack(&self) -> Script { // we must confirm the stack state look like below after the inputs enter to match the recover_message_at_altstack: // bit_commits[0].sig <- top // bit_commits[1].sig // ... // bit_commits[N].sig let script = script! { - for i in 0..F::U32_SIZE{ - {self.commitments[i].recover_message_euqal_to_commit_message()} - {self.commitments[i].value} + for i in 0..self.u32_values.len(){ + {self.commitments[i].recover_message_at_stack()} OP_TOALTSTACK } @@ -94,27 +144,9 @@ impl BitCommitment { script } - // signuture is the input of this script - pub fn recover_message_euqal_to_commit_message(&self) -> Script { - let u32_values = self.value.as_u32_vec(); - script! { - {self.recover_message_at_stack()} - for i in (0..F::U32_SIZE).rev(){ - // the value compare sequence: { u32_values[3] } { u32_values[2]} { u32_values[1] } { u32_values[0]} - {u32_values[i]} - } - - if F::U32_SIZE == 1{ - {u31_equalverify()} - }else { - {u31ext_equalverify::()} - } - } - } - - pub fn signature(&self) -> Vec> { + fn signature(&self) -> Vec> { let mut sigs = Vec::new(); - for i in (0..F::U32_SIZE).rev() { + for i in (0..self.u32_values.len()).rev() { sigs.append(&mut self.commitments[i].signature()); } sigs @@ -125,12 +157,37 @@ mod test { use core::ops::{Add, Mul, Neg}; + use bitcoin_script::{define_pushable, script}; use p3_baby_bear::BabyBear; use p3_field::{AbstractExtensionField, AbstractField, PrimeField32}; + use primitives::field::BfField; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; - use scripts::u31_lib::{u31ext_add, u31ext_equalverify, BabyBear4}; - use scripts::{execute_script, execute_script_with_inputs}; + + use crate::u31_lib::{ + u31_equalverify, u31ext_add, u31ext_double, u31ext_equalverify, BabyBear4, + }; + use crate::{execute_script, execute_script_with_inputs}; + + // signuture is the input of this script + pub fn recover_message_euqal_to_commit_message( + checked: BitCommitment, + ) -> Script { + let u32_values = checked.value.bc_as_u32_vec(); + script! { + {checked.check_and_recover()} + for i in (0..checked.u32_values.len()).rev(){ + // the value compare sequence: { u32_values[3] } { u32_values[2]} { u32_values[1] } { u32_values[0]} + {u32_values[i]} + } + + if checked.u32_values.len() == 1{ + {u31_equalverify()} + }else { + {u31ext_equalverify::()} + } + } + } use super::*; @@ -144,8 +201,8 @@ mod test { let a = rng.gen::(); let b = rng.gen::(); - let a_commit = BitCommitment::new("b138982ce17ac813d505b5b40b665d404e9528e7", a); - let b_commit = BitCommitment::new("b138982ce17ac813d505b5b40b665d404e9528e6", b); + let a_commit = BitCommitment::new::(a); + let b_commit = BitCommitment::new::(b); let c = a.add(b); @@ -178,6 +235,7 @@ mod test { b_sigs.append(&mut a_sigs); let exec_result = execute_script_with_inputs(script, b_sigs); assert!(exec_result.success); + assert_eq!(exec_result.final_stack.len(), 1); } #[test] @@ -193,15 +251,16 @@ mod test { ] .as_slice(), ); - let a_commit = BitCommitment::new("b138982ce17ac813d505b5b40b665d404e9528e7", a); + let a_commit = BitCommitment::new::(a); let script = script! { - {a_commit.recover_message_euqal_to_commit_message()} + {recover_message_euqal_to_commit_message(a_commit.clone())} OP_1 }; - let a_sigs = a_commit.signature(); + let a_sigs = a_commit.witness(); let exec_result = execute_script_with_inputs(script, a_sigs); assert!(exec_result.success); + assert_eq!(exec_result.final_stack.len(), 1); } #[test] @@ -209,14 +268,15 @@ mod test { let mut rng = ChaCha20Rng::seed_from_u64(0u64); let mut a = rng.gen::(); a = BabyBear::from_u32(1u32); - let a_commit = BitCommitment::new("b138982ce17ac813d505b5b40b665d404e9528e7", a); + let a_commit = BitCommitment::new::(a); let script = script! { - {a_commit.recover_message_euqal_to_commit_message()} + {recover_message_euqal_to_commit_message(a_commit.clone())} OP_1 }; - let a_sigs = a_commit.signature(); + let a_sigs = a_commit.witness(); let exec_result = execute_script_with_inputs(script, a_sigs); assert!(exec_result.success); + assert_eq!(exec_result.final_stack.len(), 1); } } diff --git a/scripts/src/bit_comm/bit_comm_u32.rs b/scripts/src/bit_comm/bit_comm_u32.rs index 6ca1091..8a0d097 100644 --- a/scripts/src/bit_comm/bit_comm_u32.rs +++ b/scripts/src/bit_comm/bit_comm_u32.rs @@ -1,10 +1,9 @@ -use bitcoin::opcodes::OP_FROMALTSTACK; use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; use super::winternitz::*; +use crate::bit_comm::winternitz; use crate::u32_std::u32_compress; -use crate::winternitz; define_pushable!(); #[derive(Clone, Debug, PartialEq, Eq)] @@ -25,6 +24,16 @@ impl BitCommitmentU32 { } } + pub fn change_value(&mut self, value: &u32) -> Self { + let message = to_digits(value.clone(), winternitz::N0); + let winternitz = self.winternitz.clone(); + Self { + value: value.clone(), + winternitz, + message, + } + } + pub fn commit_u32_as_4bytes(&self) -> Vec { let message = self.message.clone(); let mut commit_message = vec![0u8; winternitz::N0 / 2]; diff --git a/scripts/src/bit_comm/mod.rs b/scripts/src/bit_comm/mod.rs index b720e32..45d75e8 100644 --- a/scripts/src/bit_comm/mod.rs +++ b/scripts/src/bit_comm/mod.rs @@ -1,5 +1,9 @@ +pub mod bit_comm; +pub mod bit_comm_u32; +pub mod secret_generator; pub mod winternitz; -pub use winternitz::*; +pub use common::{AsU32Vec, BabyBear, BinomialExtensionField}; +use winternitz::*; -pub mod bit_comm_u32; +type Witness = Vec>; diff --git a/scripts/src/bit_comm/secret_generator.rs b/scripts/src/bit_comm/secret_generator.rs new file mode 100644 index 0000000..5b89596 --- /dev/null +++ b/scripts/src/bit_comm/secret_generator.rs @@ -0,0 +1,34 @@ +use std::fmt::Debug; + +use bitcoin::hex::DisplayHex; +use rand::{thread_rng, Rng}; + +pub trait SecretGen: Debug + Clone + Default + PartialEq + Eq { + fn gen() -> String; +} + +#[derive(Debug, Clone, Default, PartialEq, Eq)] +pub struct ConstantSecretGen; + +impl SecretGen for ConstantSecretGen { + fn gen() -> String { + // temporary secret + "0000".to_owned() + } +} + +// not security enough +#[derive(Debug, Clone, Default, PartialEq, Eq)] +pub struct ThreadSecretGen; + +impl SecretGen for ThreadSecretGen { + fn gen() -> String { + let s: String = rand::thread_rng() + .sample_iter::(rand::distributions::Standard) + .take(20) + .collect(); + s.as_bytes().to_lower_hex_string() + } +} + +// TODO: find some more security random source diff --git a/scripts/src/bit_comm/winternitz.rs b/scripts/src/bit_comm/winternitz.rs index ebf5c4c..2d8f5aa 100644 --- a/scripts/src/bit_comm/winternitz.rs +++ b/scripts/src/bit_comm/winternitz.rs @@ -1,7 +1,8 @@ // -// Winternitz One-time Signatures +// License Claim: This file is optimized based https://github.com/BitVM/BitVM/blob/main/src/signatures/winternitz.rs // +// Winternitz One-time Signatures // // Winternitz signatures are an improved version of Lamport signatures. // A detailed introduction to Winternitz signatures can be found From a56c53b9f4f99febb888901c17abcb8e32411ef6 Mon Sep 17 00:00:00 2001 From: AndreW0ng Date: Wed, 19 Jun 2024 18:57:40 +0800 Subject: [PATCH 04/25] Bitcommitment Manager (part 2) (#7) * add interface of planners * add simple planner, to be tested * add simple test for the simple planner * add more test and fix some bugs of simple planner * update .gitignore * add readme for bc planner --- .gitignore | 1 + common/src/lib.rs | 6 + primitives/src/mmcs/point.rs | 2 +- script_manager/README.md | 46 +++ script_manager/src/planner.rs | 534 +++++++++++++++++++++++++++++- script_manager/src/script_info.rs | 62 +++- 6 files changed, 619 insertions(+), 32 deletions(-) create mode 100644 script_manager/README.md diff --git a/.gitignore b/.gitignore index ba697ef..067f740 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ Cargo.lock **/*.rs.bk .DS_Store +.vscode/ diff --git a/common/src/lib.rs b/common/src/lib.rs index 1bcbf5f..1710836 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -27,3 +27,9 @@ impl AsU32Vec for BabyBear { vec![self.as_canonical_u32()] } } + +impl AsU32Vec for Vec { + fn bc_as_u32_vec(&self) -> Vec { + self.clone() + } +} diff --git a/primitives/src/mmcs/point.rs b/primitives/src/mmcs/point.rs index e497842..f812dd8 100644 --- a/primitives/src/mmcs/point.rs +++ b/primitives/src/mmcs/point.rs @@ -2,7 +2,7 @@ use std::usize; use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; -use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; +use script_manager::bc_assignment::DefaultBCAssignment; use scripts::bit_comm::bit_comm::BitCommitment; use scripts::secret_generator::ConstantSecretGen; diff --git a/script_manager/README.md b/script_manager/README.md new file mode 100644 index 0000000..2b14096 --- /dev/null +++ b/script_manager/README.md @@ -0,0 +1,46 @@ +# Bitcommitment Manager + +Bitcommitment is a great tool to connect state between different bitcoin script, but costs huge script size and stack limit. This crate implements a manager for bitcommitment, making it more compacted and more convenient. + +## How to use it? + +A multi-layer loop may produce too much scripts. E.g., this example below: `single script_size = 2501, script_info_cnt = 100, total = 250100` + +```rust +let mut scripts = vec![]; +let mut sum: u32 = 0; +for i in 0..10 { + // more loop will lead to be over the stack limit + let added: u32 = i; + for j in 0..10 { + // record prestate + let pre_sum = sum; + sum += added; + // record state + scripts.push(script_info!( + &format!("add_{}_{}", i, j), + script! { + OP_ADD + }, + [added, pre_sum], + [sum] + )); + } +} +``` + +After using the compiler `SimplePlanner`, make it: `single combined script_size = 2974, combined_script_cnt = 17, total = 50558` + +```rust +let (leafs, _) = SimplePlanner::compile_to_eq(scripts); +``` + +## Futures + +- [x] Basic Script Info +- [x] Combine small scripts (Simple Planner) +- [ ] Split large scripts +- [ ] Integrity verification +- [ ] More optimized Planners + - [ ] When build connection with different input and outputs, not just `OP_DUP`, others op_code can be used (`OP_ADD1`, `OP_SUB1`, ...) + - [ ] Reduce more intermidiate state by marking it private \ No newline at end of file diff --git a/script_manager/src/planner.rs b/script_manager/src/planner.rs index 595c868..3b5bfe2 100644 --- a/script_manager/src/planner.rs +++ b/script_manager/src/planner.rs @@ -1,58 +1,560 @@ -use bitcoin::ScriptBuf; +use std::collections::VecDeque; + +use bitcoin::opcodes::{OP_RESERVED, OP_TOALTSTACK}; +use bitcoin::{witness, ScriptBuf}; +use bitcoin_script::script; +use scripts::pushable; use crate::bc_assignment::DefaultBCAssignment; +use crate::script_info; use crate::script_info::ScriptInfo; struct TaprootLeaf { script_buf: ScriptBuf, witness: Vec>, - meta_info: Vec, // record name of combined scriptInfo + meta_info: String, // record name of combined scriptInfo debug: bool, } +impl TaprootLeaf { + fn from_eq(value: &ScriptInfo) -> Self { + Self { + script_buf: value.get_eq_script(), + witness: value.witness(), + meta_info: value.name(), + debug: true, + } + } + + fn from_neq(value: &ScriptInfo) -> Self { + Self { + script_buf: value.get_neq_script(), + witness: value.witness(), + meta_info: value.name(), + debug: true, + } + } +} + type DefaultPlanner = SimplePlanner; const SCRIPT_LIMIT: usize = 350 * 1000; // 350kb +const SOFT_u32_LIMIT: usize = 20 * 20; // a bitcommitment for u32 cost 20 element in the stack, limit the stack to 600 trait Planner { /// combine - fn combine(infos: Vec) -> Vec; - /// compile infos to a set of success taprootleafs in debug mode - fn compile_to_eq(infos: Vec) -> (Vec, DefaultBCAssignment) { - let mut acc = 0; + fn core_combine(infos: Vec, debug: bool) -> ScriptInfo; + + fn combine(mut infos: Vec, debug: bool) -> Vec { + Self::dry_run_infos(&mut infos); + + let mut script_cnt = 0; + let mut u32_bc_cnt = 0; let mut combined_infos: Vec = vec![]; let mut res = vec![]; - for mut info in infos { + for info in infos { let info_size = info.script_size() + info.witness_size(); - if acc + info_size < SCRIPT_LIMIT { - acc += info_size; + let bc_u32_size = info.witness().len(); + if script_cnt + info_size <= SCRIPT_LIMIT && u32_bc_cnt + bc_u32_size <= SOFT_u32_LIMIT + { + script_cnt += info_size; + u32_bc_cnt += bc_u32_size; combined_infos.push(info); } else { - res.push(Self::combine(combined_infos)); + res.push(Self::core_combine(combined_infos, debug)); // clear status + script_cnt = info_size; + u32_bc_cnt = bc_u32_size; combined_infos = vec![info]; - acc = info_size; } } + // combine last infos + if !combined_infos.is_empty() { + res.push(Self::core_combine(combined_infos, debug)); + } + + res + } + + fn dry_run_infos(infos: &mut Vec) { + let mut mock_bc_assginer = DefaultBCAssignment::new(); + for info in infos { + info.gen(&mut mock_bc_assginer); + } + } + + /// compile infos to a set of success taprootleafs in debug mode + fn compile_to_eq(infos: Vec) -> (Vec, DefaultBCAssignment) { // now process res infos + let mut bc_assigner = DefaultBCAssignment::new(); + let taproot_leafs = Self::combine(infos, true) + .iter_mut() + .map(|info: &mut ScriptInfo| TaprootLeaf::from_eq(info.gen(&mut bc_assigner))) + .collect::>(); - todo!() + (taproot_leafs, bc_assigner) } + /// compile infos to a set of fail taprootleafs in release mode - fn compile_to_neq(infos: Vec) -> (Vec, DefaultBCAssignment); + fn compile_to_neq(infos: Vec) -> (Vec, DefaultBCAssignment) { + // now process res infos + let mut bc_assginer = DefaultBCAssignment::new(); + let taproot_leafs = Self::combine(infos, false) + .iter_mut() + .map(|info: &mut ScriptInfo| TaprootLeaf::from_eq(info.gen(&mut bc_assginer))) + .collect::>(); + + (taproot_leafs, bc_assginer) + } + /// check whether all infos can be linked with commitments - fn integrity_check(infos: Vec) -> bool; + fn integrity_check(infos: Vec) -> bool { + todo!() + } +} + +/// A inner helper structure +#[derive(Clone, Default)] +struct Cell { + value: u32, + source: u32, // TODO: inc and dec +} + +impl From<&u32> for Cell { + fn from(value: &u32) -> Self { + Self { + value: value.clone(), + source: 0, + } + } } -/// There no too much combine rules in the simple planner +/// There are no much combine rules in the simple planner /// 1. Simple planner just combine neighbouring script infos, so the order of vector is a important hint. /// 2. Some small script infos will be combined to a big one, limited by the `SCRIPT_LIMIT`. /// 3. For before script's output and after script's input, equivalent bitcommitment is eliminated. /// 4. u32_add_1 or u32_dec_1 can be thinked of it as equivalent. + struct SimplePlanner {} -// impl Planner for SimplePlanner {} +impl Planner for SimplePlanner { + // warninig: this function shouldn't be use alone, because the res is depended on the `debug` flag. + fn core_combine(infos: Vec, debug: bool) -> ScriptInfo { + let combined_name: String = infos + .iter() + .map(|x| x.name()) + .collect::>() + .join("+"); + + let mut big_table: Vec> = vec![]; + for info in infos.clone() { + let mut witness: Vec = Default::default(); + info.intput_values.iter().for_each(|input| { + witness.extend( + input + .bc_as_u32_vec() + .iter() + .map(|x| x.into()) + .collect::>(), + ); + }); + info.output_values.iter().for_each(|output| { + witness.extend( + output + .bc_as_u32_vec() + .iter() + .map(|x| x.into()) + .collect::>(), + ); + }); + big_table.push(witness.into()); + } + + // the max size of big_table is 1000, so it will be ok to find in a two-layer loop + // pre assign offset to cell + let mut offset: u32 = 0; + for (i, cells) in big_table.iter_mut().enumerate() { + for cell in cells.iter_mut() { + cell.source = offset; + offset += 1; + } + } + + let mut offset: u32 = 0; + let mut bc_values = vec![]; + let cloned_table = big_table.clone(); + for (i, cells) in big_table.iter_mut().enumerate() { + for cell in cells.iter_mut() { + // Can this cell be founded before ? + for j in 0..i { + let dup_cell = cloned_table + .get(j) + .unwrap() + .iter() + .find(|x| x.value == cell.value); + match dup_cell { + Some(inner_cell) => { + // Push currect offset + cell.source = inner_cell.source; + break; + } + None => cell.source = offset, + } + } + offset += 1; + } + } + + // process big table from begin to end and dup-push to correspond offset + let mut offset = 0; + let mut copy_script = vec![]; + for cells in big_table { + for cell in cells { + if cell.source != offset { + // TODO: can be optimized more + copy_script.extend_from_slice( + script! { + for _ in 0..cell.source { + OP_TOALTSTACK + } + OP_DUP // not just OP_DUP, possible OP_DUP, OP_ADD1 + for _ in 0..(offset - cell.source) { + OP_SWAP OP_TOALTSTACK + } + + for _ in 0..(offset) { + OP_FROMALTSTACK + } + } + .as_bytes(), + ); + // println!("put source {} to offset {}", cell.source, offset); + } else { + bc_values.push(cell.value); + } + offset += 1; + } + } + + // println!("copy scripts len = {}", copy_script.len()); + + let script = script_info! { + &combined_name, + script! { + {ScriptBuf::from(copy_script)} + for info in infos { + {info.script.clone()} + {ScriptInfo::ext_equalverify(info.get_output_total_size(), debug)} + } + }, + [bc_values], + [] + }; + + script + } +} +#[cfg(test)] mod test { + use bitcoin_script::script; + use rand_chacha::rand_core::le; + use scripts::{execute_script_with_inputs, pushable}; + + use crate::bc_assignment::{self, DefaultBCAssignment}; + use crate::planner::{Planner, SimplePlanner}; + use crate::script_info; + use crate::script_info::ScriptInfo; + // some tests + #[test] + fn test_simple_planner() { + let mut bc_assigner = DefaultBCAssignment::new(); + let mut script1 = script_info!( + "add1", + script! { + OP_ADD + // OP_ADD + }, + [1, 2], + [3] + ); + + let mut script2 = script_info!( + "add1", + script! { + OP_ADD + // OP_ADD + }, + [3, 1], + [4] + ); + + let mut script = SimplePlanner::core_combine(vec![script1, script2], true); + script.gen(&mut bc_assigner); + let res = execute_script_with_inputs(script.get_eq_script(), script.witness()); + assert!(res.success); + assert_eq!(bc_assigner.value_assigns.len(), 4); + } + + #[test] + fn test_simple_planner2() { + let mut bc_assigner = DefaultBCAssignment::new(); + let mut script1 = script_info!( + "add1", + script! { + OP_ADD + OP_ADD + }, + [10, 11, 12], + [33] + ); + + let mut script2 = script_info!( + "add1", + script! { + OP_ADD + OP_ADD + }, + [33, 10, 11], + [54] + ); + + let mut script = SimplePlanner::core_combine(vec![script1, script2], true); + script.gen(&mut bc_assigner); + let res = execute_script_with_inputs(script.get_eq_script(), script.witness()); + assert!(res.success); + assert_eq!(bc_assigner.value_assigns.len(), 5); + } + + // loop test + #[test] + fn test_simple_planner_for_loop() { + let mut bc_assigner = DefaultBCAssignment::new(); + let mut scripts = vec![]; + let mut sum: u32 = 0; + for i in 0..10 { + // record prestate + let pre_sum = sum; + sum += 100; + // record state + scripts.push(script_info!( + &format!("add_{}", i), + script! { + {100} + OP_ADD + }, + [pre_sum], + [sum] + )); + } + assert_eq!(sum, 1000); + + let mut script = SimplePlanner::core_combine(scripts, true); + script.gen(&mut bc_assigner); + let res = execute_script_with_inputs(script.get_eq_script(), script.witness()); + assert!(res.success); + assert_eq!(bc_assigner.value_assigns.len(), 11); + } + + // two-layer loop test + #[test] + fn test_simple_planner_for_loop2() { + let mut bc_assigner = DefaultBCAssignment::new(); + let mut scripts = vec![]; + let mut sum: u32 = 0; + for i in 0..10 { + for j in 0..2 { + // record prestate + let pre_sum = sum; + sum += 10; + // record state + scripts.push(script_info!( + &format!("add_{}_{}", i, j), + script! { + {10} + OP_ADD + }, + [pre_sum], + [sum] + )); + } + } + + println!( + "single script_size = {}, combined_size = {}", + scripts + .get_mut(0) + .unwrap() + .gen(&mut bc_assigner) + .script_size(), + scripts.len() + ); + + assert_eq!(sum, 200); + let mut script = SimplePlanner::core_combine(scripts, true); + script.gen(&mut bc_assigner); + println!( + "combined script_size = {}, script_name = {}", + script.script_size(), + script.name() + ); + let res = execute_script_with_inputs(script.get_eq_script(), script.witness()); + println!("res: {:?}", res); + assert!(res.success); + // assert_eq!(bc_assigner.value_assigns.len(), 101); + } + + #[test] + fn test_simple_planner_for_loop3() { + let mut bc_assigner = DefaultBCAssignment::new(); + let mut scripts = vec![]; + let mut sum: u32 = 0; + for i in 0..10 { + // more loop will lead to be over the stack limit + for j in 0..4 { + // record prestate + let pre_sum = sum; + sum += 10; + // record state + scripts.push(script_info!( + &format!("add_{}_{}", i, j), + script! { + {10} + OP_ADD + }, + [pre_sum], + [sum] + )); + } + } + + println!( + "single script_size = {}, combined_size = {}", + scripts + .get_mut(0) + .unwrap() + .gen(&mut bc_assigner) + .script_size(), + scripts.len() + ); + + let mut script = SimplePlanner::core_combine(scripts, true); + script.gen(&mut bc_assigner); + println!( + "combined script_size = {}, script_name = {}", + script.script_size(), + script.name() + ); + let res = execute_script_with_inputs(script.get_eq_script(), script.witness()); + println!("res: {:?}", res); + assert!(res.success); + // assert_eq!(bc_assigner.value_assigns.len(), 101); + } + + #[test] + fn test_simple_planner_for_loop4() { + let mut bc_assigner = DefaultBCAssignment::new(); + let mut scripts = vec![]; + let mut sum: u32 = 0; + for i in 0..10 { + // more loop will lead to be over the stack limit + for j in 0..10 { + // record prestate + let pre_sum = sum; + sum += 10; + // record state + scripts.push(script_info!( + &format!("add_{}_{}", i, j), + script! { + {10} + OP_ADD + }, + [pre_sum], + [sum] + )); + } + } + + println!( + "single script_size = {}, script_info_cnt = {}, total = {}", + scripts + .get_mut(0) + .unwrap() + .gen(&mut bc_assigner) + .script_size(), + scripts.len(), + scripts + .get_mut(0) + .unwrap() + .gen(&mut bc_assigner) + .script_size() + * scripts.len() + ); + + let (leafs, _) = SimplePlanner::compile_to_eq(scripts); + println!( + "single combined script_size = {}, combined_script_cnt = {}, total = {}", + leafs.get(0).unwrap().script_buf.len(), + leafs.len(), + leafs.get(0).unwrap().script_buf.len() * leafs.len(), + ); + for leaf in leafs { + let res = execute_script_with_inputs(leaf.script_buf, leaf.witness); + assert_eq!(res.success, true); + } + } + + #[test] + fn test_simple_planner_for_complicated_scripts() { + let mut bc_assigner = DefaultBCAssignment::new(); + let mut scripts = vec![]; + let mut sum: u32 = 0; + for i in 0..10 { + // more loop will lead to be over the stack limit + let added: u32 = i; + for j in 0..10 { + // record prestate + let pre_sum = sum; + sum += added; + // record state + scripts.push(script_info!( + &format!("add_{}_{}", i, j), + script! { + OP_ADD + }, + [added, pre_sum], + [sum] + )); + } + } + + println!( + "single script_size = {}, script_info_cnt = {}, total = {}", + scripts + .get_mut(0) + .unwrap() + .gen(&mut bc_assigner) + .script_size(), + scripts.len(), + scripts + .get_mut(0) + .unwrap() + .gen(&mut bc_assigner) + .script_size() + * scripts.len() + ); + + let (leafs, _) = SimplePlanner::compile_to_eq(scripts); + println!( + "single combined script_size = {}, combined_script_cnt = {}, total = {}", + leafs.get(0).unwrap().script_buf.len(), + leafs.len(), + leafs.get(0).unwrap().script_buf.len() * leafs.len(), + ); + for leaf in leafs { + let res = execute_script_with_inputs(leaf.script_buf, leaf.witness); + assert_eq!(res.success, true); + } + } } diff --git a/script_manager/src/script_info.rs b/script_manager/src/script_info.rs index 92ed9d2..6201f8f 100644 --- a/script_manager/src/script_info.rs +++ b/script_manager/src/script_info.rs @@ -3,18 +3,17 @@ use std::sync::Arc; use bitcoin::{Script, ScriptBuf}; use bitcoin_script::{define_pushable, script}; -use scripts::bit_comm::bit_comm::BitCommitment; -use scripts::secret_generator::ThreadSecretGen; use scripts::{pushable, unroll, AsU32Vec}; -use crate::bc_assignment::{BCAssignment, DefaultBCAssignment}; +use crate::bc_assignment::DefaultBCAssignment; // Implement basic script, and can be commpiled by planner +#[derive(Default, Clone)] pub struct ScriptInfo { name: String, - intput_values: Vec>>, - output_values: Vec>>, - script: ScriptBuf, + pub intput_values: Vec>>, + pub output_values: Vec>>, + pub script: ScriptBuf, final_script: Option<(ScriptBuf, Vec>)>, } @@ -23,7 +22,7 @@ impl ScriptInfo { pub fn new(name: &str, script: ScriptBuf) -> Self { assert!(Self::is_valid_name(name)); Self { - name: name.clone().into(), + name: name.into(), intput_values: vec![], output_values: vec![], script, @@ -40,9 +39,13 @@ impl ScriptInfo { self } + pub fn name(&self) -> String { + self.name.clone() + } + /// After executing this script, the stacks will be like this. /// stack: [..., input1, input0], altstack: [..., output1, ouput0] - fn check_witness(&mut self) -> ScriptBuf { + fn check_witness(&self) -> ScriptBuf { match self.final_script.clone() { Some((script, _)) => script, None => { @@ -53,7 +56,7 @@ impl ScriptInfo { // witness: [..., output1, output0, ..., input1, input0] // success with eq_script, and fail in neq_script - pub fn witness(&mut self) -> Vec> { + pub fn witness(&self) -> Vec> { match self.final_script.clone() { Some((_, witness)) => witness, None => { @@ -62,7 +65,7 @@ impl ScriptInfo { } } - pub fn gen(&mut self, bc_assigner: &mut DefaultBCAssignment) -> &mut Self { + pub fn gen(&mut self, bc_assigner: &mut DefaultBCAssignment) -> &Self { if !self.final_script.is_none() { return self; } @@ -127,7 +130,11 @@ impl ScriptInfo { self } + // FIXME: for neq mode, it should be success when just some equalverify fail pub fn ext_equalverify(size: u32, eq: bool) -> ScriptBuf { + if size == 0 { + return script!(); + } script! { { unroll(size - 1, |i| { let gap = size - i; @@ -139,14 +146,14 @@ impl ScriptInfo { } } - fn get_output_total_size(&self) -> u32 { + pub fn get_output_total_size(&self) -> u32 { self.output_values .iter() .fold(0, |sum, x| sum + x.bc_as_u32_vec().len()) as u32 } // for debug and unit test - pub fn get_eq_script(&mut self) -> ScriptBuf { + pub fn get_eq_script(&self) -> ScriptBuf { script! { {self.check_witness()} {self.script.clone()} @@ -157,7 +164,7 @@ impl ScriptInfo { } // for release - pub fn get_neq_script(&mut self) -> ScriptBuf { + pub fn get_neq_script(&self) -> ScriptBuf { script! { {self.check_witness()} {self.script.clone()} @@ -171,11 +178,11 @@ impl ScriptInfo { true } - pub fn script_size(&mut self) -> usize { + pub fn script_size(&self) -> usize { self.get_neq_script().len() } - pub fn witness_size(&mut self) -> usize { + pub fn witness_size(&self) -> usize { let mut res = 0; self.witness().iter().for_each(|x| res += x.len()); res @@ -191,6 +198,7 @@ impl ScriptInfo { // }}; // } +#[macro_export] macro_rules! script_info { ($name:expr, $script:expr, [$($inputs:expr),*], [$($outputs:expr),*]) => {{ let mut temp_script_info = ScriptInfo::new($name, $script); @@ -335,4 +343,28 @@ mod test { let res = execute_script_with_inputs(x.get_neq_script(), x.witness()); assert!(!res.success); } + + #[test] + fn test_basic_script_info6() { + let mut bc_assigner = DefaultBCAssignment::new(); + let input = (0..40).map(|x| x * 10).collect::>(); + let mut x = script_info!( + "add", + script! { + for _ in 0..40 { + OP_DROP + } + }, + [input], + [] + ); + x.gen(&mut bc_assigner); + println!("witness_stack: {}", x.witness().len()); + + let res = execute_script_with_inputs(x.get_eq_script(), x.witness()); + println!("res stack: {:?}", res); + assert!(res.success); + let res = execute_script_with_inputs(x.get_neq_script(), x.witness()); + assert!(res.success); + } } From ac4739cb6939c5d37cbfa4483e766dd0566c0298 Mon Sep 17 00:00:00 2001 From: dylanCai9 <22110240060@m.fudan.edu.cn> Date: Thu, 20 Jun 2024 17:36:48 +0800 Subject: [PATCH 05/25] feat: extend mmcs (#10) * extend mmcs * fix conflict * add test for failed case * fix query index * cargo fmt * add test mmcs get_max_height --- fri/src/prover.rs | 8 +- fri/src/script_verifier.rs | 12 +- fri/src/verifier.rs | 15 ++- primitives/src/mmcs/bf_mmcs.rs | 19 ++++ primitives/src/mmcs/point.rs | 100 +++++++++-------- primitives/src/mmcs/taptree.rs | 160 +++++++++++++++------------ primitives/src/mmcs/taptree_mmcs.rs | 165 +++++++++++++++++++++++++++- 7 files changed, 340 insertions(+), 139 deletions(-) diff --git a/fri/src/prover.rs b/fri/src/prover.rs index 999e681..ea60734 100644 --- a/fri/src/prover.rs +++ b/fri/src/prover.rs @@ -34,10 +34,9 @@ where let pow_witness = challenger.grind(config.proof_of_work_bits); - let query_indices: Vec = (0..config.num_queries) + let mut query_indices: Vec = (0..config.num_queries) .map(|_| challenger.sample_bits(log_max_height)) .collect(); - let query_proofs = info_span!("query phase").in_scope(|| { query_indices .iter() @@ -65,13 +64,14 @@ where F: BfField, M: BFMmcs>, { + //println!("query index:{}", index); let commit_phase_openings = commit_phase_commits .iter() .enumerate() .map(|(i, commit)| { - let index_i = index >> i; + let index_i_pair = index >> i >> 1; - let proof = config.mmcs.open_taptree(index_i, commit); + let proof = config.mmcs.open_taptree(index_i_pair, commit); proof }) .collect(); diff --git a/fri/src/script_verifier.rs b/fri/src/script_verifier.rs index 522c826..7fd2e1f 100644 --- a/fri/src/script_verifier.rs +++ b/fri/src/script_verifier.rs @@ -106,11 +106,13 @@ where &proof.commit_phase_openings, betas, ) { - let index_sibling = index ^ 1; + let point_index = index & 1; + let index_sibling = point_index ^ 1; + // let index_sibling = index ^ 1; let index_pair = index >> 1; let poins_leaf: PointsLeaf = step.points_leaf.clone(); - let challenge_point: Point = poins_leaf.get_point_by_index(index).unwrap().clone(); + let challenge_point: Point = poins_leaf.get_point_by_index(point_index).unwrap().clone(); let opening = reduced_openings[log_folded_height + 1]; let reduction_value = opening + folded_eval; @@ -131,7 +133,7 @@ where .unwrap() .clone(); - assert_eq!(challenge_point.x, x); + // assert_eq!(challenge_point.x, x); let neg_x = x * F::two_adic_generator(1); let cal_negx_leaf = CalNegXLeaf::<1, F>::new_from_assign(x, neg_x, assign); let exec_success = cal_negx_leaf.execute_leaf_script(); @@ -140,7 +142,7 @@ where SVError::VerifyCalNegXScriptError, )); } - assert_eq!(sibling_point.x, neg_x); + // assert_eq!(sibling_point.x, neg_x); let mut evals = vec![reduction_value; 2]; evals[index_sibling % 2] = sibling_point.y; @@ -174,7 +176,7 @@ where let folding_leaf = VerifyFoldingLeaf::<1, F>::new_from_assign( challenge_point.y, sibling_point.y, - challenge_point.x, + x, beta, folded_eval, assign, diff --git a/fri/src/verifier.rs b/fri/src/verifier.rs index f6380f4..09c5521 100644 --- a/fri/src/verifier.rs +++ b/fri/src/verifier.rs @@ -120,23 +120,28 @@ where &proof.commit_phase_openings, betas, ) { - let index_sibling = index ^ 1; + let point_index = index & 1; + let index_sibling = point_index ^ 1; let index_pair = index >> 1; + //println!("ch point index:{}, sib point index:{}, index_pair:{}", point_index, index_sibling, index_pair); let open_leaf: PointsLeaf = step.points_leaf.clone(); - let challenge_point: Point = open_leaf.get_point_by_index(index).unwrap().clone(); + let challenge_point: Point = open_leaf.get_point_by_index(point_index).unwrap().clone(); let opening = reduced_openings[log_folded_height + 1]; folded_eval = opening + folded_eval; + let sibling_point: Point = open_leaf.get_point_by_index(index_sibling).unwrap().clone(); + + //println!("challenge_point.y:{}", challenge_point.y); + //println!("sibling_point.y:{}", sibling_point.y); if log_folded_height < log_max_height - 1 { assert_eq!(folded_eval, challenge_point.y); } - let sibling_point: Point = open_leaf.get_point_by_index(index_sibling).unwrap().clone(); - assert_eq!(challenge_point.x, x); + // assert_eq!(challenge_point.x, x); let neg_x = x * F::two_adic_generator(1); - assert_eq!(sibling_point.x, neg_x); + // assert_eq!(sibling_point.x, neg_x); let mut evals = vec![folded_eval; 2]; evals[index_sibling % 2] = sibling_point.y; diff --git a/primitives/src/mmcs/bf_mmcs.rs b/primitives/src/mmcs/bf_mmcs.rs index af32757..fe8e37f 100644 --- a/primitives/src/mmcs/bf_mmcs.rs +++ b/primitives/src/mmcs/bf_mmcs.rs @@ -1,6 +1,7 @@ // use alloc::vec; // use alloc::vec::Vec; use core::fmt::Debug; +use std::borrow::Borrow; use p3_matrix::dense::RowMajorMatrix; // use serde::de::DeserializeOwned; @@ -41,4 +42,22 @@ pub trait BFMmcs: Clone { proof: &Self::Proof, root: &Self::Commitment, ) -> Result<(), Self::Error>; + + /// Get the matrices that were committed to. + fn get_matrices(&self, prover_data: &Self::ProverData) -> Vec>; + + fn get_matrix_heights(&self, prover_data: &Self::ProverData) -> Vec { + self.get_matrices(prover_data) + .iter() + .map(|matrix| matrix.values.len() / matrix.width) + .collect() + } + + /// Get the largest height of any committed matrix. + fn get_max_height(&self, prover_data: &Self::ProverData) -> usize { + self.get_matrix_heights(prover_data) + .into_iter() + .max() + .unwrap_or_else(|| panic!("No committed matrices?")) + } } diff --git a/primitives/src/mmcs/point.rs b/primitives/src/mmcs/point.rs index f812dd8..7f26176 100644 --- a/primitives/src/mmcs/point.rs +++ b/primitives/src/mmcs/point.rs @@ -11,81 +11,83 @@ define_pushable!(); #[derive(Debug, Clone)] pub struct PointsLeaf { - leaf_index_1: usize, - leaf_index_2: usize, - points: Points, + leaf_index: usize, + leaf_evals: Points, } impl PointsLeaf { - pub fn new( - leaf_index_1: usize, - leaf_index_2: usize, - x: F, - y: F, - x2: F, - y2: F, - ) -> PointsLeaf { - let points = Points::::new(x, y, x2, y2); + pub fn new(leaf_index: usize, xs: &[F], ys: &[F]) -> PointsLeaf { + let leaf_evals = Points::::new(xs, ys); Self { - leaf_index_1, - leaf_index_2, - points, + leaf_index, + leaf_evals, } } pub fn recover_points_euqal_to_commited_point(&self) -> Script { let scripts = script! { - {self.points.p1.recover_point_euqal_to_commited_point()} - {self.points.p2.recover_point_euqal_to_commited_point()} + {self.leaf_evals.recover_points_euqal_to_commited_points()} OP_1 }; scripts } pub fn witness(&self) -> Vec> { - let mut p1_sigs = self.points.p1.signature(); - let mut p2_sigs = self.points.p2.signature(); - p2_sigs.append(p1_sigs.as_mut()); - p2_sigs + self.leaf_evals.witness() } pub fn get_point_by_index(&self, index: usize) -> Option<&Point> { - if index == self.leaf_index_1 { - Some(&self.points.p1) - } else if self.leaf_index_2 == index { - Some(&self.points.p2) + if self.leaf_evals.points.len() > index { + Some(&self.leaf_evals.points[index]) } else { None } } + pub fn print_point_evals(&self) -> Result<(), ()> { + if self.leaf_evals.points.is_empty() { + println!("No points to evaluate"); + } + for i in self.leaf_evals.points.iter() { + println!("point_eval: {:?}", i.y); + } + Ok(()) + } } #[derive(Debug, Clone)] pub struct Points { - p1: Point, - p2: Point, + pub points: Vec>, } impl Points { - pub fn new(x1: F, y1: F, x2: F, y2: F) -> Points { - let p1 = Point::::new(x1, y1); - let p2 = Point::::new(x2, y2); - Self { p1, p2 } + pub fn new(xs: &[F], ys: &[F]) -> Points { + let mut points = vec![]; + for (x, y) in xs.iter().zip(ys.iter()) { + //we should use refer here? + points.push(Point::::new(*x, *y)); + } + Self { points } } pub fn recover_points_euqal_to_commited_points(&self) -> Script { + // let scripts = script! { + // {self.p1.recover_point_euqal_to_commited_point()} + // {self.p2.recover_point_euqal_to_commited_point()} + // }; let scripts = script! { - {self.p1.recover_point_euqal_to_commited_point()} - {self.p2.recover_point_euqal_to_commited_point()} + for p in self.points.iter() { + { p.recover_point_euqal_to_commited_point() } + } }; scripts } - pub fn signature(&self) -> Vec> { - let mut p1_sigs = self.p1.signature(); - let mut p2_sigs = self.p2.signature(); - p2_sigs.append(p1_sigs.as_mut()); - p2_sigs + pub fn witness(&self) -> Vec> { + let mut sigs = vec![]; + for p in self.points.iter().rev() { + sigs.extend(p.witness()); + } + sigs } } @@ -156,7 +158,7 @@ impl Point { scripts } - pub fn signature(&self) -> Vec> { + pub fn witness(&self) -> Vec> { let mut x_sigs = self.x_commit.witness(); let mut y_sigs = self.y_commit.witness(); y_sigs.append(x_sigs.as_mut()); @@ -187,7 +189,7 @@ mod test { {p.recover_point_euqal_to_commited_point()} OP_1 }; - let inputs = p.signature(); + let inputs = p.witness(); let res = execute_script_with_inputs(script, inputs); assert!(res.success); } @@ -205,7 +207,7 @@ mod test { {p.recover_point_euqal_to_commited_point()} OP_1 }; - let inputs = p.signature(); + let inputs = p.witness(); let res = execute_script_with_inputs(script, inputs); assert!(res.success); } @@ -214,17 +216,15 @@ mod test { fn test_points_Babybear() { use p3_baby_bear::BabyBear; let p = Points::::new( - BabyBear::from_u32(1), - BabyBear::from_u32(2), - BabyBear::from_u32(3), - BabyBear::from_u32(4), + &vec![BabyBear::from_u32(1), BabyBear::from_u32(3)], + &vec![BabyBear::from_u32(2), BabyBear::from_u32(4)], ); let script = script! { {p.recover_points_euqal_to_commited_points()} OP_1 }; - let inputs = p.signature(); + let inputs = p.witness(); let res = execute_script_with_inputs(script, inputs); assert!(res.success); } @@ -237,14 +237,18 @@ mod test { let b = rng.gen::(); let c = rng.gen::(); let d = rng.gen::(); + let e = rng.gen::(); + let f = rng.gen::(); - let p = Points::new(a, b, c, d); + let xs = vec![a, c, e]; + let ys = vec![b, d, f]; + let p = Points::new(&xs, &ys); let script = script! { {p.recover_points_euqal_to_commited_points()} OP_1 }; - let inputs = p.signature(); + let inputs = p.witness(); let res = execute_script_with_inputs(script, inputs); assert!(res.success); } diff --git a/primitives/src/mmcs/taptree.rs b/primitives/src/mmcs/taptree.rs index c2e7b06..d99a92a 100644 --- a/primitives/src/mmcs/taptree.rs +++ b/primitives/src/mmcs/taptree.rs @@ -1,11 +1,14 @@ use core::ops::{Deref, DerefMut}; use core::{mem, usize}; +use std::cmp::Reverse; use bitcoin::taproot::LeafVersion::TapScript; use bitcoin::taproot::{LeafNode, LeafNodes, NodeInfo, TaprootMerkleBranch}; use bitcoin::{ScriptBuf, TapNodeHash}; use itertools::{Chunk, Itertools}; -use p3_util::{log2_strict_usize, reverse_slice_index_bits}; +use p3_matrix::dense::RowMajorMatrix; +use p3_matrix::Matrix; +use p3_util::{log2_ceil_usize, log2_strict_usize, reverse_slice_index_bits}; use scripts::secret_generator::ThreadSecretGen; use super::error::BfError; @@ -104,53 +107,65 @@ pub struct GlobalTree {} pub struct PolyCommitTree { pub tree: BasicTree, pub points_leafs: Vec>, + pub leaves: Vec>, } impl PolyCommitTree { - pub fn new(log_poly_points: usize) -> Self { + pub fn new() -> Self { Self { - tree: BasicTree::::new(log_poly_points), + tree: BasicTree::::new(), points_leafs: Vec::new(), + leaves: Vec::new(), } } - pub fn commit_points(&mut self, evaluations: Vec) { - let poly_points = evaluations.len(); - let evas = Polynomials::new_eva_poly( - evaluations, - F::sub_group(log2_strict_usize(poly_points)), - PolynomialType::Eva, - ); - let mut builder = TreeBuilder::::new(); - for i in 0..evas.values.len() { - let leaf_script = construct_evaluation_leaf_script::<1, F>( - i, - evas.points[i], - vec![evas.values[i].clone()], - ) - .unwrap(); - } - self.tree = builder.build_tree(); - } + pub fn commit_points(&mut self, leaves: Vec>) { + self.leaves = leaves.clone(); + //evaluations sorted by height + let mut leaves_largest_first = leaves + .iter() + .sorted_by_key(|l| Reverse(l.height())) + .peekable(); + let max_height = leaves_largest_first.peek().unwrap().height(); + let log_max_height = log2_ceil_usize(max_height); - pub fn commit_rev_points(&mut self, evaluations: Vec, width: usize) { - let poly_points = evaluations.len(); - let mut subgroup = F::sub_group(log2_strict_usize(poly_points)); - let leaf_indexs: Vec = (0..poly_points).into_iter().collect(); - reverse_slice_index_bits(&mut subgroup); + //println!("max height:{:?}", max_height); let mut tree_builder = TreeBuilder::::new(); - for i in (0..poly_points).into_iter().step_by(width) { - let leaf = PointsLeaf::new( - leaf_indexs[i], - leaf_indexs[i + 1], - subgroup[i], - evaluations[i], - subgroup[i + 1], - evaluations[i + 1], - ); - self.add_leaf(&mut tree_builder, &leaf) + + let mut leaf_xs = vec![vec![]; max_height]; + let mut leaf_ys = vec![vec![]; max_height]; + + for log_height in (0..log_max_height + 1).rev() { + let matrices = leaves_largest_first + .peeking_take_while(|m| log2_ceil_usize(m.height()) == log_height) + .collect_vec(); + if matrices.len() != 0 { + let curr_height = matrices[0].height(); + for matrix in matrices.iter() { + let width = matrix.width(); + for index in 0..curr_height { + //find which leaf to store + let curr_index = index << (log_max_height - log_height); + let next_index = (index + 1) << (log_max_height - log_height); + for i in 0..width { + for leaf_index in curr_index..next_index { + //default x to F::one(), may be we will delete x in struct point soon + leaf_xs[leaf_index].push(F::one()); + leaf_ys[leaf_index].push(matrix.values[index * matrix.width() + i]); + } + } + } + } + } } + for index in 0..max_height { + if leaf_ys[index].len() != 0 { + //println!("index:{:?}, ys:{:?}", index, leaf_ys[index]); + let leaf = PointsLeaf::new(index, &leaf_xs[index], &leaf_ys[index]); + self.add_leaf(&mut tree_builder, &leaf); + } + } self.tree = tree_builder.build_tree(); } @@ -162,8 +177,6 @@ impl PolyCommitTree { self.tree.get_tapleaf(index) } - // pub fn combine_tree() - pub fn verify_inclusion_by_index(&self, index: usize) -> bool { self.tree.verify_inclusion_by_index(index) } @@ -224,6 +237,7 @@ impl TreeBuilder { let mut t_idx_to_m_idx = self.leaf_indices.clone(); while working_nodes.len() > 1 { + println!("working_nodes len:{:?}", working_nodes.len()); //the tuple() method in itertool will drop the elements in Iter if the size is not enough to //generate a tuple, so we have to save the last node if the size of working node is odd. let mut reminder_node: Option = None; @@ -245,6 +259,7 @@ impl TreeBuilder { todo.push(ret_node); + //swap index when !left_first if !left_first { let mut temp_a_leaf_indices = vec![0usize; a_leaf_size]; temp_a_leaf_indices @@ -262,6 +277,7 @@ impl TreeBuilder { a_start_idx += a_leaf_size + b_leaf_size; } working_nodes = todo; + todo = Vec::new(); } BasicTree { @@ -281,7 +297,7 @@ fn reverse_idx_dict(idx_dict: &Vec) -> Vec { } impl BasicTree { - pub fn new(log_poly_points: usize) -> Self { + pub fn new() -> Self { Self { root_node: None, leaf_count: 0, @@ -562,39 +578,39 @@ mod tests { // assert!(root_node.leaf_nodes().len()==8); } - fn commit_with_poly_tree(degree: usize) -> PolyCommitTree - where - Standard: Distribution, - { - let mut rng = thread_rng(); - let coeffs = (0..degree).map(|_| rng.gen::()).collect::>(); - - let poly = Polynomials::new(coeffs, PolynomialType::Coeff); - let eva_poly = poly.convert_to_evals_at_subgroup(); - let evas = eva_poly.values(); - let mut poly_taptree = PolyCommitTree::::new(2); - poly_taptree.commit_rev_points(evas.clone(), 2); - poly_taptree - } - - #[test] - fn test_poly_commit_tree() { - // x^2 + 2 x + 3 - type F = BabyBear; - let poly_taptree = commit_with_poly_tree::(8); - - (0..4).into_iter().for_each(|index| { - let leaf = poly_taptree.get_tapleaf(index).unwrap(); - let script = leaf.leaf().as_script().unwrap(); - let points_leaf = poly_taptree.get_points_leaf(index); - assert_eq!( - points_leaf.recover_points_euqal_to_commited_point(), - *script.0 - ); - let success = verify_inclusion(poly_taptree.root().node_hash(), leaf); - assert_eq!(success, true); - }); - } + // fn commit_with_poly_tree(degree: usize) -> PolyCommitTree + // where + // Standard: Distribution, + // { + // let mut rng = thread_rng(); + // let coeffs = (0..degree).map(|_| rng.gen::()).collect::>(); + + // let poly = Polynomials::new(coeffs, PolynomialType::Coeff); + // let eva_poly = poly.convert_to_evals_at_subgroup(); + // let evas = eva_poly.values(); + // let mut poly_taptree = PolyCommitTree::::new(2); + // poly_taptree.commit_rev_points(evas.clone(), 2); + // poly_taptree + // } + + // #[test] + // fn test_poly_commit_tree() { + // // x^2 + 2 x + 3 + // type F = BabyBear; + // let poly_taptree = commit_with_poly_tree::(8); + + // (0..4).into_iter().for_each(|index| { + // let leaf = poly_taptree.get_tapleaf(index).unwrap(); + // let script = leaf.leaf().as_script().unwrap(); + // let points_leaf = poly_taptree.get_points_leaf(index); + // assert_eq!( + // points_leaf.recover_points_euqal_to_commited_point(), + // *script.0 + // ); + // let success = verify_inclusion(poly_taptree.root().node_hash(), leaf); + // assert_eq!(success, true); + // }); + // } #[test] fn test_swap_slice() { diff --git a/primitives/src/mmcs/taptree_mmcs.rs b/primitives/src/mmcs/taptree_mmcs.rs index 5f5e43d..0ef7bac 100644 --- a/primitives/src/mmcs/taptree_mmcs.rs +++ b/primitives/src/mmcs/taptree_mmcs.rs @@ -47,8 +47,7 @@ impl BFMmcs for TapTreeMmcs { type Error = BfError; fn open_taptree(&self, index: usize, prover_data: &PolyCommitTree) -> Self::Proof { - // The matrix with width-2 lead to the index need to right shift 1-bit - let leaf_index = index >> LOG_DEFAULT_MATRIX_WIDTH; + let leaf_index = index; let leaf = prover_data.get_tapleaf(leaf_index); let opening_leaf = match leaf { Some(v) => v, @@ -61,6 +60,7 @@ impl BFMmcs for TapTreeMmcs { panic!("invalid leaf index") } }; + println!("leaf_index:{:?}", leaf_index); let open_leaf = prover_data.get_points_leaf(leaf_index).clone(); CommitProof { points_leaf: open_leaf, @@ -83,12 +83,167 @@ impl BFMmcs for TapTreeMmcs { } fn commit(&self, inputs: Vec>) -> (Self::Commitment, Self::ProverData) { - let log_leaves = log2_strict_usize(inputs[0].height()); - let mut tree = PolyCommitTree::::new(log_leaves); + // let log_leaves = log2_strict_usize(inputs[0].height()); + let mut tree = PolyCommitTree::::new(); - tree.commit_rev_points(inputs[0].values.clone(), inputs[0].width); + tree.commit_points(inputs); let root: U256 = tree.root().node_hash().as_byte_array().clone(); (u256_to_u32(root), tree) } + fn get_matrices(&self, prover_data: &Self::ProverData) -> Vec> { + prover_data.leaves.clone() + } +} + +#[cfg(test)] +mod test { + use bitcoin::taproot::TapLeaf; + use p3_baby_bear::BabyBear; + use p3_field::AbstractField; + use p3_matrix::dense::RowMajorMatrix; + use scripts::execute_script_with_inputs; + + use super::TapTreeMmcs; + use crate::mmcs::bf_mmcs::BFMmcs; + type F = BabyBear; + + #[test] + fn test_taptree_mmcs() { + // mat_1 = [ + // 0 1 + // 2 1 + // 2 2 + // 1 0 + // ] + let mat_1 = RowMajorMatrix::new( + vec![ + F::zero(), + F::one(), + F::two(), + F::one(), + F::two(), + F::two(), + F::one(), + F::zero(), + ], + 2, + ); + + // mat_2 = [ + // 0 1 2 1 + // 2 2 1 0 + // 0 1 2 1 + // 2 2 1 0 + // ] + let mat_2 = RowMajorMatrix::new( + vec![ + F::zero(), + F::one(), + F::two(), + F::one(), + F::two(), + F::two(), + F::one(), + F::zero(), + F::zero(), + F::one(), + F::two(), + F::one(), + F::two(), + F::two(), + F::one(), + F::zero(), + ], + 4, + ); + + // mat_3 = [ + // 0 + // 1 + // 2 + // 1 + // 2 + // 2 + // 1 + // 0 + // ] + let mat_3 = RowMajorMatrix::new( + vec![ + F::zero(), + F::one(), + F::two(), + F::one(), + F::two(), + F::two(), + F::one(), + F::zero(), + ], + 1, + ); + + // we get pointleafs like: + // index:0, ys:[0, 0, 1, 0, 1, 2, 1] + // index:1, ys:[1, 0, 1, 0, 1, 2, 1] + // index:2, ys:[2, 2, 1, 2, 2, 1, 0] + // index:3, ys:[1, 2, 1, 2, 2, 1, 0] + // index:4, ys:[2, 2, 2, 0, 1, 2, 1] + // index:5, ys:[2, 2, 2, 0, 1, 2, 1] + // index:6, ys:[1, 1, 0, 2, 2, 1, 0] + // index:7, ys:[0, 1, 0, 2, 2, 1, 0] + + let inputs = vec![mat_1, mat_2, mat_3]; + let mmcs = TapTreeMmcs::new(); + let (commit, prover_data) = mmcs.commit(inputs); + + //test get_max_height + let max_height = mmcs.get_max_height(&prover_data); + assert_eq!(max_height, 8); + + let index = 2; + let proof = mmcs.open_taptree(index, &prover_data); + + let wrong_index = 3; + let wrong_proof = mmcs.open_taptree(wrong_index, &prover_data); + + // let _ = proof.points_leaf.print_point_evals(); + { + let points_leaf = proof.points_leaf.clone(); + let input = points_leaf.witness(); + if let TapLeaf::Script(script, _ver) = proof.leaf_node.clone().leaf().clone() { + assert_eq!(script, points_leaf.recover_points_euqal_to_commited_point()); + let res = execute_script_with_inputs( + points_leaf.recover_points_euqal_to_commited_point(), + input, + ); + if !res.success { + println!("execute_script_with_inputs error"); + } + assert_eq!(res.success, true); + } else { + panic!("Invalid script") + } + } + + { + let points_leaf = proof.points_leaf.clone(); + let wrong_points_leaf = wrong_proof.points_leaf.clone(); + let wrong_input = wrong_points_leaf.witness(); + if let TapLeaf::Script(script, _ver) = proof.leaf_node.clone().leaf().clone() { + assert_eq!(script, points_leaf.recover_points_euqal_to_commited_point()); + let res = execute_script_with_inputs( + points_leaf.recover_points_euqal_to_commited_point(), + wrong_input, + ); + if !res.success { + println!("execute_script_with_inputs error as expected"); + } + assert_eq!(res.success, false); + } else { + panic!("Invalid script") + } + } + + let success = mmcs.verify_taptree(&proof, &commit); + } } From 8f887719d610b1d37c22e742afb5e8a66e69a726 Mon Sep 17 00:00:00 2001 From: 0xhhh <52317293+cyl19970726@users.noreply.github.com> Date: Mon, 1 Jul 2024 14:36:47 +0800 Subject: [PATCH 06/25] add two_adic_pcs (#11) * extend mmcs * fix query index * add two_adic_pcs && update fri * add two_adic_pcs * add pcs test * add u31ext_mul_u31 * add pcs::accmulator script * update two_adic_pcs * update permutation as Blake3Permutation for pcs-test * add script_manager for pcs and fri * fmt * update pcs-test and move fri-test * remove unuse code * update Cargo.lock * remove unuse comment and code * fix point bug * optimize comment * fix doc-test --------- Co-authored-by: dylanCai9 <22110240060@m.fudan.edu.cn> --- Cargo.lock | 1458 ++++++++++++++++++++++++++- fri/Cargo.toml | 1 + fri/src/config.rs | 32 + fri/src/error.rs | 7 +- fri/src/fri_scripts/mod.rs | 1 + fri/src/fri_scripts/pcs.rs | 484 +++++++++ fri/src/lib.rs | 2 + fri/src/proof.rs | 9 +- fri/src/prover.rs | 664 ++---------- fri/src/script_verifier.rs | 75 +- fri/src/two_adic_pcs.rs | 526 ++++++++++ fri/src/verifier.rs | 79 +- fri/tests/fri.rs | 617 ++++++++++++ fri/tests/pcs.rs | 214 ++++ primitives/Cargo.toml | 1 + primitives/src/bf_pcs.rs | 93 ++ primitives/src/lib.rs | 1 + primitives/src/mmcs/bf_mmcs.rs | 17 +- primitives/src/mmcs/error.rs | 1 + primitives/src/mmcs/point.rs | 8 + primitives/src/mmcs/taptree.rs | 6 +- primitives/src/mmcs/taptree_mmcs.rs | 83 +- scripts/Cargo.toml | 2 +- scripts/src/lib.rs | 5 +- 24 files changed, 3645 insertions(+), 741 deletions(-) create mode 100644 fri/src/fri_scripts/pcs.rs create mode 100644 fri/src/two_adic_pcs.rs create mode 100644 fri/tests/fri.rs create mode 100644 fri/tests/pcs.rs create mode 100644 primitives/src/bf_pcs.rs diff --git a/Cargo.lock b/Cargo.lock index f52617f..1e97872 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,33 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -53,7 +80,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -63,7 +90,187 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-crypto-primitives" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3a13b34da09176a8baba701233fdffbaa7c1b1192ce031a3da4e55ce1f1a56" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-relations", + "ark-serialize", + "ark-snark", + "ark-std", + "blake2", + "derivative", + "digest", + "rayon", + "sha2", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools 0.10.5", + "num-traits", + "rayon", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rayon", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-groth16" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20ceafa83848c3e390f1cbf124bc3193b3e639b3f02009e0e290809a501b95fc" +dependencies = [ + "ark-crypto-primitives", + "ark-ec", + "ark-ff", + "ark-poly", + "ark-relations", + "ark-serialize", + "ark-std", + "rayon", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "rayon", +] + +[[package]] +name = "ark-relations" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00796b6efc05a3f48225e59cb6a2cda78881e7c390872d5786aaf112f31fb4f0" +dependencies = [ + "ark-ff", + "ark-std", + "tracing", + "tracing-subscriber 0.2.25", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-snark" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d3cc6833a335bb8a600241889ead68ee89a3cf8448081fb7694c0fe503da63" +dependencies = [ + "ark-ff", + "ark-relations", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", + "rayon", ] [[package]] @@ -84,6 +291,21 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base58ck" version = "0.1.0" @@ -94,6 +316,18 @@ dependencies = [ "bitcoin_hashes", ] +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "bech32" version = "0.11.0" @@ -145,6 +379,17 @@ dependencies = [ "quote", ] +[[package]] +name = "bitcoin-script-stack" +version = "0.0.1" +source = "git+https://github.com/bitlayer-org/rust-bitcoin-script-stack#8e85b5253597cd2af564d68e9830d87127a87e25" +dependencies = [ + "bitcoin", + "bitcoin-script", + "bitcoin-scriptexec", + "hex", +] + [[package]] name = "bitcoin-scriptexec" version = "0.0.0" @@ -182,6 +427,56 @@ dependencies = [ "serde", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "bitvm" +version = "0.1.0" +source = "git+https://github.com/bitlayer-org/BitVM#561f67786d370dc9b32f4dcedec41a70fab166c0" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-groth16", + "bitcoin", + "bitcoin-script", + "bitcoin-script-stack", + "bitcoin-scriptexec", + "esplora-client", + "hex", + "lazy_static", + "num-bigint", + "num-traits", + "once_cell", + "rand", + "rand_chacha", + "serde", + "serde_json", + "sha2", + "strum", + "strum_macros", + "tokio", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + [[package]] name = "blake3" version = "1.5.1" @@ -195,12 +490,27 @@ dependencies = [ "constant_time_eq", ] +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + [[package]] name = "cast" version = "0.3.0" @@ -209,9 +519,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "c891175c3fb232128f48de6590095e59198bbeb8620c310be349bfc3afd12c7b" [[package]] name = "cfg-if" @@ -277,7 +587,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -316,6 +626,31 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + [[package]] name = "criterion" version = "0.5.1" @@ -383,12 +718,118 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + [[package]] name = "either" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "esplora-client" +version = "0.7.0" +source = "git+https://github.com/bitlayer-org/rust-esplora-client#e63c2eb84456358cef10ef4c0a0192fb8ecd2e3c" +dependencies = [ + "bitcoin", + "hex-conservative", + "log", + "minreq", + "reqwest", + "serde", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "fri" version = "0.1.0" @@ -402,6 +843,7 @@ dependencies = [ "p3-baby-bear", "p3-blake3", "p3-challenger", + "p3-commit", "p3-dft", "p3-field", "p3-goldilocks", @@ -422,14 +864,63 @@ dependencies = [ "segment", "serde", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.18", ] [[package]] -name = "gcd" -version = "2.3.0" +name = "futures-channel" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "gcd" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] [[package]] name = "getrandom" @@ -444,6 +935,31 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" version = "2.4.1" @@ -454,6 +970,21 @@ dependencies = [ "crunchy", ] +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "heck" version = "0.5.0" @@ -487,6 +1018,103 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + [[package]] name = "is-terminal" version = "0.4.12" @@ -495,7 +1123,7 @@ checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ "hermit-abi", "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -548,9 +1176,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" @@ -558,6 +1186,22 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.21" @@ -579,6 +1223,61 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "minreq" +version = "2.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fdef521c74c2884a4f3570bcdb6d2a77b3c533feb6b27ac2ae72673cc221c64" +dependencies = [ + "base64 0.12.3", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -618,6 +1317,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "nums" version = "0.1.0" @@ -630,6 +1339,15 @@ dependencies = [ "rand", ] +[[package]] +name = "object" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -642,6 +1360,50 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "openssl" +version = "0.10.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +dependencies = [ + "bitflags 2.5.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "overload" version = "0.1.1" @@ -655,7 +1417,7 @@ version = "0.1.0" [[package]] name = "p3-baby-bear" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" dependencies = [ "num-bigint", "p3-field", @@ -669,7 +1431,7 @@ dependencies = [ [[package]] name = "p3-blake3" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" dependencies = [ "blake3", "p3-symmetric", @@ -678,7 +1440,7 @@ dependencies = [ [[package]] name = "p3-challenger" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" dependencies = [ "p3-field", "p3-maybe-rayon", @@ -690,7 +1452,7 @@ dependencies = [ [[package]] name = "p3-commit" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" dependencies = [ "itertools 0.13.0", "p3-challenger", @@ -703,7 +1465,7 @@ dependencies = [ [[package]] name = "p3-dft" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" dependencies = [ "p3-field", "p3-matrix", @@ -715,7 +1477,7 @@ dependencies = [ [[package]] name = "p3-field" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" dependencies = [ "itertools 0.13.0", "num-bigint", @@ -730,7 +1492,7 @@ dependencies = [ [[package]] name = "p3-goldilocks" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" dependencies = [ "num-bigint", "p3-dft", @@ -746,7 +1508,7 @@ dependencies = [ [[package]] name = "p3-interpolation" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" dependencies = [ "p3-field", "p3-matrix", @@ -756,7 +1518,7 @@ dependencies = [ [[package]] name = "p3-keccak" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" dependencies = [ "p3-symmetric", "tiny-keccak", @@ -765,7 +1527,7 @@ dependencies = [ [[package]] name = "p3-matrix" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" dependencies = [ "itertools 0.13.0", "p3-field", @@ -779,12 +1541,12 @@ dependencies = [ [[package]] name = "p3-maybe-rayon" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" [[package]] name = "p3-mds" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" dependencies = [ "itertools 0.12.1", "p3-dft", @@ -798,7 +1560,7 @@ dependencies = [ [[package]] name = "p3-merkle-tree" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" dependencies = [ "itertools 0.13.0", "p3-commit", @@ -814,7 +1576,7 @@ dependencies = [ [[package]] name = "p3-mersenne-31" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" dependencies = [ "itertools 0.13.0", "num-bigint", @@ -833,7 +1595,7 @@ dependencies = [ [[package]] name = "p3-poseidon2" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" dependencies = [ "gcd", "p3-field", @@ -845,7 +1607,7 @@ dependencies = [ [[package]] name = "p3-symmetric" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" dependencies = [ "itertools 0.13.0", "p3-field", @@ -855,17 +1617,64 @@ dependencies = [ [[package]] name = "p3-util" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#33b94a8ebaf8fbaace3def6e792cba0dd97b3c42" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" dependencies = [ "serde", ] +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.5", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "pin-project-lite" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + [[package]] name = "plotters" version = "0.3.6" @@ -913,6 +1722,7 @@ dependencies = [ "lazy_static", "p3-baby-bear", "p3-challenger", + "p3-commit", "p3-dft", "p3-field", "p3-interpolation", @@ -927,7 +1737,7 @@ dependencies = [ "segment", "serde", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.18", ] [[package]] @@ -956,9 +1766,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -1022,6 +1832,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "redox_syscall" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +dependencies = [ + "bitflags 2.5.0", +] + [[package]] name = "regex" version = "1.10.5" @@ -1066,14 +1885,57 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tokio-socks", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + [[package]] name = "rust-bitcoin-u31-or-u30" version = "0.1.0" -source = "git+https://github.com/bitlayer-org/rust-bitcoin-m31-or-babybear.git?branch=bf-stark#5d28e196d7306d6f3094a8f02ad04dfdff370f30" +source = "git+https://github.com/bitlayer-org/rust-bitcoin-m31-or-babybear.git?branch=bf-pcs#81cd06773e38e0b0421a0342f0d58ecf05967ae9" dependencies = [ + "ark-ff", "bitcoin", "bitcoin-script", "bitcoin-scriptexec", + "bitvm", "p3-baby-bear", "p3-field", "p3-mersenne-31", @@ -1081,6 +1943,49 @@ dependencies = [ "rand_chacha", ] +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + [[package]] name = "ryu" version = "1.0.18" @@ -1096,6 +2001,21 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "script_manager" version = "0.1.0" @@ -1155,6 +2075,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" dependencies = [ "bitcoin_hashes", + "rand", "secp256k1-sys", "serde", ] @@ -1168,6 +2089,29 @@ dependencies = [ "cc", ] +[[package]] +name = "security-framework" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +dependencies = [ + "bitflags 2.5.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "segment" version = "0.1.0" @@ -1178,6 +2122,12 @@ dependencies = [ "scripts", ] +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" version = "1.0.203" @@ -1206,7 +2156,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -1220,6 +2170,29 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -1229,18 +2202,71 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.68", +] + +[[package]] +name = "subtle" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d0208408ba0c3df17ed26eb06992cb1a1268d41b2c0e12e65203fbe3972cee5" + [[package]] name = "syn" version = "1.0.109" @@ -1248,20 +2274,80 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", + "quote", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.66" +version = "2.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "thiserror" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + [[package]] name = "thread_local" version = "1.1.8" @@ -1291,6 +2377,92 @@ dependencies = [ "serde_json", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-socks" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0" +dependencies = [ + "either", + "futures-util", + "thiserror", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + [[package]] name = "tracing" version = "0.1.40" @@ -1310,7 +2482,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -1334,6 +2506,15 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.18" @@ -1352,12 +2533,50 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "utf8parse" version = "0.2.2" @@ -1370,6 +2589,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" @@ -1386,6 +2611,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1413,10 +2647,22 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.92" @@ -1435,7 +2681,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1478,7 +2724,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -1487,13 +2733,37 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -1502,28 +2772,46 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.5" @@ -1536,26 +2824,100 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "zerocopy" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] diff --git a/fri/Cargo.toml b/fri/Cargo.toml index 0dc6e68..431ba1f 100644 --- a/fri/Cargo.toml +++ b/fri/Cargo.toml @@ -9,6 +9,7 @@ bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } +p3-commit ={ git = "https://github.com/Plonky3/Plonky3.git" } p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git" } p3-dft = { git = "https://github.com/Plonky3/Plonky3.git" } p3-field = { git = "https://github.com/Plonky3/Plonky3.git" } diff --git a/fri/src/config.rs b/fri/src/config.rs index d0ece0b..692d673 100644 --- a/fri/src/config.rs +++ b/fri/src/config.rs @@ -1,3 +1,10 @@ +use alloc::vec::Vec; +use core::fmt::Debug; + +use p3_field::Field; +use p3_matrix::Matrix; + +#[derive(Debug)] pub struct FriConfig { pub log_blowup: usize, pub num_queries: usize, @@ -10,3 +17,28 @@ impl FriConfig { 1 << self.log_blowup } } + +/// Whereas `FriConfig` encompasses parameters the end user can set, `FriGenericConfig` is +/// set by the PCS calling FRI, and abstracts over implementation details of the PCS. +pub trait FriGenericConfig { + type InputProof; + type InputError: Debug; + + /// We can ask FRI to sample extra query bits (LSB) for our own purposes. + /// They will be passed to our callbacks, but ignored (shifted off) by FRI. + fn extra_query_index_bits(&self) -> usize; + + /// Fold a row, returning a single column. + /// Right now the input row will always be 2 columns wide, + /// but we may support higher folding arity in the future. + fn fold_row( + &self, + index: usize, + log_height: usize, + beta: F, + evals: impl Iterator, + ) -> F; + + /// Same as applying fold_row to every row, possibly faster. + fn fold_matrix>(&self, beta: F, m: M) -> Vec; +} diff --git a/fri/src/error.rs b/fri/src/error.rs index 858c84c..8172232 100644 --- a/fri/src/error.rs +++ b/fri/src/error.rs @@ -12,14 +12,15 @@ pub enum SVError { InvalidWitness, } -impl From for FriError { +impl From for FriError { fn from(error: BfError) -> Self { - FriError::::BFError(error) + FriError::::BFError(error) } } #[derive(Debug, PartialEq, Eq, Clone)] -pub enum FriError { +pub enum FriError { + InputError(InputErr), InvalidProofShape, CommitPhaseMmcsError(CommitMmcsErr), ScriptVerifierError(SVError), diff --git a/fri/src/fri_scripts/mod.rs b/fri/src/fri_scripts/mod.rs index da09dd1..37b5aa8 100644 --- a/fri/src/fri_scripts/mod.rs +++ b/fri/src/fri_scripts/mod.rs @@ -1,3 +1,4 @@ pub mod fiat_shamir_subtree; pub mod leaf; +pub mod pcs; pub mod verify_folding; diff --git a/fri/src/fri_scripts/pcs.rs b/fri/src/fri_scripts/pcs.rs new file mode 100644 index 0000000..850a84a --- /dev/null +++ b/fri/src/fri_scripts/pcs.rs @@ -0,0 +1,484 @@ +use std::marker::PhantomData; +use std::ops::Add; + +use bitcoin::opcodes::{OP_SUB, OP_TOALTSTACK, OP_TRUE}; +use bitcoin::{script, ScriptBuf as Script}; +use bitcoin_script::{define_pushable, script}; +use itertools::izip; +use primitives::field::BfField; +use script_manager::script_info::{self, ScriptInfo}; +use scripts::pseudo::{ + OP_4DROP, OP_4DUP, OP_4FROMALTSTACK, OP_4MUL, OP_4PICK, OP_4ROLL, OP_4TOALTSTACK, OP_NDUP, +}; +use scripts::u31_lib::{ + u31_add, u31_double, u31_mul, u31_sub, u31_sub_u31ext, u31_to_u31ext, u31ext_add, + u31ext_double, u31ext_equalverify, u31ext_mul, u31ext_mul_u31, u31ext_mul_u31_by_constant, + u31ext_sub, u31ext_sub_u31, BabyBear4, BabyBearU31, +}; + +define_pushable!(); +/** + * input + altstack: + current_alpha_pow <-- top + alpha + * output: + altstack: + next_alpha_pow <-- top + alpha +*/ +fn compute_next_alpha_pow() -> Script { + script! { + if Challenge::U32_SIZE == 4{ + OP_4FROMALTSTACK + OP_4FROMALTSTACK + OP_4DUP + OP_4TOALTSTACK + {u31ext_mul::()} + OP_4TOALTSTACK + }else{ + OP_FROMALTSTACK + OP_FROMALTSTACK + OP_DUP + OP_TOALTSTACK + {u31_mul::()} + OP_TOALTSTACK + } + } +} +/** + * compute alpha_pow * (p(x) - p(z)) at the same index of column + * input: + * altstack: + * cur_alpha_pow <--top babybear4 + * alpha babybear4 + * stack: + * prev_accmulator <--top babybear4 + * p_at_x_{i} babybear + * p_at_z_{i} babybear4 + * output: + * altstack: + * next_alpha_pow <--top babybear4 + * alpha babybear4 + * stack: + * accmulator = prev_accmulator + cur_alpha_pow*(p_at_x_{i} - p_at_z_{i}) <--top babybear4 + */ +fn alphapow_mul_px_minus_pz() -> Script { + assert_eq!(Val::U32_SIZE, 1); + assert_eq!(Challenge::U32_SIZE, 4); + script! { + OP_4TOALTSTACK // prev_ro to altstack + {u31_sub_u31ext::()} // babybear4 + OP_4FROMALTSTACK // prev_ro back to stack + OP_4FROMALTSTACK // cur_alpha_pow to stack + OP_4DUP + OP_4TOALTSTACK + + 8 OP_4ROLL // places p(x)-p(z) at the top of the stack + // + // expect stack: + // p(x) - p(z) <--top exists at babybear4 + // alpha_pow exists at babybear4 + // prev_accmulator exists at babybear4 + {u31ext_mul::()} + {u31ext_add::()} // accmulate at accmulator + + {compute_next_alpha_pow::()} // babybear4 + } +} + +/** + * compute: + * alpha_pow_0 * (p_at_x_0 - p_at_z_0) + + * alpha_pow_1 (p_at_x_1 - p_at_z_1) + + * ... + * alpha_pow_i (p_at_x_i - p_at_z_i) + * output: alpha_pow_i , res1 + * + * + * input: + * altstack: + * empty + * stack: + * alpha + * prev_alpha_pow // the prev_alpha_pow is 1 when intialization + * p_at_x_{0..0} + * p_at_z_{0..0} + * ... + * p_at_x_{0..matrix_width} + * p_at_z_{0..matrix_width} + * + * output + * altstack: + * stack: + * alpha + * next_alpha_pow + * accmulator + * + * +*/ +fn compute_accmulator(matrix_width: usize) -> Script { + assert_eq!(Val::U32_SIZE, 1); + assert_eq!(Challenge::U32_SIZE, 4); + script! { + OP_4TOALTSTACK + OP_4TOALTSTACK + + OP_0 OP_0 OP_0 OP_0 // the accmulator is 0 when intialization + for i in 0..matrix_width{ + {alphapow_mul_px_minus_pz::()} + } + OP_4FROMALTSTACK + OP_4FROMALTSTACK + + } +} + +pub fn accmulator_script( + alpha: Challenge, + prev_alpha_pow: Challenge, + p_at_x_row: Vec, + p_at_z_row: Vec, + next_alpha_pow: Challenge, + accmulator: Challenge, +) -> ScriptInfo { + assert_eq!(p_at_x_row.len(), p_at_z_row.len()); + let mut si = ScriptInfo::new( + "compute_accmulator", + compute_accmulator::(p_at_x_row.len()), + ); + si.add_input(alpha).add_input(prev_alpha_pow); + for (px, pz) in izip!(p_at_x_row.clone(), p_at_z_row.clone()) { + si.add_input(px).add_input(pz); + } + si.add_output(alpha) + .add_output(next_alpha_pow) + .add_output(accmulator); + si +} + +fn zip(vec1: Vec, vec2: Vec) -> Script { + assert_eq!(vec1.len(), vec2.len()); + script! { + for i in (0..vec1.len()).rev(){ + for j in (0..F1::U32_SIZE).rev(){ + {vec1[i].as_u32_vec()[j]} + } + for j in (0..F2::U32_SIZE).rev(){ + {vec2[i].as_u32_vec()[j]} + } + } + } +} + +/** + * + * compute: + * (ro_final - ro_prev) * (x - z) + * + * input: + * stack: + * ro_prev // babybear4 + * ro_final // babybear4 + * x // babybear + * z // babybear4 + * + * output: + * stack: + * accmulator = (ro_final - ro_prev) * (x - z) // babybear4 + */ +fn ro_mul_x_minus_z() -> Script { + script! { + {u31ext_sub::()} // ro_final-ro_prev + OP_4TOALTSTACK + + {u31_sub_u31ext::()} + OP_4FROMALTSTACK + + {u31ext_mul::()} + } +} + +pub fn ro_mul_x_minus_z_script( + ro_prev: Challenge, + ro_final: Challenge, + x: Val, + z: Challenge, + accmulator: Challenge, +) -> ScriptInfo { + let mut si = ScriptInfo::new("ro_mul_x_minus_z", ro_mul_x_minus_z()); + si.add_input(ro_prev) + .add_input(ro_final) + .add_input(x) + .add_input(z) + .add_output(accmulator); + si +} + +// +// Compute: +// (ro_final - ro_prev) * (x - z) == accumulator +// +// Input: +// Stack: +// --------- accumulator input --------- +// alpha +// prev_alpha_pow // the prev_alpha_pow is 1 during initialization +// p_at_x_{0..0} +// p_at_z_{0..0} +// ... +// p_at_x_{0..matrix_width} +// p_at_z_{0..matrix_width} +// --------- ro_mul_x_minus_z input --------- +// ro_prev // babybear4 +// ro_final // babybear4 +// x // babybear +// z // babybear4 +// +// final_alpha_pow +// Output: +// Stack: +// alpha +// next_alpha_pow +// accumulator +// +// (ro_final - ro_prev) * (x - z) // babybear4 +// +// +pub fn verify_quotient(matrix_width: usize) -> Script { + script! { + {compute_accmulator::(matrix_width)} + + // * output: + // * stack: + // * accmulator babybear4 + // * alpha babybear4 + // * next_alpha_pow babybear4 + // * ro_prev babybear4 + // * ro_final babybear4 + // * x babybear + // * z babybear4 + // * + // * final_alpha_pow + OP_4TOALTSTACK + OP_4TOALTSTACK + OP_4TOALTSTACK + + {ro_mul_x_minus_z()} + + // verify accmulator + OP_4FROMALTSTACK // back accmulator to stack + {u31ext_equalverify::()} + + OP_4FROMALTSTACK // back next_alpha_pow to stack + {u31ext_equalverify::()} // verify next_alpha_pow == final_alpha_pow + + OP_4FROMALTSTACK + OP_4DROP // drop alpha + + OP_TRUE + } +} + +#[cfg(test)] +mod tests { + use bitcoin::opcodes::{OP_FROMALTSTACK, OP_TRUE}; + use bitcoin::ScriptBuf as Script; + use bitcoin_script::{define_pushable, script}; + use itertools::izip; + use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; + use p3_field::{AbstractExtensionField, AbstractField}; + use p3_interpolation::interpolate_coset; + use p3_matrix::dense::RowMajorMatrix; + use p3_matrix::util::reverse_matrix_index_bits; + use primitives::field::BfField; + use rand::{Rng, SeedableRng}; + use rand_chacha::ChaCha20Rng; + use script_manager::bc_assignment::DefaultBCAssignment; + use scripts::pseudo::{OP_4DROP, OP_4FROMALTSTACK, OP_4TOALTSTACK}; + use scripts::u31_lib::{u31ext_equalverify, BabyBear4}; + use scripts::{execute_script, execute_script_with_inputs, BabyBear, BinomialExtensionField}; + + use crate::fri_scripts::pcs::{ + accmulator_script, alphapow_mul_px_minus_pz, compute_accmulator, compute_next_alpha_pow, + zip, + }; + + define_pushable!(); + + #[test] + fn test_alpha_pow_mul_px_minus_pz() { + type Challenge = BinomialExtensionField; + type Val = BabyBear; + + let mut rng = ChaCha20Rng::seed_from_u64(0u64); + + let index: usize = 1; + let x = Val::generator(); + let z = Challenge::generator(); + let matrix_width: usize = 3; + let p_at_x_vector = vec![rng.gen::()]; + let p_at_z_vector = vec![rng.gen::()]; + let alpha = Challenge::two(); + let init_alpha_pow = Challenge::one(); + let init_ro = Challenge::zero(); + + let mut cur_alpha_pow = init_alpha_pow.clone(); + let mut cur_ro = init_ro.clone(); + for (p_at_x, p_at_z) in izip!(p_at_x_vector.clone(), p_at_z_vector.clone()) { + cur_ro += cur_alpha_pow.clone() * (-p_at_z + p_at_x); + cur_alpha_pow = cur_alpha_pow * alpha; + } + + let compute_alpha_pow_script = script! { + {alpha.as_u32_vec()[3]}{alpha.as_u32_vec()[2]}{alpha.as_u32_vec()[1]}{alpha.as_u32_vec()[0]} + OP_4TOALTSTACK + + {init_alpha_pow.as_u32_vec()[3]}{init_alpha_pow.as_u32_vec()[2]}{init_alpha_pow.as_u32_vec()[1]}{init_alpha_pow.as_u32_vec()[0]} + OP_4TOALTSTACK + + {compute_next_alpha_pow::()} + + OP_4FROMALTSTACK + {alpha.as_u32_vec()[3]}{alpha.as_u32_vec()[2]}{alpha.as_u32_vec()[1]}{alpha.as_u32_vec()[0]} + {u31ext_equalverify::()} + + OP_4FROMALTSTACK + {alpha.as_u32_vec()[3]}{alpha.as_u32_vec()[2]}{alpha.as_u32_vec()[1]}{alpha.as_u32_vec()[0]} + {u31ext_equalverify::()} + + OP_TRUE + }; + + let res = execute_script(compute_alpha_pow_script); + if !res.success { + println!("{:?}", res); + } + assert!(res.success); + + // let cur_ro = init_ro + init_alpha_pow * (-p_at_z_vector[0] + p_at_x_vector[0]); + let alphapow_mul_px_minus_pz_script = script! { + {alpha.as_u32_vec()[3]}{alpha.as_u32_vec()[2]}{alpha.as_u32_vec()[1]}{alpha.as_u32_vec()[0]} + OP_4TOALTSTACK + + {init_alpha_pow.as_u32_vec()[3]}{init_alpha_pow.as_u32_vec()[2]}{init_alpha_pow.as_u32_vec()[1]}{init_alpha_pow.as_u32_vec()[0]} + OP_4TOALTSTACK + + {p_at_z_vector[0].as_u32_vec()[3]}{p_at_z_vector[0].as_u32_vec()[2]}{p_at_z_vector[0].as_u32_vec()[1]}{p_at_z_vector[0].as_u32_vec()[0]} + {p_at_x_vector[0].as_u32_vec()[0]} + + {init_ro.as_u32_vec()[3]}{init_ro.as_u32_vec()[2]}{init_ro.as_u32_vec()[1]}{init_ro.as_u32_vec()[0]} + {alphapow_mul_px_minus_pz::()} + + {cur_ro.as_u32_vec()[3]}{cur_ro.as_u32_vec()[2]}{cur_ro.as_u32_vec()[1]}{cur_ro.as_u32_vec()[0]} + {u31ext_equalverify::()} + + OP_4FROMALTSTACK + {cur_alpha_pow.as_u32_vec()[3]}{cur_alpha_pow.as_u32_vec()[2]}{cur_alpha_pow.as_u32_vec()[1]}{cur_alpha_pow.as_u32_vec()[0]} + {u31ext_equalverify::()} + + OP_4FROMALTSTACK + {alpha.as_u32_vec()[3]}{alpha.as_u32_vec()[2]}{alpha.as_u32_vec()[1]}{alpha.as_u32_vec()[0]} + {u31ext_equalverify::()} + + OP_TRUE + }; + + let res = execute_script(alphapow_mul_px_minus_pz_script); + if !res.success { + println!("{:?}", res); + } + assert!(res.success); + } + + #[test] + fn test_accmulator() { + type Challenge = BinomialExtensionField; + type Val = BabyBear; + + let mut rng = ChaCha20Rng::seed_from_u64(0u64); + + let index: usize = 1; + let x = Val::generator(); + let z = Challenge::generator(); + let matrix_width: usize = 3; + let p_at_x_vector = vec![rng.gen::(), rng.gen::(), rng.gen::()]; + let p_at_z_vector = vec![ + rng.gen::(), + rng.gen::(), + rng.gen::(), + ]; + let alpha = Challenge::two(); + let init_alpha_pow = Challenge::one(); + let init_ro = Challenge::zero(); + + let mut cur_alpha_pow = init_alpha_pow.clone(); + let mut cur_ro = init_ro.clone(); + for (p_at_x, p_at_z) in izip!(p_at_x_vector.clone(), p_at_z_vector.clone()) { + cur_ro += cur_alpha_pow.clone() * (-p_at_z + p_at_x); + cur_alpha_pow = cur_alpha_pow * alpha; + } + + let mut bc_assigner = DefaultBCAssignment::new(); + let mut exec_script_info = accmulator_script::( + alpha, + init_alpha_pow, + p_at_x_vector.clone(), + p_at_z_vector.clone(), + cur_alpha_pow, + cur_ro, + ); + exec_script_info.gen(&mut bc_assigner); + let res = execute_script_with_inputs( + exec_script_info.get_eq_script(), + exec_script_info.witness(), + ); + assert!(res.success); + let res = execute_script_with_inputs( + exec_script_info.get_neq_script(), + exec_script_info.witness(), + ); + assert!(!res.success); + + let acc_script = script! { + {zip::(p_at_z_vector,p_at_x_vector)} + + {init_alpha_pow.as_u32_vec()[3]}{init_alpha_pow.as_u32_vec()[2]}{init_alpha_pow.as_u32_vec()[1]}{init_alpha_pow.as_u32_vec()[0]} + + {alpha.as_u32_vec()[3]}{alpha.as_u32_vec()[2]}{alpha.as_u32_vec()[1]}{alpha.as_u32_vec()[0]} + + {compute_accmulator::(matrix_width)} + + {alpha.as_u32_vec()[3]}{alpha.as_u32_vec()[2]}{alpha.as_u32_vec()[1]}{alpha.as_u32_vec()[0]} + {u31ext_equalverify::()} + + {cur_alpha_pow.as_u32_vec()[3]}{cur_alpha_pow.as_u32_vec()[2]}{cur_alpha_pow.as_u32_vec()[1]}{cur_alpha_pow.as_u32_vec()[0]} + {u31ext_equalverify::()} + + {cur_ro.as_u32_vec()[3]}{cur_ro.as_u32_vec()[2]}{cur_ro.as_u32_vec()[1]}{cur_ro.as_u32_vec()[0]} + {u31ext_equalverify::()} + + OP_TRUE + }; + + let res = execute_script(acc_script); + if !res.success { + println!("{:?}", res); + } + assert!(res.success); + + // let dft = Radix2Dit::default(); + // let log_height:usize = 3; + // let matrix_width:usize = 4; + // let poly_len:usize = matrix_width *2^log_height; + // let log_blowup = 1; + // let mut rng = ChaCha20Rng::seed_from_u64(0); + // let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << log_height, matrix_width); + // let shift = Val::generator(); + // let mut lde = dft.coset_lde_batch(evals, log_blowup, shift); + // reverse_matrix_index_bits(&mut lde); + + // interpolate_coset(lde, shift, point) + // let (low_coset,_) = lde.split_at(matr); + } +} diff --git a/fri/src/lib.rs b/fri/src/lib.rs index eed31ea..bc9b722 100644 --- a/fri/src/lib.rs +++ b/fri/src/lib.rs @@ -8,6 +8,7 @@ mod fold_even_odd; mod proof; pub mod prover; pub mod script_verifier; +pub mod two_adic_pcs; pub mod verifier; pub use config::*; @@ -15,3 +16,4 @@ pub use fold_even_odd::*; pub use proof::*; pub use script_verifier::*; pub mod fri_scripts; +pub use two_adic_pcs::*; diff --git a/fri/src/proof.rs b/fri/src/proof.rs index 0c2b025..4a79c17 100644 --- a/fri/src/proof.rs +++ b/fri/src/proof.rs @@ -11,9 +11,10 @@ use primitives::mmcs::taptree_mmcs::CommitProof; // serialize = "Witness: Serialize", // deserialize = "Witness: Deserialize<'de>" // ))] -pub struct FriProof, Witness> { +#[derive(Clone)] +pub struct FriProof, Witness, InputProof> { pub(crate) commit_phase_commits: Vec, - pub(crate) query_proofs: Vec>, + pub(crate) query_proofs: Vec>, // This could become Vec if this library was generalized to support non-constant // final polynomials. pub(crate) final_poly: F, @@ -22,7 +23,9 @@ pub struct FriProof, Witness> { // #[derive(Serialize, Deserialize)] // #[serde(bound = "")] -pub struct BfQueryProof { +#[derive(Clone)] +pub struct BfQueryProof { + pub input_proof: InputProof, /// For each commit phase commitment, this contains openings of a commit phase codeword at the /// queried location, along with an opening proof. pub(crate) commit_phase_openings: Vec>, diff --git a/fri/src/prover.rs b/fri/src/prover.rs index ea60734..3e72567 100644 --- a/fri/src/prover.rs +++ b/fri/src/prover.rs @@ -1,122 +1,134 @@ use alloc::vec; use alloc::vec::Vec; +use core::cmp::Reverse; +use core::iter; -use itertools::Itertools; +use itertools::{izip, Itertools}; use p3_challenger::{CanObserve, CanSample}; use p3_field::TwoAdicField; use p3_matrix::dense::RowMajorMatrix; +use p3_util::log2_strict_usize; use primitives::challenger::BfGrindingChallenger; use primitives::field::BfField; use primitives::mmcs::bf_mmcs::BFMmcs; use primitives::mmcs::taptree_mmcs::{CommitProof, DEFAULT_MATRIX_WIDTH}; use tracing::{info_span, instrument}; -use tracing_subscriber::layer::SubscriberExt; -use tracing_subscriber::util::SubscriberInitExt; -use crate::fold_even_odd::fold_even_odd; -use crate::{BfQueryProof, FriConfig, FriProof}; +use crate::{BfQueryProof, FriConfig, FriGenericConfig, FriProof}; #[instrument(name = "FRI prover", skip_all)] -pub fn bf_prove( +pub fn bf_prove( + g: &G, config: &FriConfig, - input: &[Option>; 32], + inputs: Vec>, challenger: &mut Challenger, -) -> (FriProof, Vec) + open_input: impl Fn(usize) -> G::InputProof, +) -> FriProof where F: BfField, M: BFMmcs>, Challenger: BfGrindingChallenger + CanObserve + CanSample, + G: FriGenericConfig, { - // 1. rposition start iterator from the end and calculate the valid leagth of the polynomial want commit - let log_max_height = input.iter().rposition(Option::is_some).unwrap(); + // check sorted descending + assert!(inputs + .iter() + .tuple_windows() + .all(|(l, r)| l.len() >= r.len())); + + // inputs input + let log_max_height = log2_strict_usize(inputs[0].len()); - let commit_phase_result = bf_commit_phase(config, input, log_max_height, challenger); + let commit_phase_result = bf_commit_phase(g, config, inputs, challenger); let pow_witness = challenger.grind(config.proof_of_work_bits); - let mut query_indices: Vec = (0..config.num_queries) - .map(|_| challenger.sample_bits(log_max_height)) - .collect(); let query_proofs = info_span!("query phase").in_scope(|| { - query_indices - .iter() - .map(|&index| bf_answer_query(config, &commit_phase_result.data, index)) + iter::repeat_with(|| challenger.sample_bits(log_max_height + g.extra_query_index_bits())) + .take(config.num_queries) + .map(|index| BfQueryProof { + input_proof: open_input(index), + commit_phase_openings: bf_answer_query( + config, + &commit_phase_result.data, + index >> g.extra_query_index_bits(), + ), + }) .collect() }); - ( - FriProof { - commit_phase_commits: commit_phase_result.commits, - query_proofs, - final_poly: commit_phase_result.final_poly, - pow_witness, - }, - query_indices, - ) + FriProof { + commit_phase_commits: commit_phase_result.commits, + query_proofs, + final_poly: commit_phase_result.final_poly, + pow_witness, + } } fn bf_answer_query( config: &FriConfig, commit_phase_commits: &[M::ProverData], index: usize, -) -> BfQueryProof +) -> Vec> where F: BfField, M: BFMmcs>, { - //println!("query index:{}", index); let commit_phase_openings = commit_phase_commits .iter() .enumerate() .map(|(i, commit)| { - let index_i_pair = index >> i >> 1; + let index_i = index >> i >> 1; - let proof = config.mmcs.open_taptree(index_i_pair, commit); + let proof = config.mmcs.open_taptree(index_i, commit); proof }) .collect(); - BfQueryProof { - commit_phase_openings, - } + commit_phase_openings } #[instrument(name = "commit phase", skip_all)] -fn bf_commit_phase( +fn bf_commit_phase( + g: &G, config: &FriConfig, - input: &[Option>; 32], - log_max_height: usize, + inputs: Vec>, challenger: &mut Challenger, ) -> CommitPhaseResult where F: TwoAdicField, M: BFMmcs, Challenger: CanObserve + CanSample, + G: FriGenericConfig, { - let mut current = input[log_max_height].as_ref().unwrap().clone(); + let mut inputs_iter = inputs.into_iter().peekable(); + let mut folded = inputs_iter.next().unwrap(); let mut commits = vec![]; let mut data = vec![]; - for log_folded_height in (config.log_blowup..log_max_height).rev() { - let leaves = RowMajorMatrix::new(current.clone(), DEFAULT_MATRIX_WIDTH); + while folded.len() > config.blowup() { + let leaves = RowMajorMatrix::new(folded.clone(), 2); let (commit, prover_data) = config.mmcs.commit_matrix(leaves); challenger.observe(commit.clone()); - commits.push(commit); - data.push(prover_data); let beta: F = challenger.sample(); - current = fold_even_odd(current, beta); + // We passed ownership of `current` to the MMCS, so get a reference to it + let leaves = config.mmcs.get_matrices(&prover_data).pop().unwrap(); + folded = g.fold_matrix(beta, leaves.as_view()); + + commits.push(commit); + data.push(prover_data); - if let Some(v) = &input[log_folded_height] { - current.iter_mut().zip_eq(v).for_each(|(c, v)| *c += *v); + if let Some(v) = inputs_iter.next_if(|v| v.len() == folded.len()) { + izip!(&mut folded, v).for_each(|(c, x)| *c += x); } } // We should be left with `blowup` evaluations of a constant polynomial. - assert_eq!(current.len(), config.blowup()); - let final_poly = current[0]; - for x in current { + assert_eq!(folded.len(), config.blowup()); + let final_poly = folded[0]; + for x in folded { assert_eq!(x, final_poly); } @@ -132,561 +144,3 @@ struct CommitPhaseResult> { data: Vec, final_poly: F, } - -#[cfg(test)] -mod tests { - - use itertools::Itertools; - use p3_baby_bear::BabyBear; - use p3_challenger::CanSampleBits; - use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; - use p3_field::extension::BinomialExtensionField; - use p3_field::AbstractField; - use p3_matrix::util::reverse_matrix_index_bits; - use p3_matrix::Matrix; - use p3_symmetric::{CryptographicPermutation, Permutation}; - use p3_util::log2_strict_usize; - use primitives::challenger::chan_field::U32; - use primitives::challenger::{BfChallenger, Blake3Permutation}; - use primitives::mmcs::taptree_mmcs::TapTreeMmcs; - use rand::SeedableRng; - use rand_chacha::ChaCha20Rng; - use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; - use tracing_subscriber::fmt; - - use super::*; - use crate::script_verifier::bf_verify_challenges; - use crate::verifier; - - type PF = U32; - const WIDTH: usize = 16; - type SpongeState = [PF; WIDTH]; - type F = BabyBear; - #[derive(Clone)] - struct TestPermutation {} - - impl Permutation for TestPermutation { - fn permute(&self, mut input: SpongeState) -> SpongeState { - self.permute_mut(&mut input); - input - } - - fn permute_mut(&self, input: &mut SpongeState) { - input.reverse(); - } - } - - impl CryptographicPermutation for TestPermutation {} - type Val = BabyBear; - type ValMmcs = TapTreeMmcs; - type MyFriConfig = FriConfig; - - #[test] - fn test_compelte_fri_process() { - let permutation = TestPermutation {}; - let mut challenger = - BfChallenger::::new(permutation).unwrap(); - let mmcs = ValMmcs::new(); - let fri_config = FriConfig { - log_blowup: 1, - num_queries: 10, - proof_of_work_bits: 8, - mmcs, - }; - - let dft = Radix2Dit::default(); - - let shift = Val::generator(); - let mut rng = ChaCha20Rng::seed_from_u64(0); - - let ldes: Vec> = (1..10) - .map(|deg_bits| { - let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); - let mut lde = dft.coset_lde_batch(evals, 1, shift); - reverse_matrix_index_bits(&mut lde); - lde - }) - .collect(); - - let alpha = BabyBear::one(); - let input: [_; 32] = core::array::from_fn(|log_height| { - let matrices_with_log_height: Vec<&RowMajorMatrix> = ldes - .iter() - .filter(|m| log2_strict_usize(m.height()) == log_height) - .collect(); - if matrices_with_log_height.is_empty() { - None - } else { - let reduced: Vec = (0..(1 << log_height)) - .map(|r| { - alpha - .powers() - .zip(matrices_with_log_height.iter().flat_map(|m| m.row(r))) - .map(|(alpha_pow, v)| alpha_pow * v) - .sum() - }) - .collect(); - Some(reduced) - } - }); - - let (proof, idxs) = bf_prove(&fri_config, &input, &mut challenger); - let p_sample = challenger.sample_bits(8); - - let log_max_height = input.iter().rposition(Option::is_some).unwrap(); - let reduced_openings: Vec<[BabyBear; 32]> = idxs - .into_iter() - .map(|idx| { - input - .iter() - .enumerate() - .map(|(log_height, v)| { - if let Some(v) = v { - v[idx >> (log_max_height - log_height)] - } else { - BabyBear::zero() - } - }) - .collect_vec() - .try_into() - .unwrap() - }) - .collect(); - - // let _alpha: Challenge = challenger.sample_ext_element(); - let v_permutation = TestPermutation {}; - let mut v_challenger = - BfChallenger::::new(v_permutation).unwrap(); - let fri_challenges = - verifier::verify_shape_and_sample_challenges(&fri_config, &proof, &mut v_challenger) - .expect("failed verify shape and sample"); - - verifier::verify_challenges(&fri_config, &proof, &fri_challenges, &reduced_openings) - .expect("failed verify challenges"); - - assert_eq!( - p_sample, - v_challenger.sample_bits(8), - "prover and verifier transcript have same state after FRI" - ); - } - - #[test] - fn test_script_verifier() { - let permutation = TestPermutation {}; - let mut challenger = - BfChallenger::::new(permutation).unwrap(); - let mmcs = ValMmcs::new(); - let fri_config = FriConfig { - log_blowup: 1, - num_queries: 10, - proof_of_work_bits: 8, - mmcs, - }; - - let mut assign = DefaultBCAssignment::new(); - - let dft = Radix2Dit::default(); - - let shift = Val::generator(); - let mut rng = ChaCha20Rng::seed_from_u64(0); - - let ldes: Vec> = (4..5) - .map(|deg_bits| { - let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); - let mut lde = dft.coset_lde_batch(evals, 1, shift); - reverse_matrix_index_bits(&mut lde); - lde - }) - .collect(); - - let alpha = BabyBear::one(); - let input: [_; 32] = core::array::from_fn(|log_height| { - let matrices_with_log_height: Vec<&RowMajorMatrix> = ldes - .iter() - .filter(|m| log2_strict_usize(m.height()) == log_height) - .collect(); - if matrices_with_log_height.is_empty() { - None - } else { - let reduced: Vec = (0..(1 << log_height)) - .map(|r| { - alpha - .powers() - .zip(matrices_with_log_height.iter().flat_map(|m| m.row(r))) - .map(|(alpha_pow, v)| alpha_pow * v) - .sum() - }) - .collect(); - Some(reduced) - } - }); - - let (proof, idxs) = bf_prove(&fri_config, &input, &mut challenger); - let p_sample = challenger.sample_bits(8); - - let log_max_height = input.iter().rposition(Option::is_some).unwrap(); - let reduced_openings: Vec<[BabyBear; 32]> = idxs - .into_iter() - .map(|idx| { - input - .iter() - .enumerate() - .map(|(log_height, v)| { - if let Some(v) = v { - v[idx >> (log_max_height - log_height)] - } else { - BabyBear::zero() - } - }) - .collect_vec() - .try_into() - .unwrap() - }) - .collect(); - - // let _alpha: Challenge = challenger.sample_ext_element(); - let v_permutation = TestPermutation {}; - let mut v_challenger = - BfChallenger::::new(v_permutation).unwrap(); - let fri_challenges = - verifier::verify_shape_and_sample_challenges(&fri_config, &proof, &mut v_challenger) - .expect("failed verify shape and sample"); - - bf_verify_challenges( - &mut assign, - &fri_config, - &proof, - &fri_challenges, - &reduced_openings, - ) - .expect("failed verify challenges"); - - assert_eq!( - p_sample, - v_challenger.sample_bits(8), - "prover and verifier transcript have same state after FRI" - ); - } - - #[test] - fn test_bf_prove_with_blake3_permutation() { - // tracing_subscriber::registry().with(fmt::layer()).init(); // open some log information - - let permutation = Blake3Permutation {}; - let mut challenger: BfChallenger = - BfChallenger::::new(permutation).unwrap(); - let mmcs = ValMmcs::new(); - let fri_config = FriConfig { - log_blowup: 1, - num_queries: 10, - proof_of_work_bits: 8, - mmcs, - }; - - let dft = Radix2Dit::default(); - - let shift = Val::generator(); - let mut rng = ChaCha20Rng::seed_from_u64(0); - - let ldes: Vec> = (5..6) - .map(|deg_bits| { - let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); - let mut lde = dft.coset_lde_batch(evals, 1, shift); - reverse_matrix_index_bits(&mut lde); - lde - }) - .collect(); - - let alpha = BabyBear::one(); - let input: [_; 32] = core::array::from_fn(|log_height| { - let matrices_with_log_height: Vec<&RowMajorMatrix> = ldes - .iter() - .filter(|m| log2_strict_usize(m.height()) == log_height) - .collect(); - if matrices_with_log_height.is_empty() { - None - } else { - let reduced: Vec = (0..(1 << log_height)) - .map(|r| { - alpha - .powers() - .zip(matrices_with_log_height.iter().flat_map(|m| m.row(r))) - .map(|(alpha_pow, v)| alpha_pow * v) - .sum() - }) - .collect(); - Some(reduced) - } - }); - - let (proof, idxs) = bf_prove(&fri_config, &input, &mut challenger); - - let log_max_height = input.iter().rposition(Option::is_some).unwrap(); - let reduced_openings: Vec<[BabyBear; 32]> = idxs - .into_iter() - .map(|idx| { - input - .iter() - .enumerate() - .map(|(log_height, v)| { - if let Some(v) = v { - v[idx >> (log_max_height - log_height)] - } else { - BabyBear::zero() - } - }) - .collect_vec() - .try_into() - .unwrap() - }) - .collect(); - - // let _alpha: Challenge = challenger.sample_ext_element(); - let permutation = Blake3Permutation {}; - let mut v_challenger = - BfChallenger::::new(permutation).unwrap(); - let fri_challenges = - verifier::verify_shape_and_sample_challenges(&fri_config, &proof, &mut v_challenger) - .expect("failed verify shape and sample"); - - verifier::verify_challenges(&fri_config, &proof, &fri_challenges, &reduced_openings) - .expect("failed verify challenges"); - } -} - -#[cfg(test)] -mod tests2 { - - use itertools::Itertools; - use p3_baby_bear::BabyBear; - use p3_challenger::CanSampleBits; - use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; - use p3_field::extension::BinomialExtensionField; - use p3_field::AbstractField; - use p3_matrix::util::reverse_matrix_index_bits; - use p3_matrix::Matrix; - use p3_symmetric::{CryptographicPermutation, Permutation}; - use p3_util::log2_strict_usize; - use primitives::challenger::chan_field::U32; - use primitives::challenger::{BfChallenger, Blake3Permutation}; - use primitives::mmcs::taptree_mmcs::{TapTreeMmcs, ROOT_WIDTH}; - use rand::SeedableRng; - use rand_chacha::ChaCha20Rng; - use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; - use tracing_subscriber::fmt; - - use super::*; - use crate::{bf_verify_challenges, verifier}; - - type PF = U32; - const WIDTH: usize = 16; - type SpongeState = [PF; WIDTH]; - type F = BinomialExtensionField; - #[derive(Clone)] - struct TestPermutation {} - - impl Permutation for TestPermutation { - fn permute(&self, mut input: SpongeState) -> SpongeState { - self.permute_mut(&mut input); - input - } - - fn permute_mut(&self, input: &mut SpongeState) { - input.reverse(); - } - } - - impl CryptographicPermutation for TestPermutation {} - type Val = F; - type ValMmcs = TapTreeMmcs; - type MyFriConfig = FriConfig; - - #[test] - fn test_compelte_fri_process_with_ext_babybear() { - let permutation = TestPermutation {}; - let mut challenger = - BfChallenger::::new(permutation).unwrap(); - let mmcs = ValMmcs::new(); - let fri_config = FriConfig { - log_blowup: 1, - num_queries: 10, - proof_of_work_bits: 8, - mmcs, - }; - - let dft = Radix2Dit::default(); - - let shift = Val::generator(); - let mut rng = ChaCha20Rng::seed_from_u64(0); - - let ldes: Vec> = (1..10) - .map(|deg_bits| { - let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); - let mut lde = dft.coset_lde_batch(evals, 1, shift); - reverse_matrix_index_bits(&mut lde); - lde - }) - .collect(); - - let alpha = F::one(); - let input: [_; 32] = core::array::from_fn(|log_height| { - let matrices_with_log_height: Vec<&RowMajorMatrix> = ldes - .iter() - .filter(|m| log2_strict_usize(m.height()) == log_height) - .collect(); - if matrices_with_log_height.is_empty() { - None - } else { - let reduced: Vec = (0..(1 << log_height)) - .map(|r| { - alpha - .powers() - .zip(matrices_with_log_height.iter().flat_map(|m| m.row(r))) - .map(|(alpha_pow, v)| alpha_pow * v) - .sum() - }) - .collect(); - Some(reduced) - } - }); - - let (proof, idxs) = bf_prove(&fri_config, &input, &mut challenger); - let p_sample = challenger.sample_bits(8); - - let log_max_height = input.iter().rposition(Option::is_some).unwrap(); - let reduced_openings: Vec<[F; 32]> = idxs - .into_iter() - .map(|idx| { - input - .iter() - .enumerate() - .map(|(log_height, v)| { - if let Some(v) = v { - v[idx >> (log_max_height - log_height)] - } else { - F::zero() - } - }) - .collect_vec() - .try_into() - .unwrap() - }) - .collect(); - - // let _alpha: Challenge = challenger.sample_ext_element(); - let v_permutation = TestPermutation {}; - let mut v_challenger = - BfChallenger::::new(v_permutation).unwrap(); - let fri_challenges = - verifier::verify_shape_and_sample_challenges(&fri_config, &proof, &mut v_challenger) - .expect("failed verify shape and sample"); - - verifier::verify_challenges(&fri_config, &proof, &fri_challenges, &reduced_openings) - .expect("failed verify challenges"); - - assert_eq!( - p_sample, - v_challenger.sample_bits(8), - "prover and verifier transcript have same state after FRI" - ); - } - - #[test] - fn test_script_verifier() { - let permutation = TestPermutation {}; - let mut challenger = - BfChallenger::::new(permutation).unwrap(); - let mmcs = ValMmcs::new(); - let fri_config = FriConfig { - log_blowup: 1, - num_queries: 10, - proof_of_work_bits: 8, - mmcs, - }; - - let mut assign = DefaultBCAssignment::new(); - - let dft = Radix2Dit::default(); - - let shift = Val::generator(); - let mut rng = ChaCha20Rng::seed_from_u64(0); - - let ldes: Vec> = (2..3) - .map(|deg_bits| { - let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); - let mut lde = dft.coset_lde_batch(evals, 1, shift); - reverse_matrix_index_bits(&mut lde); - lde - }) - .collect(); - - let alpha = F::one(); - let input: [_; 32] = core::array::from_fn(|log_height| { - let matrices_with_log_height: Vec<&RowMajorMatrix> = ldes - .iter() - .filter(|m| log2_strict_usize(m.height()) == log_height) - .collect(); - if matrices_with_log_height.is_empty() { - None - } else { - let reduced: Vec = (0..(1 << log_height)) - .map(|r| { - alpha - .powers() - .zip(matrices_with_log_height.iter().flat_map(|m| m.row(r))) - .map(|(alpha_pow, v)| alpha_pow * v) - .sum() - }) - .collect(); - Some(reduced) - } - }); - - let (proof, idxs) = bf_prove(&fri_config, &input, &mut challenger); - let p_sample = challenger.sample_bits(8); - - let log_max_height = input.iter().rposition(Option::is_some).unwrap(); - let reduced_openings: Vec<[F; 32]> = idxs - .into_iter() - .map(|idx| { - input - .iter() - .enumerate() - .map(|(log_height, v)| { - if let Some(v) = v { - v[idx >> (log_max_height - log_height)] - } else { - F::zero() - } - }) - .collect_vec() - .try_into() - .unwrap() - }) - .collect(); - - // let _alpha: Challenge = challenger.sample_ext_element(); - let v_permutation = TestPermutation {}; - let mut v_challenger = - BfChallenger::::new(v_permutation).unwrap(); - let fri_challenges = - verifier::verify_shape_and_sample_challenges(&fri_config, &proof, &mut v_challenger) - .expect("failed verify shape and sample"); - - bf_verify_challenges( - &mut assign, - &fri_config, - &proof, - &fri_challenges, - &reduced_openings, - ) - .expect("failed verify challenges"); - - assert_eq!( - p_sample, - v_challenger.sample_bits(8), - "prover and verifier transcript have same state after FRI" - ); - } -} diff --git a/fri/src/script_verifier.rs b/fri/src/script_verifier.rs index 7fd2e1f..c61d4a2 100644 --- a/fri/src/script_verifier.rs +++ b/fri/src/script_verifier.rs @@ -3,6 +3,7 @@ use alloc::vec::Vec; use core::panic; use bitcoin::taproot::TapLeaf; +use bitcoin::Script; use itertools::izip; use p3_challenger::{CanObserve, CanSample}; use p3_util::reverse_bits_len; @@ -12,6 +13,7 @@ use primitives::mmcs::bf_mmcs::BFMmcs; use primitives::mmcs::point::{Point, PointsLeaf}; use primitives::mmcs::taptree_mmcs::CommitProof; use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; +use script_manager::script_info::ScriptInfo; use scripts::execute_script_with_inputs; use segment::SegmentLeaf; @@ -20,26 +22,33 @@ use crate::fri_scripts::leaf::{ CalNegXLeaf, IndexToROULeaf, ReductionLeaf, RevIndexLeaf, SquareFLeaf, VerifyFoldingLeaf, }; use crate::verifier::*; -use crate::{BfQueryProof, FriConfig, FriProof}; +use crate::{BfQueryProof, FriConfig, FriGenericConfig, FriProof}; -pub fn bf_verify_challenges( +pub fn bf_verify_challenges( + g: &G, assign: &mut DefaultBCAssignment, config: &FriConfig, - proof: &FriProof, + proof: &FriProof, challenges: &FriChallenges, - reduced_openings: &[[F; 32]], -) -> Result<(), FriError> + script_manager: &mut Vec, + open_input: impl Fn( + usize, + &G::InputProof, + &mut Vec, + ) -> Result, G::InputError>, +) -> Result<(), FriError> where F: BfField, M: BFMmcs>, + G: FriGenericConfig, { let log_max_height = proof.commit_phase_commits.len() + config.log_blowup; - for (&index, query_proof, ro) in izip!( - &challenges.query_indices, - &proof.query_proofs, - reduced_openings - ) { + for (&index, query_proof) in izip!(&challenges.query_indices, &proof.query_proofs,) { + let ro = open_input(index, &query_proof.input_proof, script_manager) + .map_err(|e| FriError::InputError(e))?; + let folded_eval = bf_verify_query( + g, assign, config, &proof.commit_phase_commits, @@ -58,21 +67,24 @@ where Ok(()) } -fn bf_verify_query( +fn bf_verify_query( + g: &G, assign: &mut DefaultBCAssignment, config: &FriConfig, commit_phase_commits: &[M::Commitment], mut index: usize, - proof: &BfQueryProof, + proof: &BfQueryProof, betas: &[F], - reduced_openings: &[F; 32], + reduced_openings: Vec<(usize, F)>, log_max_height: usize, -) -> Result> +) -> Result> where F: BfField, M: BFMmcs>, + G: FriGenericConfig, { let mut folded_eval = F::zero(); + let mut ro_iter = reduced_openings.into_iter().peekable(); let rev_index = reverse_bits_len(index, log_max_height); let rev_index_leaf = RevIndexLeaf::new_from_assign( @@ -111,22 +123,25 @@ where // let index_sibling = index ^ 1; let index_pair = index >> 1; - let poins_leaf: PointsLeaf = step.points_leaf.clone(); - let challenge_point: Point = poins_leaf.get_point_by_index(point_index).unwrap().clone(); + if let Some((_, ro)) = ro_iter.next_if(|(lh, _)| *lh == log_folded_height + 1) { + let reduction_leaf = + ReductionLeaf::<1, F>::new_from_assign(folded_eval, ro, folded_eval + ro, assign); + let exec_success = reduction_leaf.execute_leaf_script(); + if !exec_success { + return Err(FriError::ScriptVerifierError( + SVError::VerifyReductionScriptError, + )); + } - let opening = reduced_openings[log_folded_height + 1]; - let reduction_value = opening + folded_eval; - let reduction_leaf = - ReductionLeaf::<1, F>::new_from_assign(folded_eval, opening, reduction_value, assign); - let exec_success = reduction_leaf.execute_leaf_script(); - if !exec_success { - return Err(FriError::ScriptVerifierError( - SVError::VerifyReductionScriptError, - )); + println!("ro:{}", ro); + folded_eval += ro; } + let poins_leaf: PointsLeaf = step.points_leaf.clone(); + let challenge_point: Point = poins_leaf.get_point_by_index(point_index).unwrap().clone(); + if log_folded_height < log_max_height - 1 { - assert_eq!(reduction_value, challenge_point.y); + assert_eq!(folded_eval, challenge_point.y); } let sibling_point: Point = poins_leaf .get_point_by_index(index_sibling) @@ -144,7 +159,7 @@ where } // assert_eq!(sibling_point.x, neg_x); - let mut evals = vec![reduction_value; 2]; + let mut evals = vec![folded_eval; 2]; evals[index_sibling % 2] = sibling_point.y; let mut xs = vec![x; 2]; @@ -172,7 +187,8 @@ where .verify_taptree(step, commit) .map_err(FriError::CommitPhaseMmcsError)?; - folded_eval = evals[0] + (beta - xs[0]) * (evals[1] - evals[0]) / (xs[1] - xs[0]); + index = index_pair; + folded_eval = g.fold_row(index, log_folded_height, beta, evals.into_iter()); let folding_leaf = VerifyFoldingLeaf::<1, F>::new_from_assign( challenge_point.y, sibling_point.y, @@ -187,10 +203,9 @@ where SVError::VerifyFoldingScriptError, )); } - index = index_pair; x = x.square(); let square_leaf = SquareFLeaf::<1, F>::new_from_assign(x, x.square(), assign); - let exec_success = folding_leaf.execute_leaf_script(); + let exec_success = square_leaf.execute_leaf_script(); if !exec_success { return Err(FriError::ScriptVerifierError( SVError::VerifySquareFScriptError, diff --git a/fri/src/two_adic_pcs.rs b/fri/src/two_adic_pcs.rs new file mode 100644 index 0000000..293f50f --- /dev/null +++ b/fri/src/two_adic_pcs.rs @@ -0,0 +1,526 @@ +use alloc::collections::BTreeMap; +use alloc::vec; +use alloc::vec::Vec; +use core::fmt::Debug; +use core::marker::PhantomData; + +use itertools::{izip, Itertools}; +use p3_challenger::{CanObserve, CanSample, GrindingChallenger}; +use p3_commit::{OpenedValues, PolynomialSpace, TwoAdicMultiplicativeCoset}; +use p3_dft::TwoAdicSubgroupDft; +use p3_field::{ + batch_multiplicative_inverse, cyclic_subgroup_coset_known_order, dot_product, ExtensionField, + Field, TwoAdicField, +}; +use p3_interpolation::interpolate_coset; +use p3_matrix::bitrev::{BitReversableMatrix, BitReversalPerm}; +use p3_matrix::dense::RowMajorMatrix; +use p3_matrix::{Dimensions, Matrix}; +use p3_maybe_rayon::prelude::*; +use p3_util::linear_map::LinearMap; +use p3_util::{log2_strict_usize, reverse_bits_len, reverse_slice_index_bits, VecExt}; +use primitives::bf_pcs::Pcs; +use primitives::challenger::BfGrindingChallenger; +use primitives::field::BfField; +use primitives::mmcs::bf_mmcs::BFMmcs; +use primitives::mmcs::taptree_mmcs::{CommitProof, TapTreeMmcs}; +use script_manager::script_info::ScriptInfo; +use serde::{Deserialize, Serialize}; +use tracing::{info_span, instrument}; + +use crate::error::{self, FriError}; +use crate::fri_scripts::pcs::{accmulator_script, ro_mul_x_minus_z_script}; +use crate::{prover, verifier, FriConfig, FriGenericConfig, FriProof}; + +#[derive(Debug)] +pub struct TwoAdicFriPcs { + dft: Dft, + mmcs: InputMmcs, + fri: FriConfig, + _phantom: PhantomData, +} + +impl TwoAdicFriPcs { + pub const fn new(dft: Dft, mmcs: InputMmcs, fri: FriConfig) -> Self { + Self { + dft, + mmcs, + fri, + _phantom: PhantomData, + } + } +} + +#[derive(Clone)] +pub struct BatchOpening>> { + pub opened_values: Vec>, + pub opening_proof: >::Proof, +} + +pub struct TwoAdicFriGenericConfig( + pub PhantomData<(InputProof, InputError)>, +); + +pub type TwoAdicFriGenericConfigForMmcs = + TwoAdicFriGenericConfig>, >::Error>; + +impl FriGenericConfig + for TwoAdicFriGenericConfig +{ + type InputProof = InputProof; + type InputError = InputError; + + fn extra_query_index_bits(&self) -> usize { + 0 + } + + fn fold_row( + &self, + index: usize, + log_height: usize, + beta: F, + evals: impl Iterator, + ) -> F { + let arity = 2; + let log_arity = 1; + let (e0, e1) = evals + .collect_tuple() + .expect("TwoAdicFriFolder only supports arity=2"); + // If performance critical, make this API stateful to avoid this + // This is a bit more math than is necessary, but leaving it here + // in case we want higher arity in the future + let subgroup_start = F::two_adic_generator(log_height + log_arity) + .exp_u64(reverse_bits_len(index, log_height) as u64); + let mut xs = F::two_adic_generator(log_arity) + .shifted_powers(subgroup_start) + .take(arity) + .collect_vec(); + reverse_slice_index_bits(&mut xs); + assert_eq!(log_arity, 1, "can only interpolate two points for now"); + // interpolate and evaluate at beta + e0 + (beta - xs[0]) * (e1 - e0) / (xs[1] - xs[0]) + } + + fn fold_matrix>(&self, beta: F, m: M) -> Vec { + // We use the fact that + // p_e(x^2) = (p(x) + p(-x)) / 2 + // p_o(x^2) = (p(x) - p(-x)) / (2 x) + // that is, + // p_e(g^(2i)) = (p(g^i) + p(g^(n/2 + i))) / 2 + // p_o(g^(2i)) = (p(g^i) - p(g^(n/2 + i))) / (2 g^i) + // so + // result(g^(2i)) = p_e(g^(2i)) + beta p_o(g^(2i)) + // = (1/2 + beta/2 g_inv^i) p(g^i) + // + (1/2 - beta/2 g_inv^i) p(g^(n/2 + i)) + let g_inv = F::two_adic_generator(log2_strict_usize(m.height()) + 1).inverse(); + let one_half = F::two().inverse(); + let half_beta = beta * one_half; + + // TODO: vectorize this (after we have packed extension fields) + + // beta/2 times successive powers of g_inv + let mut powers = g_inv + .shifted_powers(half_beta) + .take(m.height()) + .collect_vec(); + reverse_slice_index_bits(&mut powers); + + m.par_rows() + .zip(powers) + .map(|(mut row, power)| { + let (lo, hi) = row.next_tuple().unwrap(); + (one_half + power) * lo + (one_half - power) * hi + }) + .collect() + } +} + +impl Pcs + for TwoAdicFriPcs +where + Val: BfField, + Dft: TwoAdicSubgroupDft, + InputMmcs: BFMmcs>, + FriMmcs: BFMmcs>, + Challenge: BfField + ExtensionField, + Challenger: CanObserve + CanSample + BfGrindingChallenger, +{ + type Domain = TwoAdicMultiplicativeCoset; + type Commitment = InputMmcs::Commitment; + type ProverData = InputMmcs::ProverData; + type Proof = + FriProof>>; + type Error = FriError; + + fn natural_domain_for_degree(&self, degree: usize) -> Self::Domain { + let log_n = log2_strict_usize(degree); + TwoAdicMultiplicativeCoset { + log_n, + shift: Val::one(), + } + } + + fn commit( + &self, + evaluations: Vec<(Self::Domain, RowMajorMatrix)>, + ) -> (Self::Commitment, Self::ProverData) { + let ldes: Vec<_> = evaluations + .into_iter() + .map(|(domain, evals)| { + assert_eq!(domain.size(), evals.height()); + let shift = Val::generator() / domain.shift; + // Commit to the bit-reversed LDE. + self.dft + .coset_lde_batch(evals, self.fri.log_blowup, shift) + .bit_reverse_rows() + .to_row_major_matrix() + }) + .collect(); + + self.mmcs.commit(ldes) + } + + fn get_evaluations_on_domain<'a>( + &self, + prover_data: &'a Self::ProverData, + idx: usize, + domain: Self::Domain, + ) -> impl Matrix + 'a { + // todo: handle extrapolation for LDEs we don't have + assert_eq!(domain.shift, Val::generator()); + let lde = self.mmcs.get_matrices(prover_data)[idx]; + assert!(lde.height() >= domain.size()); + lde.split_rows(domain.size()).0.bit_reverse_rows() + } + + fn open( + &self, + // For each round, + // each round means a polynomial with multi open-points + rounds: Vec<( + &Self::ProverData, + // for each matrix, + Vec< + // points to open + Vec, + >, + )>, + challenger: &mut Challenger, + ) -> (OpenedValues, Self::Proof) { + /* + A quick rundown of the optimizations in this function: + We are trying to compute sum_i alpha^i * (p(X) - y)/(X - z), + for each z an opening point, y = p(z). + Each p(X) is given as evaluations in bit-reversed order + in the columns of the matrices. + y is computed by barycentric interpolation. + X and p(X) are in the base field; alpha, y and z are in the extension. + The primary goal is to minimize extension multiplications. + + - Instead of computing all alpha^i, we just compute alpha^i for i up to the largest width + of a matrix, then multiply by an "alpha offset" when accumulating. + a^0 x0 + a^1 x1 + a^2 x2 + a^3 x3 + ... + = a^0 ( a^0 x0 + a^1 x1 ) + a^2 ( a^0 x2 + a^1 x3 ) + ... + (see `alpha_pows`, `alpha_pow_offset`, `num_reduced`) + + - For each unique point z, we precompute 1/(X-z) for the largest subgroup opened at this point. + Since we compute it in bit-reversed order, smaller subgroups can simply truncate the vector. + (see `inv_denoms`) + + - Then, for each matrix (with columns p_i) and opening point z, we want: + for each row (corresponding to subgroup element X): + reduced[X] += alpha_offset * sum_i [ alpha^i * inv_denom[X] * (p_i[X] - y[i]) ] + + We can factor out inv_denom, and expand what's left: + reduced[X] += alpha_offset * inv_denom[X] * sum_i [ alpha^i * p_i[X] - alpha^i * y[i] ] + + And separate the sum: + reduced[X] += alpha_offset * inv_denom[X] * [ sum_i [ alpha^i * p_i[X] ] - sum_i [ alpha^i * y[i] ] ] + + And now the last sum doesn't depend on X, so we can precompute that for the matrix, too. + So the hot loop (that depends on both X and i) is just: + sum_i [ alpha^i * p_i[X] ] + + with alpha^i an extension, p_i[X] a base + + */ + // Batch combination challenge + let alpha: Challenge = challenger.sample(); + + let mats_and_points = rounds + .iter() + .map(|(data, points)| { + ( + self.mmcs + .get_matrices(data) + .into_iter() + .map(|m| m.as_view()) + .collect_vec(), + points, + ) + }) + .collect_vec(); + let mats = mats_and_points + .iter() + .flat_map(|(mats, _)| mats) + .collect_vec(); + + let global_max_height = mats.iter().map(|m| m.height()).max().unwrap(); + let log_global_max_height = log2_strict_usize(global_max_height); + + // For each unique opening point z, we will find the largest degree bound + // for that point, and precompute 1/(X - z) for the largest subgroup (in bitrev order). + let inv_denoms = compute_inverse_denominators(&mats_and_points, Val::generator()); + + let mut all_opened_values: OpenedValues = vec![]; + + let mut reduced_openings: [_; 32] = core::array::from_fn(|_| None); + let mut num_reduced = [0; 32]; + + for (mats, points) in mats_and_points { + let opened_values_for_round = all_opened_values.pushed_mut(vec![]); + for (mat, points_for_mat) in izip!(mats, points) { + let log_height = log2_strict_usize(mat.height()); + let reduced_opening_for_log_height = reduced_openings[log_height] + .get_or_insert_with(|| vec![Challenge::zero(); mat.height()]); + debug_assert_eq!(reduced_opening_for_log_height.len(), mat.height()); + + let opened_values_for_mat = opened_values_for_round.pushed_mut(vec![]); + for &point in points_for_mat { + let _guard = + info_span!("reduce matrix quotient", dims = %mat.dimensions()).entered(); + + // Use Barycentric interpolation to evaluate the matrix at the given point. + let ys: Vec = info_span!( + "compute opened values with Lagrange interpolation" + ) + .in_scope(|| { + let (low_coset, _) = mat.split_rows(mat.height() >> self.fri.log_blowup); + + interpolate_coset( + &BitReversalPerm::new_view(low_coset), + Val::generator(), + point, + ) + }); + + let alpha_pow_offset = alpha.exp_u64(num_reduced[log_height] as u64); + let reduced_ys: Challenge = dot_product(alpha.powers(), ys.iter().copied()); + + info_span!("reduce rows").in_scope(|| { + mat.dot_ext_powers(alpha) + .zip(reduced_opening_for_log_height.par_iter_mut()) + .zip(inv_denoms.get(&point).unwrap().par_iter()) + .for_each(|((reduced_row, ro), &inv_denom)| { + *ro += alpha_pow_offset * (reduced_row - reduced_ys) * inv_denom + }) + }); + + num_reduced[log_height] += mat.width(); + opened_values_for_mat.push(ys); + } + } + } + + let fri_input = reduced_openings.into_iter().rev().flatten().collect_vec(); + + let g: TwoAdicFriGenericConfigForMmcs = + TwoAdicFriGenericConfig(PhantomData); + + let fri_proof = prover::bf_prove(&g, &self.fri, fri_input, challenger, |index| { + rounds + .iter() + .map(|(data, _)| { + let log_max_height = log2_strict_usize(self.mmcs.get_max_height(data)); + let bits_reduced = log_global_max_height - log_max_height; + let reduced_index = index >> bits_reduced; + // return the p_1(challenger), p_3(challenger) as Opening opening values + let (opened_values, opening_proof) = self.mmcs.open_batch(reduced_index, data); + BatchOpening { + opened_values: opened_values, + opening_proof: opening_proof, + } + }) + .collect() + }); + + (all_opened_values, fri_proof) + } + + fn verify( + &self, + // For each round: + rounds: Vec<( + Self::Commitment, + // for each matrix: + Vec<( + // its domain, + Self::Domain, + // for each point: + Vec<( + // the point, + Challenge, + // values at the point + Vec, // ys + )>, + )>, + )>, + proof: &Self::Proof, + challenger: &mut Challenger, + script_manager: &mut Vec, + ) -> Result<(), Self::Error> { + // Batch combination challenge + let alpha: Challenge = challenger.sample(); + + let log_global_max_height = proof.commit_phase_commits.len() + self.fri.log_blowup; + + let g: TwoAdicFriGenericConfigForMmcs = + TwoAdicFriGenericConfig(PhantomData); + + let fri_challenges = + verifier::verify_shape_and_sample_challenges(&g, &self.fri, proof, challenger) + .expect("failed verify shape and sample"); + + verifier::verify_challenges( + &g, + &self.fri, + proof, + &fri_challenges, + script_manager, + |index, input_proof, sm| { + // TODO: separate this out into functions + + // log_height -> (alpha_pow, reduced_opening) + let mut reduced_openings = BTreeMap::::new(); + + for (batch_opening, (batch_commit, mats)) in izip!(input_proof, &rounds) { + let batch_heights = mats + .iter() + .map(|(domain, _)| domain.size() << self.fri.log_blowup) + .collect_vec(); + + let batch_max_height = batch_heights.iter().max().expect("Empty batch?"); + let log_batch_max_height = log2_strict_usize(*batch_max_height); + let bits_reduced = log_global_max_height - log_batch_max_height; + let reduced_index = index >> bits_reduced; + + self.mmcs.verify_batch( + &batch_opening.opened_values, + &batch_opening.opening_proof, + batch_commit, + )?; + + // mat_opening places vec![p_1(k),p_2(k)] + // mat_points_and_values places vec![ vec![(z_1,p_1(z_1)),(z_2,p_1(z_2))], vec![(z_3,p_2(z_3))]] + for (mat_opening, (mat_domain, mat_points_and_values)) in + izip!(&batch_opening.opened_values, mats) + { + let log_height = log2_strict_usize(mat_domain.size()) + self.fri.log_blowup; + + let bits_reduced = log_global_max_height - log_height; + let rev_reduced_index = reverse_bits_len(index >> bits_reduced, log_height); + + // todo: this can be nicer with domain methods? + + let x = Val::generator() + * Val::two_adic_generator(log_height).exp_u64(rev_reduced_index as u64); // calculate k + + let (alpha_pow, ro) = reduced_openings + .entry(log_height) + .or_insert((Challenge::one(), Challenge::zero())); + + for (z, ps_at_z) in mat_points_and_values { + let mut acc = Challenge::zero(); + let prev_alpha_pow = *alpha_pow; + for (&p_at_x, &p_at_z) in izip!(mat_opening, ps_at_z) { + // + // Compute the value of ro: + // + // Original formula: + // ro = alpha^0 * (p(x)_{0} - p(z)_{0}) / (x - z) + alpha^1 * (p(x)_{1} -p(z)_{1}) / (x - z) + ... + alpha^i * (p(x)_{i} -p(z)_{i}) / (x - z) + // + // Optimized formula: + // ro = (alpha^0 * (p(x)_{0} - p(z)_{0}) + alpha^1 * (p(x)_{1} -p(z)_{1}) + ... + alpha^i * (p(x)_{i} -p(z)_{i})) / (x - z) + // + acc += *alpha_pow * (-p_at_z + p_at_x); + *alpha_pow *= alpha; + } + let final_alpha_pow = *alpha_pow; + let prev_ro = *ro; + let final_ro = prev_ro + acc / (-*z + x); + *ro = final_ro; + + let compute_acc = accmulator_script( + alpha, + prev_alpha_pow, + mat_opening.clone(), + ps_at_z.clone(), + final_alpha_pow, + acc.clone(), + ); + let compute_ro = + ro_mul_x_minus_z_script(prev_ro, final_ro, x.clone(), *z, acc); + sm.push(compute_acc); + sm.push(compute_ro); + } + } + } + + // Return reduced openings descending by log_height. + Ok(reduced_openings + .into_iter() + .rev() + .map(|(log_height, (_alpha_pow, ro))| (log_height, ro)) + .collect()) + }, + ) + .expect("fri err"); + + Ok(()) + } +} + +#[instrument(skip_all)] +fn compute_inverse_denominators, M: Matrix>( + mats_and_points: &[(Vec, &Vec>)], + coset_shift: F, +) -> LinearMap> { + let mut max_log_height_for_point: LinearMap = LinearMap::new(); + for (mats, points) in mats_and_points { + for (mat, points_for_mat) in izip!(mats, *points) { + let log_height = log2_strict_usize(mat.height()); + for &z in points_for_mat { + if let Some(lh) = max_log_height_for_point.get_mut(&z) { + *lh = core::cmp::max(*lh, log_height); + } else { + max_log_height_for_point.insert(z, log_height); + } + } + } + } + + // Compute the largest subgroup we will use, in bitrev order. + let max_log_height = *max_log_height_for_point.values().max().unwrap(); + let mut subgroup = cyclic_subgroup_coset_known_order( + F::two_adic_generator(max_log_height), + coset_shift, + 1 << max_log_height, + ) + .collect_vec(); + reverse_slice_index_bits(&mut subgroup); + + max_log_height_for_point + .into_iter() + .map(|(z, log_height)| { + ( + z, + batch_multiplicative_inverse( + &subgroup[..(1 << log_height)] + .iter() + .map(|&x| EF::from_base(x) - z) + .collect_vec(), + ), + ) + }) + .collect() +} diff --git a/fri/src/verifier.rs b/fri/src/verifier.rs index 09c5521..6f0e2e7 100644 --- a/fri/src/verifier.rs +++ b/fri/src/verifier.rs @@ -9,12 +9,14 @@ use p3_util::reverse_bits_len; use primitives::challenger::BfGrindingChallenger; use primitives::field::BfField; use primitives::mmcs::bf_mmcs::BFMmcs; +use primitives::mmcs::error::BfError; use primitives::mmcs::point::{Point, PointsLeaf}; use primitives::mmcs::taptree_mmcs::CommitProof; +use script_manager::script_info::ScriptInfo; use scripts::execute_script_with_inputs; use crate::error::FriError; -use crate::{BfQueryProof, FriConfig, FriProof}; +use crate::{BfQueryProof, FriConfig, FriGenericConfig, FriProof}; #[derive(Debug)] pub struct FriChallenges { @@ -22,15 +24,17 @@ pub struct FriChallenges { pub(crate) betas: Vec, } -pub fn verify_shape_and_sample_challenges( +pub fn verify_shape_and_sample_challenges( + g: &G, config: &FriConfig, - proof: &FriProof, + proof: &FriProof, challenger: &mut Challenger, -) -> Result, FriError> +) -> Result, FriError> where F: BfField, M: BFMmcs>, Challenger: BfGrindingChallenger + CanObserve + CanSample, + G: FriGenericConfig, { let betas: Vec = proof .commit_phase_commits @@ -62,23 +66,29 @@ where }) } -pub fn verify_challenges( +pub fn verify_challenges( + g: &G, config: &FriConfig, - proof: &FriProof, + proof: &FriProof, challenges: &FriChallenges, - reduced_openings: &[[F; 32]], -) -> Result<(), FriError> + script_manager: &mut Vec, + open_input: impl Fn( + usize, + &G::InputProof, + &mut Vec, + ) -> Result, G::InputError>, +) -> Result<(), FriError> where F: BfField, M: BFMmcs>, + G: FriGenericConfig, { let log_max_height = proof.commit_phase_commits.len() + config.log_blowup; - for (&index, query_proof, ro) in izip!( - &challenges.query_indices, - &proof.query_proofs, - reduced_openings - ) { + for (&index, query_proof) in izip!(&challenges.query_indices, &proof.query_proofs,) { + let ro = open_input(index, &query_proof.input_proof, script_manager) + .map_err(|e| FriError::InputError(e))?; let folded_eval = verify_query( + g, config, &proof.commit_phase_commits, index, @@ -96,23 +106,23 @@ where Ok(()) } -fn verify_query( +fn verify_query( + g: &G, config: &FriConfig, commit_phase_commits: &[M::Commitment], mut index: usize, - proof: &BfQueryProof, + proof: &BfQueryProof, betas: &[F], - reduced_openings: &[F; 32], + reduced_openings: Vec<(usize, F)>, log_max_height: usize, -) -> Result> +) -> Result> where F: BfField, M: BFMmcs>, + G: FriGenericConfig, { let mut folded_eval = F::zero(); - - let mut x = F::two_adic_generator(log_max_height) - .exp_u64(reverse_bits_len(index, log_max_height) as u64); + let mut ro_iter = reduced_openings.into_iter().peekable(); for (log_folded_height, commit, step, &beta) in izip!( (0..log_max_height).rev(), @@ -124,31 +134,29 @@ where let index_sibling = point_index ^ 1; let index_pair = index >> 1; - //println!("ch point index:{}, sib point index:{}, index_pair:{}", point_index, index_sibling, index_pair); + if let Some((_, ro)) = ro_iter.next_if(|(lh, _)| *lh == log_folded_height + 1) { + println!("ro:{}", ro); + folded_eval += ro; + } + + println!( + "ch point index:{}, sib point index:{}, index_pair:{}", + point_index, index_sibling, index_pair + ); let open_leaf: PointsLeaf = step.points_leaf.clone(); let challenge_point: Point = open_leaf.get_point_by_index(point_index).unwrap().clone(); - let opening = reduced_openings[log_folded_height + 1]; - folded_eval = opening + folded_eval; - let sibling_point: Point = open_leaf.get_point_by_index(index_sibling).unwrap().clone(); - //println!("challenge_point.y:{}", challenge_point.y); - //println!("sibling_point.y:{}", sibling_point.y); + println!("challenge_point.y:{}", challenge_point.y); + println!("sibling_point.y:{}", sibling_point.y); if log_folded_height < log_max_height - 1 { assert_eq!(folded_eval, challenge_point.y); } - // assert_eq!(challenge_point.x, x); - let neg_x = x * F::two_adic_generator(1); - // assert_eq!(sibling_point.x, neg_x); - let mut evals = vec![folded_eval; 2]; evals[index_sibling % 2] = sibling_point.y; - let mut xs = vec![x; 2]; - xs[index_sibling % 2] = neg_x; - let input = open_leaf.witness(); if let TapLeaf::Script(script, _ver) = step.leaf_node.leaf().clone() { @@ -167,14 +175,11 @@ where .verify_taptree(step, commit) .map_err(FriError::CommitPhaseMmcsError)?; - folded_eval = evals[0] + (beta - xs[0]) * (evals[1] - evals[0]) / (xs[1] - xs[0]); - index = index_pair; - x = x.square(); + folded_eval = g.fold_row(index, log_folded_height, beta, evals.into_iter()); } debug_assert!(index < config.blowup(), "index was {}", index); - debug_assert_eq!(x.exp_power_of_2(config.log_blowup), F::one()); Ok(folded_eval) } diff --git a/fri/tests/fri.rs b/fri/tests/fri.rs new file mode 100644 index 0000000..0c24879 --- /dev/null +++ b/fri/tests/fri.rs @@ -0,0 +1,617 @@ +use core::cmp::Reverse; +use std::marker::PhantomData; + +use fri::prover::bf_prove; +// use super::*; +use fri::script_verifier::bf_verify_challenges; +use fri::two_adic_pcs::TwoAdicFriGenericConfig; +use fri::{verifier, FriConfig}; +use itertools::Itertools; +use p3_baby_bear::BabyBear; +use p3_challenger::CanSampleBits; +use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; +use p3_field::extension::BinomialExtensionField; +use p3_field::AbstractField; +use p3_matrix::dense::RowMajorMatrix; +use p3_matrix::util::reverse_matrix_index_bits; +use p3_matrix::Matrix; +use p3_symmetric::{CryptographicPermutation, Permutation}; +use p3_util::log2_strict_usize; +use primitives::challenger::chan_field::U32; +use primitives::challenger::{BfChallenger, Blake3Permutation}; +use primitives::mmcs::taptree_mmcs::TapTreeMmcs; +use rand::SeedableRng; +use rand_chacha::ChaCha20Rng; +use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; +use script_manager::script_info::ScriptInfo; +use tracing_subscriber::fmt; + +type PF = U32; +const WIDTH: usize = 16; +type SpongeState = [PF; WIDTH]; +type F = BabyBear; +#[derive(Clone)] +struct TestPermutation {} + +impl Permutation for TestPermutation { + fn permute(&self, mut input: SpongeState) -> SpongeState { + self.permute_mut(&mut input); + input + } + + fn permute_mut(&self, input: &mut SpongeState) { + input.reverse(); + } +} + +impl CryptographicPermutation for TestPermutation {} +type Val = BabyBear; +type ValMmcs = TapTreeMmcs; +type MyFriConfig = FriConfig; +#[test] +fn test_compelte_fri_process() { + let mut script_manager: Vec = Vec::new(); + let permutation = TestPermutation {}; + let mut challenger = BfChallenger::::new(permutation).unwrap(); + let mmcs = ValMmcs::new(); + let fri_config = FriConfig { + log_blowup: 1, + num_queries: 10, + proof_of_work_bits: 8, + mmcs, + }; + + let dft = Radix2Dit::default(); + + let shift = Val::generator(); + let mut rng = ChaCha20Rng::seed_from_u64(0); + + let ldes: Vec> = (1..10) + .map(|deg_bits| { + let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); + let mut lde = dft.coset_lde_batch(evals, 1, shift); + reverse_matrix_index_bits(&mut lde); + lde + }) + .collect(); + + let alpha = BabyBear::one(); + let input: [_; 32] = core::array::from_fn(|log_height| { + let matrices_with_log_height: Vec<&RowMajorMatrix> = ldes + .iter() + .filter(|m| log2_strict_usize(m.height()) == log_height) + .collect(); + if matrices_with_log_height.is_empty() { + None + } else { + let reduced: Vec = (0..(1 << log_height)) + .map(|r| { + alpha + .powers() + .zip(matrices_with_log_height.iter().flat_map(|m| m.row(r))) + .map(|(alpha_pow, v)| alpha_pow * v) + .sum() + }) + .collect(); + Some(reduced) + } + }); + + let input: Vec> = input.into_iter().rev().flatten().collect(); + let log_max_height = log2_strict_usize(input[0].len()); + + let proof = bf_prove( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + input.clone(), + &mut challenger, + |idx| { + // As our "input opening proof", just pass through the literal reduced openings. + let mut ro = vec![]; + for v in &input { + let log_height = log2_strict_usize(v.len()); + ro.push((log_height, v[idx >> (log_max_height - log_height)])); + } + ro.sort_by_key(|(lh, _)| Reverse(*lh)); + ro + }, + ); + let p_sample = challenger.sample_bits(8); + + let v_permutation = TestPermutation {}; + let mut v_challenger = + BfChallenger::::new(v_permutation).unwrap(); + let fri_challenges = verifier::verify_shape_and_sample_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + &proof, + &mut v_challenger, + ) + .expect("failed verify shape and sample"); + + verifier::verify_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + &proof, + &fri_challenges, + &mut script_manager, + |_index, proof, sm| Ok(proof.clone()), + ) + .expect("failed verify challenges"); + + assert_eq!( + p_sample, + v_challenger.sample_bits(8), + "prover and verifier transcript have same state after FRI" + ); +} + +#[test] +fn test_script_verifier() { + let mut script_manager: Vec = Vec::new(); + let permutation = TestPermutation {}; + let mut challenger = BfChallenger::::new(permutation).unwrap(); + let mmcs = ValMmcs::new(); + let fri_config = FriConfig { + log_blowup: 1, + num_queries: 10, + proof_of_work_bits: 8, + mmcs, + }; + + let mut assign = DefaultBCAssignment::new(); + + let dft = Radix2Dit::default(); + + let shift = Val::generator(); + let mut rng = ChaCha20Rng::seed_from_u64(0); + + let ldes: Vec> = (4..5) + .map(|deg_bits| { + let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); + let mut lde = dft.coset_lde_batch(evals, 1, shift); + reverse_matrix_index_bits(&mut lde); + lde + }) + .collect(); + + let alpha = BabyBear::one(); + let input: [_; 32] = core::array::from_fn(|log_height| { + let matrices_with_log_height: Vec<&RowMajorMatrix> = ldes + .iter() + .filter(|m| log2_strict_usize(m.height()) == log_height) + .collect(); + if matrices_with_log_height.is_empty() { + None + } else { + let reduced: Vec = (0..(1 << log_height)) + .map(|r| { + alpha + .powers() + .zip(matrices_with_log_height.iter().flat_map(|m| m.row(r))) + .map(|(alpha_pow, v)| alpha_pow * v) + .sum() + }) + .collect(); + Some(reduced) + } + }); + + let input: Vec> = input.into_iter().rev().flatten().collect(); + let log_max_height = log2_strict_usize(input[0].len()); + + let proof = bf_prove( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + input.clone(), + &mut challenger, + |idx| { + // As our "input opening proof", just pass through the literal reduced openings. + let mut ro = vec![]; + for v in &input { + let log_height = log2_strict_usize(v.len()); + ro.push((log_height, v[idx >> (log_max_height - log_height)])); + } + ro.sort_by_key(|(lh, _)| Reverse(*lh)); + ro + }, + ); + + let p_sample = challenger.sample_bits(8); + + let v_permutation = TestPermutation {}; + let mut v_challenger = + BfChallenger::::new(v_permutation).unwrap(); + let fri_challenges = verifier::verify_shape_and_sample_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + &proof, + &mut v_challenger, + ) + .expect("failed verify shape and sample"); + + verifier::verify_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + &proof, + &fri_challenges, + &mut script_manager, + |_index, proof, sm| Ok(proof.clone()), + ) + .expect("failed verify challenges"); + + bf_verify_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &mut assign, + &fri_config, + &proof, + &fri_challenges, + &mut script_manager, + |_index, proof, sm| Ok(proof.clone()), + ) + .expect("failed verify challenges"); + assert_eq!( + p_sample, + v_challenger.sample_bits(8), + "prover and verifier transcript have same state after FRI" + ); +} + +#[test] +fn test_bf_prove_with_blake3_permutation() { + // tracing_subscriber::registry().with(fmt::layer()).init(); // open some log information + + let mut script_manager: Vec = Vec::new(); + let permutation = Blake3Permutation {}; + let mut challenger: BfChallenger = + BfChallenger::::new(permutation).unwrap(); + let mmcs = ValMmcs::new(); + let fri_config = FriConfig { + log_blowup: 1, + num_queries: 10, + proof_of_work_bits: 8, + mmcs, + }; + + let dft = Radix2Dit::default(); + + let shift = Val::generator(); + let mut rng = ChaCha20Rng::seed_from_u64(0); + + let ldes: Vec> = (5..6) + .map(|deg_bits| { + let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); + let mut lde = dft.coset_lde_batch(evals, 1, shift); + reverse_matrix_index_bits(&mut lde); + lde + }) + .collect(); + + let alpha = BabyBear::one(); + let input: [_; 32] = core::array::from_fn(|log_height| { + let matrices_with_log_height: Vec<&RowMajorMatrix> = ldes + .iter() + .filter(|m| log2_strict_usize(m.height()) == log_height) + .collect(); + if matrices_with_log_height.is_empty() { + None + } else { + let reduced: Vec = (0..(1 << log_height)) + .map(|r| { + alpha + .powers() + .zip(matrices_with_log_height.iter().flat_map(|m| m.row(r))) + .map(|(alpha_pow, v)| alpha_pow * v) + .sum() + }) + .collect(); + Some(reduced) + } + }); + + let input: Vec> = input.into_iter().rev().flatten().collect(); + let log_max_height = log2_strict_usize(input[0].len()); + + let proof = bf_prove( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + input.clone(), + &mut challenger, + |idx| { + // As our "input opening proof", just pass through the literal reduced openings. + let mut ro = vec![]; + for v in &input { + let log_height = log2_strict_usize(v.len()); + ro.push((log_height, v[idx >> (log_max_height - log_height)])); + } + ro.sort_by_key(|(lh, _)| Reverse(*lh)); + ro + }, + ); + + let permutation = Blake3Permutation {}; + let mut v_challenger: BfChallenger = + BfChallenger::::new(permutation).unwrap(); + let fri_challenges = verifier::verify_shape_and_sample_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + &proof, + &mut v_challenger, + ) + .expect("failed verify shape and sample"); + + verifier::verify_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + &proof, + &fri_challenges, + &mut script_manager, + |_index, proof, sm| Ok(proof.clone()), + ) + .expect("failed verify challenges"); +} + +#[cfg(test)] +mod tests2 { + + use std::marker::PhantomData; + + use fri::two_adic_pcs::TwoAdicFriGenericConfig; + use itertools::Itertools; + use p3_baby_bear::BabyBear; + use p3_challenger::CanSampleBits; + use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; + use p3_field::extension::BinomialExtensionField; + use p3_field::AbstractField; + use p3_matrix::util::reverse_matrix_index_bits; + use p3_matrix::Matrix; + use p3_symmetric::{CryptographicPermutation, Permutation}; + use p3_util::log2_strict_usize; + use primitives::challenger::chan_field::U32; + use primitives::challenger::{BfChallenger, Blake3Permutation}; + use primitives::mmcs::taptree_mmcs::{TapTreeMmcs, ROOT_WIDTH}; + use rand::SeedableRng; + use rand_chacha::ChaCha20Rng; + use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; + use script_manager::script_info::ScriptInfo; + use tracing_subscriber::fmt; + + use super::*; + use crate::{bf_verify_challenges, verifier}; + + type PF = U32; + const WIDTH: usize = 16; + type SpongeState = [PF; WIDTH]; + type F = BinomialExtensionField; + #[derive(Clone)] + struct TestPermutation {} + + impl Permutation for TestPermutation { + fn permute(&self, mut input: SpongeState) -> SpongeState { + self.permute_mut(&mut input); + input + } + + fn permute_mut(&self, input: &mut SpongeState) { + input.reverse(); + } + } + + impl CryptographicPermutation for TestPermutation {} + type Val = F; + type ValMmcs = TapTreeMmcs; + type MyFriConfig = FriConfig; + + #[test] + fn test_compelte_fri_process_with_ext_babybear() { + let mut script_manager: Vec = Vec::new(); + let permutation = TestPermutation {}; + let mut challenger = + BfChallenger::::new(permutation).unwrap(); + let mmcs = ValMmcs::new(); + let fri_config = FriConfig { + log_blowup: 1, + num_queries: 10, + proof_of_work_bits: 8, + mmcs, + }; + + let dft = Radix2Dit::default(); + + let shift = Val::generator(); + let mut rng = ChaCha20Rng::seed_from_u64(0); + + let ldes: Vec> = (1..10) + .map(|deg_bits| { + let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); + let mut lde = dft.coset_lde_batch(evals, 1, shift); + reverse_matrix_index_bits(&mut lde); + lde + }) + .collect(); + + let alpha = F::one(); + let input: [_; 32] = core::array::from_fn(|log_height| { + let matrices_with_log_height: Vec<&RowMajorMatrix> = ldes + .iter() + .filter(|m| log2_strict_usize(m.height()) == log_height) + .collect(); + if matrices_with_log_height.is_empty() { + None + } else { + let reduced: Vec = (0..(1 << log_height)) + .map(|r| { + alpha + .powers() + .zip(matrices_with_log_height.iter().flat_map(|m| m.row(r))) + .map(|(alpha_pow, v)| alpha_pow * v) + .sum() + }) + .collect(); + Some(reduced) + } + }); + + // let (proof, idxs) = bf_prove(&fri_config, &input, &mut challenger); + let input: Vec> = input.into_iter().rev().flatten().collect(); + let log_max_height = log2_strict_usize(input[0].len()); + + let proof = bf_prove( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + input.clone(), + &mut challenger, + |idx| { + // As our "input opening proof", just pass through the literal reduced openings. + let mut ro = vec![]; + for v in &input { + let log_height = log2_strict_usize(v.len()); + ro.push((log_height, v[idx >> (log_max_height - log_height)])); + } + ro.sort_by_key(|(lh, _)| Reverse(*lh)); + ro + }, + ); + let p_sample = challenger.sample_bits(8); + + let v_permutation = TestPermutation {}; + let mut v_challenger = + BfChallenger::::new(v_permutation).unwrap(); + let fri_challenges = verifier::verify_shape_and_sample_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + &proof, + &mut v_challenger, + ) + .expect("failed verify shape and sample"); + + verifier::verify_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + &proof, + &fri_challenges, + &mut script_manager, + |_index, proof, sm| Ok(proof.clone()), + ) + .expect("failed verify challenges"); + + assert_eq!( + p_sample, + v_challenger.sample_bits(8), + "prover and verifier transcript have same state after FRI" + ); + } + + #[test] + fn test_script_verifier() { + let mut script_manager: Vec = Vec::new(); + let permutation = TestPermutation {}; + let mut challenger = + BfChallenger::::new(permutation).unwrap(); + let mmcs = ValMmcs::new(); + let fri_config = FriConfig { + log_blowup: 1, + num_queries: 10, + proof_of_work_bits: 8, + mmcs, + }; + + let mut assign = DefaultBCAssignment::new(); + + let dft = Radix2Dit::default(); + + let shift = Val::generator(); + let mut rng = ChaCha20Rng::seed_from_u64(0); + + let ldes: Vec> = (2..3) + .map(|deg_bits| { + let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); + let mut lde = dft.coset_lde_batch(evals, 1, shift); + reverse_matrix_index_bits(&mut lde); + lde + }) + .collect(); + + let alpha = F::one(); + let input: [_; 32] = core::array::from_fn(|log_height| { + let matrices_with_log_height: Vec<&RowMajorMatrix> = ldes + .iter() + .filter(|m| log2_strict_usize(m.height()) == log_height) + .collect(); + if matrices_with_log_height.is_empty() { + None + } else { + let reduced: Vec = (0..(1 << log_height)) + .map(|r| { + alpha + .powers() + .zip(matrices_with_log_height.iter().flat_map(|m| m.row(r))) + .map(|(alpha_pow, v)| alpha_pow * v) + .sum() + }) + .collect(); + Some(reduced) + } + }); + + let input: Vec> = input.into_iter().rev().flatten().collect(); + let log_max_height = log2_strict_usize(input[0].len()); + + let proof = bf_prove( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + input.clone(), + &mut challenger, + |idx| { + // As our "input opening proof", just pass through the literal reduced openings. + let mut ro = vec![]; + for v in &input { + let log_height = log2_strict_usize(v.len()); + ro.push((log_height, v[idx >> (log_max_height - log_height)])); + } + ro.sort_by_key(|(lh, _)| Reverse(*lh)); + ro + }, + ); + + let p_sample = challenger.sample_bits(8); + + // let _alpha: Challenge = challenger.sample_ext_element(); + let v_permutation = TestPermutation {}; + let mut v_challenger = + BfChallenger::::new(v_permutation).unwrap(); + let fri_challenges = verifier::verify_shape_and_sample_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + &proof, + &mut v_challenger, + ) + .expect("failed verify shape and sample"); + + verifier::verify_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + &proof, + &fri_challenges, + &mut script_manager, + |_index, proof, sm| Ok(proof.clone()), + ) + .expect("failed verify challenges"); + + bf_verify_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &mut assign, + &fri_config, + &proof, + &fri_challenges, + &mut script_manager, + |_index, proof, sm| Ok(proof.clone()), + ) + .expect("failed verify challenges"); + assert_eq!( + p_sample, + v_challenger.sample_bits(8), + "prover and verifier transcript have same state after FRI" + ); + } +} diff --git a/fri/tests/pcs.rs b/fri/tests/pcs.rs new file mode 100644 index 0000000..99e5a8d --- /dev/null +++ b/fri/tests/pcs.rs @@ -0,0 +1,214 @@ +use fri::{FriConfig, TwoAdicFriPcs}; +use itertools::{izip, Itertools}; +use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; +use p3_challenger::{CanObserve, CanSample, DuplexChallenger, FieldChallenger}; +use p3_commit::{ExtensionMmcs, PolynomialSpace}; +use p3_dft::Radix2DitParallel; +use p3_field::extension::BinomialExtensionField; +use p3_field::{ExtensionField, Field}; +use p3_matrix::dense::RowMajorMatrix; +use primitives::bf_pcs::Pcs; +use primitives::challenger::chan_field::U32; +use primitives::challenger::{BfChallenger, Blake3Permutation}; +use primitives::field::BfField; +use primitives::mmcs::taptree_mmcs::TapTreeMmcs; +use rand::distributions::{Distribution, Standard}; +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha20Rng; +use script_manager::bc_assignment::DefaultBCAssignment; +use scripts::execute_script_with_inputs; + +fn seeded_rng() -> impl Rng { + ChaCha20Rng::seed_from_u64(0) +} + +fn do_test_fri_pcs( + (pcs, challenger): &(P, Challenger), + log_degrees_by_round: &[&[usize]], +) where + P: Pcs, + P::Domain: PolynomialSpace, + Val: Field, + Standard: Distribution, + Challenge: BfField + ExtensionField, + Challenger: Clone + CanObserve + CanSample, +{ + let num_rounds = log_degrees_by_round.len(); + let mut rng = seeded_rng(); + + let mut p_challenger = challenger.clone(); + + let domains_and_polys_by_round = log_degrees_by_round + .iter() + .map(|log_degrees| { + log_degrees + .iter() + .map(|&log_degree| { + let d = 1 << log_degree; + // random width 5-15 + let width = 2 + rng.gen_range(0..=2); + ( + pcs.natural_domain_for_degree(d), + RowMajorMatrix::::rand(&mut rng, d, width), + ) + }) + .collect_vec() + }) + .collect_vec(); + + let (commits_by_round, data_by_round): (Vec<_>, Vec<_>) = domains_and_polys_by_round + .iter() + .map(|domains_and_polys| pcs.commit(domains_and_polys.clone())) + .unzip(); + assert_eq!(commits_by_round.len(), num_rounds); + assert_eq!(data_by_round.len(), num_rounds); + p_challenger.observe_slice(&commits_by_round); + + let zeta: Challenge = p_challenger.sample(); + + let points_by_round = log_degrees_by_round + .iter() + .map(|log_degrees| vec![vec![zeta]; log_degrees.len()]) + .collect_vec(); + let data_and_points = data_by_round.iter().zip(points_by_round).collect(); + let (opening_by_round, proof) = pcs.open(data_and_points, &mut p_challenger); + assert_eq!(opening_by_round.len(), num_rounds); + + // Verify the proof. + let mut v_challenger = challenger.clone(); + v_challenger.observe_slice(&commits_by_round); + let verifier_zeta: Challenge = v_challenger.sample(); + assert_eq!(verifier_zeta, zeta); + + let commits_and_claims_by_round = izip!( + commits_by_round, + domains_and_polys_by_round, + opening_by_round + ) + .map(|(commit, domains_and_polys, openings)| { + let claims = domains_and_polys + .iter() + .zip(openings) + .map(|((domain, _), mat_openings)| (*domain, vec![(zeta, mat_openings[0].clone())])) + .collect_vec(); + (commit, claims) + }) + .collect_vec(); + assert_eq!(commits_and_claims_by_round.len(), num_rounds); + + let mut script_manager = vec![]; + pcs.verify( + commits_and_claims_by_round, + &proof, + &mut v_challenger, + &mut script_manager, + ) + .unwrap(); + + let mut bc_assigner = DefaultBCAssignment::new(); + // execute script verifier + for item in script_manager.iter_mut() { + item.gen(&mut bc_assigner); + let res = execute_script_with_inputs(item.get_eq_script(), item.witness()); + // println!("res: {:?}", res); + assert!(res.success); + } +} + +// Set it up so we create tests inside a module for each pcs, so we get nice error reports +// specific to a failing PCS. +macro_rules! make_tests_for_pcs { + ($p:expr) => { + #[test] + fn single() { + let p = $p; + for i in 3..6 { + $crate::do_test_fri_pcs(&p, &[&[i]]); + } + } + + #[test] + fn small() { + let p = $p; + $crate::do_test_fri_pcs(&p, &[&[2, 1]]); + } + + #[test] + fn many_equal() { + let p = $p; + for i in 2..3 { + $crate::do_test_fri_pcs(&p, &[&[i; 5]]); + } + } + + // #[test] + // fn many_different() { + // let p = $p; + // for i in 2..4 { + // let degrees = (3..3 + i).collect::>(); + // $crate::do_test_fri_pcs(&p, &[°rees]); + // } + // } + + #[test] + fn many_different_rev() { + let p = $p; + for i in 1..3 { + let degrees = (3..3 + i).rev().collect::>(); + $crate::do_test_fri_pcs(&p, &[°rees]); + } + } + + #[test] + fn multiple_rounds() { + let p = $p; + $crate::do_test_fri_pcs(&p, &[&[3]]); + $crate::do_test_fri_pcs(&p, &[&[3], &[3]]); + $crate::do_test_fri_pcs(&p, &[&[3], &[2]]); + $crate::do_test_fri_pcs(&p, &[&[2], &[3]]); + // $crate::do_test_fri_pcs(&p, &[&[3, 4], &[3, 4]]); + $crate::do_test_fri_pcs(&p, &[&[4, 2], &[4, 2]]); + $crate::do_test_fri_pcs(&p, &[&[2, 2], &[3, 3]]); + $crate::do_test_fri_pcs(&p, &[&[3, 3], &[2, 2]]); + $crate::do_test_fri_pcs(&p, &[&[2], &[3, 3]]); + } + }; +} + +mod babybear_fri_pcs { + use super::*; + + type PF = U32; + const WIDTH: usize = 16; + + type Val = BabyBear; + type Challenge = BinomialExtensionField; + type ValMmcs = TapTreeMmcs; + type ChallengeMmcs = TapTreeMmcs; + type Dft = Radix2DitParallel; + type Challenger = BfChallenger; + type MyPcs = TwoAdicFriPcs; + + fn get_pcs(log_blowup: usize) -> (MyPcs, Challenger) { + let val_mmcs = ValMmcs::new(); + let challenge_mmscs = ChallengeMmcs::new(); + let fri_config = FriConfig { + log_blowup, + num_queries: 10, + proof_of_work_bits: 8, + mmcs: challenge_mmscs, + }; + + let permutation = Blake3Permutation {}; + let mut challenger = Challenger::new(permutation).unwrap(); + let pcs = MyPcs::new(Dft {}, val_mmcs, fri_config); + (pcs, challenger) + } + + mod blowup_1 { + make_tests_for_pcs!(super::get_pcs(1)); + } + mod blowup_2 { + make_tests_for_pcs!(super::get_pcs(2)); + } +} diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 69ec34c..7fae2ec 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -24,6 +24,7 @@ p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git" } p3-util = { git = "https://github.com/Plonky3/Plonky3.git" } p3-maybe-rayon ={ git = "https://github.com/Plonky3/Plonky3.git" } p3-matrix = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-commit = { git = "https://github.com/Plonky3/Plonky3.git" } segment ={ path = "../segment" } common = { path = "../common"} diff --git a/primitives/src/bf_pcs.rs b/primitives/src/bf_pcs.rs new file mode 100644 index 0000000..27c6152 --- /dev/null +++ b/primitives/src/bf_pcs.rs @@ -0,0 +1,93 @@ +//! Traits for polynomial commitment schemes. + +use core::fmt::Debug; + +use bitcoin::script; +use p3_commit::PolynomialSpace; +use p3_field::ExtensionField; +use p3_matrix::dense::RowMajorMatrix; +use p3_matrix::Matrix; +use script_manager::script_info::ScriptInfo; +use serde::de::DeserializeOwned; +use serde::Serialize; + +pub type Val = ::Val; + +/// A (not necessarily hiding) polynomial commitment scheme, for committing to (batches of) polynomials +// TODO: Should we have a super-trait for weakly-binding PCSs, like FRI outside unique decoding radius? +pub trait Pcs +where + Challenge: ExtensionField>, +{ + type Domain: PolynomialSpace; + + /// The commitment that's sent to the verifier. + type Commitment: Clone; + + /// Data that the prover stores for committed polynomials, to help the prover with opening. + type ProverData; + + /// The opening argument. + type Proof: Clone; + + type Error: Debug; + + /// This should return a coset domain (s.t. Domain::next_point returns Some) + fn natural_domain_for_degree(&self, degree: usize) -> Self::Domain; + + #[allow(clippy::type_complexity)] + fn commit( + &self, + evaluations: Vec<(Self::Domain, RowMajorMatrix>)>, + ) -> (Self::Commitment, Self::ProverData); + + fn get_evaluations_on_domain<'a>( + &self, + prover_data: &'a Self::ProverData, + idx: usize, + domain: Self::Domain, + ) -> impl Matrix> + 'a; + + fn open( + &self, + // For each round, + rounds: Vec<( + &Self::ProverData, + // for each matrix, + Vec< + // points to open + Vec, + >, + )>, + challenger: &mut Challenger, + ) -> (OpenedValues, Self::Proof); + + #[allow(clippy::type_complexity)] + fn verify( + &self, + // For each round: + rounds: Vec<( + Self::Commitment, + // for each matrix: + Vec<( + // its domain, + Self::Domain, + // for each point: + Vec<( + // the point, + Challenge, + // values at the point + Vec, + )>, + )>, + )>, + proof: &Self::Proof, + challenger: &mut Challenger, + script_managers: &mut Vec, + ) -> Result<(), Self::Error>; +} + +pub type OpenedValues = Vec>; +pub type OpenedValuesForRound = Vec>; +pub type OpenedValuesForMatrix = Vec>; +pub type OpenedValuesForPoint = Vec; diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 88373df..4c2c235 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -1,3 +1,4 @@ +pub mod bf_pcs; pub mod challenger; pub mod field; pub mod mmcs; diff --git a/primitives/src/mmcs/bf_mmcs.rs b/primitives/src/mmcs/bf_mmcs.rs index fe8e37f..18d0382 100644 --- a/primitives/src/mmcs/bf_mmcs.rs +++ b/primitives/src/mmcs/bf_mmcs.rs @@ -37,6 +37,21 @@ pub trait BFMmcs: Clone { } fn open_taptree(&self, index: usize, prover_data: &Self::ProverData) -> Self::Proof; + fn open_batch( + &self, + index: usize, + prover_data: &Self::ProverData, + ) -> (Vec>, Self::Proof) { + unimplemented!() + } + + fn verify_batch( + &self, + opened_values: &Vec>, + proof: &Self::Proof, + root: &Self::Commitment, + ) -> Result<(), Self::Error>; + fn verify_taptree( &self, proof: &Self::Proof, @@ -44,7 +59,7 @@ pub trait BFMmcs: Clone { ) -> Result<(), Self::Error>; /// Get the matrices that were committed to. - fn get_matrices(&self, prover_data: &Self::ProverData) -> Vec>; + fn get_matrices<'a>(&self, prover_data: &'a Self::ProverData) -> Vec<&'a RowMajorMatrix>; fn get_matrix_heights(&self, prover_data: &Self::ProverData) -> Vec { self.get_matrices(prover_data) diff --git a/primitives/src/mmcs/error.rs b/primitives/src/mmcs/error.rs index ff2c0b1..63bf56f 100644 --- a/primitives/src/mmcs/error.rs +++ b/primitives/src/mmcs/error.rs @@ -8,6 +8,7 @@ pub enum BfError { EvaluationLeafError, ExecuteScriptError, InvalidMerkleProof, + InvalidOpenedValue, IndexWithEmptyLeaf(u32, u32), } diff --git a/primitives/src/mmcs/point.rs b/primitives/src/mmcs/point.rs index 7f26176..761cab6 100644 --- a/primitives/src/mmcs/point.rs +++ b/primitives/src/mmcs/point.rs @@ -52,6 +52,14 @@ impl PointsLeaf { } Ok(()) } + + pub fn get_all_points_value(&self) -> Vec { + let mut points = vec![]; + for p in self.leaf_evals.points.iter() { + points.push(p.y); + } + points + } } #[derive(Debug, Clone)] diff --git a/primitives/src/mmcs/taptree.rs b/primitives/src/mmcs/taptree.rs index d99a92a..a38f816 100644 --- a/primitives/src/mmcs/taptree.rs +++ b/primitives/src/mmcs/taptree.rs @@ -128,7 +128,6 @@ impl PolyCommitTree { .peekable(); let max_height = leaves_largest_first.peek().unwrap().height(); let log_max_height = log2_ceil_usize(max_height); - //println!("max height:{:?}", max_height); let mut tree_builder = TreeBuilder::::new(); @@ -194,6 +193,10 @@ impl PolyCommitTree { pub fn get_points_leaf(&self, index: usize) -> &PointsLeaf { &self.points_leafs[index] } + + pub fn get_matrix_widths(&self) -> Vec { + self.leaves.iter().map(|m| m.width()).collect() + } } #[derive(Clone, Debug, PartialEq, PartialOrd)] @@ -277,7 +280,6 @@ impl TreeBuilder { a_start_idx += a_leaf_size + b_leaf_size; } working_nodes = todo; - todo = Vec::new(); } BasicTree { diff --git a/primitives/src/mmcs/taptree_mmcs.rs b/primitives/src/mmcs/taptree_mmcs.rs index 0ef7bac..6c6be8e 100644 --- a/primitives/src/mmcs/taptree_mmcs.rs +++ b/primitives/src/mmcs/taptree_mmcs.rs @@ -2,11 +2,12 @@ use core::marker::PhantomData; use core::{panic, usize}; use bitcoin::hashes::Hash as Bitcoin_HASH; -use bitcoin::taproot::LeafNode; +use bitcoin::taproot::{LeafNode, TapLeaf}; use bitcoin::TapNodeHash; use p3_matrix::dense::RowMajorMatrix; use p3_matrix::Matrix; use p3_util::log2_strict_usize; +use scripts::execute_script_with_inputs; use super::bf_mmcs::BFMmcs; use super::error::BfError; @@ -40,6 +41,31 @@ pub struct CommitProof { pub leaf_node: LeafNode, } +impl CommitProof { + pub fn new(points_leaf: PointsLeaf, leaf_node: LeafNode) -> Self { + Self { + points_leaf, + leaf_node, + } + } + + pub fn verify_points_leaf(&self) -> bool { + if let TapLeaf::Script(script, _ver) = self.leaf_node.leaf().clone() { + let res = execute_script_with_inputs( + script, + self.points_leaf.witness(), + ); + return res.success; + } else { + panic!("Invalid script") + } + } + + pub fn get_open_values(&self) -> Vec { + self.points_leaf.get_all_points_value() + } +} + impl BFMmcs for TapTreeMmcs { type ProverData = PolyCommitTree; type Proof = CommitProof; @@ -52,15 +78,10 @@ impl BFMmcs for TapTreeMmcs { let opening_leaf = match leaf { Some(v) => v, None => { - // println!( - // "leaf index:{:?}, leaf count:{:?}", - // index, - // prover_data.leaf_count() - // ); panic!("invalid leaf index") } }; - println!("leaf_index:{:?}", leaf_index); + //println!("leaf_index:{:?}", leaf_index); let open_leaf = prover_data.get_points_leaf(leaf_index).clone(); CommitProof { points_leaf: open_leaf, @@ -68,6 +89,49 @@ impl BFMmcs for TapTreeMmcs { } } + fn open_batch( + &self, + index: usize, // This is the index corresponding to the highest matrix + prover_data: &PolyCommitTree, + ) -> (Vec>, Self::Proof) { + let comm_proof = self.open_taptree(index, prover_data); + let open_values = comm_proof.get_open_values(); + let matrix_widths = prover_data.get_matrix_widths(); + let mut result = Vec::with_capacity(matrix_widths.len()); + let mut start = 0; + + for &width in &matrix_widths { + let end = start + width; + result.push(Vec::from(&open_values[start..end])); + start = end; + } + + (result, comm_proof) + } + + fn verify_batch( + &self, + opened_values: &Vec>, + proof: &Self::Proof, + root: &Self::Commitment, + ) -> Result<(), Self::Error> { + let total_len: usize = opened_values.iter().map(|v| v.len()).sum(); + let mut result = Vec::with_capacity(total_len); + for vec in opened_values { + result.extend(vec); + } + + let points = proof.get_open_values(); + assert_eq!(points.len(), result.len()); + for (p, r) in points.iter().zip(result.iter()) { + if p != r { + return Err(BfError::InvalidOpenedValue); + } + } + + self.verify_taptree(proof, root) + } + fn verify_taptree( &self, proof: &Self::Proof, @@ -91,8 +155,9 @@ impl BFMmcs for TapTreeMmcs { (u256_to_u32(root), tree) } - fn get_matrices(&self, prover_data: &Self::ProverData) -> Vec> { - prover_data.leaves.clone() + + fn get_matrices<'a>(&self, prover_data: &'a Self::ProverData) -> Vec<&'a RowMajorMatrix> { + prover_data.leaves.iter().collect() } } diff --git a/scripts/Cargo.toml b/scripts/Cargo.toml index abd4cfe..33e0a9a 100644 --- a/scripts/Cargo.toml +++ b/scripts/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } -rust-bitcoin-u31-or-u30 ={ git = "https://github.com/bitlayer-org/rust-bitcoin-m31-or-babybear.git", branch = "bf-stark" } +rust-bitcoin-u31-or-u30 ={ git = "https://github.com/bitlayer-org/rust-bitcoin-m31-or-babybear.git", branch = "bf-pcs" } lazy_static = "1.4.0" rand_chacha = "0.3.1" diff --git a/scripts/src/lib.rs b/scripts/src/lib.rs index 52e4dfa..22c4694 100644 --- a/scripts/src/lib.rs +++ b/scripts/src/lib.rs @@ -27,8 +27,9 @@ pub mod u31_lib { define_pushable!(); pub use rust_bitcoin_u31_or_u30::{ - u31_add, u31_double, u31_mul, u31_sub, u31ext_add, u31ext_double, u31ext_equalverify, - u31ext_mul, u31ext_sub, BabyBear as BabyBearU31, BabyBear4, + u31_add, u31_double, u31_mul, u31_sub, u31_sub_u31ext, u31_to_u31ext, u31ext_add, + u31ext_add_u31, u31ext_double, u31ext_equalverify, u31ext_mul, u31ext_mul_u31, + u31ext_mul_u31_by_constant, u31ext_sub, u31ext_sub_u31, BabyBear as BabyBearU31, BabyBear4, }; pub fn u31_equalverify() -> Script { From dae8f0c6458db5311d0924cba936c7706e54c76c Mon Sep 17 00:00:00 2001 From: dylanCai9 <22110240060@m.fudan.edu.cn> Date: Mon, 8 Jul 2024 17:25:40 +0800 Subject: [PATCH 07/25] migrate p3 unistark (#17) * extend mmcs * fix query index * add two_adic_pcs && update fri * add two_adic_pcs * update two_adic_pcs * update permutation as Blake3Permutation for pcs-test * add script_manager for pcs and fri * fmt * update pcs-test and move fri-test * remove unuse comment and code * migrate p3 unistark * fix --------- Co-authored-by: cyl19970726 <15258378443@163.com> --- Cargo.lock | 126 ++++++++++ Cargo.toml | 3 +- fri/src/two_adic_pcs.rs | 3 +- fri/src/verifier.rs | 1 - primitives/src/mmcs/taptree_mmcs.rs | 5 +- uni-stark/Cargo.toml | 40 ++++ uni-stark/src/check_constraints.rs | 108 +++++++++ uni-stark/src/config.rs | 82 +++++++ uni-stark/src/folder.rs | 114 +++++++++ uni-stark/src/lib.rs | 30 +++ uni-stark/src/proof.rs | 40 ++++ uni-stark/src/prover.rs | 194 ++++++++++++++++ uni-stark/src/symbolic_builder.rs | 148 ++++++++++++ uni-stark/src/symbolic_expression.rs | 268 ++++++++++++++++++++++ uni-stark/src/symbolic_variable.rs | 142 ++++++++++++ uni-stark/src/verifier.rs | 167 ++++++++++++++ uni-stark/src/zerofier_coset.rs | 86 +++++++ uni-stark/tests/fib_air.rs | 187 +++++++++++++++ uni-stark/tests/mul_air.rs | 331 +++++++++++++++++++++++++++ 19 files changed, 2067 insertions(+), 8 deletions(-) create mode 100644 uni-stark/Cargo.toml create mode 100644 uni-stark/src/check_constraints.rs create mode 100644 uni-stark/src/config.rs create mode 100644 uni-stark/src/folder.rs create mode 100644 uni-stark/src/lib.rs create mode 100644 uni-stark/src/proof.rs create mode 100644 uni-stark/src/prover.rs create mode 100644 uni-stark/src/symbolic_builder.rs create mode 100644 uni-stark/src/symbolic_expression.rs create mode 100644 uni-stark/src/symbolic_variable.rs create mode 100644 uni-stark/src/verifier.rs create mode 100644 uni-stark/src/zerofier_coset.rs create mode 100644 uni-stark/tests/fib_air.rs create mode 100644 uni-stark/tests/mul_air.rs diff --git a/Cargo.lock b/Cargo.lock index 1e97872..52a1d2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,6 +44,15 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + [[package]] name = "anstream" version = "0.6.14" @@ -596,6 +605,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +[[package]] +name = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + [[package]] name = "colorchoice" version = "1.0.1" @@ -756,6 +771,12 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + [[package]] name = "encoding_rs" version = "0.8.34" @@ -1414,6 +1435,15 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" name = "p3" version = "0.1.0" +[[package]] +name = "p3-air" +version = "0.1.0" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +dependencies = [ + "p3-field", + "p3-matrix", +] + [[package]] name = "p3-baby-bear" version = "0.1.0" @@ -1449,6 +1479,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "p3-circle" +version = "0.1.0" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +dependencies = [ + "itertools 0.13.0", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "serde", + "tracing", +] + [[package]] name = "p3-commit" version = "0.1.0" @@ -1489,6 +1537,24 @@ dependencies = [ "serde", ] +[[package]] +name = "p3-fri" +version = "0.1.0" +source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +dependencies = [ + "itertools 0.13.0", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-interpolation", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "serde", + "tracing", +] + [[package]] name = "p3-goldilocks" version = "0.1.0" @@ -1703,6 +1769,17 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "postcard" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" +dependencies = [ + "cobs", + "embedded-io", + "serde", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -2495,6 +2572,19 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-forest" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee40835db14ddd1e3ba414292272eddde9dad04d3d4b65509656414d1c42592f" +dependencies = [ + "ansi_term", + "smallvec", + "thiserror", + "tracing", + "tracing-subscriber 0.3.18", +] + [[package]] name = "tracing-log" version = "0.2.0" @@ -2545,6 +2635,42 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "uni-stark" +version = "0.1.0" +dependencies = [ + "fri", + "itertools 0.13.0", + "p3-air", + "p3-baby-bear", + "p3-challenger", + "p3-circle", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-goldilocks", + "p3-keccak", + "p3-matrix", + "p3-maybe-rayon", + "p3-mds", + "p3-merkle-tree", + "p3-mersenne-31", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "postcard", + "primitives", + "rand", + "script_manager", + "scripts", + "segment", + "serde", + "tracing", + "tracing-forest", + "tracing-subscriber 0.3.18", +] + [[package]] name = "unicode-bidi" version = "0.3.15" diff --git a/Cargo.toml b/Cargo.toml index ea9749e..b834db6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "scripts", "script_manager", "segment", - "common" + "common", + "uni-stark" ] diff --git a/fri/src/two_adic_pcs.rs b/fri/src/two_adic_pcs.rs index 293f50f..aab2571 100644 --- a/fri/src/two_adic_pcs.rs +++ b/fri/src/two_adic_pcs.rs @@ -5,7 +5,7 @@ use core::fmt::Debug; use core::marker::PhantomData; use itertools::{izip, Itertools}; -use p3_challenger::{CanObserve, CanSample, GrindingChallenger}; +use p3_challenger::{CanObserve, CanSample}; use p3_commit::{OpenedValues, PolynomialSpace, TwoAdicMultiplicativeCoset}; use p3_dft::TwoAdicSubgroupDft; use p3_field::{ @@ -159,7 +159,6 @@ where shift: Val::one(), } } - fn commit( &self, evaluations: Vec<(Self::Domain, RowMajorMatrix)>, diff --git a/fri/src/verifier.rs b/fri/src/verifier.rs index 6f0e2e7..2379012 100644 --- a/fri/src/verifier.rs +++ b/fri/src/verifier.rs @@ -147,7 +147,6 @@ where let challenge_point: Point = open_leaf.get_point_by_index(point_index).unwrap().clone(); let sibling_point: Point = open_leaf.get_point_by_index(index_sibling).unwrap().clone(); - println!("challenge_point.y:{}", challenge_point.y); println!("sibling_point.y:{}", sibling_point.y); if log_folded_height < log_max_height - 1 { diff --git a/primitives/src/mmcs/taptree_mmcs.rs b/primitives/src/mmcs/taptree_mmcs.rs index 6c6be8e..e87d05f 100644 --- a/primitives/src/mmcs/taptree_mmcs.rs +++ b/primitives/src/mmcs/taptree_mmcs.rs @@ -51,10 +51,7 @@ impl CommitProof { pub fn verify_points_leaf(&self) -> bool { if let TapLeaf::Script(script, _ver) = self.leaf_node.leaf().clone() { - let res = execute_script_with_inputs( - script, - self.points_leaf.witness(), - ); + let res = execute_script_with_inputs(script, self.points_leaf.witness()); return res.success; } else { panic!("Invalid script") diff --git a/uni-stark/Cargo.toml b/uni-stark/Cargo.toml new file mode 100644 index 0000000..a6c00ff --- /dev/null +++ b/uni-stark/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "uni-stark" +version = "0.1.0" +edition = "2021" +license = "MIT OR Apache-2.0" + +[dependencies] +p3-air = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-field = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-commit ={ git = "https://github.com/Plonky3/Plonky3.git" } +p3-dft = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-matrix = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-maybe-rayon = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-util = { git = "https://github.com/Plonky3/Plonky3.git" } +itertools = "0.13.0" +tracing = "0.1.37" +serde = { version = "1.0", default-features = false, features = ["derive", "alloc"] } +scripts = { path = "../scripts"} +primitives = {path = "../primitives"} +segment ={ path = "../segment"} +script_manager = {path = "../script_manager"} +fri = { path = "../fri"} + + +[dev-dependencies] +p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-circle = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-fri = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-keccak = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-mds = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-merkle-tree = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-goldilocks = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-mersenne-31 = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-poseidon2 = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-symmetric = { git = "https://github.com/Plonky3/Plonky3.git" } +rand = "0.8.5" +tracing-subscriber = { version = "0.3.17", features = ["std", "env-filter"] } +tracing-forest = { version = "0.1.6", features = ["ansi", "smallvec"] } +postcard = { version = "1.0.0", default-features = false, features = ["alloc"] } diff --git a/uni-stark/src/check_constraints.rs b/uni-stark/src/check_constraints.rs new file mode 100644 index 0000000..1028ef9 --- /dev/null +++ b/uni-stark/src/check_constraints.rs @@ -0,0 +1,108 @@ +use alloc::vec::Vec; + +use p3_air::{Air, AirBuilder, AirBuilderWithPublicValues}; +use p3_field::Field; +use p3_matrix::dense::{RowMajorMatrix, RowMajorMatrixView}; +use p3_matrix::stack::VerticalPair; +use p3_matrix::Matrix; +use tracing::instrument; + +#[instrument(name = "check constraints", skip_all)] +pub(crate) fn check_constraints(air: &A, main: &RowMajorMatrix, public_values: &Vec) +where + F: Field, + A: for<'a> Air>, +{ + let height = main.height(); + + (0..height).for_each(|i| { + let i_next = (i + 1) % height; + + let local = main.row_slice(i); + let next = main.row_slice(i_next); + let main = VerticalPair::new( + RowMajorMatrixView::new_row(&*local), + RowMajorMatrixView::new_row(&*next), + ); + + let mut builder = DebugConstraintBuilder { + row_index: i, + main, + public_values, + is_first_row: F::from_bool(i == 0), + is_last_row: F::from_bool(i == height - 1), + is_transition: F::from_bool(i != height - 1), + }; + + air.eval(&mut builder); + }); +} + +/// An `AirBuilder` which asserts that each constraint is zero, allowing any failed constraints to +/// be detected early. +#[derive(Debug)] +pub struct DebugConstraintBuilder<'a, F: Field> { + row_index: usize, + main: VerticalPair, RowMajorMatrixView<'a, F>>, + public_values: &'a [F], + is_first_row: F, + is_last_row: F, + is_transition: F, +} + +impl<'a, F> AirBuilder for DebugConstraintBuilder<'a, F> +where + F: Field, +{ + type F = F; + type Expr = F; + type Var = F; + type M = VerticalPair, RowMajorMatrixView<'a, F>>; + + fn is_first_row(&self) -> Self::Expr { + self.is_first_row + } + + fn is_last_row(&self) -> Self::Expr { + self.is_last_row + } + + fn is_transition_window(&self, size: usize) -> Self::Expr { + if size == 2 { + self.is_transition + } else { + panic!("only supports a window size of 2") + } + } + + fn main(&self) -> Self::M { + self.main + } + + fn assert_zero>(&mut self, x: I) { + assert_eq!( + x.into(), + F::zero(), + "constraints had nonzero value on row {}", + self.row_index + ); + } + + fn assert_eq, I2: Into>(&mut self, x: I1, y: I2) { + let x = x.into(); + let y = y.into(); + assert_eq!( + x, y, + "values didn't match on row {}: {} != {}", + self.row_index, x, y + ); + } +} + +impl<'a, F: Field> AirBuilderWithPublicValues for DebugConstraintBuilder<'a, F> { + type PublicVar = Self::F; + + fn public_values(&self) -> &[Self::F] { + self.public_values + } +} diff --git a/uni-stark/src/config.rs b/uni-stark/src/config.rs new file mode 100644 index 0000000..452a8ee --- /dev/null +++ b/uni-stark/src/config.rs @@ -0,0 +1,82 @@ +use core::marker::PhantomData; + +use p3_challenger::{CanObserve, CanSample, FieldChallenger}; +use p3_commit::PolynomialSpace; +use p3_field::{ExtensionField, Field}; +use primitives::bf_pcs; +use primitives::bf_pcs::Pcs; +use primitives::challenger::BfGrindingChallenger; + +pub type PcsError = <::Pcs as Pcs< + ::Challenge, + ::Challenger, +>>::Error; + +pub type Domain = <::Pcs as Pcs< + ::Challenge, + ::Challenger, +>>::Domain; + +//TODO: Val: p3_field::Field, we need Val: BfField? +pub type Val = <<::Pcs as Pcs< + ::Challenge, + ::Challenger, +>>::Domain as PolynomialSpace>::Val; + +pub type PackedVal = as Field>::Packing; + +pub type PackedChallenge = + <::Challenge as ExtensionField>>::ExtensionPacking; + +pub trait StarkGenericConfig { + /// The PCS used to commit to trace polynomials. + type Pcs: Pcs; + + /// The field from which most random challenges are drawn. + type Challenge: ExtensionField>; + + /// The challenger (Fiat-Shamir) implementation used. + // type Challenger: FieldChallenger> + // + CanObserve<>::Commitment> + // + CanSample; + + // TODO: we need a field challenger too? + type Challenger: BfGrindingChallenger + + CanObserve<>::Commitment> + + CanSample; + // + CanObserve<<>::Domain as PolynomialSpace>::Val> + + fn pcs(&self) -> &Self::Pcs; +} + +#[derive(Debug)] +pub struct StarkConfig { + pcs: Pcs, + _phantom: PhantomData<(Challenge, Challenger)>, +} + +impl StarkConfig { + pub const fn new(pcs: Pcs) -> Self { + Self { + pcs, + _phantom: PhantomData, + } + } +} + +impl StarkGenericConfig for StarkConfig +where + Challenge: ExtensionField<::Val>, + Pcs: bf_pcs::Pcs, + Challenger: BfGrindingChallenger + + CanObserve<>::Commitment> + + CanSample, +{ + type Pcs = Pcs; + type Challenge = Challenge; + type Challenger = Challenger; + + fn pcs(&self) -> &Self::Pcs { + &self.pcs + } +} diff --git a/uni-stark/src/folder.rs b/uni-stark/src/folder.rs new file mode 100644 index 0000000..d7536b0 --- /dev/null +++ b/uni-stark/src/folder.rs @@ -0,0 +1,114 @@ +use alloc::vec::Vec; + +use p3_air::{AirBuilder, AirBuilderWithPublicValues}; +use p3_field::AbstractField; +use p3_matrix::dense::{RowMajorMatrix, RowMajorMatrixView}; +use p3_matrix::stack::VerticalPair; + +use crate::{PackedChallenge, PackedVal, StarkGenericConfig, Val}; + +#[derive(Debug)] +pub struct ProverConstraintFolder<'a, SC: StarkGenericConfig> { + pub main: RowMajorMatrix>, + pub public_values: &'a Vec>, + pub is_first_row: PackedVal, + pub is_last_row: PackedVal, + pub is_transition: PackedVal, + pub alpha: SC::Challenge, + pub accumulator: PackedChallenge, +} + +type ViewPair<'a, T> = VerticalPair, RowMajorMatrixView<'a, T>>; + +#[derive(Debug)] +pub struct VerifierConstraintFolder<'a, SC: StarkGenericConfig> { + pub main: ViewPair<'a, SC::Challenge>, + pub public_values: &'a Vec>, + pub is_first_row: SC::Challenge, + pub is_last_row: SC::Challenge, + pub is_transition: SC::Challenge, + pub alpha: SC::Challenge, + pub accumulator: SC::Challenge, +} + +impl<'a, SC: StarkGenericConfig> AirBuilder for ProverConstraintFolder<'a, SC> { + type F = Val; + type Expr = PackedVal; + type Var = PackedVal; + type M = RowMajorMatrix>; + + fn main(&self) -> Self::M { + self.main.clone() + } + + fn is_first_row(&self) -> Self::Expr { + self.is_first_row + } + + fn is_last_row(&self) -> Self::Expr { + self.is_last_row + } + + fn is_transition_window(&self, size: usize) -> Self::Expr { + if size == 2 { + self.is_transition + } else { + panic!("uni-stark only supports a window size of 2") + } + } + + fn assert_zero>(&mut self, x: I) { + let x: PackedVal = x.into(); + self.accumulator *= PackedChallenge::::from_f(self.alpha); + self.accumulator += x; + } +} + +impl<'a, SC: StarkGenericConfig> AirBuilderWithPublicValues for ProverConstraintFolder<'a, SC> { + type PublicVar = Self::F; + + fn public_values(&self) -> &[Self::F] { + self.public_values + } +} + +impl<'a, SC: StarkGenericConfig> AirBuilder for VerifierConstraintFolder<'a, SC> { + type F = Val; + type Expr = SC::Challenge; + type Var = SC::Challenge; + type M = ViewPair<'a, SC::Challenge>; + + fn main(&self) -> Self::M { + self.main + } + + fn is_first_row(&self) -> Self::Expr { + self.is_first_row + } + + fn is_last_row(&self) -> Self::Expr { + self.is_last_row + } + + fn is_transition_window(&self, size: usize) -> Self::Expr { + if size == 2 { + self.is_transition + } else { + panic!("uni-stark only supports a window size of 2") + } + } + + fn assert_zero>(&mut self, x: I) { + let x: SC::Challenge = x.into(); + self.accumulator *= self.alpha; + self.accumulator += x; + } +} + +impl<'a, SC: StarkGenericConfig> AirBuilderWithPublicValues for VerifierConstraintFolder<'a, SC> { + type PublicVar = Self::F; + + fn public_values(&self) -> &[Self::F] { + self.public_values + } +} diff --git a/uni-stark/src/lib.rs b/uni-stark/src/lib.rs new file mode 100644 index 0000000..488c8f2 --- /dev/null +++ b/uni-stark/src/lib.rs @@ -0,0 +1,30 @@ +//! A minimal univariate STARK framework. + +#![no_std] + +extern crate alloc; + +mod config; +mod folder; +mod proof; +mod prover; +mod symbolic_builder; +mod symbolic_expression; +mod symbolic_variable; +mod verifier; +mod zerofier_coset; + +#[cfg(debug_assertions)] +mod check_constraints; + +#[cfg(debug_assertions)] +pub use check_constraints::*; +pub use config::*; +pub use folder::*; +pub use proof::*; +pub use prover::*; +pub use symbolic_builder::*; +pub use symbolic_expression::*; +pub use symbolic_variable::*; +pub use verifier::*; +pub use zerofier_coset::*; diff --git a/uni-stark/src/proof.rs b/uni-stark/src/proof.rs new file mode 100644 index 0000000..5c3ac97 --- /dev/null +++ b/uni-stark/src/proof.rs @@ -0,0 +1,40 @@ +use alloc::vec::Vec; + +use primitives::bf_pcs::Pcs; + +// use serde::{Deserialize, Serialize}; +use crate::StarkGenericConfig; + +type Com = <::Pcs as Pcs< + ::Challenge, + ::Challenger, +>>::Commitment; +type PcsProof = <::Pcs as Pcs< + ::Challenge, + ::Challenger, +>>::Proof; + +// #[derive(Serialize, Deserialize)] +// #[serde(bound = "")] +#[derive(Clone)] +pub struct Proof { + pub(crate) commitments: Commitments>, + pub(crate) opened_values: OpenedValues, + pub(crate) opening_proof: PcsProof, + pub(crate) degree_bits: usize, +} + +// #[derive(Debug, Serialize, Deserialize)] +#[derive(Clone)] +pub struct Commitments { + pub(crate) trace: Com, + pub(crate) quotient_chunks: Com, +} + +// #[derive(Debug, Serialize, Deserialize)] +#[derive(Clone)] +pub struct OpenedValues { + pub(crate) trace_local: Vec, + pub(crate) trace_next: Vec, + pub(crate) quotient_chunks: Vec>, +} diff --git a/uni-stark/src/prover.rs b/uni-stark/src/prover.rs new file mode 100644 index 0000000..c542582 --- /dev/null +++ b/uni-stark/src/prover.rs @@ -0,0 +1,194 @@ +use alloc::vec; +use alloc::vec::Vec; +use core::iter; + +use itertools::{izip, Itertools}; +use p3_air::Air; +use p3_challenger::{CanObserve, CanSample}; +use p3_commit::PolynomialSpace; +use p3_field::{AbstractExtensionField, AbstractField, PackedValue}; +use p3_matrix::dense::RowMajorMatrix; +use p3_matrix::Matrix; +use p3_maybe_rayon::prelude::*; +use p3_util::log2_strict_usize; +use primitives::bf_pcs::Pcs; +use tracing::{info_span, instrument}; + +use crate::symbolic_builder::{get_log_quotient_degree, SymbolicAirBuilder}; +use crate::{ + Commitments, Domain, OpenedValues, PackedChallenge, PackedVal, Proof, ProverConstraintFolder, + StarkGenericConfig, Val, +}; + +#[instrument(skip_all)] +#[allow(clippy::multiple_bound_locations)] // cfg not supported in where clauses? +pub fn prove< + SC, + #[cfg(debug_assertions)] A: for<'a> Air>>, + #[cfg(not(debug_assertions))] A, +>( + config: &SC, + air: &A, + challenger: &mut SC::Challenger, + trace: RowMajorMatrix>, + public_values: &Vec>, +) -> Proof +where + SC: StarkGenericConfig, + A: Air>> + for<'a> Air>, +{ + #[cfg(debug_assertions)] + crate::check_constraints::check_constraints(air, &trace, public_values); + + let degree = trace.height(); + let log_degree = log2_strict_usize(degree); + + let log_quotient_degree = get_log_quotient_degree::, A>(air, 0, public_values.len()); + let quotient_degree = 1 << log_quotient_degree; + + let pcs = config.pcs(); + let trace_domain = pcs.natural_domain_for_degree(degree); + + let (trace_commit, trace_data) = + info_span!("commit to trace data").in_scope(|| pcs.commit(vec![(trace_domain, trace)])); + + // Observe the instance. + // TODO: recover observe when we have CanObserve + // challenger.observe(Val::::from_canonical_usize(log_degree)); + // TODO: Might be best practice to include other instance data here; see verifier comment. + + challenger.observe(trace_commit.clone()); + // challenger.observe_slice(public_values); + + let alpha: SC::Challenge = challenger.sample(); + + let quotient_domain = + trace_domain.create_disjoint_domain(1 << (log_degree + log_quotient_degree)); + + let trace_on_quotient_domain = pcs.get_evaluations_on_domain(&trace_data, 0, quotient_domain); + + let quotient_values = quotient_values( + air, + public_values, + trace_domain, + quotient_domain, + trace_on_quotient_domain, + alpha, + ); + let quotient_flat = RowMajorMatrix::new_col(quotient_values).flatten_to_base(); + let quotient_chunks = quotient_domain.split_evals(quotient_degree, quotient_flat); + let qc_domains = quotient_domain.split_domains(quotient_degree); + + let (quotient_commit, quotient_data) = info_span!("commit to quotient poly chunks") + .in_scope(|| pcs.commit(izip!(qc_domains, quotient_chunks).collect_vec())); + challenger.observe(quotient_commit.clone()); + + let commitments = Commitments { + trace: trace_commit, + quotient_chunks: quotient_commit, + }; + + let zeta: SC::Challenge = challenger.sample(); + let zeta_next = trace_domain.next_point(zeta).unwrap(); + + let (opened_values, opening_proof) = pcs.open( + vec![ + (&trace_data, vec![vec![zeta, zeta_next]]), + ( + "ient_data, + // open every chunk at zeta + (0..quotient_degree).map(|_| vec![zeta]).collect_vec(), + ), + ], + challenger, + ); + let trace_local = opened_values[0][0][0].clone(); + let trace_next = opened_values[0][0][1].clone(); + let quotient_chunks = opened_values[1].iter().map(|v| v[0].clone()).collect_vec(); + let opened_values = OpenedValues { + trace_local, + trace_next, + quotient_chunks, + }; + Proof { + commitments, + opened_values, + opening_proof, + degree_bits: log_degree, + } +} + +#[instrument(name = "compute quotient polynomial", skip_all)] +fn quotient_values( + air: &A, + public_values: &Vec>, + trace_domain: Domain, + quotient_domain: Domain, + trace_on_quotient_domain: Mat, + alpha: SC::Challenge, +) -> Vec +where + SC: StarkGenericConfig, + A: for<'a> Air>, + Mat: Matrix> + Sync, +{ + let quotient_size = quotient_domain.size(); + let width = trace_on_quotient_domain.width(); + let mut sels = trace_domain.selectors_on_coset(quotient_domain); + + let qdb = log2_strict_usize(quotient_domain.size()) - log2_strict_usize(trace_domain.size()); + let next_step = 1 << qdb; + + // We take PackedVal::::WIDTH worth of values at a time from a quotient_size slice, so we need to + // pad with default values in the case where quotient_size is smaller than PackedVal::::WIDTH. + for _ in quotient_size..PackedVal::::WIDTH { + sels.is_first_row.push(Val::::default()); + sels.is_last_row.push(Val::::default()); + sels.is_transition.push(Val::::default()); + sels.inv_zeroifier.push(Val::::default()); + } + + (0..quotient_size) + .into_par_iter() + .step_by(PackedVal::::WIDTH) + .flat_map_iter(|i_start| { + let i_range = i_start..i_start + PackedVal::::WIDTH; + + let is_first_row = *PackedVal::::from_slice(&sels.is_first_row[i_range.clone()]); + let is_last_row = *PackedVal::::from_slice(&sels.is_last_row[i_range.clone()]); + let is_transition = *PackedVal::::from_slice(&sels.is_transition[i_range.clone()]); + let inv_zeroifier = *PackedVal::::from_slice(&sels.inv_zeroifier[i_range.clone()]); + + let main = RowMajorMatrix::new( + iter::empty() + .chain(trace_on_quotient_domain.vertically_packed_row(i_start)) + .chain(trace_on_quotient_domain.vertically_packed_row(i_start + next_step)) + .collect_vec(), + width, + ); + + let accumulator = PackedChallenge::::zero(); + let mut folder = ProverConstraintFolder { + main, + public_values, + is_first_row, + is_last_row, + is_transition, + alpha, + accumulator, + }; + air.eval(&mut folder); + + // quotient(x) = constraints(x) / Z_H(x) + let quotient = folder.accumulator * inv_zeroifier; + + // "Transpose" D packed base coefficients into WIDTH scalar extension coefficients. + (0..core::cmp::min(quotient_size, PackedVal::::WIDTH)).map(move |idx_in_packing| { + let quotient_value = (0..>>::D) + .map(|coeff_idx| quotient.as_base_slice()[coeff_idx].as_slice()[idx_in_packing]) + .collect::>(); + SC::Challenge::from_base_slice("ient_value) + }) + }) + .collect() +} diff --git a/uni-stark/src/symbolic_builder.rs b/uni-stark/src/symbolic_builder.rs new file mode 100644 index 0000000..1b106c6 --- /dev/null +++ b/uni-stark/src/symbolic_builder.rs @@ -0,0 +1,148 @@ +use alloc::vec; +use alloc::vec::Vec; + +use p3_air::{Air, AirBuilder, AirBuilderWithPublicValues, PairBuilder}; +use p3_field::Field; +use p3_matrix::dense::RowMajorMatrix; +use p3_util::log2_ceil_usize; +use tracing::instrument; + +use crate::symbolic_expression::SymbolicExpression; +use crate::symbolic_variable::SymbolicVariable; +use crate::Entry; + +#[instrument(name = "infer log of constraint degree", skip_all)] +pub fn get_log_quotient_degree( + air: &A, + preprocessed_width: usize, + num_public_values: usize, +) -> usize +where + F: Field, + A: Air>, +{ + // We pad to at least degree 2, since a quotient argument doesn't make sense with smaller degrees. + let constraint_degree = + get_max_constraint_degree(air, preprocessed_width, num_public_values).max(2); + + // The quotient's actual degree is approximately (max_constraint_degree - 1) n, + // where subtracting 1 comes from division by the zerofier. + // But we pad it to a power of two so that we can efficiently decompose the quotient. + log2_ceil_usize(constraint_degree - 1) +} + +#[instrument(name = "infer constraint degree", skip_all, level = "debug")] +pub fn get_max_constraint_degree( + air: &A, + preprocessed_width: usize, + num_public_values: usize, +) -> usize +where + F: Field, + A: Air>, +{ + get_symbolic_constraints(air, preprocessed_width, num_public_values) + .iter() + .map(|c| c.degree_multiple()) + .max() + .unwrap_or(0) +} + +#[instrument(name = "evaluate constraints symbolically", skip_all, level = "debug")] +pub fn get_symbolic_constraints( + air: &A, + preprocessed_width: usize, + num_public_values: usize, +) -> Vec> +where + F: Field, + A: Air>, +{ + let mut builder = SymbolicAirBuilder::new(preprocessed_width, air.width(), num_public_values); + air.eval(&mut builder); + builder.constraints() +} + +/// An `AirBuilder` for evaluating constraints symbolically, and recording them for later use. +#[derive(Debug)] +pub struct SymbolicAirBuilder { + preprocessed: RowMajorMatrix>, + main: RowMajorMatrix>, + public_values: Vec>, + constraints: Vec>, +} + +impl SymbolicAirBuilder { + pub(crate) fn new(preprocessed_width: usize, width: usize, num_public_values: usize) -> Self { + let prep_values = [0, 1] + .into_iter() + .flat_map(|offset| { + (0..preprocessed_width) + .map(move |index| SymbolicVariable::new(Entry::Preprocessed { offset }, index)) + }) + .collect(); + let main_values = [0, 1] + .into_iter() + .flat_map(|offset| { + (0..width).map(move |index| SymbolicVariable::new(Entry::Main { offset }, index)) + }) + .collect(); + let public_values = (0..num_public_values) + .map(move |index| SymbolicVariable::new(Entry::Public, index)) + .collect(); + Self { + preprocessed: RowMajorMatrix::new(prep_values, preprocessed_width), + main: RowMajorMatrix::new(main_values, width), + public_values, + constraints: vec![], + } + } + + pub(crate) fn constraints(self) -> Vec> { + self.constraints + } +} + +impl AirBuilder for SymbolicAirBuilder { + type F = F; + type Expr = SymbolicExpression; + type Var = SymbolicVariable; + type M = RowMajorMatrix; + + fn main(&self) -> Self::M { + self.main.clone() + } + + fn is_first_row(&self) -> Self::Expr { + SymbolicExpression::IsFirstRow + } + + fn is_last_row(&self) -> Self::Expr { + SymbolicExpression::IsLastRow + } + + fn is_transition_window(&self, size: usize) -> Self::Expr { + if size == 2 { + SymbolicExpression::IsTransition + } else { + panic!("uni-stark only supports a window size of 2") + } + } + + fn assert_zero>(&mut self, x: I) { + self.constraints.push(x.into()); + } +} + +impl AirBuilderWithPublicValues for SymbolicAirBuilder { + type PublicVar = SymbolicVariable; + fn public_values(&self) -> &[Self::PublicVar] { + &self.public_values + } +} + +impl PairBuilder for SymbolicAirBuilder { + fn preprocessed(&self) -> Self::M { + self.preprocessed.clone() + } +} diff --git a/uni-stark/src/symbolic_expression.rs b/uni-stark/src/symbolic_expression.rs new file mode 100644 index 0000000..498bf96 --- /dev/null +++ b/uni-stark/src/symbolic_expression.rs @@ -0,0 +1,268 @@ +use alloc::rc::Rc; +use core::fmt::Debug; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +use p3_field::{AbstractField, Field}; + +use crate::symbolic_variable::SymbolicVariable; + +/// An expression over `SymbolicVariable`s. +#[derive(Clone, Debug)] +pub enum SymbolicExpression { + Variable(SymbolicVariable), + IsFirstRow, + IsLastRow, + IsTransition, + Constant(F), + Add { + x: Rc, + y: Rc, + degree_multiple: usize, + }, + Sub { + x: Rc, + y: Rc, + degree_multiple: usize, + }, + Neg { + x: Rc, + degree_multiple: usize, + }, + Mul { + x: Rc, + y: Rc, + degree_multiple: usize, + }, +} + +impl SymbolicExpression { + /// Returns the multiple of `n` (the trace length) in this expression's degree. + pub const fn degree_multiple(&self) -> usize { + match self { + SymbolicExpression::Variable(v) => v.degree_multiple(), + SymbolicExpression::IsFirstRow => 1, + SymbolicExpression::IsLastRow => 1, + SymbolicExpression::IsTransition => 0, + SymbolicExpression::Constant(_) => 0, + SymbolicExpression::Add { + degree_multiple, .. + } => *degree_multiple, + SymbolicExpression::Sub { + degree_multiple, .. + } => *degree_multiple, + SymbolicExpression::Neg { + degree_multiple, .. + } => *degree_multiple, + SymbolicExpression::Mul { + degree_multiple, .. + } => *degree_multiple, + } + } +} + +impl Default for SymbolicExpression { + fn default() -> Self { + Self::Constant(F::zero()) + } +} + +impl From for SymbolicExpression { + fn from(value: F) -> Self { + Self::Constant(value) + } +} + +impl AbstractField for SymbolicExpression { + type F = F; + + fn zero() -> Self { + Self::Constant(F::zero()) + } + fn one() -> Self { + Self::Constant(F::one()) + } + fn two() -> Self { + Self::Constant(F::two()) + } + fn neg_one() -> Self { + Self::Constant(F::neg_one()) + } + + #[inline] + fn from_f(f: Self::F) -> Self { + f.into() + } + + fn from_bool(b: bool) -> Self { + Self::Constant(F::from_bool(b)) + } + + fn from_canonical_u8(n: u8) -> Self { + Self::Constant(F::from_canonical_u8(n)) + } + + fn from_canonical_u16(n: u16) -> Self { + Self::Constant(F::from_canonical_u16(n)) + } + + fn from_canonical_u32(n: u32) -> Self { + Self::Constant(F::from_canonical_u32(n)) + } + + fn from_canonical_u64(n: u64) -> Self { + Self::Constant(F::from_canonical_u64(n)) + } + + fn from_canonical_usize(n: usize) -> Self { + Self::Constant(F::from_canonical_usize(n)) + } + + fn from_wrapped_u32(n: u32) -> Self { + Self::Constant(F::from_wrapped_u32(n)) + } + + fn from_wrapped_u64(n: u64) -> Self { + Self::Constant(F::from_wrapped_u64(n)) + } + + fn generator() -> Self { + Self::Constant(F::generator()) + } +} + +impl Add for SymbolicExpression { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + let degree_multiple = self.degree_multiple().max(rhs.degree_multiple()); + Self::Add { + x: Rc::new(self), + y: Rc::new(rhs), + degree_multiple, + } + } +} + +impl Add for SymbolicExpression { + type Output = Self; + + fn add(self, rhs: F) -> Self { + self + Self::from(rhs) + } +} + +impl AddAssign for SymbolicExpression { + fn add_assign(&mut self, rhs: Self) { + *self = self.clone() + rhs; + } +} + +impl AddAssign for SymbolicExpression { + fn add_assign(&mut self, rhs: F) { + *self += Self::from(rhs); + } +} + +impl Sum for SymbolicExpression { + fn sum>(iter: I) -> Self { + iter.reduce(|x, y| x + y).unwrap_or(Self::zero()) + } +} + +impl Sum for SymbolicExpression { + fn sum>(iter: I) -> Self { + iter.map(|x| Self::from(x)).sum() + } +} + +impl Sub for SymbolicExpression { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + let degree_multiple = self.degree_multiple().max(rhs.degree_multiple()); + Self::Sub { + x: Rc::new(self), + y: Rc::new(rhs), + degree_multiple, + } + } +} + +impl Sub for SymbolicExpression { + type Output = Self; + + fn sub(self, rhs: F) -> Self { + self - Self::from(rhs) + } +} + +impl SubAssign for SymbolicExpression { + fn sub_assign(&mut self, rhs: Self) { + *self = self.clone() - rhs; + } +} + +impl SubAssign for SymbolicExpression { + fn sub_assign(&mut self, rhs: F) { + *self -= Self::from(rhs); + } +} + +impl Neg for SymbolicExpression { + type Output = Self; + + fn neg(self) -> Self { + let degree_multiple = self.degree_multiple(); + Self::Neg { + x: Rc::new(self), + degree_multiple, + } + } +} + +impl Mul for SymbolicExpression { + type Output = Self; + + fn mul(self, rhs: Self) -> Self { + #[allow(clippy::suspicious_arithmetic_impl)] + let degree_multiple = self.degree_multiple() + rhs.degree_multiple(); + Self::Mul { + x: Rc::new(self), + y: Rc::new(rhs), + degree_multiple, + } + } +} + +impl Mul for SymbolicExpression { + type Output = Self; + + fn mul(self, rhs: F) -> Self { + self * Self::from(rhs) + } +} + +impl MulAssign for SymbolicExpression { + fn mul_assign(&mut self, rhs: Self) { + *self = self.clone() * rhs; + } +} + +impl MulAssign for SymbolicExpression { + fn mul_assign(&mut self, rhs: F) { + *self *= Self::from(rhs); + } +} + +impl Product for SymbolicExpression { + fn product>(iter: I) -> Self { + iter.reduce(|x, y| x * y).unwrap_or(Self::one()) + } +} + +impl Product for SymbolicExpression { + fn product>(iter: I) -> Self { + iter.map(|x| Self::from(x)).product() + } +} diff --git a/uni-stark/src/symbolic_variable.rs b/uni-stark/src/symbolic_variable.rs new file mode 100644 index 0000000..7a3b8ad --- /dev/null +++ b/uni-stark/src/symbolic_variable.rs @@ -0,0 +1,142 @@ +use core::marker::PhantomData; +use core::ops::{Add, Mul, Sub}; + +use p3_field::Field; + +use crate::symbolic_expression::SymbolicExpression; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum Entry { + Preprocessed { offset: usize }, + Main { offset: usize }, + Permutation { offset: usize }, + Public, + Challenge, +} + +/// A variable within the evaluation window, i.e. a column in either the local or next row. +#[derive(Copy, Clone, Debug)] +pub struct SymbolicVariable { + pub entry: Entry, + pub index: usize, + pub(crate) _phantom: PhantomData, +} + +impl SymbolicVariable { + pub const fn new(entry: Entry, index: usize) -> Self { + Self { + entry, + index, + _phantom: PhantomData, + } + } + + pub const fn degree_multiple(&self) -> usize { + match self.entry { + Entry::Preprocessed { .. } | Entry::Main { .. } | Entry::Permutation { .. } => 1, + Entry::Public | Entry::Challenge => 0, + } + } +} + +impl From> for SymbolicExpression { + fn from(value: SymbolicVariable) -> Self { + SymbolicExpression::Variable(value) + } +} + +impl Add for SymbolicVariable { + type Output = SymbolicExpression; + + fn add(self, rhs: Self) -> Self::Output { + SymbolicExpression::from(self) + SymbolicExpression::from(rhs) + } +} + +impl Add for SymbolicVariable { + type Output = SymbolicExpression; + + fn add(self, rhs: F) -> Self::Output { + SymbolicExpression::from(self) + SymbolicExpression::from(rhs) + } +} + +impl Add> for SymbolicVariable { + type Output = SymbolicExpression; + + fn add(self, rhs: SymbolicExpression) -> Self::Output { + SymbolicExpression::from(self) + rhs + } +} + +impl Add> for SymbolicExpression { + type Output = Self; + + fn add(self, rhs: SymbolicVariable) -> Self::Output { + self + Self::from(rhs) + } +} + +impl Sub for SymbolicVariable { + type Output = SymbolicExpression; + + fn sub(self, rhs: Self) -> Self::Output { + SymbolicExpression::from(self) - SymbolicExpression::from(rhs) + } +} + +impl Sub for SymbolicVariable { + type Output = SymbolicExpression; + + fn sub(self, rhs: F) -> Self::Output { + SymbolicExpression::from(self) - SymbolicExpression::from(rhs) + } +} + +impl Sub> for SymbolicVariable { + type Output = SymbolicExpression; + + fn sub(self, rhs: SymbolicExpression) -> Self::Output { + SymbolicExpression::from(self) - rhs + } +} + +impl Sub> for SymbolicExpression { + type Output = Self; + + fn sub(self, rhs: SymbolicVariable) -> Self::Output { + self - Self::from(rhs) + } +} + +impl Mul for SymbolicVariable { + type Output = SymbolicExpression; + + fn mul(self, rhs: Self) -> Self::Output { + SymbolicExpression::from(self) * SymbolicExpression::from(rhs) + } +} + +impl Mul for SymbolicVariable { + type Output = SymbolicExpression; + + fn mul(self, rhs: F) -> Self::Output { + SymbolicExpression::from(self) * SymbolicExpression::from(rhs) + } +} + +impl Mul> for SymbolicVariable { + type Output = SymbolicExpression; + + fn mul(self, rhs: SymbolicExpression) -> Self::Output { + SymbolicExpression::from(self) * rhs + } +} + +impl Mul> for SymbolicExpression { + type Output = Self; + + fn mul(self, rhs: SymbolicVariable) -> Self::Output { + self * Self::from(rhs) + } +} diff --git a/uni-stark/src/verifier.rs b/uni-stark/src/verifier.rs new file mode 100644 index 0000000..5d8b459 --- /dev/null +++ b/uni-stark/src/verifier.rs @@ -0,0 +1,167 @@ +use alloc::vec; +use alloc::vec::Vec; + +use itertools::Itertools; +use p3_air::{Air, BaseAir}; +use p3_challenger::{CanObserve, CanSample}; +use p3_commit::PolynomialSpace; +use p3_field::{AbstractExtensionField, AbstractField, Field}; +use p3_matrix::dense::RowMajorMatrixView; +use p3_matrix::stack::VerticalPair; +use primitives::bf_pcs::Pcs; +use script_manager::script_info::ScriptInfo; +use tracing::instrument; + +use crate::symbolic_builder::{get_log_quotient_degree, SymbolicAirBuilder}; +use crate::{PcsError, Proof, StarkGenericConfig, Val, VerifierConstraintFolder}; + +#[instrument(skip_all)] +pub fn verify( + config: &SC, + air: &A, + challenger: &mut SC::Challenger, + proof: &Proof, + public_values: &Vec>, + script_managers: &mut Vec, +) -> Result<(), VerificationError>> +where + SC: StarkGenericConfig, + A: Air>> + for<'a> Air>, +{ + let Proof { + commitments, + opened_values, + opening_proof, + degree_bits, + } = proof; + + let degree = 1 << degree_bits; + let log_quotient_degree = get_log_quotient_degree::, A>(air, 0, public_values.len()); + let quotient_degree = 1 << log_quotient_degree; + + let pcs = config.pcs(); + let trace_domain = pcs.natural_domain_for_degree(degree); + let quotient_domain = + trace_domain.create_disjoint_domain(1 << (degree_bits + log_quotient_degree)); + let quotient_chunks_domains = quotient_domain.split_domains(quotient_degree); + + let air_width = >>::width(air); + let valid_shape = opened_values.trace_local.len() == air_width + && opened_values.trace_next.len() == air_width + && opened_values.quotient_chunks.len() == quotient_degree + && opened_values + .quotient_chunks + .iter() + .all(|qc| qc.len() == >>::D); + if !valid_shape { + return Err(VerificationError::InvalidProofShape); + } + + // Observe the instance. // TODO: recover observe when we have CanObserve trait + // challenger.observe(Val::::from_canonical_usize(proof.degree_bits)); + // TODO: Might be best practice to include other instance data here in the transcript, like some + // encoding of the AIR. This protects against transcript collisions between distinct instances. + // Practically speaking though, the only related known attack is from failing to include public + // values. It's not clear if failing to include other instance data could enable a transcript + // collision, since most such changes would completely change the set of satisfying witnesses. + + challenger.observe(commitments.trace.clone()); + // challenger.observe_slice(public_values); + let alpha: SC::Challenge = challenger.sample(); + challenger.observe(commitments.quotient_chunks.clone()); + + let zeta: SC::Challenge = challenger.sample(); + let zeta_next = trace_domain.next_point(zeta).unwrap(); + + pcs.verify( + vec![ + ( + commitments.trace.clone(), + vec![( + trace_domain, + vec![ + (zeta, opened_values.trace_local.clone()), + (zeta_next, opened_values.trace_next.clone()), + ], + )], + ), + ( + commitments.quotient_chunks.clone(), + quotient_chunks_domains + .iter() + .zip(&opened_values.quotient_chunks) + .map(|(domain, values)| (*domain, vec![(zeta, values.clone())])) + .collect_vec(), + ), + ], + opening_proof, + challenger, + script_managers, + ) + .map_err(VerificationError::InvalidOpeningArgument)?; + + let zps = quotient_chunks_domains + .iter() + .enumerate() + .map(|(i, domain)| { + quotient_chunks_domains + .iter() + .enumerate() + .filter(|(j, _)| *j != i) + .map(|(_, other_domain)| { + other_domain.zp_at_point(zeta) + * other_domain.zp_at_point(domain.first_point()).inverse() + }) + .product::() + }) + .collect_vec(); + + let quotient = opened_values + .quotient_chunks + .iter() + .enumerate() + .map(|(ch_i, ch)| { + ch.iter() + .enumerate() + .map(|(e_i, &c)| zps[ch_i] * SC::Challenge::monomial(e_i) * c) + .sum::() + }) + .sum::(); + + let sels = trace_domain.selectors_at_point(zeta); + + let main = VerticalPair::new( + RowMajorMatrixView::new_row(&opened_values.trace_local), + RowMajorMatrixView::new_row(&opened_values.trace_next), + ); + + let mut folder = VerifierConstraintFolder { + main, + public_values, + is_first_row: sels.is_first_row, + is_last_row: sels.is_last_row, + is_transition: sels.is_transition, + alpha, + accumulator: SC::Challenge::zero(), + }; + air.eval(&mut folder); + let folded_constraints = folder.accumulator; + + // Finally, check that + // folded_constraints(zeta) / Z_H(zeta) = quotient(zeta) + if folded_constraints * sels.inv_zeroifier != quotient { + return Err(VerificationError::OodEvaluationMismatch); + } + + Ok(()) +} + +#[derive(Debug)] +pub enum VerificationError { + InvalidProofShape, + /// An error occurred while verifying the claimed openings. + InvalidOpeningArgument(PcsErr), + /// Out-of-domain evaluation mismatch, i.e. `constraints(zeta)` did not match + /// `quotient(zeta) Z_H(zeta)`. + OodEvaluationMismatch, +} diff --git a/uni-stark/src/zerofier_coset.rs b/uni-stark/src/zerofier_coset.rs new file mode 100644 index 0000000..a396742 --- /dev/null +++ b/uni-stark/src/zerofier_coset.rs @@ -0,0 +1,86 @@ +use alloc::vec::Vec; + +use itertools::Itertools; +use p3_field::{ + batch_multiplicative_inverse, cyclic_subgroup_coset_known_order, Field, PackedField, + TwoAdicField, +}; +use primitives::field::BfField; + +/// Precomputations of the evaluation of `Z_H(X) = X^n - 1` on a coset `s K` with `H <= K`. +#[derive(Debug)] +pub struct ZerofierOnCoset { + /// `n = |H|`. + log_n: usize, + /// `rate = |K|/|H|`. + rate_bits: usize, + coset_shift: F, + /// Holds `g^n * (w^n)^i - 1 = g^n * v^i - 1` for `i in 0..rate`, with `w` a generator of `K` and `v` a + /// `rate`-primitive root of unity. + evals: Vec, + /// Holds the multiplicative inverses of `evals`. + inverses: Vec, +} + +impl ZerofierOnCoset { + pub fn new(log_n: usize, rate_bits: usize, coset_shift: F) -> Self { + let s_pow_n = coset_shift.exp_power_of_2(log_n); + let evals = F::two_adic_generator(rate_bits) + .powers() + .take(1 << rate_bits) + .map(|x| s_pow_n * x - F::one()) + .collect::>(); + let inverses = batch_multiplicative_inverse(&evals); + Self { + log_n, + rate_bits, + coset_shift, + evals, + inverses, + } + } + + /// Returns `Z_H(g * w^i)`. + pub fn eval(&self, i: usize) -> F { + self.evals[i & ((1 << self.rate_bits) - 1)] + } + + /// Returns `1 / Z_H(g * w^i)`. + pub fn eval_inverse(&self, i: usize) -> F { + self.inverses[i & ((1 << self.rate_bits) - 1)] + } + + /// Like `eval_inverse`, but for a range of indices starting with `i_start`. + pub fn eval_inverse_packed>(&self, i_start: usize) -> P { + let mut packed = P::zero(); + packed + .as_slice_mut() + .iter_mut() + .enumerate() + .for_each(|(j, packed_j)| *packed_j = self.eval_inverse(i_start + j)); + packed + } + + /// Evaluate the Langrange basis polynomial, `L_i(x) = Z_H(x) / (x - g_H^i)`, on our coset `s K`. + /// Here `L_i(x)` is unnormalized in the sense that it evaluates to some nonzero value at `g_H^i`, + /// not necessarily 1. + pub fn lagrange_basis_unnormalized(&self, i: usize) -> Vec { + let log_coset_size = self.log_n + self.rate_bits; + let coset_size = 1 << log_coset_size; + let g_h = F::two_adic_generator(self.log_n); + let g_k = F::two_adic_generator(log_coset_size); + + let target_point = g_h.exp_u64(i as u64); + let denominators = cyclic_subgroup_coset_known_order(g_k, self.coset_shift, coset_size) + .map(|x| x - target_point) + .collect_vec(); + let inverses = batch_multiplicative_inverse(&denominators); + + self.evals + .iter() + .cycle() + .zip(inverses) + .map(|(&z_h, inv)| z_h * inv) + .collect() + } +} diff --git a/uni-stark/tests/fib_air.rs b/uni-stark/tests/fib_air.rs new file mode 100644 index 0000000..fefe196 --- /dev/null +++ b/uni-stark/tests/fib_air.rs @@ -0,0 +1,187 @@ +use std::borrow::Borrow; + +use fri::{FriConfig, TwoAdicFriPcs}; +use p3_air::{Air, AirBuilder, AirBuilderWithPublicValues, BaseAir}; +use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; +use p3_commit::ExtensionMmcs; +use p3_dft::Radix2DitParallel; +use p3_field::extension::BinomialExtensionField; +use p3_field::{AbstractField, Field, PrimeField64}; +use p3_matrix::dense::RowMajorMatrix; +use p3_matrix::Matrix; +use p3_merkle_tree::FieldMerkleTreeMmcs; +use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral}; +use p3_symmetric::{PaddingFreeSponge, TruncatedPermutation}; +use primitives::challenger::chan_field::U32; +// use p3_challenger::DuplexChallenger; +use primitives::challenger::{BfChallenger, Blake3Permutation}; +use primitives::mmcs::taptree_mmcs::TapTreeMmcs; +use rand::thread_rng; +use uni_stark::{prove, verify, StarkConfig}; + +/// For testing the public values feature + +pub struct FibonacciAir {} + +impl BaseAir for FibonacciAir { + fn width(&self) -> usize { + NUM_FIBONACCI_COLS + } +} + +impl Air for FibonacciAir { + fn eval(&self, builder: &mut AB) { + let main = builder.main(); + let pis = builder.public_values(); + + let a = pis[0]; + let b = pis[1]; + let x = pis[2]; + + let (local, next) = (main.row_slice(0), main.row_slice(1)); + let local: &FibonacciRow = (*local).borrow(); + let next: &FibonacciRow = (*next).borrow(); + + let mut when_first_row = builder.when_first_row(); + + when_first_row.assert_eq(local.left, a); + when_first_row.assert_eq(local.right, b); + + let mut when_transition = builder.when_transition(); + + // a' <- b + when_transition.assert_eq(local.right, next.left); + + // b' <- a + b + when_transition.assert_eq(local.left + local.right, next.right); + + builder.when_last_row().assert_eq(local.right, x); + } +} + +pub fn generate_trace_rows(a: u64, b: u64, n: usize) -> RowMajorMatrix { + assert!(n.is_power_of_two()); + + let mut trace = + RowMajorMatrix::new(vec![F::zero(); n * NUM_FIBONACCI_COLS], NUM_FIBONACCI_COLS); + + let (prefix, rows, suffix) = unsafe { trace.values.align_to_mut::>() }; + assert!(prefix.is_empty(), "Alignment should match"); + assert!(suffix.is_empty(), "Alignment should match"); + assert_eq!(rows.len(), n); + + rows[0] = FibonacciRow::new(F::from_canonical_u64(a), F::from_canonical_u64(b)); + + for i in 1..n { + rows[i].left = rows[i - 1].right; + rows[i].right = rows[i - 1].left + rows[i - 1].right; + } + + trace +} + +const NUM_FIBONACCI_COLS: usize = 2; + +pub struct FibonacciRow { + pub left: F, + pub right: F, +} + +impl FibonacciRow { + const fn new(left: F, right: F) -> FibonacciRow { + FibonacciRow { left, right } + } +} + +impl Borrow> for [F] { + fn borrow(&self) -> &FibonacciRow { + debug_assert_eq!(self.len(), NUM_FIBONACCI_COLS); + let (prefix, shorts, suffix) = unsafe { self.align_to::>() }; + debug_assert!(prefix.is_empty(), "Alignment should match"); + debug_assert!(suffix.is_empty(), "Alignment should match"); + debug_assert_eq!(shorts.len(), 1); + &shorts[0] + } +} + +type PF = U32; +const WIDTH: usize = 16; + +type Val = BabyBear; +type Challenge = BinomialExtensionField; +type ValMmcs = TapTreeMmcs; +type ChallengeMmcs = TapTreeMmcs; +type Challenger = BfChallenger; + +type Dft = Radix2DitParallel; +type Pcs = TwoAdicFriPcs; +type MyConfig = StarkConfig; + +#[test] +fn test_public_value() { + let val_mmcs = ValMmcs::new(); + let challenge_mmcs = ChallengeMmcs::new(); + let dft = Dft {}; + let trace = generate_trace_rows::(0, 1, 1 << 3); + let fri_config = FriConfig { + log_blowup: 2, + num_queries: 28, + proof_of_work_bits: 8, + mmcs: challenge_mmcs, + }; + let pcs = Pcs::new(dft, val_mmcs, fri_config); + let config = MyConfig::new(pcs); + let permutation = Blake3Permutation {}; + let mut challenger = Challenger::new(permutation).unwrap(); + let pis = vec![ + BabyBear::from_canonical_u64(0), + BabyBear::from_canonical_u64(1), + BabyBear::from_canonical_u64(21), + ]; + let proof = prove(&config, &FibonacciAir {}, &mut challenger, trace, &pis); + + let permutation = Blake3Permutation {}; + let mut challenger = Challenger::new(permutation).unwrap(); + let mut script_manager = vec![]; + verify( + &config, + &FibonacciAir {}, + &mut challenger, + &proof, + &pis, + &mut script_manager, + ) + .expect("verification failed"); +} + +// #[cfg(debug_assertions)] +// #[test] +// #[should_panic(expected = "assertion `left == right` failed: constraints had nonzero value")] +// fn test_incorrect_public_value() { +// let perm = Perm::new_from_rng_128( +// Poseidon2ExternalMatrixGeneral, +// DiffusionMatrixBabyBear, +// &mut thread_rng(), +// ); +// let hash = MyHash::new(perm.clone()); +// let compress = MyCompress::new(perm.clone()); +// let val_mmcs = ValMmcs::new(hash, compress); +// let challenge_mmcs = ChallengeMmcs::new(val_mmcs.clone()); +// let dft = Dft {}; +// let fri_config = FriConfig { +// log_blowup: 2, +// num_queries: 28, +// proof_of_work_bits: 8, +// mmcs: challenge_mmcs, +// }; +// let trace = generate_trace_rows::(0, 1, 1 << 3); +// let pcs = Pcs::new(dft, val_mmcs, fri_config); +// let config = MyConfig::new(pcs); +// let mut challenger = Challenger::new(perm.clone()); +// let pis = vec![ +// BabyBear::from_canonical_u64(0), +// BabyBear::from_canonical_u64(1), +// BabyBear::from_canonical_u64(123_123), // incorrect result +// ]; +// prove(&config, &FibonacciAir {}, &mut challenger, trace, &pis); +// } diff --git a/uni-stark/tests/mul_air.rs b/uni-stark/tests/mul_air.rs new file mode 100644 index 0000000..5f9210d --- /dev/null +++ b/uni-stark/tests/mul_air.rs @@ -0,0 +1,331 @@ +// use std::fmt::Debug; +// use std::marker::PhantomData; + +// use itertools::Itertools; +// use p3_air::{Air, AirBuilder, BaseAir}; +// use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; +// use p3_challenger::{DuplexChallenger, HashChallenger, SerializingChallenger32}; +// use p3_circle::{Cfft, CirclePcs}; +// use p3_commit::testing::TrivialPcs; +// use p3_commit::ExtensionMmcs; +// use p3_dft::Radix2DitParallel; +// use p3_field::extension::BinomialExtensionField; +// use p3_field::{AbstractField, Field}; +// use p3_fri::{FriConfig, TwoAdicFriPcs}; +// use p3_keccak::Keccak256Hash; +// use p3_matrix::dense::RowMajorMatrix; +// use p3_matrix::Matrix; +// use p3_merkle_tree::FieldMerkleTreeMmcs; +// use p3_mersenne_31::Mersenne31; +// use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral}; +// use p3_symmetric::{ +// CompressionFunctionFromHasher, PaddingFreeSponge, SerializingHasher32, TruncatedPermutation, +// }; +// use p3_uni_stark::{prove, verify, StarkConfig, StarkGenericConfig, Val}; +// use rand::distributions::{Distribution, Standard}; +// use rand::{thread_rng, Rng}; + +// /// How many `a * b = c` operations to do per row in the AIR. +// const REPETITIONS: usize = 20; +// const TRACE_WIDTH: usize = REPETITIONS * 3; + +// /* +// In its basic form, asserts a^(self.degree-1) * b = c +// (so that the total constraint degree is self.degree) + +// If `uses_transition_constraints`, checks that on transition rows, the first a = row number +// */ +// pub struct MulAir { +// degree: u64, +// uses_boundary_constraints: bool, +// uses_transition_constraints: bool, +// } + +// impl Default for MulAir { +// fn default() -> Self { +// MulAir { +// degree: 3, +// uses_boundary_constraints: true, +// uses_transition_constraints: true, +// } +// } +// } + +// impl MulAir { +// pub fn random_valid_trace(&self, rows: usize, valid: bool) -> RowMajorMatrix +// where +// Standard: Distribution, +// { +// let mut rng = thread_rng(); +// let mut trace_values = vec![F::default(); rows * TRACE_WIDTH]; +// for (i, (a, b, c)) in trace_values.iter_mut().tuples().enumerate() { +// let row = i / REPETITIONS; + +// *a = if self.uses_transition_constraints { +// F::from_canonical_usize(i) +// } else { +// rng.gen() +// }; +// *b = if self.uses_boundary_constraints && row == 0 { +// a.square() + F::one() +// } else { +// rng.gen() +// }; +// *c = a.exp_u64(self.degree - 1) * *b; + +// if !valid { +// // make it invalid +// *c *= F::two(); +// } +// } +// RowMajorMatrix::new(trace_values, TRACE_WIDTH) +// } +// } + +// impl BaseAir for MulAir { +// fn width(&self) -> usize { +// TRACE_WIDTH +// } +// } + +// impl Air for MulAir { +// fn eval(&self, builder: &mut AB) { +// let main = builder.main(); +// let main_local = main.row_slice(0); +// let main_next = main.row_slice(1); + +// for i in 0..REPETITIONS { +// let start = i * 3; +// let a = main_local[start]; +// let b = main_local[start + 1]; +// let c = main_local[start + 2]; +// builder.assert_zero(a.into().exp_u64(self.degree - 1) * b - c); +// if self.uses_boundary_constraints { +// builder +// .when_first_row() +// .assert_eq(a * a + AB::Expr::one(), b); +// } +// if self.uses_transition_constraints { +// let next_a = main_next[start]; +// builder +// .when_transition() +// .assert_eq(a + AB::Expr::from_canonical_usize(REPETITIONS), next_a); +// } +// } +// } +// } + +// fn do_test( +// config: SC, +// air: MulAir, +// log_height: usize, +// challenger: SC::Challenger, +// ) -> Result<(), impl Debug> +// where +// SC::Challenger: Clone, +// Standard: Distribution>, +// { +// let trace = air.random_valid_trace(log_height, true); + +// let mut p_challenger = challenger.clone(); +// let proof = prove(&config, &air, &mut p_challenger, trace, &vec![]); + +// let serialized_proof = postcard::to_allocvec(&proof).expect("unable to serialize proof"); +// tracing::debug!("serialized_proof len: {} bytes", serialized_proof.len()); + +// let deserialized_proof = +// postcard::from_bytes(&serialized_proof).expect("unable to deserialize proof"); + +// let mut v_challenger = challenger.clone(); +// verify( +// &config, +// &air, +// &mut v_challenger, +// &deserialized_proof, +// &vec![], +// ) +// } + +// fn do_test_bb_trivial(degree: u64, log_n: usize) -> Result<(), impl Debug> { +// type Val = BabyBear; +// type Challenge = BinomialExtensionField; + +// type Perm = Poseidon2; +// let perm = Perm::new_from_rng_128( +// Poseidon2ExternalMatrixGeneral, +// DiffusionMatrixBabyBear, +// &mut thread_rng(), +// ); + +// type Dft = Radix2DitParallel; +// let dft = Dft {}; + +// type Challenger = DuplexChallenger; + +// type Pcs = TrivialPcs; +// let pcs = TrivialPcs { +// dft, +// log_n, +// _phantom: PhantomData, +// }; + +// type MyConfig = StarkConfig; +// let config = MyConfig::new(pcs); + +// let air = MulAir { +// degree, +// ..Default::default() +// }; + +// do_test(config, air, 1 << log_n, Challenger::new(perm)) +// } + +// #[test] +// fn prove_bb_trivial_deg2() -> Result<(), impl Debug> { +// do_test_bb_trivial(2, 8) +// } + +// #[test] +// fn prove_bb_trivial_deg3() -> Result<(), impl Debug> { +// do_test_bb_trivial(3, 8) +// } + +// #[test] +// fn prove_bb_trivial_deg4() -> Result<(), impl Debug> { +// do_test_bb_trivial(4, 8) +// } + +// fn do_test_bb_twoadic(log_blowup: usize, degree: u64, log_n: usize) -> Result<(), impl Debug> { +// type Val = BabyBear; +// type Challenge = BinomialExtensionField; + +// type Perm = Poseidon2; +// let perm = Perm::new_from_rng_128( +// Poseidon2ExternalMatrixGeneral, +// DiffusionMatrixBabyBear, +// &mut thread_rng(), +// ); + +// type MyHash = PaddingFreeSponge; +// let hash = MyHash::new(perm.clone()); + +// type MyCompress = TruncatedPermutation; +// let compress = MyCompress::new(perm.clone()); + +// type ValMmcs = FieldMerkleTreeMmcs< +// ::Packing, +// ::Packing, +// MyHash, +// MyCompress, +// 8, +// >; +// let val_mmcs = ValMmcs::new(hash, compress); + +// type ChallengeMmcs = ExtensionMmcs; +// let challenge_mmcs = ChallengeMmcs::new(val_mmcs.clone()); + +// type Dft = Radix2DitParallel; +// let dft = Dft {}; + +// type Challenger = DuplexChallenger; + +// let fri_config = FriConfig { +// log_blowup, +// num_queries: 40, +// proof_of_work_bits: 8, +// mmcs: challenge_mmcs, +// }; +// type Pcs = TwoAdicFriPcs; +// let pcs = Pcs::new(dft, val_mmcs, fri_config); + +// type MyConfig = StarkConfig; +// let config = MyConfig::new(pcs); + +// let air = MulAir { +// degree, +// ..Default::default() +// }; + +// do_test(config, air, 1 << log_n, Challenger::new(perm)) +// } + +// #[test] +// fn prove_bb_twoadic_deg2() -> Result<(), impl Debug> { +// do_test_bb_twoadic(1, 2, 7) +// } + +// #[test] +// fn prove_bb_twoadic_deg3() -> Result<(), impl Debug> { +// do_test_bb_twoadic(1, 3, 7) +// } + +// #[test] +// fn prove_bb_twoadic_deg4() -> Result<(), impl Debug> { +// do_test_bb_twoadic(2, 4, 6) +// } + +// #[test] +// fn prove_bb_twoadic_deg5() -> Result<(), impl Debug> { +// do_test_bb_twoadic(2, 5, 6) +// } + +// fn do_test_m31_circle(log_blowup: usize, degree: u64, log_n: usize) -> Result<(), impl Debug> { +// type Val = Mersenne31; +// type Challenge = BinomialExtensionField; + +// type ByteHash = Keccak256Hash; +// type FieldHash = SerializingHasher32; +// let byte_hash = ByteHash {}; +// let field_hash = FieldHash::new(byte_hash); + +// type MyCompress = CompressionFunctionFromHasher; +// let compress = MyCompress::new(byte_hash); + +// type ValMmcs = FieldMerkleTreeMmcs; +// let val_mmcs = ValMmcs::new(field_hash, compress); + +// type ChallengeMmcs = ExtensionMmcs; +// let challenge_mmcs = ChallengeMmcs::new(val_mmcs.clone()); + +// type Challenger = SerializingChallenger32>; + +// let fri_config = FriConfig { +// log_blowup, +// num_queries: 40, +// proof_of_work_bits: 8, +// mmcs: challenge_mmcs, +// }; + +// type Pcs = CirclePcs; +// let pcs = Pcs { +// cfft: Cfft::default(), +// mmcs: val_mmcs, +// fri_config, +// }; + +// type MyConfig = StarkConfig; +// let config = MyConfig::new(pcs); + +// let air = MulAir { +// degree, +// uses_boundary_constraints: true, +// uses_transition_constraints: true, +// }; + +// do_test( +// config, +// air, +// 1 << log_n, +// Challenger::from_hasher(vec![], byte_hash), +// ) +// } + +// #[test] +// fn prove_m31_circle_deg2() -> Result<(), impl Debug> { +// do_test_m31_circle(1, 2, 8) +// } + +// #[test] +// fn prove_m31_circle_deg3() -> Result<(), impl Debug> { +// do_test_m31_circle(1, 3, 9) +// } From 519960e9eba82689b2ff32cc4d2842efb8fab186 Mon Sep 17 00:00:00 2001 From: 0xhhh <52317293+cyl19970726@users.noreply.github.com> Date: Tue, 9 Jul 2024 14:45:50 +0800 Subject: [PATCH 08/25] add scripts_expression (#19) --- Cargo.lock | 241 +++--- scripts/src/lib.rs | 5 +- uni-stark/Cargo.toml | 6 +- uni-stark/src/lib.rs | 2 + uni-stark/src/scripts_expression.rs | 1143 +++++++++++++++++++++++++++ 5 files changed, 1292 insertions(+), 105 deletions(-) create mode 100644 uni-stark/src/scripts_expression.rs diff --git a/Cargo.lock b/Cargo.lock index 52a1d2a..c0a1e62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -391,7 +391,7 @@ dependencies = [ [[package]] name = "bitcoin-script-stack" version = "0.0.1" -source = "git+https://github.com/bitlayer-org/rust-bitcoin-script-stack#8e85b5253597cd2af564d68e9830d87127a87e25" +source = "git+https://github.com/bitlayer-org/rust-bitcoin-script-stack.git#67a7b0009b16da4c7de6e0329af671f38b440df0" dependencies = [ "bitcoin", "bitcoin-script", @@ -417,9 +417,9 @@ dependencies = [ [[package]] name = "bitcoin-units" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb54da0b28892f3c52203a7191534033e051b6f4b52bc15480681b57b7e036f5" +checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" dependencies = [ "bitcoin-internals", "serde", @@ -444,9 +444,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bitvm" @@ -528,9 +528,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.100" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c891175c3fb232128f48de6590095e59198bbeb8620c310be349bfc3afd12c7b" +checksum = "5208975e568d83b6b05cc0a063c8e7e9acc2b43bee6da15616a5b73e109d7437" [[package]] name = "cfg-if" @@ -567,9 +567,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.7" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" +checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d" dependencies = [ "clap_builder", "clap_derive", @@ -577,9 +577,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.7" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" +checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708" dependencies = [ "anstream", "anstyle", @@ -589,14 +589,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.5" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" +checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.69", ] [[package]] @@ -767,9 +767,9 @@ dependencies = [ [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "embedded-io" @@ -1225,9 +1225,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "matchers" @@ -1311,9 +1311,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -1362,9 +1362,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" dependencies = [ "memchr", ] @@ -1377,9 +1377,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "openssl" @@ -1387,7 +1387,7 @@ version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cfg-if", "foreign-types", "libc", @@ -1404,7 +1404,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.69", ] [[package]] @@ -1438,7 +1438,7 @@ version = "0.1.0" [[package]] name = "p3-air" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "p3-field", "p3-matrix", @@ -1447,11 +1447,12 @@ dependencies = [ [[package]] name = "p3-baby-bear" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "num-bigint", "p3-field", "p3-mds", + "p3-monty-31", "p3-poseidon2", "p3-symmetric", "rand", @@ -1461,7 +1462,7 @@ dependencies = [ [[package]] name = "p3-blake3" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "blake3", "p3-symmetric", @@ -1470,7 +1471,7 @@ dependencies = [ [[package]] name = "p3-challenger" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "p3-field", "p3-maybe-rayon", @@ -1482,7 +1483,7 @@ dependencies = [ [[package]] name = "p3-circle" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "itertools 0.13.0", "p3-challenger", @@ -1500,7 +1501,7 @@ dependencies = [ [[package]] name = "p3-commit" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "itertools 0.13.0", "p3-challenger", @@ -1513,7 +1514,7 @@ dependencies = [ [[package]] name = "p3-dft" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "p3-field", "p3-matrix", @@ -1525,7 +1526,7 @@ dependencies = [ [[package]] name = "p3-field" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "itertools 0.13.0", "num-bigint", @@ -1540,7 +1541,7 @@ dependencies = [ [[package]] name = "p3-fri" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "itertools 0.13.0", "p3-challenger", @@ -1558,7 +1559,7 @@ dependencies = [ [[package]] name = "p3-goldilocks" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "num-bigint", "p3-dft", @@ -1574,7 +1575,7 @@ dependencies = [ [[package]] name = "p3-interpolation" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "p3-field", "p3-matrix", @@ -1584,7 +1585,7 @@ dependencies = [ [[package]] name = "p3-keccak" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "p3-symmetric", "tiny-keccak", @@ -1593,7 +1594,7 @@ dependencies = [ [[package]] name = "p3-matrix" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "itertools 0.13.0", "p3-field", @@ -1602,17 +1603,18 @@ dependencies = [ "rand", "serde", "tracing", + "transpose", ] [[package]] name = "p3-maybe-rayon" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" [[package]] name = "p3-mds" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "itertools 0.12.1", "p3-dft", @@ -1626,7 +1628,7 @@ dependencies = [ [[package]] name = "p3-merkle-tree" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "itertools 0.13.0", "p3-commit", @@ -1642,7 +1644,7 @@ dependencies = [ [[package]] name = "p3-mersenne-31" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "itertools 0.13.0", "num-bigint", @@ -1658,10 +1660,24 @@ dependencies = [ "serde", ] +[[package]] +name = "p3-monty-31" +version = "0.1.0" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" +dependencies = [ + "num-bigint", + "p3-field", + "p3-mds", + "p3-poseidon2", + "p3-symmetric", + "rand", + "serde", +] + [[package]] name = "p3-poseidon2" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "gcd", "p3-field", @@ -1673,7 +1689,7 @@ dependencies = [ [[package]] name = "p3-symmetric" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "itertools 0.13.0", "p3-field", @@ -1683,7 +1699,7 @@ dependencies = [ [[package]] name = "p3-util" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#7bb6db50594e159010f11c97d110aa3ee121069b" +source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" dependencies = [ "serde", ] @@ -1708,7 +1724,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -1915,7 +1931,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] @@ -2006,7 +2022,7 @@ dependencies = [ [[package]] name = "rust-bitcoin-u31-or-u30" version = "0.1.0" -source = "git+https://github.com/bitlayer-org/rust-bitcoin-m31-or-babybear.git?branch=bf-pcs#81cd06773e38e0b0421a0342f0d58ecf05967ae9" +source = "git+https://github.com/bitlayer-org/rust-bitcoin-m31-or-babybear.git?branch=bf-pcs#ad90ef3e27f94bc69cf6d64fd3bde82128be2040" dependencies = [ "ark-ff", "bitcoin", @@ -2041,7 +2057,7 @@ version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -2172,7 +2188,7 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -2207,9 +2223,9 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] @@ -2227,20 +2243,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.69", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "itoa", "ryu", @@ -2313,6 +2329,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "strength_reduce" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" + [[package]] name = "strsim" version = "0.11.1" @@ -2335,14 +2357,14 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.68", + "syn 2.0.69", ] [[package]] name = "subtle" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d0208408ba0c3df17ed26eb06992cb1a1268d41b2c0e12e65203fbe3972cee5" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -2357,9 +2379,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.68" +version = "2.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" +checksum = "201fcda3845c23e8212cd466bfebf0bd20694490fc0356ae8e428e0824a915a6" dependencies = [ "proc-macro2", "quote", @@ -2422,7 +2444,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.69", ] [[package]] @@ -2456,9 +2478,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "ce6b6a2fb3a985e99cebfaefa9faa3024743da73304ca1c683a36429613d3d22" dependencies = [ "tinyvec_macros", ] @@ -2496,7 +2518,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.69", ] [[package]] @@ -2559,7 +2581,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.69", ] [[package]] @@ -2623,6 +2645,16 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "transpose" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad61aed86bc3faea4300c7aee358b4c6d0c8d6ccc36524c96e4c92ccf26e77e" +dependencies = [ + "num-integer", + "strength_reduce", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -2639,6 +2671,11 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" name = "uni-stark" version = "0.1.0" dependencies = [ + "bitcoin", + "bitcoin-script", + "bitcoin-script-stack", + "bitcoin-scriptexec", + "common", "fri", "itertools 0.13.0", "p3-air", @@ -2773,7 +2810,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.69", "wasm-bindgen-shared", ] @@ -2807,7 +2844,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.69", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2874,7 +2911,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -2894,18 +2931,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -2916,9 +2953,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -2928,9 +2965,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -2940,15 +2977,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -2958,9 +2995,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -2970,9 +3007,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -2982,9 +3019,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -2994,9 +3031,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winreg" @@ -3010,22 +3047,22 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.69", ] [[package]] @@ -3045,5 +3082,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.69", ] diff --git a/scripts/src/lib.rs b/scripts/src/lib.rs index 22c4694..bf779e2 100644 --- a/scripts/src/lib.rs +++ b/scripts/src/lib.rs @@ -27,9 +27,10 @@ pub mod u31_lib { define_pushable!(); pub use rust_bitcoin_u31_or_u30::{ - u31_add, u31_double, u31_mul, u31_sub, u31_sub_u31ext, u31_to_u31ext, u31ext_add, + u31_add, u31_double, u31_mul, u31_neg, u31_sub, u31_sub_u31ext, u31_to_u31ext, u31ext_add, u31ext_add_u31, u31ext_double, u31ext_equalverify, u31ext_mul, u31ext_mul_u31, - u31ext_mul_u31_by_constant, u31ext_sub, u31ext_sub_u31, BabyBear as BabyBearU31, BabyBear4, + u31ext_mul_u31_by_constant, u31ext_neg, u31ext_sub, u31ext_sub_u31, + BabyBear as BabyBearU31, BabyBear4, U31Config, U31ExtConfig, }; pub fn u31_equalverify() -> Script { diff --git a/uni-stark/Cargo.toml b/uni-stark/Cargo.toml index a6c00ff..533d6cd 100644 --- a/uni-stark/Cargo.toml +++ b/uni-stark/Cargo.toml @@ -5,6 +5,10 @@ edition = "2021" license = "MIT OR Apache-2.0" [dependencies] +bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git"} +bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } +bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } +bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } p3-air = { git = "https://github.com/Plonky3/Plonky3.git" } p3-field = { git = "https://github.com/Plonky3/Plonky3.git" } p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git" } @@ -21,7 +25,7 @@ primitives = {path = "../primitives"} segment ={ path = "../segment"} script_manager = {path = "../script_manager"} fri = { path = "../fri"} - +common = {path = "../common"} [dev-dependencies] p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } diff --git a/uni-stark/src/lib.rs b/uni-stark/src/lib.rs index 488c8f2..31ed40c 100644 --- a/uni-stark/src/lib.rs +++ b/uni-stark/src/lib.rs @@ -8,6 +8,7 @@ mod config; mod folder; mod proof; mod prover; +mod scripts_expression; mod symbolic_builder; mod symbolic_expression; mod symbolic_variable; @@ -23,6 +24,7 @@ pub use config::*; pub use folder::*; pub use proof::*; pub use prover::*; +pub use scripts_expression::*; pub use symbolic_builder::*; pub use symbolic_expression::*; pub use symbolic_variable::*; diff --git a/uni-stark/src/scripts_expression.rs b/uni-stark/src/scripts_expression.rs new file mode 100644 index 0000000..76e8dbe --- /dev/null +++ b/uni-stark/src/scripts_expression.rs @@ -0,0 +1,1143 @@ +use alloc::boxed::Box; +use alloc::collections::BTreeMap; +use alloc::rc::Rc; +use alloc::sync::Arc; +use alloc::vec::Vec; +use alloc::{format, vec}; +use core::cell::Cell; +use core::fmt::Debug; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +use bitcoin::hashes::cmp; +use bitcoin::opcodes::OP_ROLL; +use bitcoin_script_stack::stack::{StackTracker, StackVariable}; +use common::{AbstractField, AsU32Vec}; +use p3_field::Field; +use primitives::field::BfField; +use script_primitives::*; +use scripts::treepp::*; +use scripts::u31_lib::{ + u31_add, u31_double, u31_mul, u31_neg, u31_sub, u31_sub_u31ext, u31_to_u31ext, u31ext_add, + u31ext_add_u31, u31ext_double, u31ext_equalverify, u31ext_mul, u31ext_mul_u31, + u31ext_mul_u31_by_constant, u31ext_neg, u31ext_sub, u31ext_sub_u31, BabyBear4, BabyBearU31, +}; + +use crate::symbolic_variable::SymbolicVariable; +use crate::Entry; +use crate::SymbolicExpression::{self, *}; + +pub mod script_primitives { + use bitcoin_script_stack::stack::{StackTracker, StackVariable}; +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct Variable { + row_index: usize, + column_index: usize, +} + +impl From> for Variable { + fn from(value: SymbolicVariable) -> Self { + match value.entry { + Entry::Main { offset } => Variable { + row_index: value.index, + column_index: offset, + }, + Entry::Permutation { offset } => Variable { + row_index: value.index, + column_index: offset, + }, + Entry::Preprocessed { offset } => Variable { + row_index: value.index, + column_index: offset, + }, + _ => panic!("error type"), + } + } +} + +impl From<&SymbolicVariable> for Variable { + fn from(value: &SymbolicVariable) -> Self { + match value.entry { + Entry::Main { offset } => Variable { + row_index: value.index, + column_index: offset, + }, + Entry::Permutation { offset } => Variable { + row_index: value.index, + column_index: offset, + }, + Entry::Preprocessed { offset } => Variable { + row_index: value.index, + column_index: offset, + }, + _ => panic!("error type"), + } + } +} + +pub trait Expression { + fn express_to_script( + &self, + stack: &mut StackTracker, + input_variables: &BTreeMap<&Variable, StackVariable>, + ) -> Script; + + fn var_size(&self) -> u32; + + #[allow(unused)] + fn set_debug(&self); +} + +impl Expression for ScriptExpression { + fn set_debug(&self) { + match self { + ScriptExpression::InputVariable { debug, .. } => { + debug.set(true); + } + ScriptExpression::Constant(f) => {} + ScriptExpression::Add { debug, .. } => { + debug.set(true); + } + ScriptExpression::Sub { debug, .. } => { + debug.set(true); + } + ScriptExpression::Neg { debug, .. } => { + debug.set(true); + } + ScriptExpression::Mul { debug, .. } => { + debug.set(true); + } + }; + } + + fn express_to_script( + &self, + stack: &mut StackTracker, + input_variables: &BTreeMap<&Variable, StackVariable>, + ) -> Script { + match self { + ScriptExpression::InputVariable { sv, debug } => { + let var = input_variables.get(sv).unwrap(); + stack.copy_var(var.clone()); + stack.debug(); + } + ScriptExpression::Constant(f) => { + let v = f.as_u32_vec(); + stack.bignumber(v); + } + ScriptExpression::Add { + x, + y, + debug, + mut var, + } => { + x.express_to_script(stack, input_variables); // F + y.express_to_script(stack, input_variables); // EF + if debug.get() == true { + stack.debug(); + } + if x.var_size() == y.var_size() { + let vars = stack + .custom1( + script! { + if x.var_size() == 1{ + {u31_add::()} + }else{ + {u31ext_add::()} + } + }, + 2, + 1, + 0, + F::U32_SIZE as u32, + "ExprADD_Result", + ) + .unwrap(); + var = vars[0]; + assert_eq!(var.size(), x.var_size() as u32); + } else { + let mut script = Script::default(); + if x.var_size() > y.var_size() { + script = script! { + {u31ext_add_u31::()} + }; + } else { + script = script! { + 4 OP_ROLL + {u31ext_add_u31::()} + }; + } + let output_var_size = x.var_size().max(y.var_size()); + let vars = stack + .custom1( + script, + 2, // consumes 2 variable, one size is 4 and the other size is 1 + 1, // the output variable size is 4 + 0, + output_var_size, + "ExprADD_Result", + ) + .unwrap(); + var = vars[0]; + assert_eq!(var.size(), output_var_size as u32); + } + if debug.get() == true { + stack.debug(); + } + } + ScriptExpression::Sub { + x, + y, + debug, + mut var, + } => { + x.express_to_script(stack, input_variables); + y.express_to_script(stack, input_variables); + if debug.get() == true { + stack.debug(); + } + if x.var_size() == y.var_size() { + let vars = stack + .custom1( + script! { + if F::U32_SIZE == 1{ + {u31_sub::()} + }else{ + {u31ext_sub::()} + } + }, + 2, + 1, + 0, + F::U32_SIZE as u32, + "ExprSUB_Result", + ) + .unwrap(); + var = vars[0]; + } else { + let mut script = Script::default(); + if debug.get() == true { + stack.debug(); + } + + if x.var_size() > y.var_size() { + script = script! { + {u31ext_sub_u31::()} + }; + } else { + script = script! { + 4 OP_ROLL + {u31_sub_u31ext::()} + }; + } + let vars = stack + .custom1( + script, + 2, // consumes 2 variable, one size is 4 and the other size is 1 + 1, // the size of output variable is 4 + 0, + F::U32_SIZE as u32, + "ExprSUB_Result", + ) + .unwrap(); + var = vars[0]; + } + + if debug.get() == true { + stack.debug(); + } + assert_eq!(var.size(), F::U32_SIZE as u32); + } + ScriptExpression::Neg { x, debug, mut var } => { + x.express_to_script(stack, input_variables); + if debug.get() == true { + stack.debug(); + } + let vars = stack + .custom1( + script! { + if F::U32_SIZE == 1{ + {u31_neg::()} + }else{ + {u31ext_neg::()} + } + }, + 1, + 1, + 0, + F::U32_SIZE as u32, + "ExprNEG_Result", + ) + .unwrap(); + var = vars[0]; + if debug.get() == true { + stack.debug(); + } + assert_eq!(var.size(), F::U32_SIZE as u32); + } + ScriptExpression::Mul { + x, + y, + debug, + mut var, + } => { + x.express_to_script(stack, input_variables); + y.express_to_script(stack, input_variables); + if debug.get() == true { + stack.debug(); + } + if x.var_size() == y.var_size() { + let vars = stack + .custom1( + script! { + if F::U32_SIZE == 1{ + {u31_mul::()} + }else{ + {u31ext_mul::()} + } + }, + 2, + 1, + 0, + F::U32_SIZE as u32, + "ExprMUL_Result", + ) + .unwrap(); + var = vars[0]; + } else { + let mut script = Script::default(); + + if x.var_size() > y.var_size() { + script = script! { + {u31ext_mul_u31::()} + }; + } else { + script = script! { + 4 OP_ROLL + {u31ext_mul_u31::()} + }; + } + let vars = stack + .custom1( + script, + 2, // consumes 2 variable, one size is 4 and the other size is 1 + 1, // the size of output variable is 4 + 0, + F::U32_SIZE as u32, + "ExprMUL_Result", + ) + .unwrap(); + var = vars[0]; + } + if debug.get() == true { + stack.debug(); + } + assert_eq!(var.size(), F::U32_SIZE as u32); + } + }; + + stack.get_script() + } + + fn var_size(&self) -> u32 { + F::U32_SIZE as u32 + } +} + +pub enum ScriptExpression { + InputVariable { + sv: Variable, + debug: Cell, + }, + Constant(F), + Add { + x: Arc>, + y: Arc>, + var: StackVariable, + debug: Cell, + }, + Sub { + x: Arc>, + y: Arc>, + var: StackVariable, + debug: Cell, + }, + Neg { + x: Arc>, + var: StackVariable, + debug: Cell, + }, + Mul { + x: Arc>, + y: Arc>, + var: StackVariable, + debug: Cell, + }, +} + +impl From<&SymbolicExpression> for ScriptExpression { + fn from(value: &SymbolicExpression) -> Self { + match value { + SymbolicExpression::Variable(v) => ScriptExpression::InputVariable { + sv: v.into(), + debug: Cell::new(false), + }, + SymbolicExpression::IsFirstRow => ScriptExpression::one(), + SymbolicExpression::IsLastRow => ScriptExpression::one(), + SymbolicExpression::IsTransition => ScriptExpression::one(), + SymbolicExpression::Constant(f) => ScriptExpression::Constant(f.clone()), + SymbolicExpression::Add { x, y, .. } => ScriptExpression::Add { + x: Arc::new(Box::new(ScriptExpression::from(&*x.clone()))), + y: Arc::new(Box::new(ScriptExpression::from(&*y.clone()))), + debug: Cell::new(false), + var: StackVariable::null(), + }, + SymbolicExpression::Sub { x, y, .. } => ScriptExpression::Sub { + x: Arc::new(Box::new(ScriptExpression::from(&*x.clone()))), + y: Arc::new(Box::new(ScriptExpression::from(&*y.clone()))), + debug: Cell::new(false), + var: StackVariable::null(), + }, + SymbolicExpression::Neg { x, .. } => ScriptExpression::Neg { + x: Arc::new(Box::new(ScriptExpression::from(&*x.clone()))), + debug: Cell::new(false), + var: StackVariable::null(), + }, + SymbolicExpression::Mul { x, y, .. } => ScriptExpression::Mul { + x: Arc::new(Box::new(ScriptExpression::from(&*x.clone()))), + y: Arc::new(Box::new(ScriptExpression::from(&*y.clone()))), + debug: Cell::new(false), + var: StackVariable::null(), + }, + } + } +} + +impl Default for ScriptExpression { + fn default() -> Self { + Self::Constant(F::zero()) + } +} + +impl From for ScriptExpression { + fn from(value: F) -> Self { + Self::Constant(value) + } +} + +impl Debug for ScriptExpression { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + ScriptExpression::InputVariable { sv, .. } => f + .debug_struct("ScriptExpression::InputVariable") + .field("sv", sv) + .finish(), + ScriptExpression::Constant(value) => f + .debug_struct("ScriptExpression::Constant") + .field("value", value) + .finish(), + ScriptExpression::Add { x, y, debug, var } => f + .debug_struct("ScriptExpression::Add") + .field("variable", var) + .finish(), + ScriptExpression::Sub { x, y, debug, var } => f + .debug_struct("ScriptExpression::Sub") + .field("variable", var) + .finish(), + ScriptExpression::Mul { x, y, debug, var } => f + .debug_struct("ScriptExpression::Mul") + .field("variable", var) + .finish(), + ScriptExpression::Neg { x, debug, var } => f + .debug_struct("ScriptExpression::Neg") + .field("variable", var) + .finish(), + } + } +} + +impl Clone for ScriptExpression { + fn clone(&self) -> Self { + match self { + ScriptExpression::InputVariable { sv, debug } => ScriptExpression::InputVariable { + sv: sv.clone(), + debug: debug.clone(), + }, + ScriptExpression::Constant(value) => ScriptExpression::Constant(value.clone()), + ScriptExpression::Add { x, y, debug, var } => ScriptExpression::Add { + x: x.clone(), + y: y.clone(), + debug: debug.clone(), + var: var.clone(), + }, + ScriptExpression::Mul { x, y, debug, var } => ScriptExpression::Mul { + x: x.clone(), + y: y.clone(), + debug: debug.clone(), + var: var.clone(), + }, + ScriptExpression::Sub { x, y, debug, var } => ScriptExpression::Sub { + x: x.clone(), + y: y.clone(), + debug: debug.clone(), + var: var.clone(), + }, + ScriptExpression::Neg { x, debug, var } => ScriptExpression::Neg { + x: x.clone(), + debug: debug.clone(), + var: var.clone(), + }, + } + } +} + +impl AbstractField for ScriptExpression { + type F = F; + + fn zero() -> Self { + Self::Constant(F::zero()) + } + fn one() -> Self { + Self::Constant(F::one()) + } + fn two() -> Self { + Self::Constant(F::two()) + } + fn neg_one() -> Self { + Self::Constant(F::neg_one()) + } + + #[inline] + fn from_f(f: Self::F) -> Self { + f.into() + } + + fn from_bool(b: bool) -> Self { + Self::Constant(F::from_bool(b)) + } + + fn from_canonical_u8(n: u8) -> Self { + Self::Constant(F::from_canonical_u8(n)) + } + + fn from_canonical_u16(n: u16) -> Self { + Self::Constant(F::from_canonical_u16(n)) + } + + fn from_canonical_u32(n: u32) -> Self { + Self::Constant(F::from_canonical_u32(n)) + } + + fn from_canonical_u64(n: u64) -> Self { + Self::Constant(F::from_canonical_u64(n)) + } + + fn from_canonical_usize(n: usize) -> Self { + Self::Constant(F::from_canonical_usize(n)) + } + + fn from_wrapped_u32(n: u32) -> Self { + Self::Constant(F::from_wrapped_u32(n)) + } + + fn from_wrapped_u64(n: u64) -> Self { + Self::Constant(F::from_wrapped_u64(n)) + } + + fn generator() -> Self { + Self::Constant(F::generator()) + } +} + +impl Add for ScriptExpression { + type Output = Self; + + fn add(self, rhs: F) -> Self { + Self::Add { + x: Arc::new(Box::new(self)), + y: Arc::new(Box::new(Self::from(rhs))), + debug: Cell::new(false), + var: StackVariable::null(), + } + // self + Self::from(rhs) + } +} + +impl Add for ScriptExpression { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + Self::Add { + x: Arc::new(Box::new(self)), + y: Arc::new(Box::new(rhs)), + debug: Cell::new(false), + var: StackVariable::null(), + } + } +} + +impl Add<&Self> for ScriptExpression { + type Output = Self; + + fn add(self, rhs: &Self) -> Self { + Self::Add { + x: Arc::new(Box::new(self)), + y: Arc::new(Box::new(rhs.clone())), + debug: Cell::new(false), + var: StackVariable::null(), + } + } +} + +impl AddAssign for ScriptExpression { + fn add_assign(&mut self, rhs: Self) { + *self = self.clone() + rhs; + } +} + +impl AddAssign for ScriptExpression { + fn add_assign(&mut self, rhs: F) { + *self += Self::from(rhs); + } +} + +impl Sum for ScriptExpression { + fn sum>(iter: I) -> Self { + iter.reduce(|x, y| x + y).unwrap_or(Self::zero()) + } +} + +impl Sum for ScriptExpression { + fn sum>(iter: I) -> Self { + iter.map(|x| Self::from(x)).sum() + } +} + +impl Sub for ScriptExpression { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + Self::Sub { + x: Arc::new(Box::new(self)), + y: Arc::new(Box::new(rhs)), + debug: Cell::new(false), + var: StackVariable::null(), + } + } +} + +impl Sub for ScriptExpression { + type Output = Self; + + fn sub(self, rhs: F) -> Self { + self - Self::from(rhs) + } +} + +impl SubAssign for ScriptExpression { + fn sub_assign(&mut self, rhs: Self) { + *self = self.clone() - rhs; + } +} + +impl SubAssign for ScriptExpression { + fn sub_assign(&mut self, rhs: F) { + *self -= Self::from(rhs); + } +} + +impl Neg for ScriptExpression { + type Output = Self; + + fn neg(self) -> Self { + Self::Neg { + x: Arc::new(Box::new(self)), + debug: Cell::new(false), + var: StackVariable::null(), + } + } +} + +impl Mul for ScriptExpression { + type Output = Self; + + fn mul(self, rhs: Self) -> Self { + #[allow(clippy::suspicious_arithmetic_impl)] + Self::Mul { + x: Arc::new(Box::new(self)), + y: Arc::new(Box::new(rhs)), + debug: Cell::new(false), + var: StackVariable::null(), + } + } +} + +impl Mul for ScriptExpression { + type Output = Self; + + fn mul(self, rhs: F) -> Self { + self * Self::from(rhs) + } +} + +impl MulAssign for ScriptExpression { + fn mul_assign(&mut self, rhs: Self) { + *self = self.clone() * rhs; + } +} + +impl MulAssign for ScriptExpression { + fn mul_assign(&mut self, rhs: F) { + *self *= Self::from(rhs); + } +} + +impl Product for ScriptExpression { + fn product>(iter: I) -> Self { + iter.reduce(|x, y| x * y).unwrap_or(Self::one()) + } +} + +impl Product for ScriptExpression { + fn product>(iter: I) -> Self { + iter.map(|x| Self::from(x)).product() + } +} + +#[cfg(test)] +mod tests { + use alloc::boxed::Box; + use alloc::collections::BTreeMap; + use alloc::sync::Arc; + use alloc::vec::Vec; + use core::cell::{self, Cell}; + + use bitcoin_script_stack::stack::{self, StackTracker, StackVariable}; + use common::{AbstractField, BabyBear, BinomialExtensionField}; + use p3_air::AirBuilder; + use p3_matrix::Matrix; + use primitives::field::BfField; + use scripts::treepp::*; + use scripts::u31_lib::{u31ext_equalverify, BabyBear4, BabyBearU31}; + + use super::{Expression, ScriptExpression, Variable}; + use crate::{prove, verify, StarkConfig, SymbolicAirBuilder, SymbolicExpression}; + type EF = BinomialExtensionField; + + #[test] + fn test_symbolic_expr_constraints() { + let air_width: usize = 2; + let mut builder = SymbolicAirBuilder::::new(0, air_width, 0); + let main_values = builder.main(); + let (local, next) = (main_values.row_slice(0), main_values.row_slice(1)); + let mut when_transition = builder.when_transition(); + // a' <- b + when_transition.assert_eq(local[0], local[1]); + + // b' <- a + b + when_transition.assert_eq(local[0] + local[1], next[1]); + + let cs = builder.constraints(); + let script_exp: Vec> = + cs.iter().map(|cons| ScriptExpression::from(cons)).collect(); + } + + #[test] + fn test_script_expression_add() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = ScriptExpression::from(BabyBear::one()); + let b = ScriptExpression::from(BabyBear::two()); + let c = a + b; + c.set_debug(); + + let d = ScriptExpression::from(BabyBear::two()); + let e = ScriptExpression::from(BabyBear::two()); + let f = d + e; + + let g = c + f; // 4 + 3 = 7 + let script = g.express_to_script(&mut stack, &bmap); + stack.number(BabyBear::from_canonical_u32(7u32).as_u32_vec()[0]); + stack.op_equal(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_u31add_u31ext() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = ScriptExpression::from(BabyBear::one()); + let b = ScriptExpression::from(EF::two()); + // let c = b +a ; + let c = ScriptExpression::::Add { + x: Arc::new(Box::new(a)), + y: Arc::new(Box::new(b)), + debug: Cell::new(false), + var: StackVariable::null(), + }; + + let d = ScriptExpression::from(BabyBear::two()); + let e = ScriptExpression::from(EF::two()); + let f = ScriptExpression::::Add { + x: Arc::new(Box::new(e)), + y: Arc::new(Box::new(d)), + debug: Cell::new(false), + var: StackVariable::null(), + }; + + let g = c + f; // 4 + 3 = 7 + let script = g.express_to_script(&mut stack, &bmap); + stack.bignumber(EF::from_canonical_u32(7u32).as_u32_vec()); + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "u31ext_equalverify", + ); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_u31sub_u31ext() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = ScriptExpression::from(BabyBear::one()); + let b = ScriptExpression::from(EF::two()); + let c = ScriptExpression::::Sub { + x: Arc::new(Box::new(a)), + y: Arc::new(Box::new(b)), + debug: Cell::new(false), + var: StackVariable::null(), + }; + + let d = ScriptExpression::from(BabyBear::two()); + let e = ScriptExpression::from(EF::from_canonical_u32(4)); + let f = ScriptExpression::::Sub { + x: Arc::new(Box::new(e)), + y: Arc::new(Box::new(d)), + debug: Cell::new(false), + var: StackVariable::null(), + }; + + let g = c + f; // 4 + 3 = 7 + let script = g.express_to_script(&mut stack, &bmap); + stack.bignumber(EF::from_canonical_u32(1u32).as_u32_vec()); + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "u31ext_equalverify", + ); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_u31mul_u31ext() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = ScriptExpression::from(BabyBear::one()); + let b = ScriptExpression::from(EF::two()); + let c = ScriptExpression::::Mul { + x: Arc::new(Box::new(a)), + y: Arc::new(Box::new(b)), + debug: Cell::new(false), + var: StackVariable::null(), + }; + + let d = ScriptExpression::from(BabyBear::two()); + let e = ScriptExpression::from(EF::from_canonical_u32(4)); + let f = ScriptExpression::::Mul { + x: Arc::new(Box::new(e)), + y: Arc::new(Box::new(d)), + debug: Cell::new(false), + var: StackVariable::null(), + }; + + let g = c * f; + let script = g.express_to_script(&mut stack, &bmap); + stack.bignumber(EF::from_canonical_u32(16).as_u32_vec()); + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "equal result", + ); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_ext_constant() { + let mut stack = StackTracker::new(); + let bmap = BTreeMap::new(); + let a = ScriptExpression::from(EF::one()); + a.express_to_script(&mut stack, &bmap); + let res = EF::one(); + + stack.bignumber(res.as_u32_vec()); + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "u31ext_equalverify", + ); + + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expr_with_input() { + let var1 = Variable { + row_index: 0, + column_index: 0, + }; + let var2 = Variable { + row_index: 0, + column_index: 1, + }; + let var3 = Variable { + row_index: 1, + column_index: 0, + }; + let var4 = Variable { + row_index: 1, + column_index: 1, + }; + + let mut stack = StackTracker::new(); + let mut bmap = BTreeMap::new(); + bmap.insert( + &var1, + stack.var( + 1, + script! { {BabyBear::from_canonical_u32(1u32).as_u32_vec()[0]}}, + "input 1", + ), + ); + bmap.insert( + &var2, + stack.var( + 1, + script! { {BabyBear::from_canonical_u32(2u32).as_u32_vec()[0]}}, + "input 2", + ), + ); + bmap.insert( + &var3, + stack.var( + 1, + script! {{BabyBear::from_canonical_u32(3u32).as_u32_vec()[0]}}, + "input 3", + ), + ); + bmap.insert( + &var4, + stack.var( + 1, + script! {{BabyBear::from_canonical_u32(4u32).as_u32_vec()[0]}}, + "input 4", + ), + ); + + let var1_wrap = ScriptExpression::InputVariable { + sv: var1, + debug: Cell::new(false), + }; + let var2_wrap = ScriptExpression::::InputVariable { + sv: var2, + debug: Cell::new(false), + }; + let var3_wrap = ScriptExpression::InputVariable { + sv: var3, + debug: Cell::new(false), + }; + let var4_wrap = ScriptExpression::::InputVariable { + sv: var4, + debug: Cell::new(false), + }; + let res1 = var1_wrap + var2_wrap; + let res2 = var3_wrap + var4_wrap; + + let res = res1 + res2; + res.express_to_script(&mut stack, &bmap); + + stack.number(BabyBear::from_canonical_u32(10u32).as_u32_vec()[0]); + stack.op_equalverify(); + + stack.drop(*bmap.get(&var4).unwrap()); + stack.drop(*bmap.get(&var3).unwrap()); + stack.drop(*bmap.get(&var2).unwrap()); + stack.drop(*bmap.get(&var1).unwrap()); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_extadd() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = ScriptExpression::from(EF::one()); + let b = ScriptExpression::from(EF::two()); + let c = a + b; + + let script = c.express_to_script(&mut stack, &bmap); + stack.debug(); + let res = EF::one() + EF::two(); + + stack.bignumber(res.as_u32_vec()); + stack.debug(); + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "u31ext_equalverify", + ); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_sub() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = ScriptExpression::from(BabyBear::one()); + let b = ScriptExpression::from(BabyBear::two()); + let c = b - a; // 1 + + let d = ScriptExpression::from(BabyBear::two()); + let e = ScriptExpression::from(BabyBear::from_canonical_u32(8)); + let f = e - d; // 6 + + let g = f - c; // 5 + let script = g.express_to_script(&mut stack, &bmap); + stack.number(BabyBear::from_canonical_u32(5u32).as_u32_vec()[0]); + stack.op_equal(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_extsub() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = ScriptExpression::from(EF::one()); + let b = ScriptExpression::from(EF::two()); + let c = b - a; // 1 + + let d = ScriptExpression::from(EF::two()); + let e = ScriptExpression::from(EF::from_canonical_u32(8)); + let f = e - d; // 6 + let g = f - c; // 5 + let script = g.express_to_script(&mut stack, &bmap); + stack.bignumber(EF::from_canonical_u32(5u32).as_u32_vec()); + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "u31ext_equalverify", + ); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_mul() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = ScriptExpression::from(BabyBear::one()); + let b = ScriptExpression::from(BabyBear::two()); + let c = b * a; // 2 + + let d = ScriptExpression::from(BabyBear::two()); + let e = ScriptExpression::from(BabyBear::from_canonical_u32(8)); + let f = e * d * BabyBear::one(); // 16 + stack.show_stack(); + let g = f * c; // 32 + let script = g.express_to_script(&mut stack, &bmap); + stack.number(BabyBear::from_canonical_u32(32u32).as_u32_vec()[0]); + stack.op_equal(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_extmul() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = ScriptExpression::from(EF::one()); + let b = ScriptExpression::from(EF::two()); + let c = b * a; // 2 + + let d = ScriptExpression::from(EF::two()); + let e = ScriptExpression::from(EF::from_canonical_u32(8)); + let f = e * d; // 16 + let g = f * c; // 32 + let script = g.express_to_script(&mut stack, &bmap); + + stack.show_stack(); + + stack.bignumber(EF::from_canonical_u32(32u32).as_u32_vec()); + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "u31ext_equalverify", + ); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_neg() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = ScriptExpression::from(BabyBear::one()); + let b = -a * BabyBear::two(); + let script = b.express_to_script(&mut stack, &bmap); + stack.number(BabyBear::from_canonical_u32(BabyBear::MOD - 2).as_u32_vec()[0]); + stack.op_equal(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_extneg() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = ScriptExpression::from(EF::one()); + let b = -a * EF::two(); + let script = b.express_to_script(&mut stack, &bmap); + stack.bignumber(EF::from_canonical_u32(EF::MOD - 2).as_u32_vec()); + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "u31ext_equalverify", + ); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } +} From 3dfd1444507aa8c98abd59f2976161860d624422 Mon Sep 17 00:00:00 2001 From: Yao Wang Date: Tue, 9 Jul 2024 16:59:14 +0800 Subject: [PATCH 09/25] remove cargo.lock (#20) --- Cargo.lock | 3086 ---------------------------------------------------- 1 file changed, 3086 deletions(-) delete mode 100644 Cargo.lock diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index c0a1e62..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,3086 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "anes" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "anstream" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" - -[[package]] -name = "anstyle-parse" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", -] - -[[package]] -name = "ark-bn254" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-std", -] - -[[package]] -name = "ark-crypto-primitives" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3a13b34da09176a8baba701233fdffbaa7c1b1192ce031a3da4e55ce1f1a56" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-relations", - "ark-serialize", - "ark-snark", - "ark-std", - "blake2", - "derivative", - "digest", - "rayon", - "sha2", -] - -[[package]] -name = "ark-ec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" -dependencies = [ - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", - "itertools 0.10.5", - "num-traits", - "rayon", - "zeroize", -] - -[[package]] -name = "ark-ff" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" -dependencies = [ - "ark-ff-asm", - "ark-ff-macros", - "ark-serialize", - "ark-std", - "derivative", - "digest", - "itertools 0.10.5", - "num-bigint", - "num-traits", - "paste", - "rayon", - "rustc_version", - "zeroize", -] - -[[package]] -name = "ark-ff-asm" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-ff-macros" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" -dependencies = [ - "num-bigint", - "num-traits", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-groth16" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20ceafa83848c3e390f1cbf124bc3193b3e639b3f02009e0e290809a501b95fc" -dependencies = [ - "ark-crypto-primitives", - "ark-ec", - "ark-ff", - "ark-poly", - "ark-relations", - "ark-serialize", - "ark-std", - "rayon", -] - -[[package]] -name = "ark-poly" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" -dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", - "rayon", -] - -[[package]] -name = "ark-relations" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00796b6efc05a3f48225e59cb6a2cda78881e7c390872d5786aaf112f31fb4f0" -dependencies = [ - "ark-ff", - "ark-std", - "tracing", - "tracing-subscriber 0.2.25", -] - -[[package]] -name = "ark-serialize" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" -dependencies = [ - "ark-serialize-derive", - "ark-std", - "digest", - "num-bigint", -] - -[[package]] -name = "ark-serialize-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-snark" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84d3cc6833a335bb8a600241889ead68ee89a3cf8448081fb7694c0fe503da63" -dependencies = [ - "ark-ff", - "ark-relations", - "ark-serialize", - "ark-std", -] - -[[package]] -name = "ark-std" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" -dependencies = [ - "num-traits", - "rand", - "rayon", -] - -[[package]] -name = "arrayref" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" - -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "backtrace" -version = "0.3.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base58ck" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" -dependencies = [ - "bitcoin-internals", - "bitcoin_hashes", -] - -[[package]] -name = "base64" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "bech32" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" - -[[package]] -name = "bitcoin" -version = "0.31.0" -source = "git+https://github.com/bitlayer-org/rust-bitcoin?branch=bf-stark#ffad6f309054e62aacc36311fc0cc08492f81848" -dependencies = [ - "base58ck", - "bech32", - "bitcoin-internals", - "bitcoin-io", - "bitcoin-units", - "bitcoin_hashes", - "hex-conservative", - "hex_lit", - "secp256k1", - "serde", -] - -[[package]] -name = "bitcoin-internals" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" -dependencies = [ - "serde", -] - -[[package]] -name = "bitcoin-io" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" - -[[package]] -name = "bitcoin-script" -version = "0.2.0" -source = "git+https://github.com/bitlayer-org/rust-bitcoin-script#b7144e931d5e9f1e9a07df100a3dbff3210c4ab0" -dependencies = [ - "bitcoin", - "hex", - "lazy_static", - "proc-macro-error", - "proc-macro2", - "quote", -] - -[[package]] -name = "bitcoin-script-stack" -version = "0.0.1" -source = "git+https://github.com/bitlayer-org/rust-bitcoin-script-stack.git#67a7b0009b16da4c7de6e0329af671f38b440df0" -dependencies = [ - "bitcoin", - "bitcoin-script", - "bitcoin-scriptexec", - "hex", -] - -[[package]] -name = "bitcoin-scriptexec" -version = "0.0.0" -source = "git+https://github.com/bitlayer-org/rust-bitcoin-scriptexec#eabf1a9c1ba4153dc3f5042be0b21891c4355c8c" -dependencies = [ - "bitcoin", - "clap", - "console_error_panic_hook", - "getrandom", - "lazy_static", - "serde", - "serde-wasm-bindgen", - "serde_json", - "wasm-bindgen", -] - -[[package]] -name = "bitcoin-units" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" -dependencies = [ - "bitcoin-internals", - "serde", -] - -[[package]] -name = "bitcoin_hashes" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" -dependencies = [ - "bitcoin-io", - "hex-conservative", - "serde", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "bitvm" -version = "0.1.0" -source = "git+https://github.com/bitlayer-org/BitVM#561f67786d370dc9b32f4dcedec41a70fab166c0" -dependencies = [ - "ark-bn254", - "ark-ec", - "ark-ff", - "ark-groth16", - "bitcoin", - "bitcoin-script", - "bitcoin-script-stack", - "bitcoin-scriptexec", - "esplora-client", - "hex", - "lazy_static", - "num-bigint", - "num-traits", - "once_cell", - "rand", - "rand_chacha", - "serde", - "serde_json", - "sha2", - "strum", - "strum_macros", - "tokio", -] - -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest", -] - -[[package]] -name = "blake3" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "bytes" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" - -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - -[[package]] -name = "cc" -version = "1.0.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5208975e568d83b6b05cc0a063c8e7e9acc2b43bee6da15616a5b73e109d7437" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "ciborium" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" -dependencies = [ - "ciborium-io", - "ciborium-ll", - "serde", -] - -[[package]] -name = "ciborium-io" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" - -[[package]] -name = "ciborium-ll" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" -dependencies = [ - "ciborium-io", - "half", -] - -[[package]] -name = "clap" -version = "4.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.69", -] - -[[package]] -name = "clap_lex" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" - -[[package]] -name = "cobs" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" - -[[package]] -name = "colorchoice" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" - -[[package]] -name = "common" -version = "0.1.0" -dependencies = [ - "p3-baby-bear", - "p3-field", -] - -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - -[[package]] -name = "constant_time_eq" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" -dependencies = [ - "libc", -] - -[[package]] -name = "criterion" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" -dependencies = [ - "anes", - "cast", - "ciborium", - "clap", - "criterion-plot", - "is-terminal", - "itertools 0.10.5", - "num-traits", - "once_cell", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-plot" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" -dependencies = [ - "cast", - "itertools 0.10.5", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "encoding_rs" -version = "0.8.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "esplora-client" -version = "0.7.0" -source = "git+https://github.com/bitlayer-org/rust-esplora-client#e63c2eb84456358cef10ef4c0a0192fb8ecd2e3c" -dependencies = [ - "bitcoin", - "hex-conservative", - "log", - "minreq", - "reqwest", - "serde", -] - -[[package]] -name = "fastrand" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "fri" -version = "0.1.0" -dependencies = [ - "bitcoin", - "bitcoin-script", - "bitcoin-scriptexec", - "blake3", - "criterion", - "itertools 0.12.1", - "p3-baby-bear", - "p3-blake3", - "p3-challenger", - "p3-commit", - "p3-dft", - "p3-field", - "p3-goldilocks", - "p3-interpolation", - "p3-keccak", - "p3-matrix", - "p3-maybe-rayon", - "p3-mds", - "p3-merkle-tree", - "p3-mersenne-31", - "p3-symmetric", - "p3-util", - "primitives", - "rand", - "rand_chacha", - "script_manager", - "scripts", - "segment", - "serde", - "tracing", - "tracing-subscriber 0.3.18", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "gcd" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "gimli" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" - -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "half" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if", - "crunchy", -] - -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hex-conservative" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" -dependencies = [ - "arrayvec", -] - -[[package]] -name = "hex_lit" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "2.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" -dependencies = [ - "equivalent", - "hashbrown 0.14.5", -] - -[[package]] -name = "ipnet" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" - -[[package]] -name = "is-terminal" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.155" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - -[[package]] -name = "minreq" -version = "2.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fdef521c74c2884a4f3570bcdb6d2a77b3c533feb6b27ac2ae72673cc221c64" -dependencies = [ - "base64 0.12.3", - "log", - "serde", - "serde_json", -] - -[[package]] -name = "mio" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.48.0", -] - -[[package]] -name = "native-tls" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", - "rand", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "nums" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3c74f925fb8cfc49a8022f2afce48a0683b70f9e439885594e84c5edbf5b01" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", - "rand", -] - -[[package]] -name = "object" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "oorandom" -version = "11.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" - -[[package]] -name = "openssl" -version = "0.10.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" -dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.69", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "p3" -version = "0.1.0" - -[[package]] -name = "p3-air" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "p3-field", - "p3-matrix", -] - -[[package]] -name = "p3-baby-bear" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "num-bigint", - "p3-field", - "p3-mds", - "p3-monty-31", - "p3-poseidon2", - "p3-symmetric", - "rand", - "serde", -] - -[[package]] -name = "p3-blake3" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "blake3", - "p3-symmetric", -] - -[[package]] -name = "p3-challenger" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "p3-field", - "p3-maybe-rayon", - "p3-symmetric", - "p3-util", - "tracing", -] - -[[package]] -name = "p3-circle" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "itertools 0.13.0", - "p3-challenger", - "p3-commit", - "p3-dft", - "p3-field", - "p3-fri", - "p3-matrix", - "p3-maybe-rayon", - "p3-util", - "serde", - "tracing", -] - -[[package]] -name = "p3-commit" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "itertools 0.13.0", - "p3-challenger", - "p3-field", - "p3-matrix", - "p3-util", - "serde", -] - -[[package]] -name = "p3-dft" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "p3-field", - "p3-matrix", - "p3-maybe-rayon", - "p3-util", - "tracing", -] - -[[package]] -name = "p3-field" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "itertools 0.13.0", - "num-bigint", - "num-integer", - "num-traits", - "nums", - "p3-util", - "rand", - "serde", -] - -[[package]] -name = "p3-fri" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "itertools 0.13.0", - "p3-challenger", - "p3-commit", - "p3-dft", - "p3-field", - "p3-interpolation", - "p3-matrix", - "p3-maybe-rayon", - "p3-util", - "serde", - "tracing", -] - -[[package]] -name = "p3-goldilocks" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "num-bigint", - "p3-dft", - "p3-field", - "p3-mds", - "p3-poseidon2", - "p3-symmetric", - "p3-util", - "rand", - "serde", -] - -[[package]] -name = "p3-interpolation" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "p3-field", - "p3-matrix", - "p3-util", -] - -[[package]] -name = "p3-keccak" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "p3-symmetric", - "tiny-keccak", -] - -[[package]] -name = "p3-matrix" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "itertools 0.13.0", - "p3-field", - "p3-maybe-rayon", - "p3-util", - "rand", - "serde", - "tracing", - "transpose", -] - -[[package]] -name = "p3-maybe-rayon" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" - -[[package]] -name = "p3-mds" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "itertools 0.12.1", - "p3-dft", - "p3-field", - "p3-matrix", - "p3-symmetric", - "p3-util", - "rand", -] - -[[package]] -name = "p3-merkle-tree" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "itertools 0.13.0", - "p3-commit", - "p3-field", - "p3-matrix", - "p3-maybe-rayon", - "p3-symmetric", - "p3-util", - "serde", - "tracing", -] - -[[package]] -name = "p3-mersenne-31" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "itertools 0.13.0", - "num-bigint", - "p3-dft", - "p3-field", - "p3-matrix", - "p3-maybe-rayon", - "p3-mds", - "p3-poseidon2", - "p3-symmetric", - "p3-util", - "rand", - "serde", -] - -[[package]] -name = "p3-monty-31" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "num-bigint", - "p3-field", - "p3-mds", - "p3-poseidon2", - "p3-symmetric", - "rand", - "serde", -] - -[[package]] -name = "p3-poseidon2" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "gcd", - "p3-field", - "p3-mds", - "p3-symmetric", - "rand", -] - -[[package]] -name = "p3-symmetric" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "itertools 0.13.0", - "p3-field", - "serde", -] - -[[package]] -name = "p3-util" -version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3.git#c3d754ef77b9fce585b46b972af751fe6e7a9803" -dependencies = [ - "serde", -] - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "plotters" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" - -[[package]] -name = "plotters-svg" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" -dependencies = [ - "plotters-backend", -] - -[[package]] -name = "postcard" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" -dependencies = [ - "cobs", - "embedded-io", - "serde", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "primitives" -version = "0.1.0" -dependencies = [ - "bitcoin", - "bitcoin-script", - "bitcoin-scriptexec", - "blake3", - "common", - "itertools 0.12.1", - "lazy_static", - "p3-baby-bear", - "p3-challenger", - "p3-commit", - "p3-dft", - "p3-field", - "p3-interpolation", - "p3-matrix", - "p3-maybe-rayon", - "p3-symmetric", - "p3-util", - "rand", - "rand_chacha", - "script_manager", - "scripts", - "segment", - "serde", - "tracing", - "tracing-subscriber 0.3.18", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "redox_syscall" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" -dependencies = [ - "bitflags 2.6.0", -] - -[[package]] -name = "regex" -version = "1.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.4", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" - -[[package]] -name = "reqwest" -version = "0.11.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" -dependencies = [ - "base64 0.21.7", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-native-tls", - "tokio-socks", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", -] - -[[package]] -name = "rust-bitcoin-u31-or-u30" -version = "0.1.0" -source = "git+https://github.com/bitlayer-org/rust-bitcoin-m31-or-babybear.git?branch=bf-pcs#ad90ef3e27f94bc69cf6d64fd3bde82128be2040" -dependencies = [ - "ark-ff", - "bitcoin", - "bitcoin-script", - "bitcoin-scriptexec", - "bitvm", - "p3-baby-bear", - "p3-field", - "p3-mersenne-31", - "rand", - "rand_chacha", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" -dependencies = [ - "bitflags 2.6.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - -[[package]] -name = "rustversion" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "script_manager" -version = "0.1.0" -dependencies = [ - "bitcoin", - "bitcoin-script", - "bitcoin-scriptexec", - "hex", - "itertools 0.12.1", - "lazy_static", - "once_cell", - "p3-baby-bear", - "p3-challenger", - "p3-field", - "p3-util", - "primitives", - "rand", - "rand_chacha", - "scripts", -] - -[[package]] -name = "scripts" -version = "0.1.0" -dependencies = [ - "bitcoin", - "bitcoin-script", - "bitcoin-scriptexec", - "blake3", - "common", - "criterion", - "hex", - "itertools 0.12.1", - "lazy_static", - "once_cell", - "p3-baby-bear", - "p3-challenger", - "p3-dft", - "p3-field", - "p3-goldilocks", - "p3-mds", - "p3-merkle-tree", - "p3-mersenne-31", - "p3-poseidon2", - "p3-symmetric", - "p3-util", - "primitives", - "rand", - "rand_chacha", - "rust-bitcoin-u31-or-u30", -] - -[[package]] -name = "secp256k1" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" -dependencies = [ - "bitcoin_hashes", - "rand", - "secp256k1-sys", - "serde", -] - -[[package]] -name = "secp256k1-sys" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" -dependencies = [ - "cc", -] - -[[package]] -name = "security-framework" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" -dependencies = [ - "bitflags 2.6.0", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "segment" -version = "0.1.0" -dependencies = [ - "bitcoin", - "bitcoin-script", - "bitcoin-scriptexec", - "scripts", -] - -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" - -[[package]] -name = "serde" -version = "1.0.204" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-wasm-bindgen" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "serde_derive" -version = "1.0.204" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.69", -] - -[[package]] -name = "serde_json" -version = "1.0.120" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "socket2" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "strength_reduce" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" - -[[package]] -name = "strum_macros" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.69", -] - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201fcda3845c23e8212cd466bfebf0bd20694490fc0356ae8e428e0824a915a6" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "tempfile" -version = "3.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" -dependencies = [ - "cfg-if", - "fastrand", - "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "thiserror" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.69", -] - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "tinyvec" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6b6a2fb3a985e99cebfaefa9faa3024743da73304ca1c683a36429613d3d22" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-macros" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.69", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-socks" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0" -dependencies = [ - "either", - "futures-util", - "thiserror", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.69", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-forest" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee40835db14ddd1e3ba414292272eddde9dad04d3d4b65509656414d1c42592f" -dependencies = [ - "ansi_term", - "smallvec", - "thiserror", - "tracing", - "tracing-subscriber 0.3.18", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" -dependencies = [ - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "transpose" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad61aed86bc3faea4300c7aee358b4c6d0c8d6ccc36524c96e4c92ccf26e77e" -dependencies = [ - "num-integer", - "strength_reduce", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "uni-stark" -version = "0.1.0" -dependencies = [ - "bitcoin", - "bitcoin-script", - "bitcoin-script-stack", - "bitcoin-scriptexec", - "common", - "fri", - "itertools 0.13.0", - "p3-air", - "p3-baby-bear", - "p3-challenger", - "p3-circle", - "p3-commit", - "p3-dft", - "p3-field", - "p3-fri", - "p3-goldilocks", - "p3-keccak", - "p3-matrix", - "p3-maybe-rayon", - "p3-mds", - "p3-merkle-tree", - "p3-mersenne-31", - "p3-poseidon2", - "p3-symmetric", - "p3-util", - "postcard", - "primitives", - "rand", - "script_manager", - "scripts", - "segment", - "serde", - "tracing", - "tracing-forest", - "tracing-subscriber 0.3.18", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "url" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.69", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.69", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "web-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.69", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.69", -] From 28767437bbfe7b95ecd85da3e480e564a8e3be37 Mon Sep 17 00:00:00 2001 From: dylanCai9 <22110240060@m.fudan.edu.cn> Date: Mon, 15 Jul 2024 09:59:47 +0800 Subject: [PATCH 10/25] compute quotient script (#22) * compute zps * split script * compute quotient script * refactor and clean --- primitives/src/mmcs/taptree.rs | 2 +- uni-stark/Cargo.toml | 1 + uni-stark/src/lib.rs | 4 +- uni-stark/src/proof.rs | 28 +- uni-stark/src/scripts/bf_unistark.rs | 592 +++++++++++++++++++++++++++ uni-stark/src/scripts/mod.rs | 5 + uni-stark/src/scripts/utils.rs | 92 +++++ uni-stark/src/verifier.rs | 140 ++++++- uni-stark/tests/fib_air.rs | 131 +++++- 9 files changed, 976 insertions(+), 19 deletions(-) create mode 100644 uni-stark/src/scripts/bf_unistark.rs create mode 100644 uni-stark/src/scripts/mod.rs create mode 100644 uni-stark/src/scripts/utils.rs diff --git a/primitives/src/mmcs/taptree.rs b/primitives/src/mmcs/taptree.rs index a38f816..7e1e654 100644 --- a/primitives/src/mmcs/taptree.rs +++ b/primitives/src/mmcs/taptree.rs @@ -240,7 +240,7 @@ impl TreeBuilder { let mut t_idx_to_m_idx = self.leaf_indices.clone(); while working_nodes.len() > 1 { - println!("working_nodes len:{:?}", working_nodes.len()); + // println!("working_nodes len:{:?}", working_nodes.len()); //the tuple() method in itertool will drop the elements in Iter if the size is not enough to //generate a tuple, so we have to save the last node if the size of working node is odd. let mut reminder_node: Option = None; diff --git a/uni-stark/Cargo.toml b/uni-stark/Cargo.toml index 533d6cd..b7adda5 100644 --- a/uni-stark/Cargo.toml +++ b/uni-stark/Cargo.toml @@ -39,6 +39,7 @@ p3-mersenne-31 = { git = "https://github.com/Plonky3/Plonky3.git" } p3-poseidon2 = { git = "https://github.com/Plonky3/Plonky3.git" } p3-symmetric = { git = "https://github.com/Plonky3/Plonky3.git" } rand = "0.8.5" +rand_chacha = "0.3.1" tracing-subscriber = { version = "0.3.17", features = ["std", "env-filter"] } tracing-forest = { version = "0.1.6", features = ["ansi", "smallvec"] } postcard = { version = "1.0.0", default-features = false, features = ["alloc"] } diff --git a/uni-stark/src/lib.rs b/uni-stark/src/lib.rs index 31ed40c..832857b 100644 --- a/uni-stark/src/lib.rs +++ b/uni-stark/src/lib.rs @@ -1,6 +1,6 @@ //! A minimal univariate STARK framework. -#![no_std] +// #![no_std] extern crate alloc; @@ -8,6 +8,7 @@ mod config; mod folder; mod proof; mod prover; +mod scripts; mod scripts_expression; mod symbolic_builder; mod symbolic_expression; @@ -24,6 +25,7 @@ pub use config::*; pub use folder::*; pub use proof::*; pub use prover::*; +pub use scripts::*; pub use scripts_expression::*; pub use symbolic_builder::*; pub use symbolic_expression::*; diff --git a/uni-stark/src/proof.rs b/uni-stark/src/proof.rs index 5c3ac97..8561d4d 100644 --- a/uni-stark/src/proof.rs +++ b/uni-stark/src/proof.rs @@ -18,23 +18,33 @@ type PcsProof = <::Pcs as Pcs< // #[serde(bound = "")] #[derive(Clone)] pub struct Proof { - pub(crate) commitments: Commitments>, - pub(crate) opened_values: OpenedValues, - pub(crate) opening_proof: PcsProof, - pub(crate) degree_bits: usize, + // pub(crate) commitments: Commitments>, + // pub(crate) opened_values: OpenedValues, + // pub(crate) opening_proof: PcsProof, + // pub(crate) degree_bits: usize, + //remove crate for test + pub commitments: Commitments>, + pub opened_values: OpenedValues, + pub opening_proof: PcsProof, + pub degree_bits: usize, } // #[derive(Debug, Serialize, Deserialize)] #[derive(Clone)] pub struct Commitments { - pub(crate) trace: Com, - pub(crate) quotient_chunks: Com, + // pub(crate) trace: Com, + // pub(crate) quotient_chunks: Com, + pub trace: Com, + pub quotient_chunks: Com, } // #[derive(Debug, Serialize, Deserialize)] #[derive(Clone)] pub struct OpenedValues { - pub(crate) trace_local: Vec, - pub(crate) trace_next: Vec, - pub(crate) quotient_chunks: Vec>, + // pub(crate) trace_local: Vec, + // pub(crate) trace_next: Vec, + // pub(crate) quotient_chunks: Vec>, + pub trace_local: Vec, + pub trace_next: Vec, + pub quotient_chunks: Vec>, } diff --git a/uni-stark/src/scripts/bf_unistark.rs b/uni-stark/src/scripts/bf_unistark.rs new file mode 100644 index 0000000..873f82f --- /dev/null +++ b/uni-stark/src/scripts/bf_unistark.rs @@ -0,0 +1,592 @@ +use bitcoin::opcodes::{OP_ADD, OP_DROP, OP_SUB, OP_SWAP, OP_TOALTSTACK, OP_TRUE}; +use bitcoin::{script, ScriptBuf as Script}; +use bitcoin_script::{define_pushable, script}; +use itertools::izip; +use p3_field::AbstractField; +use p3_util::log2_strict_usize; +use primitives::field::BfField; +use script_manager::script_info::{self, ScriptInfo}; +use scripts::pseudo::{ + OP_4DROP, OP_4DUP, OP_4FROMALTSTACK, OP_4MUL, OP_4PICK, OP_4ROLL, OP_4SWAP, OP_4TOALTSTACK, + OP_NDUP, +}; +use scripts::u31_lib::{ + u31_add, u31_double, u31_mul, u31_sub, u31_sub_u31ext, u31_to_u31ext, u31ext_add, + u31ext_double, u31ext_equalverify, u31ext_mul, u31ext_mul_u31, u31ext_mul_u31_by_constant, + u31ext_sub, u31ext_sub_u31, BabyBear4, BabyBearU31, +}; + +use crate::{get_generator, value_exp_n_minus_one}; + +define_pushable!(); + +// * input: +// * altstack: +// * empty +// * stack: +// * zeta/a babybear4 +// * (quotient_chunk_nums - 1 - j_i) + +// * output: +// * altstack: +// * acc_numerator babybear4 +// * stack: +// * zeta/a babybear4 +fn compute_acc_numerator( + log_n_conf: usize, + generator: Val, + quotient_chunk_nums: usize, +) -> Script { + script! { + OP_0 OP_0 OP_0 OP_1 // the accmulator is 1 when intialization + for _ in 0..(quotient_chunk_nums - 1) { + OP_4TOALTSTACK //alt: acc stack: zeta/a index + OP_4DUP + OP_4TOALTSTACK + OP_4TOALTSTACK //alt: zeta/a zeta/a acc stack:index + {get_generator::(generator, quotient_chunk_nums)} //get w^-j at top + OP_4FROMALTSTACK //get zeta/babybear_generator at top + 4 OP_ROLL + {u31ext_mul_u31::()} //zeta/(babybear_generator * w^j) + {value_exp_n_minus_one::(log_n_conf)} //x^n - 1 + OP_4FROMALTSTACK + OP_4SWAP + OP_4FROMALTSTACK //acc + {u31ext_mul::()} //new_acc zeta/babybear_generator -j + } + OP_4TOALTSTACK + } +} + +pub fn compute_acc_numerator_all( + log_n_conf: usize, + generator: Val, + quotient_chunk_nums: usize, +) -> Script { + script! { + //push babybeay_generator.inverse() + {64944062 as u32} + {u31ext_mul_u31::()} // stack: zeta/a + for i in 0..quotient_chunk_nums{ + OP_4TOALTSTACK + for j in 0..quotient_chunk_nums { + if j != i { + {(quotient_chunk_nums - 1 - j) as u32} + } + } + OP_4FROMALTSTACK + {compute_acc_numerator::(log_n_conf, generator,quotient_chunk_nums)} //babybear4 + } + OP_4DROP + for _ in 0..quotient_chunk_nums { + OP_4FROMALTSTACK + } + } +} + +pub fn compute_acc_numerator_script( + zeta: Challenge, + quotient_chunk_nums: usize, + degree_bits: usize, + generator: Val, + numerators: Vec, +) -> ScriptInfo { + assert_eq!(numerators.len(), quotient_chunk_nums); + let mut si = ScriptInfo::new( + "compute_acc_numerator", + compute_acc_numerator_all::(degree_bits, generator, quotient_chunk_nums), + ); + si.add_input(zeta); + for i in 0..quotient_chunk_nums { + si.add_output(numerators[i]); + } + si +} + +// * input: +// * altstack: +// * empty +// * stack: +// * i +// * (quotient_chunk_nums-1-j_i) +// * zps[i] babybear4 + +// * output: +// * altstack: +// * acc_denominator babybear +// * stack: +// * zps[i] +fn compute_acc_denominator( + log_n_conf: usize, + generator: Val, + quotient_chunk_nums: usize, +) -> Script { + script! { + OP_1 //the accmulator is 1 when intialization + for _ in 0..(quotient_chunk_nums - 1) { + OP_TOALTSTACK //alt: acc s:i, (S-1-j) + OP_DUP //alt: acc s:i,i,(S-1-j) + OP_TOALTSTACK //alt: i, acc s:i, (S-1-j) + OP_ADD //alt: i, acc s:i + (S-1-j) = lookup_index + {get_generator::(generator, quotient_chunk_nums)} + {value_exp_n_minus_one::(log_n_conf)} //alt: i, acc s: (w^(i-j))^n - 1 + OP_FROMALTSTACK + OP_SWAP + OP_FROMALTSTACK // s: acc, (w^(i-j))^n - 1, i + {u31_mul::()} // s: new_acc i j + } + OP_TOALTSTACK + OP_DROP //DROP i + } +} + +// * +// * compute: +// * zps[i] * denominator +// * +// * input: +// * altstack: +// * empty +// * stack: +// * zps[i] babybear4 + +// * output: +// * altstack: +// * zps[i] * acc_denominator babybear4 +// * stack: +// * zps[i+1] or empty babybear4 +fn zps_i_mul_denominator( + i: usize, + log_n_conf: usize, + generator: Val, + quotient_chunk_nums: usize, +) -> Script { + script! { + for j in 0..quotient_chunk_nums { + if j != i { + {(quotient_chunk_nums - 1 - j) as u32} + } + } + {i as u32} + // * input: + // * altstack: + // * empty + // * stack: + // * i + // * (quotient_chunk_nums-1-j_i) + // * zps[i] babybear4 + {compute_acc_denominator::(log_n_conf, generator,quotient_chunk_nums)} //babybear + OP_FROMALTSTACK + {u31ext_mul_u31::()} + OP_4TOALTSTACK + } +} + +pub fn zps_mul_denominator_all( + log_n_conf: usize, + generator: Val, + quotient_chunk_nums: usize, +) -> Script { + script! { + for i in 0..quotient_chunk_nums { + {zps_i_mul_denominator::(i, log_n_conf, generator,quotient_chunk_nums)} + } + for _ in 0..quotient_chunk_nums { + OP_4FROMALTSTACK + } + + } +} + +pub fn compute_zps_mul_denominator_script( + quotient_chunk_nums: usize, + degree_bits: usize, + generator: Val, + zps: Vec, + numerators: Vec, +) -> ScriptInfo { + assert_eq!(numerators.len(), quotient_chunk_nums); + let mut si = ScriptInfo::new( + "compute_zps_mul_denominator", + zps_mul_denominator_all::(degree_bits, generator, quotient_chunk_nums), + ); + for i in 0..quotient_chunk_nums { + si.add_input(zps[i]); + si.add_output(numerators[i]); + } + si +} + +// * +// * compute: +// * sum(zps[i] * open_value_i) +// * +// * input: +// * altstack: +// * empty +// * stack: +// * open_value_i[0] babybear4 +// * open_value_i[1] babybear4 +// * open_value_i[2] babybear4 +// * open_value_i[3] babybear4 +// * zps[i] babybear4 + +// * output: +// * altstack: +// * empty +// * stack: +// * quotient_zeta babybear4 +pub fn compute_quotient_zeta( + quotient_chunk_nums: usize, +) -> Script { + script! { + OP_0 OP_0 OP_0 OP_0 //init quotient_zeta to 0 + for _ in 0..quotient_chunk_nums { + OP_4TOALTSTACK + {compute_quotient_i::()} + OP_4FROMALTSTACK + {u31ext_add::()} + } + } +} + +//SC::Challenge::monomial(e_i) * c +//quotient value is EF, but we use EF as F_slice for commit. +pub fn compute_quotient_i() -> Script { + script! { + OP_0 OP_0 OP_0 OP_1 + {u31ext_mul::()} + OP_4TOALTSTACK + OP_0 OP_0 OP_1 OP_0 + {u31ext_mul::()} + OP_4FROMALTSTACK + {u31ext_add::()} + OP_4TOALTSTACK + OP_0 OP_1 OP_0 OP_0 + {u31ext_mul::()} + OP_4FROMALTSTACK + {u31ext_add::()} + OP_4TOALTSTACK + OP_1 OP_0 OP_0 OP_0 + {u31ext_mul::()} + OP_4FROMALTSTACK + {u31ext_add::()} + {u31ext_mul::()} + } +} + +pub fn compute_quotient_zeta_script( + quotient_chunk_nums: usize, + zps: Vec, + open_values: Vec>, + quotient_zeta: Challenge, +) -> ScriptInfo { + assert_eq!(zps.len(), quotient_chunk_nums); + assert_eq!(open_values.len(), quotient_chunk_nums); + let mut si = ScriptInfo::new( + "compute_quotient_zeta", + compute_quotient_zeta::(quotient_chunk_nums), + ); + let width = open_values[0].len(); + assert_eq!(width, 4); + for i in 0..quotient_chunk_nums { + for j in 0..width { + si.add_input(open_values[i][j]); + } + si.add_input(zps[i]); + } + si.add_output(quotient_zeta); + si +} + +// * input: +// * altstack: +// * zeta/a babybear4 +// * stack: +// * zeta/a babybear4 +// * zps[i] babybear4 + +// * output: +// * altstack: +// * zeta/a babybear4 +// * stack: +// * zps[i+1] or empty + +pub fn verify_quotient_i( + i: usize, + log_n_conf: usize, + generator: Val, + quotient_chunk_nums: usize, +) -> Script { + println!( + "verify_quotient i:{}, log_n_conf:{}, quotient_chunk_nums:{}", + i, log_n_conf, quotient_chunk_nums + ); + script! { + OP_4TOALTSTACK + for j in 0..quotient_chunk_nums { + if j != i { + {(quotient_chunk_nums - 1 - j) as u32} + } + } + OP_4FROMALTSTACK + {compute_acc_numerator::(log_n_conf, generator,quotient_chunk_nums)} //babybear4 + + {zps_i_mul_denominator::(i, log_n_conf, generator,quotient_chunk_nums)} + + OP_4FROMALTSTACK + OP_4FROMALTSTACK + + {u31ext_equalverify::()} + } +} + +// * input: +// * altstack: +// * +// * stack: +// a +//* zeta +//* zps[0] +//* zps[1] +//* ... +//* zps[quotient_chunk_nums-1] +pub fn verify_quotient( + quotient_chunk_nums: usize, + generator: Val, + log_n_conf: usize, +) -> Script { + script! { + {u31ext_mul_u31::()} // stack: zeta/a + OP_4TOALTSTACK + for i in 0..quotient_chunk_nums { + OP_4FROMALTSTACK + OP_4DUP + OP_4TOALTSTACK + {verify_quotient_i::(i, log_n_conf, generator,quotient_chunk_nums)} + } + OP_4FROMALTSTACK + OP_4DROP + // OP_TRUE + } +} + +pub fn verify_quotient_script( + zeta: Challenge, + quotient_chunk_nums: usize, + degree_bits: usize, + generator: Val, + zps: Vec, +) -> ScriptInfo { + assert_eq!(zps.len(), quotient_chunk_nums); + let mut si = ScriptInfo::new( + "verify_zps", + verify_quotient::(quotient_chunk_nums, generator, degree_bits), + ); + si.add_input(Val::generator().try_inverse().unwrap()) + .add_input(zeta); + for i in 0..quotient_chunk_nums { + si.add_input(zps[i]); + } + si +} + +#[cfg(test)] +mod tests { + use bitcoin::opcodes::OP_TRUE; + use bitcoin_script::define_pushable; + use fri::{FriConfig, TwoAdicFriPcs}; + use itertools::{izip, Itertools}; + use p3_commit::{PolynomialSpace, TwoAdicMultiplicativeCoset}; + use p3_dft::{Radix2Dit, Radix2DitParallel, TwoAdicSubgroupDft}; + use p3_field::{AbstractExtensionField, AbstractField, Field, TwoAdicField}; + use p3_matrix::dense::RowMajorMatrix; + use p3_matrix::util::reverse_matrix_index_bits; + use p3_util::log2_strict_usize; + use primitives::bf_pcs::Pcs; + use primitives::challenger::{self, Blake3Permutation}; + use primitives::field::BfField; + use primitives::mmcs::taptree_mmcs::TapTreeMmcs; + use rand::{Rng, SeedableRng}; + use rand_chacha::ChaCha20Rng; + use script_manager::bc_assignment::DefaultBCAssignment; + use scripts::pseudo::{OP_4DROP, OP_4DUP, OP_4FROMALTSTACK, OP_4TOALTSTACK}; + use scripts::u31_lib::{u31ext_equalverify, u31ext_mul, BabyBear4}; + use scripts::{execute_script, execute_script_with_inputs, BabyBear, BinomialExtensionField}; + + use crate::scripts::bf_unistark::{ + compute_acc_numerator, compute_acc_numerator_script, compute_zps_mul_denominator_script, + verify_quotient, verify_quotient_script, + }; + use crate::{prove, StarkConfig}; + + define_pushable!(); + + type Val = BabyBear; + type ValMmcs = TapTreeMmcs; + type Challenge = BinomialExtensionField; + type ChallengeMmcs = TapTreeMmcs; + type Dft = Radix2DitParallel; + type MyPcs = TwoAdicFriPcs; + + fn get_pcs() -> MyPcs { + let val_mmcs = ValMmcs::new(); + let challenge_mmscs = ChallengeMmcs::new(); + let fri_config = FriConfig { + log_blowup: 2, + num_queries: 10, + proof_of_work_bits: 8, + mmcs: challenge_mmscs, + }; + let pcs = MyPcs::new(Dft {}, val_mmcs, fri_config); + pcs + } + + #[test] + fn test_numerator() { + type Challenge = BinomialExtensionField; + type Val = BabyBear; + + let degree = 8; //n + let log_degree = log2_strict_usize(degree); + let quotient_degree = 4; //s + let log_quotient_degree = log2_strict_usize(quotient_degree); + + let mut rng = ChaCha20Rng::seed_from_u64(0u64); + + let zeta = rng.gen::(); + + let a = Val::generator().try_inverse().unwrap(); + + // let trace_domain = pcs.natural_domain_for_degree(degree); + let trace_domain = TwoAdicMultiplicativeCoset { + log_n: log_degree, + shift: Val::one(), + }; + + let quotient_domain = + trace_domain.create_disjoint_domain(1 << (log_degree + log_quotient_degree)); + + let generator = Val::two_adic_generator(quotient_domain.log_n); + + let quotient_chunks_domains = quotient_domain.split_domains(quotient_degree); + + let quotient_chunk_nums = quotient_chunks_domains.len(); + + let numerators = quotient_chunks_domains + .iter() + .enumerate() + .map(|(i, domain)| { + quotient_chunks_domains + .iter() + .enumerate() + .filter(|(j, _)| *j != i) + .map(|(_, other_domain)| other_domain.zp_at_point(zeta)) + .product::() + }) + .collect_vec(); + let mut bc_assigner = DefaultBCAssignment::new(); + let mut exec_script_info = compute_acc_numerator_script::( + zeta, + quotient_chunk_nums, + log_degree, + generator, + numerators, + ); + + exec_script_info.gen(&mut bc_assigner); + + let res = execute_script_with_inputs( + exec_script_info.get_eq_script(), + exec_script_info.witness(), + ); + assert!(res.success); + + let res = execute_script_with_inputs( + exec_script_info.get_neq_script(), + exec_script_info.witness(), + ); + assert!(!res.success); + } + + #[test] + fn test_zps_mul_denominator() { + let degree = 8; //n + let log_degree = log2_strict_usize(degree); + let quotient_degree = 4; //s + let log_quotient_degree = log2_strict_usize(quotient_degree); + + let mut rng = ChaCha20Rng::seed_from_u64(0u64); + + let zeta = rng.gen::(); + + let a = Val::generator().try_inverse().unwrap(); + + // let trace_domain = pcs.natural_domain_for_degree(degree); + let trace_domain = TwoAdicMultiplicativeCoset { + log_n: log_degree, + shift: Val::one(), + }; + + let quotient_domain = + trace_domain.create_disjoint_domain(1 << (log_degree + log_quotient_degree)); + + let generator = Val::two_adic_generator(quotient_domain.log_n); + + let quotient_chunks_domains = quotient_domain.split_domains(quotient_degree); + + let quotient_chunk_nums = quotient_chunks_domains.len(); + + let zps = quotient_chunks_domains + .iter() + .enumerate() + .map(|(i, domain)| { + quotient_chunks_domains + .iter() + .enumerate() + .filter(|(j, _)| *j != i) + .map(|(_, other_domain)| { + other_domain.zp_at_point(zeta) + * other_domain.zp_at_point(domain.first_point()).inverse() + }) + .product::() + }) + .collect_vec(); + + let numerators = quotient_chunks_domains + .iter() + .enumerate() + .map(|(i, domain)| { + quotient_chunks_domains + .iter() + .enumerate() + .filter(|(j, _)| *j != i) + .map(|(_, other_domain)| other_domain.zp_at_point(zeta)) + .product::() + }) + .collect_vec(); + + let mut bc_assigner = DefaultBCAssignment::new(); + let mut exec_script_info = compute_zps_mul_denominator_script::( + quotient_chunk_nums, + log_degree, + generator, + zps, + numerators, + ); + + exec_script_info.gen(&mut bc_assigner); + + let res = execute_script_with_inputs( + exec_script_info.get_eq_script(), + exec_script_info.witness(), + ); + assert!(res.success); + + let res = execute_script_with_inputs( + exec_script_info.get_neq_script(), + exec_script_info.witness(), + ); + assert!(!res.success); + } +} diff --git a/uni-stark/src/scripts/mod.rs b/uni-stark/src/scripts/mod.rs new file mode 100644 index 0000000..70fc2ff --- /dev/null +++ b/uni-stark/src/scripts/mod.rs @@ -0,0 +1,5 @@ +mod bf_unistark; +mod utils; + +pub use bf_unistark::*; +pub use utils::*; diff --git a/uni-stark/src/scripts/utils.rs b/uni-stark/src/scripts/utils.rs new file mode 100644 index 0000000..27421ab --- /dev/null +++ b/uni-stark/src/scripts/utils.rs @@ -0,0 +1,92 @@ +use bitcoin::opcodes::{OP_ADD, OP_DROP, OP_SUB, OP_SWAP, OP_TOALTSTACK, OP_TRUE}; +use bitcoin::{script, ScriptBuf as Script}; +use bitcoin_script::{define_pushable, script}; +use primitives::field::BfField; +use scripts::pseudo::{ + OP_4DROP, OP_4DUP, OP_4FROMALTSTACK, OP_4MUL, OP_4PICK, OP_4ROLL, OP_4SWAP, OP_4TOALTSTACK, + OP_NDUP, +}; +use scripts::u31_lib::{ + u31_add, u31_double, u31_mul, u31_sub, u31_sub_u31ext, u31_to_u31ext, u31ext_add, + u31ext_double, u31ext_equalverify, u31ext_mul, u31ext_mul_u31, u31ext_mul_u31_by_constant, + u31ext_sub, u31ext_sub_u31, BabyBear4, BabyBearU31, +}; + +define_pushable!(); + +fn value_square_with_input() -> Script { + script! { + if F::U32_SIZE == 1 { + OP_DUP + {u31_mul::()} + }else{ + OP_4DUP + {u31ext_mul::()} + } + } +} + +pub fn value_exp_n_minus_one(log_n: usize) -> Script { + script! { + for _ in 0..log_n { + {value_square_with_input::()} + } + if F::U32_SIZE == 1 { + OP_1 + {u31_sub::()} + }else{ + OP_0 OP_0 OP_0 OP_1 + {u31ext_sub::()} + } + } +} + +fn push_generator_table(generator: F, quotient_chunk_nums: usize) -> Script { + script! { + for i in (0..quotient_chunk_nums).rev() { + for j in (0..F::U32_SIZE).rev(){ + {generator.exp_u64(i as u64).as_u32_vec()[j]} + } + } + for i in 1..quotient_chunk_nums { + for j in (0..F::U32_SIZE).rev(){ + {generator.exp_u64(i as u64).try_inverse().unwrap().as_u32_vec()[j]} + } + } + } +} + +fn pop_generator_table(quotient_chunk_nums: usize) -> Script { + script! { + for _ in 0..(2 * quotient_chunk_nums - 1){ + for _ in (0..F::U32_SIZE).rev(){ + OP_DROP + } + } + } +} + +// stack: index input: generator: w, quotient_chunk_nums: s +pub fn get_generator(generator: F, quotient_chunk_nums: usize) -> Script { + script! { + OP_TOALTSTACK + {push_generator_table::(generator, quotient_chunk_nums)} + OP_FROMALTSTACK + if F::U32_SIZE == 1{ + OP_PICK + OP_TOALTSTACK + }else{ + OP_4MUL + OP_4PICK + OP_4TOALTSTACK + } + + {pop_generator_table::(quotient_chunk_nums)} + + if F::U32_SIZE ==1{ + OP_FROMALTSTACK + }else{ + OP_4FROMALTSTACK + } + } +} diff --git a/uni-stark/src/verifier.rs b/uni-stark/src/verifier.rs index 5d8b459..b6820e0 100644 --- a/uni-stark/src/verifier.rs +++ b/uni-stark/src/verifier.rs @@ -9,11 +9,16 @@ use p3_field::{AbstractExtensionField, AbstractField, Field}; use p3_matrix::dense::RowMajorMatrixView; use p3_matrix::stack::VerticalPair; use primitives::bf_pcs::Pcs; +use script_manager::bc_assignment::DefaultBCAssignment; use script_manager::script_info::ScriptInfo; +use scripts::execute_script_with_inputs; use tracing::instrument; use crate::symbolic_builder::{get_log_quotient_degree, SymbolicAirBuilder}; -use crate::{PcsError, Proof, StarkGenericConfig, Val, VerifierConstraintFolder}; +use crate::{ + compute_quotient_zeta_script, PcsError, Proof, StarkGenericConfig, Val, + VerifierConstraintFolder, +}; #[instrument(skip_all)] pub fn verify( @@ -127,6 +132,8 @@ where .sum::() }) .sum::(); + //SC::Challenge::monomial(e_i) * c + //quotient value is EF, but we use EF as base_slice for commit. width from 1 to 4. let sels = trace_domain.selectors_at_point(zeta); @@ -156,6 +163,137 @@ where Ok(()) } +// pub fn verify_script( +// config: &SC, +// air: &A, +// challenger: &mut SC::Challenger, +// proof: &Proof, +// public_values: &Vec>, +// script_managers: &mut Vec, +// ) -> Result<(), VerificationError>> +// where +// SC: StarkGenericConfig, +// A: Air>> + for<'a> Air>, +// { +// let Proof { +// commitments, +// opened_values, +// opening_proof, +// degree_bits, +// } = proof; + +// let degree = 1 << degree_bits; +// let log_quotient_degree = get_log_quotient_degree::, A>(air, 0, public_values.len()); +// let quotient_degree = 1 << log_quotient_degree; + +// let pcs = config.pcs(); +// let trace_domain = pcs.natural_domain_for_degree(degree); +// let quotient_domain = +// trace_domain.create_disjoint_domain(1 << (degree_bits + log_quotient_degree)); +// let quotient_chunks_domains = quotient_domain.split_domains(quotient_degree); + +// let air_width = >>::width(air); +// let valid_shape = opened_values.trace_local.len() == air_width +// && opened_values.trace_next.len() == air_width +// && opened_values.quotient_chunks.len() == quotient_degree +// && opened_values +// .quotient_chunks +// .iter() +// .all(|qc| qc.len() == >>::D); +// if !valid_shape { +// return Err(VerificationError::InvalidProofShape); +// } + +// // Observe the instance. // TODO: recover observe when we have CanObserve trait +// // challenger.observe(Val::::from_canonical_usize(proof.degree_bits)); +// // TODO: Might be best practice to include other instance data here in the transcript, like some +// // encoding of the AIR. This protects against transcript collisions between distinct instances. +// // Practically speaking though, the only related known attack is from failing to include public +// // values. It's not clear if failing to include other instance data could enable a transcript +// // collision, since most such changes would completely change the set of satisfying witnesses. + +// challenger.observe(commitments.trace.clone()); +// // challenger.observe_slice(public_values); +// let alpha: SC::Challenge = challenger.sample(); +// challenger.observe(commitments.quotient_chunks.clone()); + +// let zeta: SC::Challenge = challenger.sample(); +// let zeta_next = trace_domain.next_point(zeta).unwrap(); + +// pcs.verify( +// vec![ +// ( +// commitments.trace.clone(), +// vec![( +// trace_domain, +// vec![ +// (zeta, opened_values.trace_local.clone()), +// (zeta_next, opened_values.trace_next.clone()), +// ], +// )], +// ), +// ( +// commitments.quotient_chunks.clone(), +// quotient_chunks_domains +// .iter() +// .zip(&opened_values.quotient_chunks) +// .map(|(domain, values)| (*domain, vec![(zeta, values.clone())])) +// .collect_vec(), +// ), +// ], +// opening_proof, +// challenger, +// script_managers, +// ) +// .map_err(VerificationError::InvalidOpeningArgument)?; + +// let zps = quotient_chunks_domains +// .iter() +// .enumerate() +// .map(|(i, domain)| { +// quotient_chunks_domains +// .iter() +// .enumerate() +// .filter(|(j, _)| *j != i) +// .map(|(_, other_domain)| { +// other_domain.zp_at_point(zeta) +// * other_domain.zp_at_point(domain.first_point()).inverse() +// }) +// .product::() +// }) +// .collect_vec(); + +// let quotient = opened_values +// .quotient_chunks +// .iter() +// .enumerate() +// .map(|(ch_i, ch)| { +// ch.iter() +// .enumerate() +// .map(|(e_i, &c)| zps[ch_i] * SC::Challenge::monomial(e_i) * c) +// .sum::() +// }) +// .sum::(); + +// let mut bc_assigner = DefaultBCAssignment::new(); +// let mut exec_script_info = compute_quotient_zeta_script::<>( +// quotient_degree, +// zps, +// opened_values.quotient_chunks, +// quotient +// ); + +// exec_script_info.gen(&mut bc_assigner); + +// let res = execute_script_with_inputs( +// exec_script_info.get_eq_script(), +// exec_script_info.witness(), +// ); +// assert!(res.success); + +// Ok(()) +// } + #[derive(Debug)] pub enum VerificationError { InvalidProofShape, diff --git a/uni-stark/tests/fib_air.rs b/uni-stark/tests/fib_air.rs index fefe196..11bee53 100644 --- a/uni-stark/tests/fib_air.rs +++ b/uni-stark/tests/fib_air.rs @@ -1,23 +1,32 @@ use std::borrow::Borrow; use fri::{FriConfig, TwoAdicFriPcs}; +use itertools::Itertools; use p3_air::{Air, AirBuilder, AirBuilderWithPublicValues, BaseAir}; use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; -use p3_commit::ExtensionMmcs; +use p3_commit::{ExtensionMmcs, PolynomialSpace, TwoAdicMultiplicativeCoset}; use p3_dft::Radix2DitParallel; use p3_field::extension::BinomialExtensionField; -use p3_field::{AbstractField, Field, PrimeField64}; +use p3_field::{ + AbstractExtensionField, AbstractField, ExtensionField, Field, PrimeField64, TwoAdicField, +}; use p3_matrix::dense::RowMajorMatrix; use p3_matrix::Matrix; use p3_merkle_tree::FieldMerkleTreeMmcs; use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral}; use p3_symmetric::{PaddingFreeSponge, TruncatedPermutation}; +use primitives::bf_pcs::Pcs; use primitives::challenger::chan_field::U32; // use p3_challenger::DuplexChallenger; use primitives::challenger::{BfChallenger, Blake3Permutation}; use primitives::mmcs::taptree_mmcs::TapTreeMmcs; -use rand::thread_rng; -use uni_stark::{prove, verify, StarkConfig}; +use rand::{thread_rng, Rng, SeedableRng}; +use rand_chacha::ChaCha20Rng; +use script_manager::bc_assignment::DefaultBCAssignment; +use scripts::execute_script_with_inputs; +use uni_stark::{ + compute_quotient_zeta_script, get_log_quotient_degree, prove, verify, Proof, StarkConfig, +}; /// For testing the public values feature @@ -114,8 +123,8 @@ type ChallengeMmcs = TapTreeMmcs; type Challenger = BfChallenger; type Dft = Radix2DitParallel; -type Pcs = TwoAdicFriPcs; -type MyConfig = StarkConfig; +type MyPcs = TwoAdicFriPcs; +type MyConfig = StarkConfig; #[test] fn test_public_value() { @@ -129,7 +138,7 @@ fn test_public_value() { proof_of_work_bits: 8, mmcs: challenge_mmcs, }; - let pcs = Pcs::new(dft, val_mmcs, fri_config); + let pcs = MyPcs::new(dft, val_mmcs, fri_config); let config = MyConfig::new(pcs); let permutation = Blake3Permutation {}; let mut challenger = Challenger::new(permutation).unwrap(); @@ -154,6 +163,114 @@ fn test_public_value() { .expect("verification failed"); } +#[test] +fn test_quotient_zeta() { + let val_mmcs = ValMmcs::new(); + let challenge_mmcs = ChallengeMmcs::new(); + let dft = Dft {}; + let trace = generate_trace_rows::(0, 1, 1 << 3); + let fri_config = FriConfig { + log_blowup: 2, + num_queries: 28, + proof_of_work_bits: 8, + mmcs: challenge_mmcs, + }; + let pcs = MyPcs::new(dft, val_mmcs, fri_config); + let config = MyConfig::new(pcs); + let permutation = Blake3Permutation {}; + let mut challenger = Challenger::new(permutation).unwrap(); + + let pis = vec![ + BabyBear::from_canonical_u64(0), + BabyBear::from_canonical_u64(1), + BabyBear::from_canonical_u64(21), + ]; + let proof = prove(&config, &FibonacciAir {}, &mut challenger, trace, &pis); + + let Proof { + commitments, + opened_values, + opening_proof, + degree_bits, + } = proof; + + let degree = 1 << degree_bits; + let log_quotient_degree = + get_log_quotient_degree::(&FibonacciAir {}, 0, pis.len()); + let quotient_degree = 1 << log_quotient_degree; + + let trace_domain = TwoAdicMultiplicativeCoset { + log_n: degree_bits, + shift: Val::one(), + }; + let quotient_domain = + trace_domain.create_disjoint_domain(1 << (degree_bits + log_quotient_degree)); + let quotient_chunks_domains = quotient_domain.split_domains(quotient_degree); + + let mut rng = ChaCha20Rng::seed_from_u64(0u64); + + let zeta = rng.gen::(); + + let a = Val::generator().try_inverse().unwrap(); + + let generator = Val::two_adic_generator(quotient_domain.log_n); + + let quotient_chunk_nums = quotient_chunks_domains.len(); + + let zps = quotient_chunks_domains + .iter() + .enumerate() + .map(|(i, domain)| { + quotient_chunks_domains + .iter() + .enumerate() + .filter(|(j, _)| *j != i) + .map(|(_, other_domain)| { + other_domain.zp_at_point(zeta) + * other_domain.zp_at_point(domain.first_point()).inverse() + }) + .product::() + }) + .collect_vec(); + + let quotient = opened_values + .quotient_chunks + .iter() + .enumerate() + .map(|(ch_i, ch)| { + ch.iter() + .enumerate() + .map(|(e_i, &c)| { + zps[ch_i] + * as AbstractExtensionField< + BabyBear, + >>::monomial(e_i) + * c + }) + .sum::() + }) + .sum::(); + + let mut bc_assigner = DefaultBCAssignment::new(); + let mut exec_script_info = compute_quotient_zeta_script::( + quotient_chunk_nums, + zps, + opened_values.quotient_chunks, + quotient, + ); + + exec_script_info.gen(&mut bc_assigner); + + let res = + execute_script_with_inputs(exec_script_info.get_eq_script(), exec_script_info.witness()); + assert!(res.success); + + let res = execute_script_with_inputs( + exec_script_info.get_neq_script(), + exec_script_info.witness(), + ); + assert!(!res.success); +} // #[cfg(debug_assertions)] // #[test] // #[should_panic(expected = "assertion `left == right` failed: constraints had nonzero value")] From 44fe9b468f8624d61a871ba8836c9ac72a2c293c Mon Sep 17 00:00:00 2001 From: 0xhhh <52317293+cyl19970726@users.noreply.github.com> Date: Mon, 15 Jul 2024 18:13:51 +0800 Subject: [PATCH 11/25] use ScriptExpression to generate script for trace constraints (#23) * update ScriptExpression && add ScriptConstraintBuilder && add accmulator script * update script-expression * remove unuse code * add check for variable var_size after executing * update package structure && add num_script_expression && rename script_expression as field_script_expression * update script_expr * update uni-stark/src/lib.rs * remoe unuse code --- .../field_script_expr.rs} | 798 ++++++++++------- uni-stark/src/expr/mod.rs | 43 + uni-stark/src/expr/num_script_expr.rs | 819 ++++++++++++++++++ uni-stark/src/expr/script_builder.rs | 162 ++++ uni-stark/src/expr/script_helper.rs | 290 +++++++ uni-stark/src/expr/variable.rs | 313 +++++++ uni-stark/src/lib.rs | 3 +- uni-stark/src/verifier.rs | 178 +--- 8 files changed, 2174 insertions(+), 432 deletions(-) rename uni-stark/src/{scripts_expression.rs => expr/field_script_expr.rs} (55%) create mode 100644 uni-stark/src/expr/mod.rs create mode 100644 uni-stark/src/expr/num_script_expr.rs create mode 100644 uni-stark/src/expr/script_builder.rs create mode 100644 uni-stark/src/expr/script_helper.rs create mode 100644 uni-stark/src/expr/variable.rs diff --git a/uni-stark/src/scripts_expression.rs b/uni-stark/src/expr/field_script_expr.rs similarity index 55% rename from uni-stark/src/scripts_expression.rs rename to uni-stark/src/expr/field_script_expr.rs index 76e8dbe..1e013eb 100644 --- a/uni-stark/src/scripts_expression.rs +++ b/uni-stark/src/expr/field_script_expr.rs @@ -1,6 +1,5 @@ use alloc::boxed::Box; use alloc::collections::BTreeMap; -use alloc::rc::Rc; use alloc::sync::Arc; use alloc::vec::Vec; use alloc::{format, vec}; @@ -9,104 +8,191 @@ use core::fmt::Debug; use core::iter::{Product, Sum}; use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; -use bitcoin::hashes::cmp; -use bitcoin::opcodes::OP_ROLL; use bitcoin_script_stack::stack::{StackTracker, StackVariable}; -use common::{AbstractField, AsU32Vec}; -use p3_field::Field; +use common::AbstractField; use primitives::field::BfField; -use script_primitives::*; use scripts::treepp::*; use scripts::u31_lib::{ - u31_add, u31_double, u31_mul, u31_neg, u31_sub, u31_sub_u31ext, u31_to_u31ext, u31ext_add, - u31ext_add_u31, u31ext_double, u31ext_equalverify, u31ext_mul, u31ext_mul_u31, - u31ext_mul_u31_by_constant, u31ext_neg, u31ext_sub, u31ext_sub_u31, BabyBear4, BabyBearU31, + u31_add, u31_mul, u31_neg, u31_sub, u31_sub_u31ext, u31ext_add, u31ext_add_u31, + u31ext_equalverify, u31ext_mul, u31ext_mul_u31, u31ext_neg, u31ext_sub, u31ext_sub_u31, + BabyBear4, BabyBearU31, }; -use crate::symbolic_variable::SymbolicVariable; -use crate::Entry; +use super::variable::{ValueVariable, Variable}; +use super::Expression; use crate::SymbolicExpression::{self, *}; -pub mod script_primitives { - use bitcoin_script_stack::stack::{StackTracker, StackVariable}; +pub enum FieldScriptExpression { + ValueVariable { + v: ValueVariable, + debug: Cell, + var: StackVariable, + }, + InputVariable { + sv: Variable, + debug: Cell, + var: StackVariable, + }, + Constant { + f: F, + debug: Cell, + var: StackVariable, + }, + Add { + x: Arc>, + y: Arc>, + var: StackVariable, + debug: Cell, + }, + Sub { + x: Arc>, + y: Arc>, + var: StackVariable, + debug: Cell, + }, + Neg { + x: Arc>, + var: StackVariable, + debug: Cell, + }, + Mul { + x: Arc>, + y: Arc>, + var: StackVariable, + debug: Cell, + }, + EqualVerify { + x: Arc>, + y: Arc>, + debug: Cell, + }, + Exp { + x: Arc>, + y: Arc>, + var: StackVariable, + debug: Cell, + }, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct Variable { - row_index: usize, - column_index: usize, -} +impl FieldScriptExpression { + pub fn add_ext( + &self, + rhs: FieldScriptExpression, + ) -> FieldScriptExpression { + assert_eq!(F::U32_SIZE, 1); + assert_eq!(EF::U32_SIZE, 4); + FieldScriptExpression::::Add { + x: Arc::new(Box::new(self.clone())), + y: Arc::new(Box::new(rhs)), + var: StackVariable::null(), + debug: Cell::new(false), + } + } -impl From> for Variable { - fn from(value: SymbolicVariable) -> Self { - match value.entry { - Entry::Main { offset } => Variable { - row_index: value.index, - column_index: offset, - }, - Entry::Permutation { offset } => Variable { - row_index: value.index, - column_index: offset, - }, - Entry::Preprocessed { offset } => Variable { - row_index: value.index, - column_index: offset, - }, - _ => panic!("error type"), + pub fn add_base(&self, rhs: FieldScriptExpression) -> Self { + assert_eq!(F::U32_SIZE, 4); + assert_eq!(Base::U32_SIZE, 1); + FieldScriptExpression::Add { + x: Arc::new(Box::new(self.clone())), + y: Arc::new(Box::new(rhs)), + var: StackVariable::null(), + debug: Cell::new(false), } } -} -impl From<&SymbolicVariable> for Variable { - fn from(value: &SymbolicVariable) -> Self { - match value.entry { - Entry::Main { offset } => Variable { - row_index: value.index, - column_index: offset, - }, - Entry::Permutation { offset } => Variable { - row_index: value.index, - column_index: offset, - }, - Entry::Preprocessed { offset } => Variable { - row_index: value.index, - column_index: offset, - }, - _ => panic!("error type"), + pub fn mul_ext( + &self, + rhs: FieldScriptExpression, + ) -> FieldScriptExpression { + assert_eq!(F::U32_SIZE, 1); + assert_eq!(EF::U32_SIZE, 4); + FieldScriptExpression::::Mul { + x: Arc::new(Box::new(self.clone())), + y: Arc::new(Box::new(rhs)), + var: StackVariable::null(), + debug: Cell::new(false), } } -} -pub trait Expression { - fn express_to_script( + pub fn mul_base(&self, rhs: FieldScriptExpression) -> Self { + assert_eq!(F::U32_SIZE, 4); + assert_eq!(Base::U32_SIZE, 1); + FieldScriptExpression::Mul { + x: Arc::new(Box::new(self.clone())), + y: Arc::new(Box::new(rhs)), + var: StackVariable::null(), + debug: Cell::new(false), + } + } + + pub fn sub_ext( &self, - stack: &mut StackTracker, - input_variables: &BTreeMap<&Variable, StackVariable>, - ) -> Script; + rhs: FieldScriptExpression, + ) -> FieldScriptExpression { + assert_eq!(F::U32_SIZE, 1); + assert_eq!(EF::U32_SIZE, 4); + FieldScriptExpression::::Sub { + x: Arc::new(Box::new(self.clone())), + y: Arc::new(Box::new(rhs)), + var: StackVariable::null(), + debug: Cell::new(false), + } + } - fn var_size(&self) -> u32; + pub fn sub_base(&self, rhs: FieldScriptExpression) -> Self { + assert_eq!(F::U32_SIZE, 4); + assert_eq!(Base::U32_SIZE, 1); + FieldScriptExpression::Sub { + x: Arc::new(Box::new(self.clone())), + y: Arc::new(Box::new(rhs)), + var: StackVariable::null(), + debug: Cell::new(false), + } + } - #[allow(unused)] - fn set_debug(&self); + pub fn equal_verify(&self, rhs: Self) -> Self { + FieldScriptExpression::EqualVerify { + x: Arc::new(Box::new(self.clone())), + y: Arc::new(Box::new(rhs.clone())), + debug: Cell::new(false), + } + } + + pub fn equal_verify_for_f(&self, rhs: F) -> Self { + FieldScriptExpression::EqualVerify { + x: Arc::new(Box::new(self.clone())), + y: Arc::new(Box::new(Self::from(rhs))), + debug: Cell::new(false), + } + } } -impl Expression for ScriptExpression { +impl Expression for FieldScriptExpression { fn set_debug(&self) { match self { - ScriptExpression::InputVariable { debug, .. } => { + FieldScriptExpression::ValueVariable { debug, .. } => { debug.set(true); } - ScriptExpression::Constant(f) => {} - ScriptExpression::Add { debug, .. } => { + FieldScriptExpression::InputVariable { debug, .. } => { debug.set(true); } - ScriptExpression::Sub { debug, .. } => { + FieldScriptExpression::Constant { debug, .. } => debug.set(true), + FieldScriptExpression::Add { debug, .. } => { debug.set(true); } - ScriptExpression::Neg { debug, .. } => { + FieldScriptExpression::Sub { debug, .. } => { debug.set(true); } - ScriptExpression::Mul { debug, .. } => { + FieldScriptExpression::Neg { debug, .. } => { + debug.set(true); + } + FieldScriptExpression::Mul { debug, .. } => { + debug.set(true); + } + FieldScriptExpression::EqualVerify { debug, .. } => { + debug.set(true); + } + FieldScriptExpression::Exp { debug, .. } => { debug.set(true); } }; @@ -115,19 +201,37 @@ impl Expression for ScriptExpression { fn express_to_script( &self, stack: &mut StackTracker, - input_variables: &BTreeMap<&Variable, StackVariable>, + input_variables: &BTreeMap, ) -> Script { match self { - ScriptExpression::InputVariable { sv, debug } => { - let var = input_variables.get(sv).unwrap(); - stack.copy_var(var.clone()); - stack.debug(); + FieldScriptExpression::ValueVariable { v, debug, mut var } => { + let intput_var = input_variables.get(v.get_var()).unwrap(); + var = stack.copy_var(intput_var.clone()); + if debug.get() == true { + stack.debug(); + } + if v.get_var().get_var_size().is_some() { + assert_eq!(var.size(), v.get_var().get_var_size().unwrap()); + } } - ScriptExpression::Constant(f) => { + FieldScriptExpression::InputVariable { sv, debug, mut var } => { + let intput_var = input_variables.get(sv).unwrap(); + var = stack.copy_var(intput_var.clone()); + if debug.get() == true { + stack.debug(); + } + if sv.get_var_size().is_some() { + assert_eq!(var.size(), sv.get_var_size().unwrap()); + } + } + FieldScriptExpression::Constant { f, mut var, debug } => { let v = f.as_u32_vec(); - stack.bignumber(v); + var = stack.bignumber(v); + if debug.get() == true { + stack.debug(); + } } - ScriptExpression::Add { + FieldScriptExpression::Add { x, y, debug, @@ -135,9 +239,6 @@ impl Expression for ScriptExpression { } => { x.express_to_script(stack, input_variables); // F y.express_to_script(stack, input_variables); // EF - if debug.get() == true { - stack.debug(); - } if x.var_size() == y.var_size() { let vars = stack .custom1( @@ -187,7 +288,7 @@ impl Expression for ScriptExpression { stack.debug(); } } - ScriptExpression::Sub { + FieldScriptExpression::Sub { x, y, debug, @@ -195,9 +296,6 @@ impl Expression for ScriptExpression { } => { x.express_to_script(stack, input_variables); y.express_to_script(stack, input_variables); - if debug.get() == true { - stack.debug(); - } if x.var_size() == y.var_size() { let vars = stack .custom1( @@ -250,11 +348,8 @@ impl Expression for ScriptExpression { } assert_eq!(var.size(), F::U32_SIZE as u32); } - ScriptExpression::Neg { x, debug, mut var } => { + FieldScriptExpression::Neg { x, debug, mut var } => { x.express_to_script(stack, input_variables); - if debug.get() == true { - stack.debug(); - } let vars = stack .custom1( script! { @@ -277,7 +372,7 @@ impl Expression for ScriptExpression { } assert_eq!(var.size(), F::U32_SIZE as u32); } - ScriptExpression::Mul { + FieldScriptExpression::Mul { x, y, debug, @@ -285,9 +380,6 @@ impl Expression for ScriptExpression { } => { x.express_to_script(stack, input_variables); y.express_to_script(stack, input_variables); - if debug.get() == true { - stack.debug(); - } if x.var_size() == y.var_size() { let vars = stack .custom1( @@ -336,78 +428,94 @@ impl Expression for ScriptExpression { } assert_eq!(var.size(), F::U32_SIZE as u32); } - }; + FieldScriptExpression::EqualVerify { x, y, debug } => { + x.express_to_script(stack, input_variables); + y.express_to_script(stack, input_variables); + assert_eq!(x.var_size(), y.var_size()); + if x.var_size() == 1 { + stack.op_equalverify(); + } else { + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "u31ext_equalverify", + ); + } + } + FieldScriptExpression::Exp { + x, + y, + debug, + mut var, + } => { + x.express_to_script(stack, input_variables); + // y.express_to_script(stack, input_variables); + // todo: check y is the NumScriptExpression + + assert_eq!(var.size(), F::U32_SIZE as u32); + } + }; stack.get_script() } fn var_size(&self) -> u32 { F::U32_SIZE as u32 } -} -pub enum ScriptExpression { - InputVariable { - sv: Variable, - debug: Cell, - }, - Constant(F), - Add { - x: Arc>, - y: Arc>, - var: StackVariable, - debug: Cell, - }, - Sub { - x: Arc>, - y: Arc>, - var: StackVariable, - debug: Cell, - }, - Neg { - x: Arc>, - var: StackVariable, - debug: Cell, - }, - Mul { - x: Arc>, - y: Arc>, - var: StackVariable, - debug: Cell, - }, + fn get_var(&self) -> Option> { + match self { + FieldScriptExpression::ValueVariable { var, .. } => Some(vec![var]), + FieldScriptExpression::InputVariable { var, .. } => Some(vec![var]), + FieldScriptExpression::Constant { var, .. } => Some(vec![var]), + FieldScriptExpression::Add { var, .. } => Some(vec![var]), + FieldScriptExpression::Sub { var, .. } => Some(vec![var]), + FieldScriptExpression::Neg { var, .. } => Some(vec![var]), + FieldScriptExpression::Mul { var, .. } => Some(vec![var]), + FieldScriptExpression::EqualVerify { .. } => None, + FieldScriptExpression::Exp { var, .. } => Some(vec![var]), + } + } } -impl From<&SymbolicExpression> for ScriptExpression { +impl From<&SymbolicExpression> for FieldScriptExpression { fn from(value: &SymbolicExpression) -> Self { match value { - SymbolicExpression::Variable(v) => ScriptExpression::InputVariable { + SymbolicExpression::Variable(v) => FieldScriptExpression::InputVariable { sv: v.into(), debug: Cell::new(false), + var: StackVariable::null(), }, - SymbolicExpression::IsFirstRow => ScriptExpression::one(), - SymbolicExpression::IsLastRow => ScriptExpression::one(), - SymbolicExpression::IsTransition => ScriptExpression::one(), - SymbolicExpression::Constant(f) => ScriptExpression::Constant(f.clone()), - SymbolicExpression::Add { x, y, .. } => ScriptExpression::Add { - x: Arc::new(Box::new(ScriptExpression::from(&*x.clone()))), - y: Arc::new(Box::new(ScriptExpression::from(&*y.clone()))), + SymbolicExpression::IsFirstRow => FieldScriptExpression::one(), + SymbolicExpression::IsLastRow => FieldScriptExpression::one(), + SymbolicExpression::IsTransition => FieldScriptExpression::one(), + SymbolicExpression::Constant(f) => FieldScriptExpression::Constant { + f: f.clone(), debug: Cell::new(false), var: StackVariable::null(), }, - SymbolicExpression::Sub { x, y, .. } => ScriptExpression::Sub { - x: Arc::new(Box::new(ScriptExpression::from(&*x.clone()))), - y: Arc::new(Box::new(ScriptExpression::from(&*y.clone()))), + SymbolicExpression::Add { x, y, .. } => FieldScriptExpression::Add { + x: Arc::new(Box::new(FieldScriptExpression::from(&*x.clone()))), + y: Arc::new(Box::new(FieldScriptExpression::from(&*y.clone()))), debug: Cell::new(false), var: StackVariable::null(), }, - SymbolicExpression::Neg { x, .. } => ScriptExpression::Neg { - x: Arc::new(Box::new(ScriptExpression::from(&*x.clone()))), + SymbolicExpression::Sub { x, y, .. } => FieldScriptExpression::Sub { + x: Arc::new(Box::new(FieldScriptExpression::from(&*x.clone()))), + y: Arc::new(Box::new(FieldScriptExpression::from(&*y.clone()))), debug: Cell::new(false), var: StackVariable::null(), }, - SymbolicExpression::Mul { x, y, .. } => ScriptExpression::Mul { - x: Arc::new(Box::new(ScriptExpression::from(&*x.clone()))), - y: Arc::new(Box::new(ScriptExpression::from(&*y.clone()))), + SymbolicExpression::Neg { x, .. } => FieldScriptExpression::Neg { + x: Arc::new(Box::new(FieldScriptExpression::from(&*x.clone()))), + debug: Cell::new(false), + var: StackVariable::null(), + }, + SymbolicExpression::Mul { x, y, .. } => FieldScriptExpression::Mul { + x: Arc::new(Box::new(FieldScriptExpression::from(&*x.clone()))), + y: Arc::new(Box::new(FieldScriptExpression::from(&*y.clone()))), debug: Cell::new(false), var: StackVariable::null(), }, @@ -415,77 +523,119 @@ impl From<&SymbolicExpression> for ScriptExpression { } } -impl Default for ScriptExpression { +impl Default for FieldScriptExpression { fn default() -> Self { - Self::Constant(F::zero()) + Self::zero() } } -impl From for ScriptExpression { +impl From for FieldScriptExpression { fn from(value: F) -> Self { - Self::Constant(value) + Self::Constant { + f: value, + debug: Cell::new(false), + var: StackVariable::null(), + } } } -impl Debug for ScriptExpression { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { +impl Debug for FieldScriptExpression { + fn fmt(&self, fm: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { - ScriptExpression::InputVariable { sv, .. } => f + FieldScriptExpression::ValueVariable { v, .. } => fm + .debug_struct("ScriptExpression::ValueVariable") + .field("var", v) + .finish(), + FieldScriptExpression::InputVariable { sv, .. } => fm .debug_struct("ScriptExpression::InputVariable") .field("sv", sv) .finish(), - ScriptExpression::Constant(value) => f + FieldScriptExpression::Constant { f, .. } => fm .debug_struct("ScriptExpression::Constant") - .field("value", value) + .field("f", f) .finish(), - ScriptExpression::Add { x, y, debug, var } => f + FieldScriptExpression::Add { x, y, debug, var } => fm .debug_struct("ScriptExpression::Add") .field("variable", var) .finish(), - ScriptExpression::Sub { x, y, debug, var } => f + FieldScriptExpression::Sub { x, y, debug, var } => fm .debug_struct("ScriptExpression::Sub") .field("variable", var) .finish(), - ScriptExpression::Mul { x, y, debug, var } => f + FieldScriptExpression::Mul { x, y, debug, var } => fm .debug_struct("ScriptExpression::Mul") .field("variable", var) .finish(), - ScriptExpression::Neg { x, debug, var } => f + FieldScriptExpression::Neg { x, debug, var } => fm .debug_struct("ScriptExpression::Neg") .field("variable", var) .finish(), + FieldScriptExpression::EqualVerify { x, y, debug } => { + fm.debug_struct("ScriptExpression::Equal").finish() + } + FieldScriptExpression::Exp { x, y, debug, var } => fm + .debug_struct("ScriptExpression::Exp") + .field("variable", var) + .finish(), } } } -impl Clone for ScriptExpression { +impl Clone for FieldScriptExpression { fn clone(&self) -> Self { match self { - ScriptExpression::InputVariable { sv, debug } => ScriptExpression::InputVariable { - sv: sv.clone(), + FieldScriptExpression::ValueVariable { v, debug, var } => { + FieldScriptExpression::ValueVariable { + v: v.clone(), + debug: debug.clone(), + var: var.clone(), + } + } + FieldScriptExpression::InputVariable { sv, debug, var } => { + FieldScriptExpression::InputVariable { + sv: sv.clone(), + debug: debug.clone(), + var: var.clone(), + } + } + FieldScriptExpression::Constant { f, debug, var } => FieldScriptExpression::Constant { + f: f.clone(), debug: debug.clone(), + var: var.clone(), }, - ScriptExpression::Constant(value) => ScriptExpression::Constant(value.clone()), - ScriptExpression::Add { x, y, debug, var } => ScriptExpression::Add { + FieldScriptExpression::Add { x, y, debug, var } => FieldScriptExpression::Add { x: x.clone(), y: y.clone(), debug: debug.clone(), var: var.clone(), }, - ScriptExpression::Mul { x, y, debug, var } => ScriptExpression::Mul { + FieldScriptExpression::Mul { x, y, debug, var } => FieldScriptExpression::Mul { x: x.clone(), y: y.clone(), debug: debug.clone(), var: var.clone(), }, - ScriptExpression::Sub { x, y, debug, var } => ScriptExpression::Sub { + FieldScriptExpression::Sub { x, y, debug, var } => FieldScriptExpression::Sub { x: x.clone(), y: y.clone(), debug: debug.clone(), var: var.clone(), }, - ScriptExpression::Neg { x, debug, var } => ScriptExpression::Neg { + FieldScriptExpression::Neg { x, debug, var } => FieldScriptExpression::Neg { + x: x.clone(), + debug: debug.clone(), + var: var.clone(), + }, + FieldScriptExpression::EqualVerify { x, y, debug } => { + FieldScriptExpression::EqualVerify { + x: x.clone(), + y: y.clone(), + debug: debug.clone(), + } + } + FieldScriptExpression::Exp { x, y, debug, var } => FieldScriptExpression::Exp { x: x.clone(), + y: y.clone(), debug: debug.clone(), var: var.clone(), }, @@ -493,20 +643,20 @@ impl Clone for ScriptExpression { } } -impl AbstractField for ScriptExpression { +impl AbstractField for FieldScriptExpression { type F = F; fn zero() -> Self { - Self::Constant(F::zero()) + Self::from(F::zero()) } fn one() -> Self { - Self::Constant(F::one()) + Self::from(F::one()) } fn two() -> Self { - Self::Constant(F::two()) + Self::from(F::two()) } fn neg_one() -> Self { - Self::Constant(F::neg_one()) + Self::from(F::neg_one()) } #[inline] @@ -515,43 +665,43 @@ impl AbstractField for ScriptExpression { } fn from_bool(b: bool) -> Self { - Self::Constant(F::from_bool(b)) + Self::from(F::from_bool(b)) } fn from_canonical_u8(n: u8) -> Self { - Self::Constant(F::from_canonical_u8(n)) + Self::from(F::from_canonical_u8(n)) } fn from_canonical_u16(n: u16) -> Self { - Self::Constant(F::from_canonical_u16(n)) + Self::from(F::from_canonical_u16(n)) } fn from_canonical_u32(n: u32) -> Self { - Self::Constant(F::from_canonical_u32(n)) + Self::from(F::from_canonical_u32(n)) } fn from_canonical_u64(n: u64) -> Self { - Self::Constant(F::from_canonical_u64(n)) + Self::from(F::from_canonical_u64(n)) } fn from_canonical_usize(n: usize) -> Self { - Self::Constant(F::from_canonical_usize(n)) + Self::from(F::from_canonical_usize(n)) } fn from_wrapped_u32(n: u32) -> Self { - Self::Constant(F::from_wrapped_u32(n)) + Self::from(F::from_wrapped_u32(n)) } fn from_wrapped_u64(n: u64) -> Self { - Self::Constant(F::from_wrapped_u64(n)) + Self::from(F::from_wrapped_u64(n)) } fn generator() -> Self { - Self::Constant(F::generator()) + Self::from(F::generator()) } } -impl Add for ScriptExpression { +impl Add for FieldScriptExpression { type Output = Self; fn add(self, rhs: F) -> Self { @@ -565,7 +715,7 @@ impl Add for ScriptExpression { } } -impl Add for ScriptExpression { +impl Add for FieldScriptExpression { type Output = Self; fn add(self, rhs: Self) -> Self { @@ -578,7 +728,7 @@ impl Add for ScriptExpression { } } -impl Add<&Self> for ScriptExpression { +impl Add<&Self> for FieldScriptExpression { type Output = Self; fn add(self, rhs: &Self) -> Self { @@ -591,31 +741,31 @@ impl Add<&Self> for ScriptExpression { } } -impl AddAssign for ScriptExpression { +impl AddAssign for FieldScriptExpression { fn add_assign(&mut self, rhs: Self) { *self = self.clone() + rhs; } } -impl AddAssign for ScriptExpression { +impl AddAssign for FieldScriptExpression { fn add_assign(&mut self, rhs: F) { *self += Self::from(rhs); } } -impl Sum for ScriptExpression { +impl Sum for FieldScriptExpression { fn sum>(iter: I) -> Self { iter.reduce(|x, y| x + y).unwrap_or(Self::zero()) } } -impl Sum for ScriptExpression { +impl Sum for FieldScriptExpression { fn sum>(iter: I) -> Self { iter.map(|x| Self::from(x)).sum() } } -impl Sub for ScriptExpression { +impl Sub for FieldScriptExpression { type Output = Self; fn sub(self, rhs: Self) -> Self { @@ -628,7 +778,7 @@ impl Sub for ScriptExpression { } } -impl Sub for ScriptExpression { +impl Sub for FieldScriptExpression { type Output = Self; fn sub(self, rhs: F) -> Self { @@ -636,19 +786,19 @@ impl Sub for ScriptExpression { } } -impl SubAssign for ScriptExpression { +impl SubAssign for FieldScriptExpression { fn sub_assign(&mut self, rhs: Self) { *self = self.clone() - rhs; } } -impl SubAssign for ScriptExpression { +impl SubAssign for FieldScriptExpression { fn sub_assign(&mut self, rhs: F) { *self -= Self::from(rhs); } } -impl Neg for ScriptExpression { +impl Neg for FieldScriptExpression { type Output = Self; fn neg(self) -> Self { @@ -660,7 +810,7 @@ impl Neg for ScriptExpression { } } -impl Mul for ScriptExpression { +impl Mul for FieldScriptExpression { type Output = Self; fn mul(self, rhs: Self) -> Self { @@ -674,7 +824,7 @@ impl Mul for ScriptExpression { } } -impl Mul for ScriptExpression { +impl Mul for FieldScriptExpression { type Output = Self; fn mul(self, rhs: F) -> Self { @@ -682,25 +832,25 @@ impl Mul for ScriptExpression { } } -impl MulAssign for ScriptExpression { +impl MulAssign for FieldScriptExpression { fn mul_assign(&mut self, rhs: Self) { *self = self.clone() * rhs; } } -impl MulAssign for ScriptExpression { +impl MulAssign for FieldScriptExpression { fn mul_assign(&mut self, rhs: F) { *self *= Self::from(rhs); } } -impl Product for ScriptExpression { +impl Product for FieldScriptExpression { fn product>(iter: I) -> Self { iter.reduce(|x, y| x * y).unwrap_or(Self::one()) } } -impl Product for ScriptExpression { +impl Product for FieldScriptExpression { fn product>(iter: I) -> Self { iter.map(|x| Self::from(x)).product() } @@ -722,7 +872,7 @@ mod tests { use scripts::treepp::*; use scripts::u31_lib::{u31ext_equalverify, BabyBear4, BabyBearU31}; - use super::{Expression, ScriptExpression, Variable}; + use super::{Expression, FieldScriptExpression, Variable, *}; use crate::{prove, verify, StarkConfig, SymbolicAirBuilder, SymbolicExpression}; type EF = BinomialExtensionField; @@ -740,21 +890,23 @@ mod tests { when_transition.assert_eq(local[0] + local[1], next[1]); let cs = builder.constraints(); - let script_exp: Vec> = - cs.iter().map(|cons| ScriptExpression::from(cons)).collect(); + let script_exp: Vec> = cs + .iter() + .map(|cons| FieldScriptExpression::from(cons)) + .collect(); } #[test] fn test_script_expression_add() { let bmap = BTreeMap::new(); let mut stack = StackTracker::new(); - let a = ScriptExpression::from(BabyBear::one()); - let b = ScriptExpression::from(BabyBear::two()); + let a = FieldScriptExpression::from(BabyBear::one()); + let b = FieldScriptExpression::from(BabyBear::two()); let c = a + b; c.set_debug(); - let d = ScriptExpression::from(BabyBear::two()); - let e = ScriptExpression::from(BabyBear::two()); + let d = FieldScriptExpression::from(BabyBear::two()); + let e = FieldScriptExpression::from(BabyBear::two()); let f = d + e; let g = c + f; // 4 + 3 = 7 @@ -769,35 +921,17 @@ mod tests { fn test_script_expression_u31add_u31ext() { let bmap = BTreeMap::new(); let mut stack = StackTracker::new(); - let a = ScriptExpression::from(BabyBear::one()); - let b = ScriptExpression::from(EF::two()); - // let c = b +a ; - let c = ScriptExpression::::Add { - x: Arc::new(Box::new(a)), - y: Arc::new(Box::new(b)), - debug: Cell::new(false), - var: StackVariable::null(), - }; + let a = FieldScriptExpression::from(BabyBear::one()); + let b = FieldScriptExpression::from(EF::two()); + let c = a.add_ext(b); - let d = ScriptExpression::from(BabyBear::two()); - let e = ScriptExpression::from(EF::two()); - let f = ScriptExpression::::Add { - x: Arc::new(Box::new(e)), - y: Arc::new(Box::new(d)), - debug: Cell::new(false), - var: StackVariable::null(), - }; + let d = FieldScriptExpression::from(BabyBear::two()); + let e = FieldScriptExpression::from(EF::two()); + let f = e.add_base(d); let g = c + f; // 4 + 3 = 7 - let script = g.express_to_script(&mut stack, &bmap); - stack.bignumber(EF::from_canonical_u32(7u32).as_u32_vec()); - stack.custom( - u31ext_equalverify::(), - 2, - false, - 0, - "u31ext_equalverify", - ); + let h = g.equal_verify_for_f(EF::from_canonical_u32(7u32)); + let script = h.express_to_script(&mut stack, &bmap); stack.op_true(); let res = stack.run(); assert!(res.success); @@ -807,24 +941,13 @@ mod tests { fn test_script_expression_u31sub_u31ext() { let bmap = BTreeMap::new(); let mut stack = StackTracker::new(); - let a = ScriptExpression::from(BabyBear::one()); - let b = ScriptExpression::from(EF::two()); - let c = ScriptExpression::::Sub { - x: Arc::new(Box::new(a)), - y: Arc::new(Box::new(b)), - debug: Cell::new(false), - var: StackVariable::null(), - }; - - let d = ScriptExpression::from(BabyBear::two()); - let e = ScriptExpression::from(EF::from_canonical_u32(4)); - let f = ScriptExpression::::Sub { - x: Arc::new(Box::new(e)), - y: Arc::new(Box::new(d)), - debug: Cell::new(false), - var: StackVariable::null(), - }; + let a = FieldScriptExpression::from(BabyBear::one()); + let b = FieldScriptExpression::from(EF::two()); + let c = a.sub_ext(b); + let d = FieldScriptExpression::from(BabyBear::two()); + let e = FieldScriptExpression::from(EF::from_canonical_u32(4)); + let f = e.sub_base(d); let g = c + f; // 4 + 3 = 7 let script = g.express_to_script(&mut stack, &bmap); stack.bignumber(EF::from_canonical_u32(1u32).as_u32_vec()); @@ -844,18 +967,18 @@ mod tests { fn test_script_expression_u31mul_u31ext() { let bmap = BTreeMap::new(); let mut stack = StackTracker::new(); - let a = ScriptExpression::from(BabyBear::one()); - let b = ScriptExpression::from(EF::two()); - let c = ScriptExpression::::Mul { + let a = FieldScriptExpression::from(BabyBear::one()); + let b = FieldScriptExpression::from(EF::two()); + let c = FieldScriptExpression::::Mul { x: Arc::new(Box::new(a)), y: Arc::new(Box::new(b)), debug: Cell::new(false), var: StackVariable::null(), }; - let d = ScriptExpression::from(BabyBear::two()); - let e = ScriptExpression::from(EF::from_canonical_u32(4)); - let f = ScriptExpression::::Mul { + let d = FieldScriptExpression::from(BabyBear::two()); + let e = FieldScriptExpression::from(EF::from_canonical_u32(4)); + let f = FieldScriptExpression::::Mul { x: Arc::new(Box::new(e)), y: Arc::new(Box::new(d)), debug: Cell::new(false), @@ -881,7 +1004,7 @@ mod tests { fn test_ext_constant() { let mut stack = StackTracker::new(); let bmap = BTreeMap::new(); - let a = ScriptExpression::from(EF::one()); + let a = FieldScriptExpression::from(EF::one()); a.express_to_script(&mut stack, &bmap); let res = EF::one(); @@ -901,27 +1024,15 @@ mod tests { #[test] fn test_script_expr_with_input() { - let var1 = Variable { - row_index: 0, - column_index: 0, - }; - let var2 = Variable { - row_index: 0, - column_index: 1, - }; - let var3 = Variable { - row_index: 1, - column_index: 0, - }; - let var4 = Variable { - row_index: 1, - column_index: 1, - }; + let var1 = Variable::new(0, 0); + let var2 = Variable::new(0, 1); + let var3 = Variable::new(1, 0); + let var4 = Variable::new(1, 1); let mut stack = StackTracker::new(); let mut bmap = BTreeMap::new(); bmap.insert( - &var1, + var1, stack.var( 1, script! { {BabyBear::from_canonical_u32(1u32).as_u32_vec()[0]}}, @@ -929,7 +1040,7 @@ mod tests { ), ); bmap.insert( - &var2, + var2, stack.var( 1, script! { {BabyBear::from_canonical_u32(2u32).as_u32_vec()[0]}}, @@ -937,7 +1048,7 @@ mod tests { ), ); bmap.insert( - &var3, + var3, stack.var( 1, script! {{BabyBear::from_canonical_u32(3u32).as_u32_vec()[0]}}, @@ -945,7 +1056,7 @@ mod tests { ), ); bmap.insert( - &var4, + var4, stack.var( 1, script! {{BabyBear::from_canonical_u32(4u32).as_u32_vec()[0]}}, @@ -953,21 +1064,25 @@ mod tests { ), ); - let var1_wrap = ScriptExpression::InputVariable { + let var1_wrap = FieldScriptExpression::InputVariable { sv: var1, debug: Cell::new(false), + var: StackVariable::null(), }; - let var2_wrap = ScriptExpression::::InputVariable { + let var2_wrap = FieldScriptExpression::::InputVariable { sv: var2, debug: Cell::new(false), + var: StackVariable::null(), }; - let var3_wrap = ScriptExpression::InputVariable { + let var3_wrap = FieldScriptExpression::InputVariable { sv: var3, debug: Cell::new(false), + var: StackVariable::null(), }; - let var4_wrap = ScriptExpression::::InputVariable { + let var4_wrap = FieldScriptExpression::::InputVariable { sv: var4, debug: Cell::new(false), + var: StackVariable::null(), }; let res1 = var1_wrap + var2_wrap; let res2 = var3_wrap + var4_wrap; @@ -987,12 +1102,111 @@ mod tests { assert!(res.success); } + #[test] + fn test_script_expr_with_extinput() { + let var1 = Variable::new(0, 0); + let var2 = Variable::new(0, 1); + let var3 = Variable::new(1, 0); + let var4 = Variable::new(1, 1); + + let mut stack = StackTracker::new(); + let mut bmap = BTreeMap::new(); + bmap.insert( + var1, + stack.var( + 4, + script! { + {EF::from_canonical_u32(1u32).as_u32_vec()[3]} + {EF::from_canonical_u32(1u32).as_u32_vec()[2]} + {EF::from_canonical_u32(1u32).as_u32_vec()[1]} + {EF::from_canonical_u32(1u32).as_u32_vec()[0]} + }, + "input 1", + ), + ); + bmap.insert( + var2, + stack.var( + 4, + script! { + {EF::from_canonical_u32(2u32).as_u32_vec()[3]} + {EF::from_canonical_u32(2u32).as_u32_vec()[2]} + {EF::from_canonical_u32(2u32).as_u32_vec()[1]} + {EF::from_canonical_u32(2u32).as_u32_vec()[0]} + }, + "input 2", + ), + ); + bmap.insert( + var3, + stack.var( + 4, + script! {{EF::from_canonical_u32(3u32).as_u32_vec()[3]} {EF::from_canonical_u32(3u32).as_u32_vec()[2]} {EF::from_canonical_u32(3u32).as_u32_vec()[1]} {EF::from_canonical_u32(3u32).as_u32_vec()[0]}}, + "input 3", + ), + ); + bmap.insert( + var4, + stack.var( + 4, + script! {{EF::from_canonical_u32(4u32).as_u32_vec()[3]} {EF::from_canonical_u32(4u32).as_u32_vec()[2]} {EF::from_canonical_u32(4u32).as_u32_vec()[1]} {EF::from_canonical_u32(4u32).as_u32_vec()[0]}}, + "input 4", + ), + ); + + let var1_wrap = FieldScriptExpression::::InputVariable { + sv: var1, + debug: Cell::new(false), + var: StackVariable::null(), + }; + let var2_wrap = FieldScriptExpression::InputVariable { + sv: var2, + debug: Cell::new(false), + var: StackVariable::null(), + }; + let var3_wrap = FieldScriptExpression::InputVariable { + sv: var3, + debug: Cell::new(false), + var: StackVariable::null(), + }; + let var4_wrap = FieldScriptExpression::InputVariable { + sv: var4, + debug: Cell::new(false), + var: StackVariable::null(), + }; + stack.debug(); + let res1 = var1_wrap + var2_wrap; + let res2 = var3_wrap + var4_wrap; + + let res = res1 + res2 + EF::from_canonical_u32(3); + res.express_to_script(&mut stack, &bmap); + + // stack.debug(); + stack.bignumber(EF::from_canonical_u32(13u32).as_u32_vec()); + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "u31ext_equalverify", + ); + stack.debug(); + + stack.drop(*bmap.get(&var4).unwrap()); + stack.drop(*bmap.get(&var3).unwrap()); + stack.drop(*bmap.get(&var2).unwrap()); + stack.drop(*bmap.get(&var1).unwrap()); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + #[test] fn test_script_expression_extadd() { let bmap = BTreeMap::new(); let mut stack = StackTracker::new(); - let a = ScriptExpression::from(EF::one()); - let b = ScriptExpression::from(EF::two()); + let a = FieldScriptExpression::from(EF::one()); + let b = FieldScriptExpression::from(EF::two()); let c = a + b; let script = c.express_to_script(&mut stack, &bmap); @@ -1017,12 +1231,12 @@ mod tests { fn test_script_expression_sub() { let bmap = BTreeMap::new(); let mut stack = StackTracker::new(); - let a = ScriptExpression::from(BabyBear::one()); - let b = ScriptExpression::from(BabyBear::two()); + let a = FieldScriptExpression::from(BabyBear::one()); + let b = FieldScriptExpression::from(BabyBear::two()); let c = b - a; // 1 - let d = ScriptExpression::from(BabyBear::two()); - let e = ScriptExpression::from(BabyBear::from_canonical_u32(8)); + let d = FieldScriptExpression::from(BabyBear::two()); + let e = FieldScriptExpression::from(BabyBear::from_canonical_u32(8)); let f = e - d; // 6 let g = f - c; // 5 @@ -1037,12 +1251,12 @@ mod tests { fn test_script_expression_extsub() { let bmap = BTreeMap::new(); let mut stack = StackTracker::new(); - let a = ScriptExpression::from(EF::one()); - let b = ScriptExpression::from(EF::two()); + let a = FieldScriptExpression::from(EF::one()); + let b = FieldScriptExpression::from(EF::two()); let c = b - a; // 1 - let d = ScriptExpression::from(EF::two()); - let e = ScriptExpression::from(EF::from_canonical_u32(8)); + let d = FieldScriptExpression::from(EF::two()); + let e = FieldScriptExpression::from(EF::from_canonical_u32(8)); let f = e - d; // 6 let g = f - c; // 5 let script = g.express_to_script(&mut stack, &bmap); @@ -1063,12 +1277,12 @@ mod tests { fn test_script_expression_mul() { let bmap = BTreeMap::new(); let mut stack = StackTracker::new(); - let a = ScriptExpression::from(BabyBear::one()); - let b = ScriptExpression::from(BabyBear::two()); + let a = FieldScriptExpression::from(BabyBear::one()); + let b = FieldScriptExpression::from(BabyBear::two()); let c = b * a; // 2 - let d = ScriptExpression::from(BabyBear::two()); - let e = ScriptExpression::from(BabyBear::from_canonical_u32(8)); + let d = FieldScriptExpression::from(BabyBear::two()); + let e = FieldScriptExpression::from(BabyBear::from_canonical_u32(8)); let f = e * d * BabyBear::one(); // 16 stack.show_stack(); let g = f * c; // 32 @@ -1083,12 +1297,12 @@ mod tests { fn test_script_expression_extmul() { let bmap = BTreeMap::new(); let mut stack = StackTracker::new(); - let a = ScriptExpression::from(EF::one()); - let b = ScriptExpression::from(EF::two()); + let a = FieldScriptExpression::from(EF::one()); + let b = FieldScriptExpression::from(EF::two()); let c = b * a; // 2 - let d = ScriptExpression::from(EF::two()); - let e = ScriptExpression::from(EF::from_canonical_u32(8)); + let d = FieldScriptExpression::from(EF::two()); + let e = FieldScriptExpression::from(EF::from_canonical_u32(8)); let f = e * d; // 16 let g = f * c; // 32 let script = g.express_to_script(&mut stack, &bmap); @@ -1112,7 +1326,7 @@ mod tests { fn test_script_expression_neg() { let bmap = BTreeMap::new(); let mut stack = StackTracker::new(); - let a = ScriptExpression::from(BabyBear::one()); + let a = FieldScriptExpression::from(BabyBear::one()); let b = -a * BabyBear::two(); let script = b.express_to_script(&mut stack, &bmap); stack.number(BabyBear::from_canonical_u32(BabyBear::MOD - 2).as_u32_vec()[0]); @@ -1125,7 +1339,7 @@ mod tests { fn test_script_expression_extneg() { let bmap = BTreeMap::new(); let mut stack = StackTracker::new(); - let a = ScriptExpression::from(EF::one()); + let a = FieldScriptExpression::from(EF::one()); let b = -a * EF::two(); let script = b.express_to_script(&mut stack, &bmap); stack.bignumber(EF::from_canonical_u32(EF::MOD - 2).as_u32_vec()); diff --git a/uni-stark/src/expr/mod.rs b/uni-stark/src/expr/mod.rs new file mode 100644 index 0000000..b43520d --- /dev/null +++ b/uni-stark/src/expr/mod.rs @@ -0,0 +1,43 @@ +use alloc::boxed::Box; +use alloc::collections::BTreeMap; +use alloc::sync::Arc; +use alloc::vec::Vec; +use core::cell::Cell; + +use bitcoin_script_stack::stack::{StackTracker, StackVariable}; +use num_script_expr::NumScriptExpression; +use primitives::field::BfField; +use scripts::treepp::*; + +use crate::SymbolicExpression::{self, *}; + +mod script_builder; +pub use script_builder::*; +mod variable; +pub use variable::{ValueVariable, Variable}; +mod num_script_expr; +// pub use num_script_expr::*; +mod field_script_expr; +pub use field_script_expr::*; +mod script_helper; + +pub struct Executor { + to_exec_expr: FieldScriptExpression, + bmap: BTreeMap, + stack: StackTracker, +} + +pub trait Expression { + fn express_to_script( + &self, + stack: &mut StackTracker, + input_variables: &BTreeMap, + ) -> Script; + + fn var_size(&self) -> u32; + + #[allow(unused)] + fn set_debug(&self); + + fn get_var(&self) -> Option>; +} diff --git a/uni-stark/src/expr/num_script_expr.rs b/uni-stark/src/expr/num_script_expr.rs new file mode 100644 index 0000000..41c4013 --- /dev/null +++ b/uni-stark/src/expr/num_script_expr.rs @@ -0,0 +1,819 @@ +use alloc::boxed::Box; +use alloc::collections::BTreeMap; +use alloc::sync::Arc; +use alloc::vec::Vec; +use alloc::{format, vec}; +use core::cell::Cell; +use core::fmt::Debug; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +use bitcoin_script_stack::stack::{StackTracker, StackVariable}; +use scripts::treepp::*; + +use super::variable::{ValueVariable, Variable}; +use super::Expression; +use crate::expr::script_helper::value_to_bits_format; + +pub enum NumScriptExpression { + InputVariable { + sv: Variable, + debug: Cell, + var: StackVariable, + }, + Constant { + values: Vec, + debug: Cell, + var: StackVariable, + }, + Add { + x: Arc>, + y: Arc>, + var: StackVariable, + debug: Cell, + }, + Sub { + x: Arc>, + y: Arc>, + var: StackVariable, + debug: Cell, + }, + Neg { + x: Arc>, + var: StackVariable, + debug: Cell, + }, + Mul { + x: Arc>, + y: Arc>, + var: StackVariable, + debug: Cell, + }, + EqualVerify { + x: Arc>, + y: Arc>, + debug: Cell, + }, + Equal { + x: Arc>, + y: Arc>, + debug: Cell, + var: StackVariable, + }, + Double { + x: Arc>, + debug: Cell, + var: StackVariable, + }, + Square { + x: Arc>, + debug: Cell, + var: StackVariable, + }, + ToBits { + x: Arc>, + debug: Cell, + var: StackVariable, + bits_len: u32, + }, + ToBitsVec { + x: Arc>, + debug: Cell, + var: Vec, + bits_len: u32, + }, + // Exp{ + // x: Arc>, + // y: Arc>, + // var: StackVariable, + // debug: Cell, + // }, +} + +impl NumScriptExpression { + pub fn zero() -> Self { + Self::from(0u32) + } + + pub fn one() -> Self { + Self::from(1u32) + } + + pub fn two() -> Self { + Self::from(2u32) + } + + pub fn euqal_verify(&self, rhs: NumScriptExpression) -> Self { + Self::EqualVerify { + x: Arc::new(Box::new(self.clone())), + y: Arc::new(Box::new(rhs)), + debug: Cell::new(false), + } + } + + pub fn euqal(&self, rhs: NumScriptExpression) -> Self { + Self::Equal { + x: Arc::new(Box::new(self.clone())), + y: Arc::new(Box::new(rhs)), + debug: Cell::new(false), + var: StackVariable::null(), + } + } + + pub fn to_bits(&self) -> Self { + Self::ToBits { + x: Arc::new(Box::new(self.clone())), + debug: Cell::new(false), + var: StackVariable::null(), + bits_len: 32, + } + } + + pub fn to_custom_bits(&self, bits_len: u32) -> Self { + Self::ToBits { + x: Arc::new(Box::new(self.clone())), + debug: Cell::new(false), + var: StackVariable::null(), + bits_len: bits_len, + } + } +} + +impl Expression for NumScriptExpression { + fn set_debug(&self) { + match self { + NumScriptExpression::InputVariable { debug, .. } => { + debug.set(true); + } + NumScriptExpression::Constant { debug, .. } => debug.set(true), + NumScriptExpression::Add { debug, .. } => { + debug.set(true); + } + NumScriptExpression::Sub { debug, .. } => { + debug.set(true); + } + NumScriptExpression::Neg { debug, .. } => { + debug.set(true); + } + NumScriptExpression::Mul { debug, .. } => { + debug.set(true); + } + NumScriptExpression::EqualVerify { debug, .. } => { + debug.set(true); + } + NumScriptExpression::Equal { debug, .. } => { + debug.set(true); + } + NumScriptExpression::Double { debug, .. } => { + debug.set(true); + } + NumScriptExpression::Square { debug, .. } => { + debug.set(true); + } + NumScriptExpression::ToBits { debug, .. } => { + debug.set(true); + } + NumScriptExpression::ToBitsVec { debug, .. } => { + debug.set(true); + } + }; + } + + fn express_to_script( + &self, + stack: &mut StackTracker, + input_variables: &BTreeMap, + ) -> Script { + match self { + NumScriptExpression::InputVariable { sv, debug, mut var } => { + let intput_var = input_variables.get(sv).unwrap(); + var = stack.copy_var(intput_var.clone()); + if debug.get() == true { + stack.debug(); + } + if sv.get_var_size().is_some() { + assert_eq!(var.size(), sv.get_var_size().unwrap()); + } + } + NumScriptExpression::Constant { + values, + mut var, + debug, + } => { + var = stack.bignumber(values.clone()); + if debug.get() == true { + stack.debug(); + } + } + NumScriptExpression::Add { + x, + y, + debug, + mut var, + } => { + assert_eq!(x.var_size(), 1); + assert_eq!(y.var_size(), 1); + x.express_to_script(stack, input_variables); // F + y.express_to_script(stack, input_variables); // EF + + var = stack.op_add(); // Bitcoin OP_ADD + + if debug.get() == true { + stack.debug(); + } + } + NumScriptExpression::Sub { + x, + y, + debug, + mut var, + } => { + x.express_to_script(stack, input_variables); // F + y.express_to_script(stack, input_variables); // EF + assert_eq!(x.var_size(), 1); + assert_eq!(y.var_size(), 1); + + var = stack.op_sub(); + + if debug.get() == true { + stack.debug(); + } + } + NumScriptExpression::Neg { x, debug, mut var } => { + x.express_to_script(stack, input_variables); // F + assert_eq!(x.var_size(), 1); + + var = stack.op_negate(); + + if debug.get() == true { + stack.debug(); + } + } + NumScriptExpression::Mul { + x, + y, + debug, + mut var, + } => { + // todo: support mul + assert_eq!(0, 1); + } + NumScriptExpression::EqualVerify { x, y, debug } => { + x.express_to_script(stack, input_variables); // F + y.express_to_script(stack, input_variables); // EF + assert_eq!(x.var_size(), 1); + assert_eq!(y.var_size(), 1); + + stack.op_equalverify(); + + if debug.get() == true { + stack.debug(); + } + } + NumScriptExpression::Equal { + x, + y, + debug, + mut var, + } => { + assert_eq!(x.var_size(), 1); + assert_eq!(y.var_size(), 1); + x.express_to_script(stack, input_variables); // F + y.express_to_script(stack, input_variables); // EF + + var = stack.op_equal(); + + if debug.get() == true { + stack.debug(); + } + } + NumScriptExpression::Double { x, debug, mut var } => { + assert_eq!(x.var_size(), 1); + x.express_to_script(stack, input_variables); // F + stack.copy_var(x.get_var().unwrap()[0].clone()); + stack.op_add(); + + if debug.get() == true { + stack.debug(); + } + } + NumScriptExpression::Square { x, debug, mut var } => { + x.express_to_script(stack, input_variables); // F + assert_eq!(x.var_size(), 1); + // todo: support square + assert_eq!(0, 1); + // var = stack.op_negate(); + + if debug.get() == true { + stack.debug(); + } + } + NumScriptExpression::ToBits { + x, + debug, + mut var, + bits_len, + } => { + x.express_to_script(stack, input_variables); // F + assert_eq!(x.var_size(), 1); + let vars = stack + .custom1( + value_to_bits_format(*bits_len), + x.var_size(), + 1, + 0, + *bits_len, + "NumExpr::ToBits", + ) + .unwrap(); + var = vars[0]; + + if debug.get() == true { + stack.debug(); + } + } + NumScriptExpression::ToBitsVec { x, debug, .. } => { + // todo: support ToBitsVec + assert_eq!(1, 2); + // var = stack.custom1(value_to_bits_format(*bits_len), x.var_size(), *bits_len, 0, 1, "NumExpr::ToBitsVec").unwrap(); + } + }; + stack.get_script() + } + + fn var_size(&self) -> u32 { + match self { + NumScriptExpression::ToBits { bits_len, .. } => *bits_len, + NumScriptExpression::ToBitsVec { .. } => 1, + _ => 1, + } + } + + fn get_var(&self) -> Option> { + match self { + NumScriptExpression::InputVariable { var, .. } => Some(vec![var]), + NumScriptExpression::Constant { var, .. } => Some(vec![var]), + NumScriptExpression::Add { var, .. } => Some(vec![var]), + NumScriptExpression::Sub { var, .. } => Some(vec![var]), + NumScriptExpression::Neg { var, .. } => Some(vec![var]), + NumScriptExpression::Mul { var, .. } => Some(vec![var]), + NumScriptExpression::EqualVerify { .. } => None, + NumScriptExpression::Equal { var, .. } => Some(vec![var]), + NumScriptExpression::Double { var, .. } => Some(vec![var]), + NumScriptExpression::Square { var, .. } => Some(vec![var]), + NumScriptExpression::ToBits { var, .. } => Some(vec![var]), + NumScriptExpression::ToBitsVec { var, .. } => { + let vec = var.iter().map(|item| item).collect(); + Some(vec) + } + } + } +} + +impl Default for NumScriptExpression { + fn default() -> Self { + Self::zero() + } +} + +impl From for NumScriptExpression { + fn from(value: u32) -> Self { + Self::Constant { + values: vec![value], + debug: Cell::new(false), + var: StackVariable::null(), + } + } +} + +impl From> for NumScriptExpression { + fn from(values: Vec) -> Self { + Self::Constant { + values, + debug: Cell::new(false), + var: StackVariable::null(), + } + } +} + +impl Debug for NumScriptExpression { + fn fmt(&self, fm: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + NumScriptExpression::InputVariable { sv, .. } => fm + .debug_struct("ScriptExpression::InputVariable") + .field("sv", sv) + .finish(), + NumScriptExpression::Constant { values, .. } => fm + .debug_struct("ScriptExpression::Constant") + .field("f", values) + .finish(), + NumScriptExpression::Add { x, y, debug, var } => fm + .debug_struct("ScriptExpression::Add") + .field("variable", var) + .finish(), + NumScriptExpression::Sub { x, y, debug, var } => fm + .debug_struct("ScriptExpression::Sub") + .field("variable", var) + .finish(), + NumScriptExpression::Mul { x, y, debug, var } => fm + .debug_struct("ScriptExpression::Mul") + .field("variable", var) + .finish(), + NumScriptExpression::Neg { x, debug, var } => fm + .debug_struct("ScriptExpression::Neg") + .field("variable", var) + .finish(), + NumScriptExpression::EqualVerify { x, y, debug } => { + fm.debug_struct("ScriptExpression::EqualVerify").finish() + } + NumScriptExpression::Equal { x, y, debug, var } => fm + .debug_struct("ScriptExpression::Equal") + .field("variable", var) + .finish(), + NumScriptExpression::Double { x, debug, var } => fm + .debug_struct("ScriptExpression::Double") + .field("variable", var) + .finish(), + NumScriptExpression::Square { x, debug, var } => fm + .debug_struct("ScriptExpression::Square") + .field("variable", var) + .finish(), + NumScriptExpression::ToBits { x, debug, var, .. } => fm + .debug_struct("ScriptExpression::ToBits") + .field("variable", var) + .finish(), + NumScriptExpression::ToBitsVec { x, debug, var, .. } => fm + .debug_struct("ScriptExpression::ToBits") + .field("variable", var) + .finish(), + } + } +} + +impl Clone for NumScriptExpression { + fn clone(&self) -> Self { + match self { + NumScriptExpression::InputVariable { sv, debug, var } => { + NumScriptExpression::InputVariable { + sv: sv.clone(), + debug: debug.clone(), + var: var.clone(), + } + } + NumScriptExpression::Constant { values, debug, var } => NumScriptExpression::Constant { + values: values.clone(), + debug: debug.clone(), + var: var.clone(), + }, + NumScriptExpression::Add { x, y, debug, var } => NumScriptExpression::Add { + x: x.clone(), + y: y.clone(), + debug: debug.clone(), + var: var.clone(), + }, + NumScriptExpression::Mul { x, y, debug, var } => NumScriptExpression::Mul { + x: x.clone(), + y: y.clone(), + debug: debug.clone(), + var: var.clone(), + }, + NumScriptExpression::Sub { x, y, debug, var } => NumScriptExpression::Sub { + x: x.clone(), + y: y.clone(), + debug: debug.clone(), + var: var.clone(), + }, + NumScriptExpression::Neg { x, debug, var } => NumScriptExpression::Neg { + x: x.clone(), + debug: debug.clone(), + var: var.clone(), + }, + NumScriptExpression::EqualVerify { x, y, debug } => NumScriptExpression::EqualVerify { + x: x.clone(), + y: y.clone(), + debug: debug.clone(), + }, + NumScriptExpression::Equal { x, y, debug, var } => NumScriptExpression::Equal { + x: x.clone(), + y: y.clone(), + debug: debug.clone(), + var: var.clone(), + }, + NumScriptExpression::Double { x, debug, var } => NumScriptExpression::Double { + x: x.clone(), + debug: debug.clone(), + var: var.clone(), + }, + NumScriptExpression::Square { x, debug, var } => NumScriptExpression::Square { + x: x.clone(), + debug: debug.clone(), + var: var.clone(), + }, + NumScriptExpression::ToBits { + x, + debug, + var, + bits_len, + } => NumScriptExpression::ToBits { + x: x.clone(), + debug: debug.clone(), + var: var.clone(), + bits_len: *bits_len, + }, + NumScriptExpression::ToBitsVec { + x, + debug, + var, + bits_len, + } => NumScriptExpression::ToBitsVec { + x: x.clone(), + debug: debug.clone(), + var: var.clone(), + bits_len: *bits_len, + }, + } + } +} + +impl Add for NumScriptExpression { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + Self::Add { + x: Arc::new(Box::new(self)), + y: Arc::new(Box::new(rhs)), + debug: Cell::new(false), + var: StackVariable::null(), + } + } +} + +impl Add<&Self> for NumScriptExpression { + type Output = Self; + + fn add(self, rhs: &Self) -> Self { + Self::Add { + x: Arc::new(Box::new(self)), + y: Arc::new(Box::new(rhs.clone())), + debug: Cell::new(false), + var: StackVariable::null(), + } + } +} + +impl AddAssign for NumScriptExpression { + fn add_assign(&mut self, rhs: Self) { + *self = self.clone() + rhs; + } +} + +impl AddAssign for NumScriptExpression { + fn add_assign(&mut self, rhs: u32) { + *self += Self::from(rhs); + } +} + +impl AddAssign> for NumScriptExpression { + fn add_assign(&mut self, rhs: Vec) { + *self += Self::from(rhs); + } +} + +impl Sum for NumScriptExpression { + fn sum>(iter: I) -> Self { + iter.reduce(|x, y| x + y).unwrap_or(Self::zero()) + } +} + +impl Sum for NumScriptExpression { + fn sum>(iter: I) -> Self { + iter.map(|x| Self::from(x)).sum() + } +} + +impl Sub for NumScriptExpression { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + Self::Sub { + x: Arc::new(Box::new(self)), + y: Arc::new(Box::new(rhs)), + debug: Cell::new(false), + var: StackVariable::null(), + } + } +} + +impl Sub for NumScriptExpression { + type Output = Self; + + fn sub(self, rhs: u32) -> Self { + self - Self::from(rhs) + } +} + +impl SubAssign for NumScriptExpression { + fn sub_assign(&mut self, rhs: Self) { + *self = self.clone() - rhs; + } +} + +impl SubAssign for NumScriptExpression { + fn sub_assign(&mut self, rhs: u32) { + *self -= Self::from(rhs); + } +} + +impl Neg for NumScriptExpression { + type Output = Self; + + fn neg(self) -> Self { + Self::Neg { + x: Arc::new(Box::new(self)), + debug: Cell::new(false), + var: StackVariable::null(), + } + } +} + +impl Mul for NumScriptExpression { + type Output = Self; + + fn mul(self, rhs: Self) -> Self { + #[allow(clippy::suspicious_arithmetic_impl)] + Self::Mul { + x: Arc::new(Box::new(self)), + y: Arc::new(Box::new(rhs)), + debug: Cell::new(false), + var: StackVariable::null(), + } + } +} + +impl Mul for NumScriptExpression { + type Output = Self; + + fn mul(self, rhs: u32) -> Self { + self * Self::from(rhs) + } +} + +impl MulAssign for NumScriptExpression { + fn mul_assign(&mut self, rhs: Self) { + *self = self.clone() * rhs; + } +} + +impl MulAssign for NumScriptExpression { + fn mul_assign(&mut self, rhs: u32) { + *self *= Self::from(rhs); + } +} + +impl Product for NumScriptExpression { + fn product>(iter: I) -> Self { + iter.reduce(|x, y| x * y).unwrap_or(Self::one()) + } +} + +impl Product for NumScriptExpression { + fn product>(iter: I) -> Self { + iter.map(|x| Self::from(x)).product() + } +} + +#[cfg(test)] +mod tests { + use alloc::collections::BTreeMap; + use core::cell::{self, Cell}; + + use bitcoin_script_stack::stack::{StackTracker, StackVariable}; + use scripts::treepp::*; + + use super::{Expression, NumScriptExpression, Variable, *}; + + #[test] + fn test_script_expression_add() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = NumScriptExpression::from(1); + let b = NumScriptExpression::from(2); + let c = a + b; + c.set_debug(); + + let d = NumScriptExpression::from(2); + let e = NumScriptExpression::from(2); + let f = d + e; + + let g: NumScriptExpression = c + f; // 4 + 3 = 7 + let h = g.euqal(NumScriptExpression::from(7)); + let script = h.express_to_script(&mut stack, &bmap); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expr_with_input() { + let var1 = Variable::new(0, 0); + let var2 = Variable::new(0, 1); + let var3 = Variable::new(1, 0); + let var4 = Variable::new(1, 1); + + let mut stack = StackTracker::new(); + let mut bmap = BTreeMap::new(); + bmap.insert(var1, stack.var(1, script! { 1 }, "input 1")); + bmap.insert(var2, stack.var(1, script! { 2}, "input 2")); + bmap.insert(var3, stack.var(1, script! {3}, "input 3")); + bmap.insert(var4, stack.var(1, script! {4}, "input 4")); + + let var1_wrap = NumScriptExpression::InputVariable { + sv: var1, + debug: Cell::new(false), + var: StackVariable::null(), + }; + let var2_wrap = NumScriptExpression::InputVariable { + sv: var2, + debug: Cell::new(false), + var: StackVariable::null(), + }; + let var3_wrap = NumScriptExpression::InputVariable { + sv: var3, + debug: Cell::new(false), + var: StackVariable::null(), + }; + let var4_wrap = NumScriptExpression::InputVariable { + sv: var4, + debug: Cell::new(false), + var: StackVariable::null(), + }; + let res1 = var1_wrap + var2_wrap; + let res2 = var3_wrap + var4_wrap; + + let res = res1 + res2; + res.express_to_script(&mut stack, &bmap); + + stack.number(10); + stack.op_equalverify(); + + stack.drop(*bmap.get(&var4).unwrap()); + stack.drop(*bmap.get(&var3).unwrap()); + stack.drop(*bmap.get(&var2).unwrap()); + stack.drop(*bmap.get(&var1).unwrap()); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_sub() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = NumScriptExpression::from(1); + let b = NumScriptExpression::from(2); + let c = b - a; // 1 + + let d = NumScriptExpression::from(2); + let e = NumScriptExpression::from(8); + let f = e - d; // 6 + + let g = f - c; // 5 + let script = g.express_to_script(&mut stack, &bmap); + stack.number(5); + stack.op_equal(); + let res = stack.run(); + assert!(res.success); + } + + // #[test] + // fn test_script_expression_mul() { + // let bmap = BTreeMap::new(); + // let mut stack = StackTracker::new(); + // let a = NumScriptExpression::from(BabyBear::one()); + // let b = NumScriptExpression::from(BabyBear::two()); + // let c = b * a; // 2 + + // let d = NumScriptExpression::from(BabyBear::two()); + // let e = NumScriptExpression::from(BabyBear::from_canonical_u32(8)); + // let f = e * d * BabyBear::one(); // 16 + // stack.show_stack(); + // let g = f * c; // 32 + // let script = g.express_to_script(&mut stack, &bmap); + // stack.number(BabyBear::from_canonical_u32(32u32).as_u32_vec()[0]); + // stack.op_equal(); + // let res = stack.run(); + // assert!(res.success); + // } + + #[test] + fn test_script_expression_neg() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = NumScriptExpression::from(1); + let b = -a + NumScriptExpression::two(); + let script = b.express_to_script(&mut stack, &bmap); + stack.number(1); + stack.op_equal(); + let res = stack.run(); + assert!(res.success); + } +} diff --git a/uni-stark/src/expr/script_builder.rs b/uni-stark/src/expr/script_builder.rs new file mode 100644 index 0000000..b6452fa --- /dev/null +++ b/uni-stark/src/expr/script_builder.rs @@ -0,0 +1,162 @@ +use alloc::collections::BTreeMap; +use alloc::format; +use alloc::vec::Vec; + +use bitcoin_script_stack::stack::{StackTracker, StackVariable}; +use p3_air::{AirBuilder, AirBuilderWithPublicValues}; +use p3_matrix::dense::RowMajorMatrix; +use primitives::field::BfField; +use scripts::treepp::*; + +use super::{FieldScriptExpression, ValueVariable, Variable}; +use crate::SymbolicExpression::{self, *}; + +pub struct ScriptConstraintBuilder { + pub main: RowMajorMatrix>, + pub public_values: Vec, + pub is_first_row: F, + pub is_last_row: F, + pub is_transition: F, + pub constraints: Vec>, + pub alpha: F, +} + +impl ScriptConstraintBuilder { + pub fn new( + local: Vec, + next: Vec, + num_public_values: usize, + is_first_row: F, + is_last_row: F, + is_transition: F, + alpha: F, + ) -> Self { + let width = local.len(); + let main_variables: Vec> = [local, next] + .into_iter() + .enumerate() + .flat_map(|(row_index, row_values)| { + (0..width).map(move |column_index| { + ValueVariable::new( + Variable::new(row_index, column_index), + row_values[column_index], + ) + }) + }) + .collect(); + + let public_values = (0..num_public_values) + // set the row_index of Variable as u32::MAX to mark public_values + .map(move |index| Variable::new(u32::MAX as usize, index)) + .collect(); + + Self { + main: RowMajorMatrix::new(main_variables, width), + public_values: public_values, + is_first_row: is_first_row, + is_last_row: is_last_row, + is_transition: is_transition, + constraints: Vec::new(), + alpha: alpha, + } + } + + pub fn get_accmulator_expr(&self) -> FieldScriptExpression { + let mut acc = self.constraints[0].clone(); + for i in 1..self.constraints.len() { + acc = acc * self.alpha + self.constraints[i].clone(); + } + acc + } + + pub fn set_variable_values( + &self, + public_values: &Vec, + bmap: &mut BTreeMap, + stack: &mut StackTracker, + ) { + assert_eq!(self.public_values().len(), public_values.len()); + for i in 0..self.public_values().len() { + let u32_vec = F::from_canonical_u32(public_values[i].as_u32_vec()[0]).as_u32_vec(); + assert_eq!(u32_vec.len(), 4); + bmap.insert( + self.public_values()[i], + stack.var( + F::U32_SIZE as u32, + script! { {u32_vec[3]} {u32_vec[2]} {u32_vec[1]} {u32_vec[0]} }, + &format!("public_var index={}", i), + ), + ); + } + + for i in 0..self.main().values.len() { + let u32_vec = self.main().values[i].get_value().unwrap().as_u32_vec(); + bmap.insert( + self.main().values[i].get_var().clone(), + stack.var( + F::U32_SIZE as u32, + script! { {u32_vec[3]} {u32_vec[2]} {u32_vec[1]} {u32_vec[0]} }, + &format!( + "main_trace row index={} column_value={}", + i / self.main().width, + i % self.main().width + ), + ), + ); + } + } + + pub fn drop_variable_values( + &self, + bmap: &mut BTreeMap, + stack: &mut StackTracker, + ) { + for i in (0..self.main().values.len()).rev() { + stack.drop(*bmap.get(self.main().values[i].get_var()).unwrap()); + } + + for i in (0..self.public_values().len()).rev() { + stack.drop(*bmap.get(&self.public_values()[i]).unwrap()); + } + } +} + +impl AirBuilder for ScriptConstraintBuilder { + type F = F; + type Expr = FieldScriptExpression; + type Var = ValueVariable; + type M = RowMajorMatrix; + + fn main(&self) -> Self::M { + self.main.clone() + } + + fn is_first_row(&self) -> Self::Expr { + Self::Expr::from(self.is_first_row) + } + + fn is_last_row(&self) -> Self::Expr { + Self::Expr::from(self.is_last_row) + } + + fn is_transition_window(&self, size: usize) -> Self::Expr { + if size == 2 { + Self::Expr::from(self.is_transition) + } else { + panic!("uni-stark only supports a window size of 2") + } + } + + fn assert_zero>(&mut self, x: I) { + let x = x.into(); + self.constraints.push(x); + } +} + +impl AirBuilderWithPublicValues for ScriptConstraintBuilder { + type PublicVar = Variable; + + fn public_values(&self) -> &[Self::PublicVar] { + &self.public_values + } +} diff --git a/uni-stark/src/expr/script_helper.rs b/uni-stark/src/expr/script_helper.rs new file mode 100644 index 0000000..a771f6c --- /dev/null +++ b/uni-stark/src/expr/script_helper.rs @@ -0,0 +1,290 @@ +use alloc::boxed::Box; +use alloc::collections::BTreeMap; +use alloc::sync::Arc; +use alloc::vec::Vec; +use alloc::{format, vec}; +use core::cell::Cell; +use core::fmt::Debug; +use core::iter::{Product, Sum}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +use bitcoin::opcodes::OP_FROMALTSTACK; +use bitcoin_script_stack::stack::{StackTracker, StackVariable}; +use common::AbstractField; +use primitives::field::BfField; +use scripts::pseudo::{OP_4FROMALTSTACK, OP_4MUL, OP_4PICK, OP_4TOALTSTACK}; +use scripts::treepp::*; +use scripts::u31_lib::{ + u31_add, u31_mul, u31_neg, u31_sub, u31_sub_u31ext, u31ext_add, u31ext_add_u31, + u31ext_equalverify, u31ext_mul, u31ext_mul_u31, u31ext_neg, u31ext_sub, u31ext_sub_u31, + BabyBear4, BabyBearU31, +}; + +use super::variable::{ValueVariable, Variable}; +use super::Expression; +use crate::SymbolicExpression::{self, *}; + +/// constraint: bits <= 31 +/// input: [b_{0}, b_{1}, ..., b_{bits-1}] +pub fn compress_bits(bits: usize) -> Script { + assert!(bits <= 31); + let script = script! { + for _ in 0..bits-1 { + OP_DUP OP_ADD // double high bits + OP_ADD // add a low bit + } + }; + script +} + +/// decompress num to a vector of bits, from lowest bit to highest bit +pub fn decompress(num: u32, bits: usize) -> Vec { + let mut res = vec![]; + for index in 0..bits { + res.push(((num >> index) & 0x1) as u8); + } + res +} + +/// input: [index, b_{0}, b_{1}, ..., b_{bits-1}] +pub fn reverse_bits_len_script(bits: usize) -> Script { + let script = script! { + for i in 0..bits { + {i*2} OP_PICK + } + {compress_bits(bits)} + OP_TOALTSTACK + + {compress_bits(bits)} + OP_EQUALVERIFY + + OP_FROMALTSTACK + }; + script +} + +// the input stack: +// rev_index <-- top +// index +pub fn reverse_bits_len_script_with_input(input_index: u32, bits: usize) -> Script { + script! { + OP_TOALTSTACK + for bit in decompress(input_index, bits) { + {bit} + } + {reverse_bits_len_script(bits)} + OP_FROMALTSTACK + OP_EQUAL + } +} + +fn push_two_adic_generator_table() -> Script { + script! { + for i in (0..28).rev(){ + for j in (0..F::U32_SIZE).rev(){ + {F::two_adic_generator(i).as_u32_vec()[j]} + } + } + } +} + +fn pop_two_adic_generator_table() -> Script { + script! { + for i in (0..28).rev(){ + for j in (0..F::U32_SIZE).rev(){ + OP_DROP + } + } + } +} + +// input: bits_len +fn get_generator() -> Script { + script! { + OP_TOALTSTACK + {push_two_adic_generator_table::()} + OP_FROMALTSTACK + if F::U32_SIZE ==1{ + OP_PICK + OP_TOALTSTACK + }else{ + OP_4MUL + OP_4PICK + OP_4TOALTSTACK + } + + {pop_two_adic_generator_table::()} + + if F::U32_SIZE ==1{ + OP_FROMALTSTACK + }else{ + OP_4FROMALTSTACK + } + } +} + +// input stack: +// value +// output stack: +// 31 <-- top high_position +// 33 // 33 respresent 0 +// ... +// 0 // low_position +pub(crate) fn value_to_bits_format(bits_len_conf: u32) -> Script { + script! { + for i in (0..bits_len_conf).rev(){ + {value_bit_to_altstack(i)} + } + + for _ in 0..bits_len_conf{ + OP_FROMALTSTACK + } + } +} + +// value_bits_len +fn value_bit_to_altstack(bits: u32) -> Script { + script! { + OP_DUP + { ((1< Script { + script! { + for i in (0..bits_len_conf).rev(){ + {value_bit_to_altstack(i)} + } + + for _ in 0..bits_len_conf{ + OP_FROMALTSTACK + } + } +} + +// value_bits_len +fn value_bit_to_altstack_special(bits: u32) -> Script { + script! { + OP_DUP + { ((1< Script { + script! { + OP_DUP + { ((1<(sub_group_bits: u32) -> Script { + assert!(sub_group_bits <= 27); + // 0..27 + script! { + if F::U32_SIZE == 1{ + OP_TOALTSTACK + }else{ + OP_4TOALTSTACK + } + + + OP_DUP + 0 + OP_EQUAL + OP_IF + // case: deal index is equal to 0 + OP_DROP + for j in (0..F::U32_SIZE).rev(){ + {F::one().as_u32_vec()[j]} + } + OP_ELSE + for i in (0..sub_group_bits).rev(){ + {value_to_generator_bit_altstack(i,sub_group_bits)} + } + + // drop the 0 + OP_0 + OP_EQUALVERIFY + + for _i in 0..sub_group_bits{ + OP_FROMALTSTACK + + // bit-size + OP_DUP + {33} + OP_EQUAL + OP_IF + OP_DROP + OP_ELSE + {get_generator::()} + if F::U32_SIZE == 1{ + OP_DEPTH + OP_2 + OP_EQUAL + OP_IF + {u31_mul::()} + }else{ + OP_DEPTH + OP_8 + OP_EQUAL + OP_IF + {u31ext_mul::()} + } + OP_ENDIF + OP_ENDIF + } + OP_ENDIF + + if F::U32_SIZE == 1{ + OP_FROMALTSTACK + OP_EQUAL + }else{ + OP_4FROMALTSTACK + {u31ext_equalverify::()} + OP_1 + } + + } +} diff --git a/uni-stark/src/expr/variable.rs b/uni-stark/src/expr/variable.rs new file mode 100644 index 0000000..ea99cc1 --- /dev/null +++ b/uni-stark/src/expr/variable.rs @@ -0,0 +1,313 @@ +use core::cell::Cell; +use core::fmt::Debug; +use core::ops::{Add, Mul, Sub}; + +use bitcoin_script_stack::stack::StackVariable; +use p3_field::Field; +use primitives::field::BfField; + +use super::FieldScriptExpression; +use crate::symbolic_variable::SymbolicVariable; +use crate::Entry; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct ValueVariable { + var: Variable, + value: Option, +} + +impl ValueVariable { + pub fn new(var: Variable, value: F) -> Self { + Self { + var, + value: Some(value), + } + } + + pub fn get_var(&self) -> &Variable { + &self.var + } + + pub fn get_value(&self) -> Option { + self.value.clone() + } +} + +impl From> for FieldScriptExpression { + fn from(var: ValueVariable) -> Self { + Self::ValueVariable { + v: var, + debug: Cell::new(false), + var: StackVariable::null(), + } + } +} + +impl Add for ValueVariable { + type Output = FieldScriptExpression; + + fn add(self, rhs: Self) -> Self::Output { + FieldScriptExpression::::from(self) + FieldScriptExpression::::from(rhs) + } +} + +impl Add for ValueVariable { + type Output = FieldScriptExpression; + + fn add(self, rhs: F) -> Self::Output { + FieldScriptExpression::::from(self) + FieldScriptExpression::::from(rhs) + } +} + +impl Add> for ValueVariable { + type Output = FieldScriptExpression; + + fn add(self, rhs: FieldScriptExpression) -> Self::Output { + FieldScriptExpression::from(self) + rhs + } +} + +impl Add> for FieldScriptExpression { + type Output = Self; + + fn add(self, rhs: ValueVariable) -> Self::Output { + self + Self::from(rhs) + } +} + +impl Sub for ValueVariable { + type Output = FieldScriptExpression; + + fn sub(self, rhs: Self) -> Self::Output { + FieldScriptExpression::::from(self) - FieldScriptExpression::::from(rhs) + } +} + +impl Sub for ValueVariable { + type Output = FieldScriptExpression; + + fn sub(self, rhs: F) -> Self::Output { + FieldScriptExpression::::from(self) - FieldScriptExpression::::from(rhs) + } +} + +impl Sub> for ValueVariable { + type Output = FieldScriptExpression; + + fn sub(self, rhs: FieldScriptExpression) -> Self::Output { + FieldScriptExpression::::from(self) - rhs + } +} + +impl Sub> for FieldScriptExpression { + type Output = Self; + + fn sub(self, rhs: ValueVariable) -> Self::Output { + self - Self::from(rhs) + } +} + +impl Mul for ValueVariable { + type Output = FieldScriptExpression; + + fn mul(self, rhs: Self) -> Self::Output { + FieldScriptExpression::::from(self) * FieldScriptExpression::::from(rhs) + } +} + +impl Mul for ValueVariable { + type Output = FieldScriptExpression; + + fn mul(self, rhs: F) -> Self::Output { + FieldScriptExpression::::from(self) * FieldScriptExpression::::from(rhs) + } +} + +impl Mul> for ValueVariable { + type Output = FieldScriptExpression; + + fn mul(self, rhs: FieldScriptExpression) -> Self::Output { + FieldScriptExpression::::from(self) * rhs + } +} + +impl Mul> for FieldScriptExpression { + type Output = Self; + + fn mul(self, rhs: ValueVariable) -> Self::Output { + self * Self::from(rhs) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct Variable { + row_index: usize, + column_index: usize, + expect_var_size: Option, +} + +impl Variable { + pub fn new(row_index: usize, column_index: usize) -> Self { + Variable { + row_index, + column_index, + expect_var_size: None, + } + } + + pub fn new_base(row_index: usize, column_index: usize) -> Self { + Variable { + row_index, + column_index, + expect_var_size: Some(1), + } + } + + pub fn new_ext(row_index: usize, column_index: usize) -> Self { + Variable { + row_index, + column_index, + expect_var_size: Some(4), + } + } + + pub fn new_with_size(row_index: usize, column_index: usize, expect_var_size: u32) -> Self { + Variable { + row_index, + column_index, + expect_var_size: Some(expect_var_size), + } + } + + pub fn get_var_size(&self) -> Option { + self.expect_var_size + } +} + +impl From for FieldScriptExpression { + fn from(var: Variable) -> Self { + Self::InputVariable { + sv: var, + debug: Cell::new(false), + var: StackVariable::null(), + } + } +} + +impl From> for Variable { + fn from(value: SymbolicVariable) -> Self { + match value.entry { + Entry::Main { offset } => Variable { + row_index: value.index, + column_index: offset, + expect_var_size: None, + }, + Entry::Permutation { offset } => Variable { + row_index: value.index, + column_index: offset, + expect_var_size: None, + }, + Entry::Preprocessed { offset } => Variable { + row_index: value.index, + column_index: offset, + expect_var_size: None, + }, + _ => panic!("error type"), + } + } +} + +impl From<&SymbolicVariable> for Variable { + fn from(value: &SymbolicVariable) -> Self { + match value.entry { + Entry::Main { offset } => Variable { + row_index: value.index, + column_index: offset, + expect_var_size: None, + }, + Entry::Permutation { offset } => Variable { + row_index: value.index, + column_index: offset, + expect_var_size: None, + }, + Entry::Preprocessed { offset } => Variable { + row_index: value.index, + column_index: offset, + expect_var_size: None, + }, + _ => panic!("error type"), + } + } +} + +impl Add for Variable { + type Output = FieldScriptExpression; + + fn add(self, rhs: F) -> Self::Output { + FieldScriptExpression::::from(self) + FieldScriptExpression::::from(rhs) + } +} + +impl Add> for Variable { + type Output = FieldScriptExpression; + + fn add(self, rhs: FieldScriptExpression) -> Self::Output { + FieldScriptExpression::from(self) + rhs + } +} + +impl Add for FieldScriptExpression { + type Output = Self; + + fn add(self, rhs: Variable) -> Self::Output { + self + Self::from(rhs) + } +} + +impl Sub for Variable { + type Output = FieldScriptExpression; + + fn sub(self, rhs: F) -> Self::Output { + FieldScriptExpression::::from(self) - FieldScriptExpression::::from(rhs) + } +} + +impl Sub> for Variable { + type Output = FieldScriptExpression; + + fn sub(self, rhs: FieldScriptExpression) -> Self::Output { + FieldScriptExpression::::from(self) - rhs + } +} + +impl Sub for FieldScriptExpression { + type Output = Self; + + fn sub(self, rhs: Variable) -> Self::Output { + self - Self::from(rhs) + } +} + +impl Mul for Variable { + type Output = FieldScriptExpression; + + fn mul(self, rhs: F) -> Self::Output { + FieldScriptExpression::::from(self) * FieldScriptExpression::::from(rhs) + } +} + +impl Mul> for Variable { + type Output = FieldScriptExpression; + + fn mul(self, rhs: FieldScriptExpression) -> Self::Output { + FieldScriptExpression::::from(self) * rhs + } +} + +impl Mul for FieldScriptExpression { + type Output = Self; + + fn mul(self, rhs: Variable) -> Self::Output { + self * Self::from(rhs) + } +} diff --git a/uni-stark/src/lib.rs b/uni-stark/src/lib.rs index 832857b..ef0e4ae 100644 --- a/uni-stark/src/lib.rs +++ b/uni-stark/src/lib.rs @@ -5,11 +5,11 @@ extern crate alloc; mod config; +mod expr; mod folder; mod proof; mod prover; mod scripts; -mod scripts_expression; mod symbolic_builder; mod symbolic_expression; mod symbolic_variable; @@ -26,7 +26,6 @@ pub use folder::*; pub use proof::*; pub use prover::*; pub use scripts::*; -pub use scripts_expression::*; pub use symbolic_builder::*; pub use symbolic_expression::*; pub use symbolic_variable::*; diff --git a/uni-stark/src/verifier.rs b/uni-stark/src/verifier.rs index b6820e0..ed5ef19 100644 --- a/uni-stark/src/verifier.rs +++ b/uni-stark/src/verifier.rs @@ -1,24 +1,25 @@ +use alloc::collections::BTreeMap; use alloc::vec; use alloc::vec::Vec; +use bitcoin_script_stack::stack::StackTracker; use itertools::Itertools; -use p3_air::{Air, BaseAir}; +use p3_air::{Air, AirBuilder, AirBuilderWithPublicValues, BaseAir}; use p3_challenger::{CanObserve, CanSample}; use p3_commit::PolynomialSpace; use p3_field::{AbstractExtensionField, AbstractField, Field}; -use p3_matrix::dense::RowMajorMatrixView; +use p3_matrix::dense::{RowMajorMatrix, RowMajorMatrixView}; use p3_matrix::stack::VerticalPair; use primitives::bf_pcs::Pcs; +use primitives::field::BfField; use script_manager::bc_assignment::DefaultBCAssignment; use script_manager::script_info::ScriptInfo; use scripts::execute_script_with_inputs; use tracing::instrument; -use crate::symbolic_builder::{get_log_quotient_degree, SymbolicAirBuilder}; -use crate::{ - compute_quotient_zeta_script, PcsError, Proof, StarkGenericConfig, Val, - VerifierConstraintFolder, -}; +use crate::expr::{Expression, FieldScriptExpression, ScriptConstraintBuilder}; +use crate::symbolic_builder::{self, get_log_quotient_degree, SymbolicAirBuilder}; +use crate::{PcsError, Proof, StarkGenericConfig, Val, VerifierConstraintFolder}; #[instrument(skip_all)] pub fn verify( @@ -31,7 +32,11 @@ pub fn verify( ) -> Result<(), VerificationError>> where SC: StarkGenericConfig, - A: Air>> + for<'a> Air>, + A: Air>> + + for<'a> Air> + + Air>, + Val: BfField, + SC::Challenge: BfField, { let Proof { commitments, @@ -115,7 +120,10 @@ where .filter(|(j, _)| *j != i) .map(|(_, other_domain)| { other_domain.zp_at_point(zeta) - * other_domain.zp_at_point(domain.first_point()).inverse() + * other_domain + .zp_at_point(domain.first_point()) + .inverse() + .into() }) .product::() }) @@ -160,139 +168,33 @@ where return Err(VerificationError::OodEvaluationMismatch); } - Ok(()) -} - -// pub fn verify_script( -// config: &SC, -// air: &A, -// challenger: &mut SC::Challenger, -// proof: &Proof, -// public_values: &Vec>, -// script_managers: &mut Vec, -// ) -> Result<(), VerificationError>> -// where -// SC: StarkGenericConfig, -// A: Air>> + for<'a> Air>, -// { -// let Proof { -// commitments, -// opened_values, -// opening_proof, -// degree_bits, -// } = proof; - -// let degree = 1 << degree_bits; -// let log_quotient_degree = get_log_quotient_degree::, A>(air, 0, public_values.len()); -// let quotient_degree = 1 << log_quotient_degree; - -// let pcs = config.pcs(); -// let trace_domain = pcs.natural_domain_for_degree(degree); -// let quotient_domain = -// trace_domain.create_disjoint_domain(1 << (degree_bits + log_quotient_degree)); -// let quotient_chunks_domains = quotient_domain.split_domains(quotient_degree); - -// let air_width = >>::width(air); -// let valid_shape = opened_values.trace_local.len() == air_width -// && opened_values.trace_next.len() == air_width -// && opened_values.quotient_chunks.len() == quotient_degree -// && opened_values -// .quotient_chunks -// .iter() -// .all(|qc| qc.len() == >>::D); -// if !valid_shape { -// return Err(VerificationError::InvalidProofShape); -// } - -// // Observe the instance. // TODO: recover observe when we have CanObserve trait -// // challenger.observe(Val::::from_canonical_usize(proof.degree_bits)); -// // TODO: Might be best practice to include other instance data here in the transcript, like some -// // encoding of the AIR. This protects against transcript collisions between distinct instances. -// // Practically speaking though, the only related known attack is from failing to include public -// // values. It's not clear if failing to include other instance data could enable a transcript -// // collision, since most such changes would completely change the set of satisfying witnesses. - -// challenger.observe(commitments.trace.clone()); -// // challenger.observe_slice(public_values); -// let alpha: SC::Challenge = challenger.sample(); -// challenger.observe(commitments.quotient_chunks.clone()); - -// let zeta: SC::Challenge = challenger.sample(); -// let zeta_next = trace_domain.next_point(zeta).unwrap(); - -// pcs.verify( -// vec![ -// ( -// commitments.trace.clone(), -// vec![( -// trace_domain, -// vec![ -// (zeta, opened_values.trace_local.clone()), -// (zeta_next, opened_values.trace_next.clone()), -// ], -// )], -// ), -// ( -// commitments.quotient_chunks.clone(), -// quotient_chunks_domains -// .iter() -// .zip(&opened_values.quotient_chunks) -// .map(|(domain, values)| (*domain, vec![(zeta, values.clone())])) -// .collect_vec(), -// ), -// ], -// opening_proof, -// challenger, -// script_managers, -// ) -// .map_err(VerificationError::InvalidOpeningArgument)?; - -// let zps = quotient_chunks_domains -// .iter() -// .enumerate() -// .map(|(i, domain)| { -// quotient_chunks_domains -// .iter() -// .enumerate() -// .filter(|(j, _)| *j != i) -// .map(|(_, other_domain)| { -// other_domain.zp_at_point(zeta) -// * other_domain.zp_at_point(domain.first_point()).inverse() -// }) -// .product::() -// }) -// .collect_vec(); - -// let quotient = opened_values -// .quotient_chunks -// .iter() -// .enumerate() -// .map(|(ch_i, ch)| { -// ch.iter() -// .enumerate() -// .map(|(e_i, &c)| zps[ch_i] * SC::Challenge::monomial(e_i) * c) -// .sum::() -// }) -// .sum::(); + let mut script_folder = ScriptConstraintBuilder::new( + opened_values.trace_local.clone(), + opened_values.trace_next.clone(), + public_values.len(), + sels.is_first_row, + sels.is_last_row, + sels.is_transition, + alpha, + ); -// let mut bc_assigner = DefaultBCAssignment::new(); -// let mut exec_script_info = compute_quotient_zeta_script::<>( -// quotient_degree, -// zps, -// opened_values.quotient_chunks, -// quotient -// ); + air.eval(&mut script_folder); + let mut stack = StackTracker::new(); + let mut bmap = BTreeMap::new(); + script_folder.set_variable_values(public_values, &mut bmap, &mut stack); -// exec_script_info.gen(&mut bc_assigner); + let acc_expr = script_folder.get_accmulator_expr(); -// let res = execute_script_with_inputs( -// exec_script_info.get_eq_script(), -// exec_script_info.witness(), -// ); -// assert!(res.success); + let equal_expr = acc_expr.equal_verify_for_f(folder.accumulator); + equal_expr.express_to_script(&mut stack, &bmap); -// Ok(()) -// } + stack.debug(); + script_folder.drop_variable_values(&mut bmap, &mut stack); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + Ok(()) +} #[derive(Debug)] pub enum VerificationError { From bd81d343be6033158105c008244bdf7de5775852 Mon Sep 17 00:00:00 2001 From: 0xhhh <52317293+cyl19970726@users.noreply.github.com> Date: Wed, 17 Jul 2024 09:55:06 +0800 Subject: [PATCH 12/25] add index_to_rou && num_to_field && exp into FieldScriptExpression (#24) --- scripts/src/lib.rs | 11 +- uni-stark/src/expr/field_script_expr.rs | 265 ++++++++++++++++++++++-- uni-stark/src/expr/num_script_expr.rs | 11 +- uni-stark/src/expr/script_helper.rs | 114 +++++++--- 4 files changed, 354 insertions(+), 47 deletions(-) diff --git a/scripts/src/lib.rs b/scripts/src/lib.rs index bf779e2..14e8d6c 100644 --- a/scripts/src/lib.rs +++ b/scripts/src/lib.rs @@ -27,8 +27,8 @@ pub mod u31_lib { define_pushable!(); pub use rust_bitcoin_u31_or_u30::{ - u31_add, u31_double, u31_mul, u31_neg, u31_sub, u31_sub_u31ext, u31_to_u31ext, u31ext_add, - u31ext_add_u31, u31ext_double, u31ext_equalverify, u31ext_mul, u31ext_mul_u31, + u31_add, u31_double, u31_mul, u31_neg, u31_sub, u31_sub_u31ext, u31_to_u31ext, u31_to_v31, + u31ext_add, u31ext_add_u31, u31ext_double, u31ext_equalverify, u31ext_mul, u31ext_mul_u31, u31ext_mul_u31_by_constant, u31ext_neg, u31ext_sub, u31ext_sub_u31, BabyBear as BabyBearU31, BabyBear4, U31Config, U31ExtConfig, }; @@ -38,6 +38,13 @@ pub mod u31_lib { OP_EQUALVERIFY } } + + pub fn u32_to_u31() -> Script { + script! { + {BabyBearU31::MOD} + {u31_sub::()} + } + } } #[allow(dead_code)] // Re-export what is needed to write treepp scripts diff --git a/uni-stark/src/expr/field_script_expr.rs b/uni-stark/src/expr/field_script_expr.rs index 1e013eb..f67a2e5 100644 --- a/uni-stark/src/expr/field_script_expr.rs +++ b/uni-stark/src/expr/field_script_expr.rs @@ -10,16 +10,19 @@ use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use bitcoin_script_stack::stack::{StackTracker, StackVariable}; use common::AbstractField; +use p3_util::log2_strict_usize; use primitives::field::BfField; use scripts::treepp::*; use scripts::u31_lib::{ - u31_add, u31_mul, u31_neg, u31_sub, u31_sub_u31ext, u31ext_add, u31ext_add_u31, + u31_add, u31_mul, u31_neg, u31_sub, u31_sub_u31ext, u31_to_u31ext, u31ext_add, u31ext_add_u31, u31ext_equalverify, u31ext_mul, u31ext_mul_u31, u31ext_neg, u31ext_sub, u31ext_sub_u31, - BabyBear4, BabyBearU31, + u32_to_u31, BabyBear4, BabyBearU31, }; +use super::num_script_expr::NumScriptExpression; use super::variable::{ValueVariable, Variable}; use super::Expression; +use crate::expr::script_helper::{index_to_rou, value_exp_n}; use crate::SymbolicExpression::{self, *}; pub enum FieldScriptExpression { @@ -66,9 +69,21 @@ pub enum FieldScriptExpression { y: Arc>, debug: Cell, }, - Exp { + ExpConstant { + x: Arc>, + y: u32, + var: StackVariable, + debug: Cell, + }, + IndexToROU { + // calculate generator^index + index: Arc>, // u32 -> NumberScriptExpression + sub_group_bits: u32, + var: StackVariable, + debug: Cell, + }, + NumToField { x: Arc>, - y: Arc>, var: StackVariable, debug: Cell, }, @@ -150,6 +165,15 @@ impl FieldScriptExpression { } } + pub fn exp_constant(&self, power: u32) -> Self { + FieldScriptExpression::ExpConstant { + x: Arc::new(Box::new(self.clone())), + y: power, + var: StackVariable::null(), + debug: Cell::new(false), + } + } + pub fn equal_verify(&self, rhs: Self) -> Self { FieldScriptExpression::EqualVerify { x: Arc::new(Box::new(self.clone())), @@ -165,6 +189,15 @@ impl FieldScriptExpression { debug: Cell::new(false), } } + + pub fn index_to_rou(index: u32, sub_group_bits: u32) -> Self { + FieldScriptExpression::IndexToROU { + index: Arc::new(Box::new(NumScriptExpression::from(index))), + sub_group_bits: sub_group_bits, + var: StackVariable::null(), + debug: Cell::new(false), + } + } } impl Expression for FieldScriptExpression { @@ -192,7 +225,13 @@ impl Expression for FieldScriptExpression { FieldScriptExpression::EqualVerify { debug, .. } => { debug.set(true); } - FieldScriptExpression::Exp { debug, .. } => { + FieldScriptExpression::ExpConstant { debug, .. } => { + debug.set(true); + } + FieldScriptExpression::IndexToROU { debug, .. } => { + debug.set(true); + } + FieldScriptExpression::NumToField { debug, .. } => { debug.set(true); } }; @@ -443,18 +482,84 @@ impl Expression for FieldScriptExpression { "u31ext_equalverify", ); } + if debug.get() == true { + stack.debug(); + } } - FieldScriptExpression::Exp { + FieldScriptExpression::ExpConstant { x, y, debug, mut var, } => { x.express_to_script(stack, input_variables); - // y.express_to_script(stack, input_variables); - // todo: check y is the NumScriptExpression + let vars = stack + .custom1( + value_exp_n::(log2_strict_usize(*y as usize)), + 1, + 1, + 0, + x.var_size(), + "FieldExpr::ExpConstant", + ) + .unwrap(); + var = vars[0]; + + if debug.get() == true { + stack.debug(); + } + assert_eq!(var.size(), F::U32_SIZE as u32); + } + FieldScriptExpression::IndexToROU { + index, + debug, + mut var, + sub_group_bits, + } => { + index.express_to_script(stack, input_variables); + let vars = stack + .custom1( + index_to_rou::(*sub_group_bits), + 1, + 1, + 0, + F::U32_SIZE as u32, + "FieldExpr::IndexToROU", + ) + .unwrap(); + var = vars[0]; + + if debug.get() == true { + stack.debug(); + } + assert_eq!(var.size(), F::U32_SIZE as u32); + } + FieldScriptExpression::NumToField { x, mut var, debug } => { + x.express_to_script(stack, input_variables); + let vars = stack + .custom1( + script! { + if F::U32_SIZE == 1 { + {u32_to_u31()} + } else { + {u32_to_u31()} + {u31_to_u31ext::()} + } + }, + 1, + 1, + 0, + F::U32_SIZE as u32, + "FieldExpr::NumToField", + ) + .unwrap(); + var = vars[0]; + + if debug.get() == true { + stack.debug(); + } assert_eq!(var.size(), F::U32_SIZE as u32); } }; @@ -475,7 +580,9 @@ impl Expression for FieldScriptExpression { FieldScriptExpression::Neg { var, .. } => Some(vec![var]), FieldScriptExpression::Mul { var, .. } => Some(vec![var]), FieldScriptExpression::EqualVerify { .. } => None, - FieldScriptExpression::Exp { var, .. } => Some(vec![var]), + FieldScriptExpression::ExpConstant { var, .. } => Some(vec![var]), + FieldScriptExpression::IndexToROU { var, .. } => Some(vec![var]), + FieldScriptExpression::NumToField { var, .. } => Some(vec![var]), } } } @@ -573,7 +680,15 @@ impl Debug for FieldScriptExpression { FieldScriptExpression::EqualVerify { x, y, debug } => { fm.debug_struct("ScriptExpression::Equal").finish() } - FieldScriptExpression::Exp { x, y, debug, var } => fm + FieldScriptExpression::ExpConstant { x, y, debug, var } => fm + .debug_struct("ScriptExpression::Exp") + .field("variable", var) + .finish(), + FieldScriptExpression::IndexToROU { debug, var, .. } => fm + .debug_struct("ScriptExpression::Exp") + .field("variable", var) + .finish(), + FieldScriptExpression::NumToField { debug, var, .. } => fm .debug_struct("ScriptExpression::Exp") .field("variable", var) .finish(), @@ -633,12 +748,32 @@ impl Clone for FieldScriptExpression { debug: debug.clone(), } } - FieldScriptExpression::Exp { x, y, debug, var } => FieldScriptExpression::Exp { - x: x.clone(), - y: y.clone(), + FieldScriptExpression::ExpConstant { x, y, debug, var } => { + FieldScriptExpression::ExpConstant { + x: x.clone(), + y: y.clone(), + debug: debug.clone(), + var: var.clone(), + } + } + FieldScriptExpression::IndexToROU { + index, + debug, + var, + sub_group_bits, + } => FieldScriptExpression::IndexToROU { + index: index.clone(), debug: debug.clone(), var: var.clone(), + sub_group_bits: *sub_group_bits, }, + FieldScriptExpression::NumToField { x, debug, var } => { + FieldScriptExpression::NumToField { + x: x.clone(), + debug: debug.clone(), + var: var.clone(), + } + } } } } @@ -867,13 +1002,14 @@ mod tests { use bitcoin_script_stack::stack::{self, StackTracker, StackVariable}; use common::{AbstractField, BabyBear, BinomialExtensionField}; use p3_air::AirBuilder; + use p3_field::TwoAdicField; use p3_matrix::Matrix; use primitives::field::BfField; use scripts::treepp::*; - use scripts::u31_lib::{u31ext_equalverify, BabyBear4, BabyBearU31}; + use scripts::u31_lib::{u31ext_equalverify, BabyBear4}; use super::{Expression, FieldScriptExpression, Variable, *}; - use crate::{prove, verify, StarkConfig, SymbolicAirBuilder, SymbolicExpression}; + use crate::SymbolicAirBuilder; type EF = BinomialExtensionField; #[test] @@ -896,6 +1032,105 @@ mod tests { .collect(); } + #[test] + fn test_field_expr_expconst() { + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a_value = BabyBear::two(); + let b_value = a_value.exp_u64(2); + let a = FieldScriptExpression::from(a_value); + let b = a.exp_constant(2); + let equal = b.equal_verify_for_f(b_value); + equal.express_to_script(&mut stack, &bmap); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a_value = EF::two(); + let b_value = a_value.exp_u64(2); + let a = FieldScriptExpression::from(a_value); + let b = a.exp_constant(2); + let equal = b.equal_verify_for_f(b_value); + equal.express_to_script(&mut stack, &bmap); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + } + + #[test] + fn test_field_expr_index_to_rou() { + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let sub_group_bits = 10u32; + let generator = BabyBear::two_adic_generator(sub_group_bits as usize); + let index = 7u32; + let res = generator.exp_u64(index as u64); + + let b = FieldScriptExpression::index_to_rou(index, sub_group_bits); + // b.set_debug(); + let res_expr = FieldScriptExpression::from(res); + let equal = b.equal_verify(res_expr); + equal.express_to_script(&mut stack, &bmap); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let sub_group_bits = 10u32; + let generator = EF::two_adic_generator(sub_group_bits as usize); + let index = 7u32; + let res = generator.exp_u64(index as u64); + + let b = FieldScriptExpression::index_to_rou(index, sub_group_bits); + let equal = b.equal_verify_for_f(res); + equal.express_to_script(&mut stack, &bmap); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + } + + #[test] + fn test_num_to_field() { + let num = 182712u32; + + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = NumScriptExpression::from(num); + let b = a.num_to_field(); + let res = BabyBear::from_canonical_u32(num); + let equal = b.equal_verify_for_f(res); + equal.express_to_script(&mut stack, &bmap); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = NumScriptExpression::from(num); + let b = a.num_to_field(); + let res = EF::from_canonical_u32(num); + let equal = b.equal_verify_for_f(res); + equal.express_to_script(&mut stack, &bmap); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + } + #[test] fn test_script_expression_add() { let bmap = BTreeMap::new(); diff --git a/uni-stark/src/expr/num_script_expr.rs b/uni-stark/src/expr/num_script_expr.rs index 41c4013..b0639be 100644 --- a/uni-stark/src/expr/num_script_expr.rs +++ b/uni-stark/src/expr/num_script_expr.rs @@ -9,10 +9,11 @@ use core::iter::{Product, Sum}; use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use bitcoin_script_stack::stack::{StackTracker, StackVariable}; +use primitives::field::BfField; use scripts::treepp::*; use super::variable::{ValueVariable, Variable}; -use super::Expression; +use super::{Expression, FieldScriptExpression}; use crate::expr::script_helper::value_to_bits_format; pub enum NumScriptExpression { @@ -137,6 +138,14 @@ impl NumScriptExpression { bits_len: bits_len, } } + + pub fn num_to_field(&self) -> FieldScriptExpression { + FieldScriptExpression::NumToField { + x: Arc::new(Box::new(self.clone())), + debug: Cell::new(false), + var: StackVariable::null(), + } + } } impl Expression for NumScriptExpression { diff --git a/uni-stark/src/expr/script_helper.rs b/uni-stark/src/expr/script_helper.rs index a771f6c..fcf9d46 100644 --- a/uni-stark/src/expr/script_helper.rs +++ b/uni-stark/src/expr/script_helper.rs @@ -1,18 +1,9 @@ -use alloc::boxed::Box; -use alloc::collections::BTreeMap; -use alloc::sync::Arc; + use alloc::vec::Vec; use alloc::{format, vec}; -use core::cell::Cell; -use core::fmt::Debug; -use core::iter::{Product, Sum}; -use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; - -use bitcoin::opcodes::OP_FROMALTSTACK; -use bitcoin_script_stack::stack::{StackTracker, StackVariable}; -use common::AbstractField; + use primitives::field::BfField; -use scripts::pseudo::{OP_4FROMALTSTACK, OP_4MUL, OP_4PICK, OP_4TOALTSTACK}; +use scripts::pseudo::{OP_4DUP, OP_4FROMALTSTACK, OP_4MUL, OP_4PICK, OP_4TOALTSTACK}; use scripts::treepp::*; use scripts::u31_lib::{ u31_add, u31_mul, u31_neg, u31_sub, u31_sub_u31ext, u31ext_add, u31ext_add_u31, @@ -20,9 +11,6 @@ use scripts::u31_lib::{ BabyBear4, BabyBearU31, }; -use super::variable::{ValueVariable, Variable}; -use super::Expression; -use crate::SymbolicExpression::{self, *}; /// constraint: bits <= 31 /// input: [b_{0}, b_{1}, ..., b_{bits-1}] @@ -217,18 +205,12 @@ fn value_to_generator_bit_altstack(bits: u32, sub_group_bits: u32) -> Script { // compute w^index // the input stack: -// w <- top -// index : exactly low than 30-bit +// generator <-- top +// index pub fn index_to_rou(sub_group_bits: u32) -> Script { assert!(sub_group_bits <= 27); // 0..27 script! { - if F::U32_SIZE == 1{ - OP_TOALTSTACK - }else{ - OP_4TOALTSTACK - } - OP_DUP 0 @@ -277,14 +259,88 @@ pub fn index_to_rou(sub_group_bits: u32) -> Script { } OP_ENDIF - if F::U32_SIZE == 1{ - OP_FROMALTSTACK - OP_EQUAL + } +} + +fn value_square_with_input() -> Script { + script! { + if F::U32_SIZE == 1 { + OP_DUP + {u31_mul::()} }else{ - OP_4FROMALTSTACK - {u31ext_equalverify::()} - OP_1 + OP_4DUP + {u31ext_mul::()} + } + } +} + +// compute value^n +pub(crate) fn value_exp_n(log_n: usize) -> Script { + script! { + for _ in 0..log_n { + {value_square_with_input::()} } + } +} +#[cfg(test)] +mod tests { + use p3_baby_bear::BabyBear; + use p3_field::extension::BinomialExtensionField; + use p3_field::{AbstractField, TwoAdicField}; + + use super::*; + type EF = BinomialExtensionField; + + #[test] + fn test_index_to_rou() { + let index: u64 = 7; // 111 ; // 7= 4 + 3=(2+1) + let subgroup_bit_size = 10; + let generator = BabyBear::two_adic_generator(subgroup_bit_size); + let w = generator.exp_u64(index); + + let script = script! { + {index as u32} + {index_to_rou::(subgroup_bit_size as u32)} + {w.as_u32_vec()[0]} + OP_EQUAL + }; + + let res = execute_script(script); + assert!(res.success); + + for j in 0..100 { + let index: u32 = j; // 111 ; // 7= 4 + 3=(2+1) + let subgroup_bit_size = 10; + let generator = BabyBear::two_adic_generator(subgroup_bit_size); + let w = generator.exp_u64(index as u64); + let script = script! { + {index as u32} + {index_to_rou::(subgroup_bit_size as u32)} + {w.as_u32_vec()[0]} + OP_EQUAL + }; + + let res = execute_script(script); + assert!(res.success); + } + + // test the index to root-of-unity over babybear extension + for j in 0..100 { + let index: u32 = j; // 111 ; // 7= 4 + 3=(2+1) + let subgroup_bit_size = 10; + let generator = EF::two_adic_generator(subgroup_bit_size); + let w = generator.exp_u64(index as u64); + let script = script! { + {index as u32} + {index_to_rou::(subgroup_bit_size as u32)} + {w.as_u32_vec()[3]}{w.as_u32_vec()[2]}{w.as_u32_vec()[1]}{w.as_u32_vec()[0]} + {u31ext_equalverify::()} + OP_1 + }; + + let res = execute_script(script); + assert!(res.success); + } } } From 3e3aba258e666267528214453f6489c0edb8d87c Mon Sep 17 00:00:00 2001 From: 0xhhh <52317293+cyl19970726@users.noreply.github.com> Date: Thu, 18 Jul 2024 18:33:38 +0800 Subject: [PATCH 13/25] Move ScriptExpr && Add Fraction && Add SelectorExpr (#25) * add index_to_rou && num_to_field && exp into FieldScriptExpression * move script_expr * fix test bug --- Cargo.toml | 2 +- script_expr/Cargo.toml | 24 ++++ .../src}/field_script_expr.rs | 77 ++-------- script_expr/src/fraction_expr.rs | 71 ++++++++++ script_expr/src/lagrange.rs | 36 +++++ .../src/expr/mod.rs => script_expr/src/lib.rs | 12 +- .../src}/num_script_expr.rs | 2 +- .../src}/script_builder.rs | 37 +++-- .../expr => script_expr/src}/script_helper.rs | 2 - .../src/expr => script_expr/src}/variable.rs | 55 +------- uni-stark/Cargo.toml | 1 + uni-stark/src/expr_helper.rs | 131 ++++++++++++++++++ uni-stark/src/lib.rs | 2 +- uni-stark/src/verifier.rs | 20 +-- 14 files changed, 328 insertions(+), 144 deletions(-) create mode 100644 script_expr/Cargo.toml rename {uni-stark/src/expr => script_expr/src}/field_script_expr.rs (94%) create mode 100644 script_expr/src/fraction_expr.rs create mode 100644 script_expr/src/lagrange.rs rename uni-stark/src/expr/mod.rs => script_expr/src/lib.rs (88%) rename {uni-stark/src/expr => script_expr/src}/num_script_expr.rs (99%) rename {uni-stark/src/expr => script_expr/src}/script_builder.rs (82%) rename {uni-stark/src/expr => script_expr/src}/script_helper.rs (99%) rename {uni-stark/src/expr => script_expr/src}/variable.rs (80%) create mode 100644 uni-stark/src/expr_helper.rs diff --git a/Cargo.toml b/Cargo.toml index b834db6..78afecd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,5 +8,5 @@ members = [ "segment", "common", "uni-stark" -] +, "script_expr"] diff --git a/script_expr/Cargo.toml b/script_expr/Cargo.toml new file mode 100644 index 0000000..4d130f0 --- /dev/null +++ b/script_expr/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "script_expr" +version = "0.1.0" +edition = "2021" + +[dependencies] +bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git"} +bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } +bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } +bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } +p3-air = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-field = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-commit ={ git = "https://github.com/Plonky3/Plonky3.git" } +p3-dft = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-matrix = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-maybe-rayon = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-util = { git = "https://github.com/Plonky3/Plonky3.git" } +primitives = { path = "../primitives" } +scripts = {path = "../scripts"} +common ={ path = "../common" } + +[dev-dependencies] +p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } \ No newline at end of file diff --git a/uni-stark/src/expr/field_script_expr.rs b/script_expr/src/field_script_expr.rs similarity index 94% rename from uni-stark/src/expr/field_script_expr.rs rename to script_expr/src/field_script_expr.rs index f67a2e5..4dfa6d9 100644 --- a/uni-stark/src/expr/field_script_expr.rs +++ b/script_expr/src/field_script_expr.rs @@ -7,6 +7,7 @@ use core::cell::Cell; use core::fmt::Debug; use core::iter::{Product, Sum}; use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use std::ops::Div; use bitcoin_script_stack::stack::{StackTracker, StackVariable}; use common::AbstractField; @@ -22,8 +23,8 @@ use scripts::u31_lib::{ use super::num_script_expr::NumScriptExpression; use super::variable::{ValueVariable, Variable}; use super::Expression; -use crate::expr::script_helper::{index_to_rou, value_exp_n}; -use crate::SymbolicExpression::{self, *}; +use crate::script_helper::{index_to_rou, value_exp_n}; +use crate::Fraction; pub enum FieldScriptExpression { ValueVariable { @@ -587,49 +588,6 @@ impl Expression for FieldScriptExpression { } } -impl From<&SymbolicExpression> for FieldScriptExpression { - fn from(value: &SymbolicExpression) -> Self { - match value { - SymbolicExpression::Variable(v) => FieldScriptExpression::InputVariable { - sv: v.into(), - debug: Cell::new(false), - var: StackVariable::null(), - }, - SymbolicExpression::IsFirstRow => FieldScriptExpression::one(), - SymbolicExpression::IsLastRow => FieldScriptExpression::one(), - SymbolicExpression::IsTransition => FieldScriptExpression::one(), - SymbolicExpression::Constant(f) => FieldScriptExpression::Constant { - f: f.clone(), - debug: Cell::new(false), - var: StackVariable::null(), - }, - SymbolicExpression::Add { x, y, .. } => FieldScriptExpression::Add { - x: Arc::new(Box::new(FieldScriptExpression::from(&*x.clone()))), - y: Arc::new(Box::new(FieldScriptExpression::from(&*y.clone()))), - debug: Cell::new(false), - var: StackVariable::null(), - }, - SymbolicExpression::Sub { x, y, .. } => FieldScriptExpression::Sub { - x: Arc::new(Box::new(FieldScriptExpression::from(&*x.clone()))), - y: Arc::new(Box::new(FieldScriptExpression::from(&*y.clone()))), - debug: Cell::new(false), - var: StackVariable::null(), - }, - SymbolicExpression::Neg { x, .. } => FieldScriptExpression::Neg { - x: Arc::new(Box::new(FieldScriptExpression::from(&*x.clone()))), - debug: Cell::new(false), - var: StackVariable::null(), - }, - SymbolicExpression::Mul { x, y, .. } => FieldScriptExpression::Mul { - x: Arc::new(Box::new(FieldScriptExpression::from(&*x.clone()))), - y: Arc::new(Box::new(FieldScriptExpression::from(&*y.clone()))), - debug: Cell::new(false), - var: StackVariable::null(), - }, - } - } -} - impl Default for FieldScriptExpression { fn default() -> Self { Self::zero() @@ -967,6 +925,14 @@ impl Mul for FieldScriptExpression { } } +impl Div for FieldScriptExpression { + type Output = Fraction; + + fn div(self, rhs: Self) -> Fraction { + Fraction::::new(self, rhs) + } +} + impl MulAssign for FieldScriptExpression { fn mul_assign(&mut self, rhs: Self) { *self = self.clone() * rhs; @@ -1009,29 +975,8 @@ mod tests { use scripts::u31_lib::{u31ext_equalverify, BabyBear4}; use super::{Expression, FieldScriptExpression, Variable, *}; - use crate::SymbolicAirBuilder; type EF = BinomialExtensionField; - #[test] - fn test_symbolic_expr_constraints() { - let air_width: usize = 2; - let mut builder = SymbolicAirBuilder::::new(0, air_width, 0); - let main_values = builder.main(); - let (local, next) = (main_values.row_slice(0), main_values.row_slice(1)); - let mut when_transition = builder.when_transition(); - // a' <- b - when_transition.assert_eq(local[0], local[1]); - - // b' <- a + b - when_transition.assert_eq(local[0] + local[1], next[1]); - - let cs = builder.constraints(); - let script_exp: Vec> = cs - .iter() - .map(|cons| FieldScriptExpression::from(cons)) - .collect(); - } - #[test] fn test_field_expr_expconst() { { diff --git a/script_expr/src/fraction_expr.rs b/script_expr/src/fraction_expr.rs new file mode 100644 index 0000000..1aba161 --- /dev/null +++ b/script_expr/src/fraction_expr.rs @@ -0,0 +1,71 @@ +use std::ops::Add; +use std::sync::Arc; + +use primitives::field::BfField; + +use super::FieldScriptExpression; +use crate::Expression; + +pub struct Fraction { + numerator: FieldScriptExpression, + denominator: FieldScriptExpression, +} + +impl Fraction { + pub(crate) fn new( + numerator: FieldScriptExpression, + denominator: FieldScriptExpression, + ) -> Self { + Self { + numerator, + denominator, + } + } + + fn get_numerator(&self) -> FieldScriptExpression { + self.numerator.clone() + } + + fn get_demonitor(&self) -> FieldScriptExpression { + self.denominator.clone() + } + + fn mul_expr(self, other: FieldScriptExpression) -> Fraction { + Fraction::new(self.numerator * other, self.denominator) + } + + fn mul_fraction(self, other: Self) -> Fraction { + Fraction::new( + self.numerator * other.numerator, + self.denominator * other.denominator, + ) + } + + fn add_expr(self, other: FieldScriptExpression) -> Fraction { + Fraction::new( + self.numerator + other * self.denominator.clone(), + self.denominator, + ) + } + + fn add_fraction(self, other: Self) -> Fraction { + Fraction::new( + self.numerator * other.denominator.clone() + other.numerator * self.denominator.clone(), + self.denominator * other.denominator, + ) + } + + fn sub_expr(self, other: FieldScriptExpression) -> Fraction { + Fraction::new( + self.numerator - other * self.denominator.clone(), + self.denominator, + ) + } + + fn sub_fraction(self, other: Self) -> Fraction { + Fraction::new( + self.numerator * other.denominator.clone() - other.numerator * self.denominator.clone(), + self.denominator * other.denominator, + ) + } +} diff --git a/script_expr/src/lagrange.rs b/script_expr/src/lagrange.rs new file mode 100644 index 0000000..b668305 --- /dev/null +++ b/script_expr/src/lagrange.rs @@ -0,0 +1,36 @@ +use common::TwoAdicField; +use p3_field::ExtensionField; +use primitives::field::BfField; + +use super::FieldScriptExpression; + +pub struct LagrangeSelectorsExpr { + pub is_first_row: FieldScriptExpression, + pub is_last_row: FieldScriptExpression, + pub is_transition: FieldScriptExpression, + pub z_h: FieldScriptExpression, +} + +pub fn selectors_at_point_expr + BfField, Val: TwoAdicField + BfField>( + shift: Val, + point: Ext, + log_n: usize, +) -> LagrangeSelectorsExpr { + let unshifted_point = point * shift.inverse(); + let mut unshifted_point_expr = FieldScriptExpression::::default(); + if shift == Val::one() { + unshifted_point_expr = FieldScriptExpression::::from(unshifted_point); + } else { + unshifted_point_expr = FieldScriptExpression::from(point) + .mul_base(FieldScriptExpression::from(shift.inverse())); + } + let z_h = unshifted_point.exp_power_of_2(log_n) - Ext::one(); // (x-w^0)...(x-w^n-1) + let z_h_expr = unshifted_point_expr.exp_constant(2 ^ log_n as u32); + LagrangeSelectorsExpr { + is_first_row: (z_h / (unshifted_point - Ext::one())).into(), // hint + is_last_row: (z_h / (unshifted_point - Val::two_adic_generator(log_n).inverse())).into(), // hint + is_transition: unshifted_point_expr + .sub_base(Val::two_adic_generator(log_n).inverse().into()), + z_h: z_h_expr, // + } +} diff --git a/uni-stark/src/expr/mod.rs b/script_expr/src/lib.rs similarity index 88% rename from uni-stark/src/expr/mod.rs rename to script_expr/src/lib.rs index b43520d..74a210a 100644 --- a/uni-stark/src/expr/mod.rs +++ b/script_expr/src/lib.rs @@ -1,3 +1,5 @@ +extern crate alloc; + use alloc::boxed::Box; use alloc::collections::BTreeMap; use alloc::sync::Arc; @@ -9,17 +11,19 @@ use num_script_expr::NumScriptExpression; use primitives::field::BfField; use scripts::treepp::*; -use crate::SymbolicExpression::{self, *}; - mod script_builder; -pub use script_builder::*; mod variable; pub use variable::{ValueVariable, Variable}; mod num_script_expr; -// pub use num_script_expr::*; +pub use num_script_expr::*; mod field_script_expr; pub use field_script_expr::*; mod script_helper; +pub use script_builder::*; +mod fraction_expr; +pub use fraction_expr::*; +mod lagrange; +pub use lagrange::*; pub struct Executor { to_exec_expr: FieldScriptExpression, diff --git a/uni-stark/src/expr/num_script_expr.rs b/script_expr/src/num_script_expr.rs similarity index 99% rename from uni-stark/src/expr/num_script_expr.rs rename to script_expr/src/num_script_expr.rs index b0639be..9c024c4 100644 --- a/uni-stark/src/expr/num_script_expr.rs +++ b/script_expr/src/num_script_expr.rs @@ -14,7 +14,7 @@ use scripts::treepp::*; use super::variable::{ValueVariable, Variable}; use super::{Expression, FieldScriptExpression}; -use crate::expr::script_helper::value_to_bits_format; +use crate::script_helper::value_to_bits_format; pub enum NumScriptExpression { InputVariable { diff --git a/uni-stark/src/expr/script_builder.rs b/script_expr/src/script_builder.rs similarity index 82% rename from uni-stark/src/expr/script_builder.rs rename to script_expr/src/script_builder.rs index b6452fa..a63465a 100644 --- a/uni-stark/src/expr/script_builder.rs +++ b/script_expr/src/script_builder.rs @@ -9,16 +9,15 @@ use primitives::field::BfField; use scripts::treepp::*; use super::{FieldScriptExpression, ValueVariable, Variable}; -use crate::SymbolicExpression::{self, *}; pub struct ScriptConstraintBuilder { pub main: RowMajorMatrix>, pub public_values: Vec, - pub is_first_row: F, - pub is_last_row: F, - pub is_transition: F, + pub is_first_row: FieldScriptExpression, + pub is_last_row: FieldScriptExpression, + pub is_transition: FieldScriptExpression, pub constraints: Vec>, - pub alpha: F, + pub alpha: FieldScriptExpression, } impl ScriptConstraintBuilder { @@ -30,6 +29,26 @@ impl ScriptConstraintBuilder { is_last_row: F, is_transition: F, alpha: F, + ) -> Self { + Self::new_with_expr( + local, + next, + num_public_values, + FieldScriptExpression::from(is_first_row), + FieldScriptExpression::from(is_last_row), + FieldScriptExpression::from(is_transition), + FieldScriptExpression::from(alpha), + ) + } + + pub fn new_with_expr( + local: Vec, + next: Vec, + num_public_values: usize, + is_first_row: FieldScriptExpression, + is_last_row: FieldScriptExpression, + is_transition: FieldScriptExpression, + alpha: FieldScriptExpression, ) -> Self { let width = local.len(); let main_variables: Vec> = [local, next] @@ -64,7 +83,7 @@ impl ScriptConstraintBuilder { pub fn get_accmulator_expr(&self) -> FieldScriptExpression { let mut acc = self.constraints[0].clone(); for i in 1..self.constraints.len() { - acc = acc * self.alpha + self.constraints[i].clone(); + acc = acc * self.alpha.clone() + self.constraints[i].clone(); } acc } @@ -132,16 +151,16 @@ impl AirBuilder for ScriptConstraintBuilder { } fn is_first_row(&self) -> Self::Expr { - Self::Expr::from(self.is_first_row) + self.is_first_row.clone() } fn is_last_row(&self) -> Self::Expr { - Self::Expr::from(self.is_last_row) + self.is_last_row.clone() } fn is_transition_window(&self, size: usize) -> Self::Expr { if size == 2 { - Self::Expr::from(self.is_transition) + self.is_transition.clone() } else { panic!("uni-stark only supports a window size of 2") } diff --git a/uni-stark/src/expr/script_helper.rs b/script_expr/src/script_helper.rs similarity index 99% rename from uni-stark/src/expr/script_helper.rs rename to script_expr/src/script_helper.rs index fcf9d46..57a4e55 100644 --- a/uni-stark/src/expr/script_helper.rs +++ b/script_expr/src/script_helper.rs @@ -1,4 +1,3 @@ - use alloc::vec::Vec; use alloc::{format, vec}; @@ -11,7 +10,6 @@ use scripts::u31_lib::{ BabyBear4, BabyBearU31, }; - /// constraint: bits <= 31 /// input: [b_{0}, b_{1}, ..., b_{bits-1}] pub fn compress_bits(bits: usize) -> Script { diff --git a/uni-stark/src/expr/variable.rs b/script_expr/src/variable.rs similarity index 80% rename from uni-stark/src/expr/variable.rs rename to script_expr/src/variable.rs index ea99cc1..3526941 100644 --- a/uni-stark/src/expr/variable.rs +++ b/script_expr/src/variable.rs @@ -3,12 +3,9 @@ use core::fmt::Debug; use core::ops::{Add, Mul, Sub}; use bitcoin_script_stack::stack::StackVariable; -use p3_field::Field; use primitives::field::BfField; use super::FieldScriptExpression; -use crate::symbolic_variable::SymbolicVariable; -use crate::Entry; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct ValueVariable { @@ -141,9 +138,9 @@ impl Mul> for FieldScriptExpression { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Variable { - row_index: usize, - column_index: usize, - expect_var_size: Option, + pub row_index: usize, + pub column_index: usize, + pub expect_var_size: Option, } impl Variable { @@ -194,52 +191,6 @@ impl From for FieldScriptExpression { } } -impl From> for Variable { - fn from(value: SymbolicVariable) -> Self { - match value.entry { - Entry::Main { offset } => Variable { - row_index: value.index, - column_index: offset, - expect_var_size: None, - }, - Entry::Permutation { offset } => Variable { - row_index: value.index, - column_index: offset, - expect_var_size: None, - }, - Entry::Preprocessed { offset } => Variable { - row_index: value.index, - column_index: offset, - expect_var_size: None, - }, - _ => panic!("error type"), - } - } -} - -impl From<&SymbolicVariable> for Variable { - fn from(value: &SymbolicVariable) -> Self { - match value.entry { - Entry::Main { offset } => Variable { - row_index: value.index, - column_index: offset, - expect_var_size: None, - }, - Entry::Permutation { offset } => Variable { - row_index: value.index, - column_index: offset, - expect_var_size: None, - }, - Entry::Preprocessed { offset } => Variable { - row_index: value.index, - column_index: offset, - expect_var_size: None, - }, - _ => panic!("error type"), - } - } -} - impl Add for Variable { type Output = FieldScriptExpression; diff --git a/uni-stark/Cargo.toml b/uni-stark/Cargo.toml index b7adda5..e2a5a0c 100644 --- a/uni-stark/Cargo.toml +++ b/uni-stark/Cargo.toml @@ -26,6 +26,7 @@ segment ={ path = "../segment"} script_manager = {path = "../script_manager"} fri = { path = "../fri"} common = {path = "../common"} +script_expr = {path = "../script_expr"} [dev-dependencies] p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } diff --git a/uni-stark/src/expr_helper.rs b/uni-stark/src/expr_helper.rs new file mode 100644 index 0000000..39f0c12 --- /dev/null +++ b/uni-stark/src/expr_helper.rs @@ -0,0 +1,131 @@ +use std::cell::Cell; +use std::sync::Arc; + +use bitcoin_script_stack::stack::StackVariable; +use p3_field::{AbstractField, Field}; +use primitives::field::BfField; +use script_expr::{FieldScriptExpression, ValueVariable, Variable}; + +use crate::symbolic_variable::SymbolicVariable; +use crate::{Entry, SymbolicExpression}; + +impl From<&SymbolicExpression> for FieldScriptExpression { + fn from(value: &SymbolicExpression) -> Self { + match value { + SymbolicExpression::Variable(v) => FieldScriptExpression::InputVariable { + sv: v.into(), + debug: Cell::new(false), + var: StackVariable::null(), + }, + SymbolicExpression::IsFirstRow => FieldScriptExpression::one(), + SymbolicExpression::IsLastRow => FieldScriptExpression::one(), + SymbolicExpression::IsTransition => FieldScriptExpression::one(), + SymbolicExpression::Constant(f) => FieldScriptExpression::Constant { + f: f.clone(), + debug: Cell::new(false), + var: StackVariable::null(), + }, + SymbolicExpression::Add { x, y, .. } => FieldScriptExpression::Add { + x: Arc::new(Box::new(FieldScriptExpression::from(&*x.clone()))), + y: Arc::new(Box::new(FieldScriptExpression::from(&*y.clone()))), + debug: Cell::new(false), + var: StackVariable::null(), + }, + SymbolicExpression::Sub { x, y, .. } => FieldScriptExpression::Sub { + x: Arc::new(Box::new(FieldScriptExpression::from(&*x.clone()))), + y: Arc::new(Box::new(FieldScriptExpression::from(&*y.clone()))), + debug: Cell::new(false), + var: StackVariable::null(), + }, + SymbolicExpression::Neg { x, .. } => FieldScriptExpression::Neg { + x: Arc::new(Box::new(FieldScriptExpression::from(&*x.clone()))), + debug: Cell::new(false), + var: StackVariable::null(), + }, + SymbolicExpression::Mul { x, y, .. } => FieldScriptExpression::Mul { + x: Arc::new(Box::new(FieldScriptExpression::from(&*x.clone()))), + y: Arc::new(Box::new(FieldScriptExpression::from(&*y.clone()))), + debug: Cell::new(false), + var: StackVariable::null(), + }, + } + } +} + +impl From> for Variable { + fn from(value: SymbolicVariable) -> Self { + match value.entry { + Entry::Main { offset } => Variable { + row_index: value.index, + column_index: offset, + expect_var_size: None, + }, + Entry::Permutation { offset } => Variable { + row_index: value.index, + column_index: offset, + expect_var_size: None, + }, + Entry::Preprocessed { offset } => Variable { + row_index: value.index, + column_index: offset, + expect_var_size: None, + }, + _ => panic!("error type"), + } + } +} + +impl From<&SymbolicVariable> for Variable { + fn from(value: &SymbolicVariable) -> Self { + match value.entry { + Entry::Main { offset } => Variable { + row_index: value.index, + column_index: offset, + expect_var_size: None, + }, + Entry::Permutation { offset } => Variable { + row_index: value.index, + column_index: offset, + expect_var_size: None, + }, + Entry::Preprocessed { offset } => Variable { + row_index: value.index, + column_index: offset, + expect_var_size: None, + }, + _ => panic!("error type"), + } + } +} + +#[cfg(test)] +mod tests { + use alloc::vec::Vec; + + use common::{BabyBear, BinomialExtensionField}; + use p3_air::AirBuilder; + use p3_matrix::Matrix; + use script_expr::{FieldScriptExpression, *}; + type EF = BinomialExtensionField; + + use crate::SymbolicAirBuilder; + #[test] + fn test_symbolic_expr_constraints() { + let air_width: usize = 2; + let mut builder = SymbolicAirBuilder::::new(0, air_width, 0); + let main_values = builder.main(); + let (local, next) = (main_values.row_slice(0), main_values.row_slice(1)); + let mut when_transition = builder.when_transition(); + // a' <- b + when_transition.assert_eq(local[0], local[1]); + + // b' <- a + b + when_transition.assert_eq(local[0] + local[1], next[1]); + + let cs = builder.constraints(); + let script_exp: Vec> = cs + .iter() + .map(|cons| FieldScriptExpression::from(cons)) + .collect(); + } +} diff --git a/uni-stark/src/lib.rs b/uni-stark/src/lib.rs index ef0e4ae..dcc764f 100644 --- a/uni-stark/src/lib.rs +++ b/uni-stark/src/lib.rs @@ -5,7 +5,7 @@ extern crate alloc; mod config; -mod expr; +mod expr_helper; mod folder; mod proof; mod prover; diff --git a/uni-stark/src/verifier.rs b/uni-stark/src/verifier.rs index ed5ef19..56473a0 100644 --- a/uni-stark/src/verifier.rs +++ b/uni-stark/src/verifier.rs @@ -4,20 +4,22 @@ use alloc::vec::Vec; use bitcoin_script_stack::stack::StackTracker; use itertools::Itertools; -use p3_air::{Air, AirBuilder, AirBuilderWithPublicValues, BaseAir}; +use p3_air::{Air, BaseAir}; use p3_challenger::{CanObserve, CanSample}; use p3_commit::PolynomialSpace; use p3_field::{AbstractExtensionField, AbstractField, Field}; use p3_matrix::dense::{RowMajorMatrix, RowMajorMatrixView}; use p3_matrix::stack::VerticalPair; +use p3_util::log2_strict_usize; use primitives::bf_pcs::Pcs; use primitives::field::BfField; -use script_manager::bc_assignment::DefaultBCAssignment; +use script_expr::{ + selectors_at_point_expr, Expression, FieldScriptExpression, ScriptConstraintBuilder, +}; use script_manager::script_info::ScriptInfo; use scripts::execute_script_with_inputs; use tracing::instrument; -use crate::expr::{Expression, FieldScriptExpression, ScriptConstraintBuilder}; use crate::symbolic_builder::{self, get_log_quotient_degree, SymbolicAirBuilder}; use crate::{PcsError, Proof, StarkGenericConfig, Val, VerifierConstraintFolder}; @@ -168,14 +170,16 @@ where return Err(VerificationError::OodEvaluationMismatch); } - let mut script_folder = ScriptConstraintBuilder::new( + let log_n = log2_strict_usize(degree); + let sels_expr = selectors_at_point_expr(Val::::one(), zeta, log_n); + let mut script_folder = ScriptConstraintBuilder::new_with_expr( opened_values.trace_local.clone(), opened_values.trace_next.clone(), public_values.len(), - sels.is_first_row, - sels.is_last_row, - sels.is_transition, - alpha, + sels_expr.is_first_row, + sels_expr.is_last_row, + sels_expr.is_transition, + alpha.into(), ); air.eval(&mut script_folder); From b4a63f7f8f18c4c2c34a2925565e6a61b6e4cf12 Mon Sep 17 00:00:00 2001 From: dylanCai9 <22110240060@m.fudan.edu.cn> Date: Fri, 19 Jul 2024 16:43:01 +0800 Subject: [PATCH 14/25] Compute quotient expr (#26) * support expr lookup table * compute quotient by expr * resolve review opt --- script_expr/src/field_script_expr.rs | 148 +++++- uni-stark/src/scripts/bf_unistark.rs | 650 ++++----------------------- uni-stark/src/scripts/utils.rs | 11 + uni-stark/tests/fib_air.rs | 79 +++- 4 files changed, 301 insertions(+), 587 deletions(-) diff --git a/script_expr/src/field_script_expr.rs b/script_expr/src/field_script_expr.rs index 4dfa6d9..50e5437 100644 --- a/script_expr/src/field_script_expr.rs +++ b/script_expr/src/field_script_expr.rs @@ -42,6 +42,11 @@ pub enum FieldScriptExpression { debug: Cell, var: StackVariable, }, + Table { + table: Vec, + debug: Cell, + var: StackVariable, + }, Add { x: Arc>, y: Arc>, @@ -88,6 +93,13 @@ pub enum FieldScriptExpression { var: StackVariable, debug: Cell, }, + Lookup { + x: Arc>, + y: Arc>, + len: usize, + var: StackVariable, + debug: Cell, + }, } impl FieldScriptExpression { @@ -211,6 +223,9 @@ impl Expression for FieldScriptExpression { debug.set(true); } FieldScriptExpression::Constant { debug, .. } => debug.set(true), + FieldScriptExpression::Table { debug, .. } => { + debug.set(true); + } FieldScriptExpression::Add { debug, .. } => { debug.set(true); } @@ -235,6 +250,9 @@ impl Expression for FieldScriptExpression { FieldScriptExpression::NumToField { debug, .. } => { debug.set(true); } + FieldScriptExpression::Lookup { debug, .. } => { + debug.set(true); + } }; } @@ -271,6 +289,20 @@ impl Expression for FieldScriptExpression { stack.debug(); } } + FieldScriptExpression::Table { + table, + mut var, + debug, + } => { + //push table + for f in table.iter().rev() { + let v = f.as_u32_vec(); + var = stack.bignumber(v); + } + if debug.get() == true { + stack.debug(); + } + } FieldScriptExpression::Add { x, y, @@ -563,6 +595,34 @@ impl Expression for FieldScriptExpression { } assert_eq!(var.size(), F::U32_SIZE as u32); } + FieldScriptExpression::Lookup { + x, + y, + len, + debug, + mut var, + } => { + x.express_to_script(stack, input_variables); + // todo: check y is the NumScriptExpression + y.express_to_script(stack, input_variables); + let vars = stack.custom1( + script! { + OP_PICK + }, + 1, + 1, + 0, + F::U32_SIZE as u32, + "ExprLookup_Result", + ); + stack.to_altstack(); + for _ in 0..(*len) { + stack.op_drop(); + } + var = stack.from_altstack(); + + assert_eq!(var.size(), F::U32_SIZE as u32); + } }; stack.get_script() } @@ -576,6 +636,7 @@ impl Expression for FieldScriptExpression { FieldScriptExpression::ValueVariable { var, .. } => Some(vec![var]), FieldScriptExpression::InputVariable { var, .. } => Some(vec![var]), FieldScriptExpression::Constant { var, .. } => Some(vec![var]), + FieldScriptExpression::Table { var, .. } => Some(vec![var]), FieldScriptExpression::Add { var, .. } => Some(vec![var]), FieldScriptExpression::Sub { var, .. } => Some(vec![var]), FieldScriptExpression::Neg { var, .. } => Some(vec![var]), @@ -584,6 +645,7 @@ impl Expression for FieldScriptExpression { FieldScriptExpression::ExpConstant { var, .. } => Some(vec![var]), FieldScriptExpression::IndexToROU { var, .. } => Some(vec![var]), FieldScriptExpression::NumToField { var, .. } => Some(vec![var]), + FieldScriptExpression::Lookup { var, .. } => Some(vec![var]), } } } @@ -619,6 +681,10 @@ impl Debug for FieldScriptExpression { .debug_struct("ScriptExpression::Constant") .field("f", f) .finish(), + FieldScriptExpression::Table { table, .. } => fm + .debug_struct("ScriptExpression::Table") + .field("table", table) + .finish(), FieldScriptExpression::Add { x, y, debug, var } => fm .debug_struct("ScriptExpression::Add") .field("variable", var) @@ -650,6 +716,16 @@ impl Debug for FieldScriptExpression { .debug_struct("ScriptExpression::Exp") .field("variable", var) .finish(), + FieldScriptExpression::Lookup { + x, + y, + len, + debug, + var, + } => fm + .debug_struct("ScriptExpression::Lookup") + .field("variable", var) + .finish(), } } } @@ -676,6 +752,11 @@ impl Clone for FieldScriptExpression { debug: debug.clone(), var: var.clone(), }, + FieldScriptExpression::Table { table, debug, var } => FieldScriptExpression::Table { + table: table.clone(), + debug: debug.clone(), + var: var.clone(), + }, FieldScriptExpression::Add { x, y, debug, var } => FieldScriptExpression::Add { x: x.clone(), y: y.clone(), @@ -732,6 +813,19 @@ impl Clone for FieldScriptExpression { var: var.clone(), } } + FieldScriptExpression::Lookup { + x, + y, + len, + debug, + var, + } => FieldScriptExpression::Lookup { + x: x.clone(), + y: y.clone(), + len: len.clone(), + debug: debug.clone(), + var: var.clone(), + }, } } } @@ -957,6 +1051,26 @@ impl Product for FieldScriptExpression { } } +impl FieldScriptExpression { + pub fn lookup(self, index: u32, len: usize) -> Self { + let index = NumScriptExpression::from(index); + Self::Lookup { + x: Arc::new(Box::new(self)), + y: Arc::new(Box::new(index)), + len: len, + debug: Cell::new(false), + var: StackVariable::null(), + } + } + pub fn from_table(table: &[F]) -> Self { + Self::Table { + table: table.into(), + debug: Cell::new(false), + var: StackVariable::null(), + } + } +} + #[cfg(test)] mod tests { use alloc::boxed::Box; @@ -972,7 +1086,7 @@ mod tests { use p3_matrix::Matrix; use primitives::field::BfField; use scripts::treepp::*; - use scripts::u31_lib::{u31ext_equalverify, BabyBear4}; + use scripts::u31_lib::{u31_equalverify, u31ext_equalverify, BabyBear4}; use super::{Expression, FieldScriptExpression, Variable, *}; type EF = BinomialExtensionField; @@ -1534,4 +1648,36 @@ mod tests { let res = stack.run(); assert!(res.success); } + + #[test] + fn test_lookup() { + let vec = vec![ + BabyBear::from_canonical_u32(1 as u32), + BabyBear::from_canonical_u32(2 as u32), + BabyBear::from_canonical_u32(3 as u32), + BabyBear::from_canonical_u32(4 as u32), + BabyBear::from_canonical_u32(5 as u32), + ]; + let mut stack = StackTracker::new(); + let bmap = BTreeMap::new(); + + let table = FieldScriptExpression::Table { + table: vec.clone(), + debug: Cell::new(false), + var: StackVariable::null(), + }; + + let index = 4; + + let m = table.lookup(index, vec.len()); + + let script = m.express_to_script(&mut stack, &bmap); + + stack.number(5 as u32); + + stack.custom(u31_equalverify(), 2, false, 0, "u31_equalverify"); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } } diff --git a/uni-stark/src/scripts/bf_unistark.rs b/uni-stark/src/scripts/bf_unistark.rs index 873f82f..3cac16c 100644 --- a/uni-stark/src/scripts/bf_unistark.rs +++ b/uni-stark/src/scripts/bf_unistark.rs @@ -1,592 +1,104 @@ -use bitcoin::opcodes::{OP_ADD, OP_DROP, OP_SUB, OP_SWAP, OP_TOALTSTACK, OP_TRUE}; -use bitcoin::{script, ScriptBuf as Script}; -use bitcoin_script::{define_pushable, script}; -use itertools::izip; -use p3_field::AbstractField; -use p3_util::log2_strict_usize; -use primitives::field::BfField; -use script_manager::script_info::{self, ScriptInfo}; -use scripts::pseudo::{ - OP_4DROP, OP_4DUP, OP_4FROMALTSTACK, OP_4MUL, OP_4PICK, OP_4ROLL, OP_4SWAP, OP_4TOALTSTACK, - OP_NDUP, -}; -use scripts::u31_lib::{ - u31_add, u31_double, u31_mul, u31_sub, u31_sub_u31ext, u31_to_u31ext, u31ext_add, - u31ext_double, u31ext_equalverify, u31ext_mul, u31ext_mul_u31, u31ext_mul_u31_by_constant, - u31ext_sub, u31ext_sub_u31, BabyBear4, BabyBearU31, -}; - -use crate::{get_generator, value_exp_n_minus_one}; - -define_pushable!(); - -// * input: -// * altstack: -// * empty -// * stack: -// * zeta/a babybear4 -// * (quotient_chunk_nums - 1 - j_i) +use std::cell::Cell; +use std::collections::BTreeMap; +use std::sync::Arc; -// * output: -// * altstack: -// * acc_numerator babybear4 -// * stack: -// * zeta/a babybear4 -fn compute_acc_numerator( - log_n_conf: usize, - generator: Val, - quotient_chunk_nums: usize, -) -> Script { - script! { - OP_0 OP_0 OP_0 OP_1 // the accmulator is 1 when intialization - for _ in 0..(quotient_chunk_nums - 1) { - OP_4TOALTSTACK //alt: acc stack: zeta/a index - OP_4DUP - OP_4TOALTSTACK - OP_4TOALTSTACK //alt: zeta/a zeta/a acc stack:index - {get_generator::(generator, quotient_chunk_nums)} //get w^-j at top - OP_4FROMALTSTACK //get zeta/babybear_generator at top - 4 OP_ROLL - {u31ext_mul_u31::()} //zeta/(babybear_generator * w^j) - {value_exp_n_minus_one::(log_n_conf)} //x^n - 1 - OP_4FROMALTSTACK - OP_4SWAP - OP_4FROMALTSTACK //acc - {u31ext_mul::()} //new_acc zeta/babybear_generator -j - } - OP_4TOALTSTACK - } -} +use bitcoin_script_stack::stack::{StackTracker, StackVariable}; +use itertools::Itertools; +use p3_field::ExtensionField; +use primitives::field::BfField; +use script_expr::{Expression, FieldScriptExpression}; +use scripts::u31_lib::u31_equalverify; -pub fn compute_acc_numerator_all( - log_n_conf: usize, - generator: Val, - quotient_chunk_nums: usize, -) -> Script { - script! { - //push babybeay_generator.inverse() - {64944062 as u32} - {u31ext_mul_u31::()} // stack: zeta/a - for i in 0..quotient_chunk_nums{ - OP_4TOALTSTACK - for j in 0..quotient_chunk_nums { - if j != i { - {(quotient_chunk_nums - 1 - j) as u32} - } - } - OP_4FROMALTSTACK - {compute_acc_numerator::(log_n_conf, generator,quotient_chunk_nums)} //babybear4 - } - OP_4DROP - for _ in 0..quotient_chunk_nums { - OP_4FROMALTSTACK - } - } -} +use crate::get_table; -pub fn compute_acc_numerator_script( +pub fn compute_quotient_expr>( zeta: Challenge, - quotient_chunk_nums: usize, - degree_bits: usize, - generator: Val, - numerators: Vec, -) -> ScriptInfo { - assert_eq!(numerators.len(), quotient_chunk_nums); - let mut si = ScriptInfo::new( - "compute_acc_numerator", - compute_acc_numerator_all::(degree_bits, generator, quotient_chunk_nums), - ); - si.add_input(zeta); - for i in 0..quotient_chunk_nums { - si.add_output(numerators[i]); - } - si -} - -// * input: -// * altstack: -// * empty -// * stack: -// * i -// * (quotient_chunk_nums-1-j_i) -// * zps[i] babybear4 - -// * output: -// * altstack: -// * acc_denominator babybear -// * stack: -// * zps[i] -fn compute_acc_denominator( - log_n_conf: usize, + trace_degree: usize, generator: Val, quotient_chunk_nums: usize, -) -> Script { - script! { - OP_1 //the accmulator is 1 when intialization - for _ in 0..(quotient_chunk_nums - 1) { - OP_TOALTSTACK //alt: acc s:i, (S-1-j) - OP_DUP //alt: acc s:i,i,(S-1-j) - OP_TOALTSTACK //alt: i, acc s:i, (S-1-j) - OP_ADD //alt: i, acc s:i + (S-1-j) = lookup_index - {get_generator::(generator, quotient_chunk_nums)} - {value_exp_n_minus_one::(log_n_conf)} //alt: i, acc s: (w^(i-j))^n - 1 - OP_FROMALTSTACK - OP_SWAP - OP_FROMALTSTACK // s: acc, (w^(i-j))^n - 1, i - {u31_mul::()} // s: new_acc i j - } - OP_TOALTSTACK - OP_DROP //DROP i - } -} - -// * -// * compute: -// * zps[i] * denominator -// * -// * input: -// * altstack: -// * empty -// * stack: -// * zps[i] babybear4 - -// * output: -// * altstack: -// * zps[i] * acc_denominator babybear4 -// * stack: -// * zps[i+1] or empty babybear4 -fn zps_i_mul_denominator( - i: usize, - log_n_conf: usize, - generator: Val, - quotient_chunk_nums: usize, -) -> Script { - script! { - for j in 0..quotient_chunk_nums { - if j != i { - {(quotient_chunk_nums - 1 - j) as u32} - } - } - {i as u32} - // * input: - // * altstack: - // * empty - // * stack: - // * i - // * (quotient_chunk_nums-1-j_i) - // * zps[i] babybear4 - {compute_acc_denominator::(log_n_conf, generator,quotient_chunk_nums)} //babybear - OP_FROMALTSTACK - {u31ext_mul_u31::()} - OP_4TOALTSTACK - } -} - -pub fn zps_mul_denominator_all( - log_n_conf: usize, - generator: Val, - quotient_chunk_nums: usize, -) -> Script { - script! { - for i in 0..quotient_chunk_nums { - {zps_i_mul_denominator::(i, log_n_conf, generator,quotient_chunk_nums)} - } - for _ in 0..quotient_chunk_nums { - OP_4FROMALTSTACK - } - - } -} - -pub fn compute_zps_mul_denominator_script( - quotient_chunk_nums: usize, - degree_bits: usize, - generator: Val, - zps: Vec, - numerators: Vec, -) -> ScriptInfo { - assert_eq!(numerators.len(), quotient_chunk_nums); - let mut si = ScriptInfo::new( - "compute_zps_mul_denominator", - zps_mul_denominator_all::(degree_bits, generator, quotient_chunk_nums), - ); - for i in 0..quotient_chunk_nums { - si.add_input(zps[i]); - si.add_output(numerators[i]); - } - si -} - -// * -// * compute: -// * sum(zps[i] * open_value_i) -// * -// * input: -// * altstack: -// * empty -// * stack: -// * open_value_i[0] babybear4 -// * open_value_i[1] babybear4 -// * open_value_i[2] babybear4 -// * open_value_i[3] babybear4 -// * zps[i] babybear4 - -// * output: -// * altstack: -// * empty -// * stack: -// * quotient_zeta babybear4 -pub fn compute_quotient_zeta( - quotient_chunk_nums: usize, -) -> Script { - script! { - OP_0 OP_0 OP_0 OP_0 //init quotient_zeta to 0 - for _ in 0..quotient_chunk_nums { - OP_4TOALTSTACK - {compute_quotient_i::()} - OP_4FROMALTSTACK - {u31ext_add::()} - } - } -} - -//SC::Challenge::monomial(e_i) * c -//quotient value is EF, but we use EF as F_slice for commit. -pub fn compute_quotient_i() -> Script { - script! { - OP_0 OP_0 OP_0 OP_1 - {u31ext_mul::()} - OP_4TOALTSTACK - OP_0 OP_0 OP_1 OP_0 - {u31ext_mul::()} - OP_4FROMALTSTACK - {u31ext_add::()} - OP_4TOALTSTACK - OP_0 OP_1 OP_0 OP_0 - {u31ext_mul::()} - OP_4FROMALTSTACK - {u31ext_add::()} - OP_4TOALTSTACK - OP_1 OP_0 OP_0 OP_0 - {u31ext_mul::()} - OP_4FROMALTSTACK - {u31ext_add::()} - {u31ext_mul::()} - } -} - -pub fn compute_quotient_zeta_script( - quotient_chunk_nums: usize, - zps: Vec, + //verify by pcs open_values: Vec>, - quotient_zeta: Challenge, -) -> ScriptInfo { - assert_eq!(zps.len(), quotient_chunk_nums); + //hint + denominator_inverse: Vec, +) -> ( + FieldScriptExpression, + Vec>, +) { assert_eq!(open_values.len(), quotient_chunk_nums); - let mut si = ScriptInfo::new( - "compute_quotient_zeta", - compute_quotient_zeta::(quotient_chunk_nums), - ); - let width = open_values[0].len(); - assert_eq!(width, 4); + assert_eq!(denominator_inverse.len(), quotient_chunk_nums); + + let open_values = open_values + .iter() + .map(|inner_v| { + inner_v + .iter() + .map(|v| FieldScriptExpression::from(*v)) + .collect_vec() + }) + .collect_vec(); + let denominator_inverse = denominator_inverse + .iter() + .map(|v| FieldScriptExpression::from(*v)) + .collect_vec(); + + let zeta = FieldScriptExpression::from(zeta); + //babybear generator inverse constant + let inverse_a = FieldScriptExpression::from(Val::from_u32(64944062 as u32)); + let zeta_div_a = inverse_a.mul_ext(zeta); + + let table = FieldScriptExpression::from_table(&get_table(generator, quotient_chunk_nums)); + + let mut numerator = vec![]; for i in 0..quotient_chunk_nums { - for j in 0..width { - si.add_input(open_values[i][j]); + let mut acc_numerator = FieldScriptExpression::from(Challenge::one()); + for j in 0..quotient_chunk_nums { + if j != i { + let w_j = table.clone().lookup( + (quotient_chunk_nums - 1 - j) as u32, + 2 * quotient_chunk_nums - 1, + ); + let zeta_div_a_mul_w = w_j.mul_ext(zeta_div_a.clone()); + let prev_exp_n = zeta_div_a_mul_w.exp_constant(trace_degree as u32); + let prev_exp_n_minus_one = + prev_exp_n.sub_ext(FieldScriptExpression::from(Challenge::one())); + acc_numerator = acc_numerator.mul_ext(prev_exp_n_minus_one); + } } - si.add_input(zps[i]); + numerator.push(acc_numerator); } - si.add_output(quotient_zeta); - si -} -// * input: -// * altstack: -// * zeta/a babybear4 -// * stack: -// * zeta/a babybear4 -// * zps[i] babybear4 - -// * output: -// * altstack: -// * zeta/a babybear4 -// * stack: -// * zps[i+1] or empty - -pub fn verify_quotient_i( - i: usize, - log_n_conf: usize, - generator: Val, - quotient_chunk_nums: usize, -) -> Script { - println!( - "verify_quotient i:{}, log_n_conf:{}, quotient_chunk_nums:{}", - i, log_n_conf, quotient_chunk_nums - ); - script! { - OP_4TOALTSTACK + let mut hint_verify = vec![]; + for i in 0..quotient_chunk_nums { + let mut acc_denominator = FieldScriptExpression::from(Val::one()); for j in 0..quotient_chunk_nums { if j != i { - {(quotient_chunk_nums - 1 - j) as u32} + let w_j = table.clone().lookup( + (i + quotient_chunk_nums - 1 - j) as u32, + 2 * quotient_chunk_nums - 1, + ); + let prev_exp_n = w_j.exp_constant(trace_degree as u32); + let prev_exp_n_minus_one = + prev_exp_n.sub_base(FieldScriptExpression::from(Val::one())); + acc_denominator = acc_denominator.mul_base(prev_exp_n_minus_one); } } - OP_4FROMALTSTACK - {compute_acc_numerator::(log_n_conf, generator,quotient_chunk_nums)} //babybear4 - - {zps_i_mul_denominator::(i, log_n_conf, generator,quotient_chunk_nums)} - - OP_4FROMALTSTACK - OP_4FROMALTSTACK - - {u31ext_equalverify::()} - } -} -// * input: -// * altstack: -// * -// * stack: -// a -//* zeta -//* zps[0] -//* zps[1] -//* ... -//* zps[quotient_chunk_nums-1] -pub fn verify_quotient( - quotient_chunk_nums: usize, - generator: Val, - log_n_conf: usize, -) -> Script { - script! { - {u31ext_mul_u31::()} // stack: zeta/a - OP_4TOALTSTACK - for i in 0..quotient_chunk_nums { - OP_4FROMALTSTACK - OP_4DUP - OP_4TOALTSTACK - {verify_quotient_i::(i, log_n_conf, generator,quotient_chunk_nums)} - } - OP_4FROMALTSTACK - OP_4DROP - // OP_TRUE + //verify hint + hint_verify.push( + (acc_denominator * denominator_inverse[i].clone()).equal_verify_for_f(Val::one()), + ); } -} -pub fn verify_quotient_script( - zeta: Challenge, - quotient_chunk_nums: usize, - degree_bits: usize, - generator: Val, - zps: Vec, -) -> ScriptInfo { - assert_eq!(zps.len(), quotient_chunk_nums); - let mut si = ScriptInfo::new( - "verify_zps", - verify_quotient::(quotient_chunk_nums, generator, degree_bits), - ); - si.add_input(Val::generator().try_inverse().unwrap()) - .add_input(zeta); + let mut quotient_zeta = FieldScriptExpression::from(Challenge::zero()); for i in 0..quotient_chunk_nums { - si.add_input(zps[i]); - } - si -} - -#[cfg(test)] -mod tests { - use bitcoin::opcodes::OP_TRUE; - use bitcoin_script::define_pushable; - use fri::{FriConfig, TwoAdicFriPcs}; - use itertools::{izip, Itertools}; - use p3_commit::{PolynomialSpace, TwoAdicMultiplicativeCoset}; - use p3_dft::{Radix2Dit, Radix2DitParallel, TwoAdicSubgroupDft}; - use p3_field::{AbstractExtensionField, AbstractField, Field, TwoAdicField}; - use p3_matrix::dense::RowMajorMatrix; - use p3_matrix::util::reverse_matrix_index_bits; - use p3_util::log2_strict_usize; - use primitives::bf_pcs::Pcs; - use primitives::challenger::{self, Blake3Permutation}; - use primitives::field::BfField; - use primitives::mmcs::taptree_mmcs::TapTreeMmcs; - use rand::{Rng, SeedableRng}; - use rand_chacha::ChaCha20Rng; - use script_manager::bc_assignment::DefaultBCAssignment; - use scripts::pseudo::{OP_4DROP, OP_4DUP, OP_4FROMALTSTACK, OP_4TOALTSTACK}; - use scripts::u31_lib::{u31ext_equalverify, u31ext_mul, BabyBear4}; - use scripts::{execute_script, execute_script_with_inputs, BabyBear, BinomialExtensionField}; - - use crate::scripts::bf_unistark::{ - compute_acc_numerator, compute_acc_numerator_script, compute_zps_mul_denominator_script, - verify_quotient, verify_quotient_script, - }; - use crate::{prove, StarkConfig}; - - define_pushable!(); - - type Val = BabyBear; - type ValMmcs = TapTreeMmcs; - type Challenge = BinomialExtensionField; - type ChallengeMmcs = TapTreeMmcs; - type Dft = Radix2DitParallel; - type MyPcs = TwoAdicFriPcs; - - fn get_pcs() -> MyPcs { - let val_mmcs = ValMmcs::new(); - let challenge_mmscs = ChallengeMmcs::new(); - let fri_config = FriConfig { - log_blowup: 2, - num_queries: 10, - proof_of_work_bits: 8, - mmcs: challenge_mmscs, - }; - let pcs = MyPcs::new(Dft {}, val_mmcs, fri_config); - pcs - } - - #[test] - fn test_numerator() { - type Challenge = BinomialExtensionField; - type Val = BabyBear; - - let degree = 8; //n - let log_degree = log2_strict_usize(degree); - let quotient_degree = 4; //s - let log_quotient_degree = log2_strict_usize(quotient_degree); - - let mut rng = ChaCha20Rng::seed_from_u64(0u64); - - let zeta = rng.gen::(); - - let a = Val::generator().try_inverse().unwrap(); - - // let trace_domain = pcs.natural_domain_for_degree(degree); - let trace_domain = TwoAdicMultiplicativeCoset { - log_n: log_degree, - shift: Val::one(), - }; - - let quotient_domain = - trace_domain.create_disjoint_domain(1 << (log_degree + log_quotient_degree)); - - let generator = Val::two_adic_generator(quotient_domain.log_n); - - let quotient_chunks_domains = quotient_domain.split_domains(quotient_degree); - - let quotient_chunk_nums = quotient_chunks_domains.len(); - - let numerators = quotient_chunks_domains - .iter() - .enumerate() - .map(|(i, domain)| { - quotient_chunks_domains - .iter() - .enumerate() - .filter(|(j, _)| *j != i) - .map(|(_, other_domain)| other_domain.zp_at_point(zeta)) - .product::() - }) - .collect_vec(); - let mut bc_assigner = DefaultBCAssignment::new(); - let mut exec_script_info = compute_acc_numerator_script::( - zeta, - quotient_chunk_nums, - log_degree, - generator, - numerators, - ); - - exec_script_info.gen(&mut bc_assigner); - - let res = execute_script_with_inputs( - exec_script_info.get_eq_script(), - exec_script_info.witness(), - ); - assert!(res.success); - - let res = execute_script_with_inputs( - exec_script_info.get_neq_script(), - exec_script_info.witness(), - ); - assert!(!res.success); + let zps_i = denominator_inverse[i].mul_ext(numerator[i].clone()); + let mut acc = FieldScriptExpression::from(Challenge::zero()); + for j in 0..4 { + acc = acc + + (open_values[i][j].clone() * FieldScriptExpression::from(Challenge::monomial(j))); + } + quotient_zeta = quotient_zeta + (acc * zps_i); } - #[test] - fn test_zps_mul_denominator() { - let degree = 8; //n - let log_degree = log2_strict_usize(degree); - let quotient_degree = 4; //s - let log_quotient_degree = log2_strict_usize(quotient_degree); - - let mut rng = ChaCha20Rng::seed_from_u64(0u64); - - let zeta = rng.gen::(); - - let a = Val::generator().try_inverse().unwrap(); - - // let trace_domain = pcs.natural_domain_for_degree(degree); - let trace_domain = TwoAdicMultiplicativeCoset { - log_n: log_degree, - shift: Val::one(), - }; - - let quotient_domain = - trace_domain.create_disjoint_domain(1 << (log_degree + log_quotient_degree)); - - let generator = Val::two_adic_generator(quotient_domain.log_n); - - let quotient_chunks_domains = quotient_domain.split_domains(quotient_degree); - - let quotient_chunk_nums = quotient_chunks_domains.len(); - - let zps = quotient_chunks_domains - .iter() - .enumerate() - .map(|(i, domain)| { - quotient_chunks_domains - .iter() - .enumerate() - .filter(|(j, _)| *j != i) - .map(|(_, other_domain)| { - other_domain.zp_at_point(zeta) - * other_domain.zp_at_point(domain.first_point()).inverse() - }) - .product::() - }) - .collect_vec(); - - let numerators = quotient_chunks_domains - .iter() - .enumerate() - .map(|(i, domain)| { - quotient_chunks_domains - .iter() - .enumerate() - .filter(|(j, _)| *j != i) - .map(|(_, other_domain)| other_domain.zp_at_point(zeta)) - .product::() - }) - .collect_vec(); - - let mut bc_assigner = DefaultBCAssignment::new(); - let mut exec_script_info = compute_zps_mul_denominator_script::( - quotient_chunk_nums, - log_degree, - generator, - zps, - numerators, - ); - - exec_script_info.gen(&mut bc_assigner); - - let res = execute_script_with_inputs( - exec_script_info.get_eq_script(), - exec_script_info.witness(), - ); - assert!(res.success); - - let res = execute_script_with_inputs( - exec_script_info.get_neq_script(), - exec_script_info.witness(), - ); - assert!(!res.success); - } + (quotient_zeta, hint_verify) } diff --git a/uni-stark/src/scripts/utils.rs b/uni-stark/src/scripts/utils.rs index 27421ab..657048f 100644 --- a/uni-stark/src/scripts/utils.rs +++ b/uni-stark/src/scripts/utils.rs @@ -90,3 +90,14 @@ pub fn get_generator(generator: F, quotient_chunk_nums: usize) -> Sc } } } + +pub fn get_table(generator: F, quotient_chunk_nums: usize) -> Vec { + let mut table = vec![]; + for i in (0..quotient_chunk_nums).rev() { + table.push(generator.exp_u64(i as u64)); + } + for i in 1..quotient_chunk_nums { + table.push(generator.exp_u64(i as u64).try_inverse().unwrap()); + } + table +} diff --git a/uni-stark/tests/fib_air.rs b/uni-stark/tests/fib_air.rs index 11bee53..b2b6c98 100644 --- a/uni-stark/tests/fib_air.rs +++ b/uni-stark/tests/fib_air.rs @@ -1,9 +1,11 @@ use std::borrow::Borrow; +use std::collections::BTreeMap; +use bitcoin_script_stack::stack::StackTracker; use fri::{FriConfig, TwoAdicFriPcs}; use itertools::Itertools; use p3_air::{Air, AirBuilder, AirBuilderWithPublicValues, BaseAir}; -use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; +use p3_baby_bear::BabyBear; use p3_commit::{ExtensionMmcs, PolynomialSpace, TwoAdicMultiplicativeCoset}; use p3_dft::Radix2DitParallel; use p3_field::extension::BinomialExtensionField; @@ -12,20 +14,20 @@ use p3_field::{ }; use p3_matrix::dense::RowMajorMatrix; use p3_matrix::Matrix; -use p3_merkle_tree::FieldMerkleTreeMmcs; -use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral}; -use p3_symmetric::{PaddingFreeSponge, TruncatedPermutation}; use primitives::bf_pcs::Pcs; use primitives::challenger::chan_field::U32; // use p3_challenger::DuplexChallenger; use primitives::challenger::{BfChallenger, Blake3Permutation}; +use primitives::field::BfField; use primitives::mmcs::taptree_mmcs::TapTreeMmcs; use rand::{thread_rng, Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; +use script_expr::Expression; use script_manager::bc_assignment::DefaultBCAssignment; use scripts::execute_script_with_inputs; +use scripts::u31_lib::{u31ext_equalverify, BabyBear4}; use uni_stark::{ - compute_quotient_zeta_script, get_log_quotient_degree, prove, verify, Proof, StarkConfig, + compute_quotient_expr, get_log_quotient_degree, prove, verify, Proof, StarkConfig, }; /// For testing the public values feature @@ -250,26 +252,69 @@ fn test_quotient_zeta() { .sum::() }) .sum::(); + let denomiator_inverse = quotient_chunks_domains + .iter() + .enumerate() + .map(|(i, domain)| { + quotient_chunks_domains + .iter() + .enumerate() + .filter(|(j, _)| *j != i) + .map(|(_, other_domain)| { + other_domain + .zp_at_point(domain.first_point()) + .inverse() + .into() + }) + .product::() + }) + .collect_vec(); - let mut bc_assigner = DefaultBCAssignment::new(); - let mut exec_script_info = compute_quotient_zeta_script::( + let (q_zeta, _hint_verify) = compute_quotient_expr::( + zeta, + degree, + generator, quotient_chunk_nums, - zps, opened_values.quotient_chunks, - quotient, + denomiator_inverse, ); - exec_script_info.gen(&mut bc_assigner); + let mut stack = StackTracker::new(); + let bmap = BTreeMap::new(); + let script = q_zeta.express_to_script(&mut stack, &bmap); - let res = - execute_script_with_inputs(exec_script_info.get_eq_script(), exec_script_info.witness()); - assert!(res.success); + stack.bignumber(quotient.as_u32_vec()); - let res = execute_script_with_inputs( - exec_script_info.get_neq_script(), - exec_script_info.witness(), + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "u31ext_equalverify", ); - assert!(!res.success); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + + // let mut bc_assigner = DefaultBCAssignment::new(); + // let mut exec_script_info = compute_quotient_zeta_script::( + // quotient_chunk_nums, + // zps, + // opened_values.quotient_chunks, + // quotient, + // ); + + // exec_script_info.gen(&mut bc_assigner); + + // let res = + // execute_script_with_inputs(exec_script_info.get_eq_script(), exec_script_info.witness()); + // assert!(res.success); + + // let res = execute_script_with_inputs( + // exec_script_info.get_neq_script(), + // exec_script_info.witness(), + // ); + // assert!(!res.success); } // #[cfg(debug_assertions)] // #[test] From aaf983c5a345c8b765d234d2e45a00f0b051e737 Mon Sep 17 00:00:00 2001 From: 0xhhh <52317293+cyl19970726@users.noreply.github.com> Date: Mon, 22 Jul 2024 15:27:21 +0800 Subject: [PATCH 15/25] ADD README.md (#27) --- README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..66876aa --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# Bf-Stark + +Bf-Stark is a bitcoin friendly proof-system which can be verified on chain based Bitvm2 Paradigm and Taptree Commitment. +Bf-Stark is also modified based on Plonky3. +Bf-Stark does not need to depend on the implementation of OP_CAT. +### Taptree Commitmtment +- [x] support taptree commmitment +- [x] intergate into fri + - [ ] genereate new taptree for per-query +- [x] intergate into pcs +- [x] intergate into uni-stark + +### ScriptExpr Verifier +- [x] uni-stark script_expr + - [x] compute selector script_expr + - [x] compute quotient script_expr + - [x] compute constraints script_expr +- [ ] two-adic-pcs script_expr +- [ ] fri script_expr +- [ ] challenge script_expr + +### ScriptExpr +- [x] support input variable +- [ ] automatic management of input variables +- [ ] implement copy variable to optimize the compiler +- [ ] Implementing automatic segmentation tool + - [ ] bitcommitment assign + - [ ] extract intermidiate value +- [ ] add verify hint gadget + + From b4ce10cfcbb884d672f0c0648894b10a8ffea61d Mon Sep 17 00:00:00 2001 From: 0xhhh <52317293+cyl19970726@users.noreply.github.com> Date: Tue, 6 Aug 2024 22:49:12 +0800 Subject: [PATCH 16/25] generate-dsl-verifier for unistark && optimize Dsl (#29) * rewrite fri and pcs with script-expr * debug fold_expr * add copy_var and implement to_copy() for mulk * support copy_to_copy * add opcode and update FieldScriptExpr::mul * update fieldscriptexpr::add,mul,sub,neg,euqal,euqalverify * update fieldexpr::lookup indextorou constant expconst * optimize fieldscriptexpr * fmt * update fieldscriptexer::to_copy() * add dsl * add dsl::exprss_with_optimize * add generate-expr-verifer for unistark * update dsl * add ManagerAssign * embeed manager_assign into bf-stark * remove unused code --- fri/Cargo.toml | 3 +- fri/src/config.rs | 17 + fri/src/script_verifier.rs | 168 +-- fri/src/two_adic_pcs.rs | 243 +++- fri/src/verifier.rs | 24 +- fri/tests/fri.rs | 802 +++++++------ fri/tests/pcs.rs | 58 +- primitives/Cargo.toml | 2 +- primitives/src/bf_pcs.rs | 27 +- script_expr/Cargo.toml | 5 +- script_expr/src/alias.rs | 1364 +++++++++++++++++++++ script_expr/src/field_script_expr.rs | 1626 +------------------------- script_expr/src/input_manager.rs | 360 ++++++ script_expr/src/lagrange.rs | 27 +- script_expr/src/lib.rs | 196 +++- script_expr/src/num_script_expr.rs | 828 ------------- script_expr/src/opcode.rs | 446 +++++++ script_expr/src/script_builder.rs | 36 +- script_expr/src/script_gen.rs | 570 +++++++++ script_expr/src/script_helper.rs | 34 +- script_expr/src/variable.rs | 171 ++- scripts/src/lib.rs | 16 + uni-stark/Cargo.toml | 2 +- uni-stark/src/config.rs | 12 +- uni-stark/src/expr_helper.rs | 118 +- uni-stark/src/lib.rs | 2 + uni-stark/src/script_verifier.rs | 277 +++++ uni-stark/src/scripts/bf_unistark.rs | 51 +- uni-stark/src/verifier.rs | 38 +- uni-stark/tests/fib_air.rs | 94 +- 30 files changed, 4366 insertions(+), 3251 deletions(-) create mode 100644 script_expr/src/alias.rs create mode 100644 script_expr/src/input_manager.rs delete mode 100644 script_expr/src/num_script_expr.rs create mode 100644 script_expr/src/opcode.rs create mode 100644 script_expr/src/script_gen.rs create mode 100644 uni-stark/src/script_verifier.rs diff --git a/fri/Cargo.toml b/fri/Cargo.toml index 431ba1f..7fdb803 100644 --- a/fri/Cargo.toml +++ b/fri/Cargo.toml @@ -8,6 +8,7 @@ license = "MIT OR Apache-2.0" bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } +bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git"} p3-commit ={ git = "https://github.com/Plonky3/Plonky3.git" } p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git" } @@ -21,7 +22,7 @@ itertools = "0.12.0" tracing = "0.1.37" tracing-subscriber = { version = "0.3.17", features = ["std", "env-filter"] } serde = { version = "1.0", default-features = false, features = ["derive", "alloc"] } - +script_expr ={ path = "../script_expr" } rand = "0.8.5" diff --git a/fri/src/config.rs b/fri/src/config.rs index 692d673..70467a8 100644 --- a/fri/src/config.rs +++ b/fri/src/config.rs @@ -1,8 +1,11 @@ use alloc::vec::Vec; use core::fmt::Debug; +use std::sync::{Arc, Mutex, MutexGuard}; use p3_field::Field; use p3_matrix::Matrix; +use primitives::field::BfField; +use script_expr::{Dsl, InputManager}; #[derive(Debug)] pub struct FriConfig { @@ -42,3 +45,17 @@ pub trait FriGenericConfig { /// Same as applying fold_row to every row, possibly faster. fn fold_matrix>(&self, beta: F, m: M) -> Vec; } + +pub trait FriGenericConfigWithExpr: FriGenericConfig { + fn fold_row_with_expr( + &self, + folded_eval: Dsl, + sibling_eval: Dsl, + x: Dsl, // x = x^2 ; neg_x = x * val::two_adic_generator(1); // xs[index%2] = x, xs[index%2+1] = neg_x + x_hint: F, + point_index: usize, + index_sibling: usize, + beta: Dsl, + manager: MutexGuard>, + ) -> Dsl; +} diff --git a/fri/src/script_verifier.rs b/fri/src/script_verifier.rs index c61d4a2..e865540 100644 --- a/fri/src/script_verifier.rs +++ b/fri/src/script_verifier.rs @@ -1,55 +1,51 @@ use alloc::vec; use alloc::vec::Vec; use core::panic; +use std::sync::{Arc, Mutex, MutexGuard}; use bitcoin::taproot::TapLeaf; -use bitcoin::Script; use itertools::izip; -use p3_challenger::{CanObserve, CanSample}; +use p3_field::AbstractField; use p3_util::reverse_bits_len; -use primitives::challenger::BfGrindingChallenger; use primitives::field::BfField; use primitives::mmcs::bf_mmcs::BFMmcs; use primitives::mmcs::point::{Point, PointsLeaf}; use primitives::mmcs::taptree_mmcs::CommitProof; -use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; -use script_manager::script_info::ScriptInfo; +use script_expr::{Dsl, InputManager, ManagerAssign}; use scripts::execute_script_with_inputs; -use segment::SegmentLeaf; +use tracing::{instrument, trace}; use crate::error::{FriError, SVError}; -use crate::fri_scripts::leaf::{ - CalNegXLeaf, IndexToROULeaf, ReductionLeaf, RevIndexLeaf, SquareFLeaf, VerifyFoldingLeaf, -}; use crate::verifier::*; -use crate::{BfQueryProof, FriConfig, FriGenericConfig, FriProof}; +use crate::{BfQueryProof, FriConfig, FriGenericConfigWithExpr, FriProof}; pub fn bf_verify_challenges( g: &G, - assign: &mut DefaultBCAssignment, config: &FriConfig, proof: &FriProof, challenges: &FriChallenges, - script_manager: &mut Vec, open_input: impl Fn( usize, &G::InputProof, - &mut Vec, - ) -> Result, G::InputError>, -) -> Result<(), FriError> + MutexGuard>, + ) -> Result)>, G::InputError>, +) -> Result> where F: BfField, M: BFMmcs>, - G: FriGenericConfig, + G: FriGenericConfigWithExpr, { let log_max_height = proof.commit_phase_commits.len() + config.log_blowup; + let mut manager_assign = ManagerAssign::new(); for (&index, query_proof) in izip!(&challenges.query_indices, &proof.query_proofs,) { - let ro = open_input(index, &query_proof.input_proof, script_manager) - .map_err(|e| FriError::InputError(e))?; - + let cur_manager = manager_assign.next_manager(); + let ro = { + let mut manager: std::sync::MutexGuard> = cur_manager.lock().unwrap(); + open_input(index, &query_proof.input_proof, manager) + .map_err(|e| FriError::InputError(e))? + }; let folded_eval = bf_verify_query( g, - assign, config, &proof.commit_phase_commits, index, @@ -57,60 +53,47 @@ where &challenges.betas, ro, log_max_height, + &cur_manager, )?; - if folded_eval != proof.final_poly { - return Err(FriError::FinalPolyMismatch); + { + let mut manager = cur_manager.lock().unwrap(); + manager.set_exec_dsl(folded_eval.equal_for_f(proof.final_poly).into()); } } - Ok(()) + Ok(manager_assign) } fn bf_verify_query( g: &G, - assign: &mut DefaultBCAssignment, config: &FriConfig, commit_phase_commits: &[M::Commitment], mut index: usize, proof: &BfQueryProof, betas: &[F], - reduced_openings: Vec<(usize, F)>, + reduced_openings: Vec<(usize, Dsl)>, log_max_height: usize, -) -> Result> + manager: &Arc>>, +) -> Result, FriError> where F: BfField, M: BFMmcs>, - G: FriGenericConfig, + G: FriGenericConfigWithExpr, { - let mut folded_eval = F::zero(); let mut ro_iter = reduced_openings.into_iter().peekable(); - + let mut folded_eval = Dsl::::zero(); + // todo: replace the rust version of reverse_bits_len as dsl version let rev_index = reverse_bits_len(index, log_max_height); - let rev_index_leaf = RevIndexLeaf::new_from_assign( - log_max_height as u32, - index as u32, - rev_index as u32, - assign, - ); - let exec_success = rev_index_leaf.execute_leaf_script(); - if !exec_success { - return Err(FriError::ScriptVerifierError( - SVError::VerifyReverseIndexScriptError, - )); - } - let generator = F::two_adic_generator(log_max_height); - let mut x = generator.exp_u64(rev_index as u64); - let index_to_rou_leaf = - IndexToROULeaf::<1, F>::new_from_assign(rev_index, log_max_height, x, assign); - assert_eq!(index_to_rou_leaf.generator(), generator); - let exec_success = index_to_rou_leaf.execute_leaf_script(); - if !exec_success { - return Err(FriError::ScriptVerifierError( - SVError::VerifyIndexToROUScriptError, - )); - } + // todo: active dsl::index_to_rou() + // let mut x = Dsl::::index_to_rou(rev_index as u32, log_max_height as u32 ); + + let mut x_hint = F::two_adic_generator(log_max_height).exp_u64(rev_index as u64); + let mut x = manager + .lock() + .unwrap() + .assign_input::(x_hint.as_u32_vec()); for (log_folded_height, commit, step, &beta) in izip!( (0..log_max_height).rev(), @@ -120,51 +103,18 @@ where ) { let point_index = index & 1; let index_sibling = point_index ^ 1; - // let index_sibling = index ^ 1; let index_pair = index >> 1; if let Some((_, ro)) = ro_iter.next_if(|(lh, _)| *lh == log_folded_height + 1) { - let reduction_leaf = - ReductionLeaf::<1, F>::new_from_assign(folded_eval, ro, folded_eval + ro, assign); - let exec_success = reduction_leaf.execute_leaf_script(); - if !exec_success { - return Err(FriError::ScriptVerifierError( - SVError::VerifyReductionScriptError, - )); - } - - println!("ro:{}", ro); folded_eval += ro; } let poins_leaf: PointsLeaf = step.points_leaf.clone(); - let challenge_point: Point = poins_leaf.get_point_by_index(point_index).unwrap().clone(); - - if log_folded_height < log_max_height - 1 { - assert_eq!(folded_eval, challenge_point.y); - } let sibling_point: Point = poins_leaf .get_point_by_index(index_sibling) .unwrap() .clone(); - // assert_eq!(challenge_point.x, x); - let neg_x = x * F::two_adic_generator(1); - let cal_negx_leaf = CalNegXLeaf::<1, F>::new_from_assign(x, neg_x, assign); - let exec_success = cal_negx_leaf.execute_leaf_script(); - if !exec_success { - return Err(FriError::ScriptVerifierError( - SVError::VerifyCalNegXScriptError, - )); - } - // assert_eq!(sibling_point.x, neg_x); - - let mut evals = vec![folded_eval; 2]; - evals[index_sibling % 2] = sibling_point.y; - - let mut xs = vec![x; 2]; - xs[index_sibling % 2] = neg_x; - let input = poins_leaf.witness(); if let TapLeaf::Script(script, _ver) = step.leaf_node.leaf().clone() { assert_eq!(script, poins_leaf.recover_points_euqal_to_commited_point()); @@ -187,34 +137,36 @@ where .verify_taptree(step, commit) .map_err(FriError::CommitPhaseMmcsError)?; - index = index_pair; - folded_eval = g.fold_row(index, log_folded_height, beta, evals.into_iter()); - let folding_leaf = VerifyFoldingLeaf::<1, F>::new_from_assign( - challenge_point.y, - sibling_point.y, - x, - beta, - folded_eval, - assign, + trace!( + "log_folded_height:{}; open_index:{}; open index_sibling:{}; point_index:{} ", + log_folded_height, + index, + index_sibling, + point_index ); - let exec_success = folding_leaf.execute_leaf_script(); - if !exec_success { - return Err(FriError::ScriptVerifierError( - SVError::VerifyFoldingScriptError, - )); - } - x = x.square(); - let square_leaf = SquareFLeaf::<1, F>::new_from_assign(x, x.square(), assign); - let exec_success = square_leaf.execute_leaf_script(); - if !exec_success { - return Err(FriError::ScriptVerifierError( - SVError::VerifySquareFScriptError, - )); + + folded_eval = { + let mut cur_manager: MutexGuard> = manager.lock().unwrap(); + g.fold_row_with_expr( + folded_eval, + cur_manager.assign_input_f::(sibling_point.y), + x.clone(), + x_hint, + point_index, + index_sibling, + cur_manager.assign_input_f::(beta), + cur_manager, + ) + }; + + index = index_pair; + if log_folded_height != 1 { + x = x.square(); + x_hint = x_hint * x_hint; } } debug_assert!(index < config.blowup(), "index was {}", index); - debug_assert_eq!(x.exp_power_of_2(config.log_blowup), F::one()); Ok(folded_eval) } diff --git a/fri/src/two_adic_pcs.rs b/fri/src/two_adic_pcs.rs index aab2571..5c73b31 100644 --- a/fri/src/two_adic_pcs.rs +++ b/fri/src/two_adic_pcs.rs @@ -3,14 +3,17 @@ use alloc::vec; use alloc::vec::Vec; use core::fmt::Debug; use core::marker::PhantomData; +use std::cell::Cell; +use std::sync::{Arc, Mutex, MutexGuard}; +use bitcoin_script_stack::stack::StackTracker; use itertools::{izip, Itertools}; use p3_challenger::{CanObserve, CanSample}; use p3_commit::{OpenedValues, PolynomialSpace, TwoAdicMultiplicativeCoset}; use p3_dft::TwoAdicSubgroupDft; use p3_field::{ - batch_multiplicative_inverse, cyclic_subgroup_coset_known_order, dot_product, ExtensionField, - Field, TwoAdicField, + batch_multiplicative_inverse, cyclic_subgroup_coset_known_order, dot_product, AbstractField, + ExtensionField, Field, TwoAdicField, }; use p3_interpolation::interpolate_coset; use p3_matrix::bitrev::{BitReversableMatrix, BitReversalPerm}; @@ -19,24 +22,27 @@ use p3_matrix::{Dimensions, Matrix}; use p3_maybe_rayon::prelude::*; use p3_util::linear_map::LinearMap; use p3_util::{log2_strict_usize, reverse_bits_len, reverse_slice_index_bits, VecExt}; -use primitives::bf_pcs::Pcs; +use primitives::bf_pcs::{Pcs, PcsExpr}; use primitives::challenger::BfGrindingChallenger; use primitives::field::BfField; use primitives::mmcs::bf_mmcs::BFMmcs; use primitives::mmcs::taptree_mmcs::{CommitProof, TapTreeMmcs}; -use script_manager::script_info::ScriptInfo; -use serde::{Deserialize, Serialize}; -use tracing::{info_span, instrument}; +use script_expr::{Dsl, InputManager, ManagerAssign}; +use tracing::{debug_span, info_span, instrument}; use crate::error::{self, FriError}; use crate::fri_scripts::pcs::{accmulator_script, ro_mul_x_minus_z_script}; -use crate::{prover, verifier, FriConfig, FriGenericConfig, FriProof}; - +use crate::{ + prover, script_verifier, verifier, FriConfig, FriGenericConfig, FriGenericConfigWithExpr, + FriProof, +}; #[derive(Debug)] pub struct TwoAdicFriPcs { dft: Dft, mmcs: InputMmcs, fri: FriConfig, + with_sript: bool, + // expr: Cell, _phantom: PhantomData, } @@ -46,9 +52,14 @@ impl TwoAdicFriPcs { dft, mmcs, fri, + with_sript: false, _phantom: PhantomData, } } + + fn with_script(&self) -> bool { + self.with_sript + } } #[derive(Clone)] @@ -95,7 +106,9 @@ impl FriGenericConfig .shifted_powers(subgroup_start) .take(arity) .collect_vec(); + reverse_slice_index_bits(&mut xs); + assert!(!(xs[1] - xs[0]).is_zero()); assert_eq!(log_arity, 1, "can only interpolate two points for now"); // interpolate and evaluate at beta e0 + (beta - xs[0]) * (e1 - e0) / (xs[1] - xs[0]) @@ -135,6 +148,59 @@ impl FriGenericConfig } } +impl FriGenericConfigWithExpr + for TwoAdicFriGenericConfig +{ + fn fold_row_with_expr( + &self, + folded_eval: Dsl, + sibling_eval: Dsl, + x: Dsl, // x = x^2 ; neg_x = x * val::two_adic_generator(1); // xs[index%2] = x, xs[index%2+1] = neg_x + x_hint: F, + _point_index: usize, + index_sibling: usize, + beta: Dsl, + mut manager: MutexGuard>, + ) -> Dsl { + let arity = 2; + let log_arity = 1; + // If performance critical, make this API stateful to avoid this + // This is a bit more math than is necessary, but leaving it here + // in case we want higher arity in the future + + let rev_x_hint = x_hint * F::two_adic_generator(log_arity); + let mut xs_hint = vec![x_hint; 2]; + xs_hint[index_sibling % 2] = rev_x_hint; + let xs1_minus_xs0_inverse_hint = F::one() / (xs_hint[1] - xs_hint[0]); + + let mut xs_0 = Dsl::default(); + let mut xs_1 = Dsl::default(); + if index_sibling % 2 == 0 { + xs_0 = x.clone() * F::two_adic_generator(log_arity); + xs_1 = x; + } else { + xs_0 = x.clone(); + xs_1 = x * F::two_adic_generator(log_arity); + } + + let mut evals = vec![Dsl::default(), Dsl::default()]; + evals[index_sibling % 2] = sibling_eval; + evals[(index_sibling + 1) % 2] = folded_eval; + assert_eq!(log_arity, 1, "can only interpolate two points for now"); + // interpolate and evaluate at beta + let next_folded = evals[0].clone() + + (beta - xs_0.clone()) + * (evals[1].clone() - evals[0].clone()) + * xs1_minus_xs0_inverse_hint; + + let one = (xs_1 - xs_0) * manager.assign_hint_input_f(xs1_minus_xs0_inverse_hint); + let verify_hint = one.equal_for_f(F::one()); + manager.add_hint_verify(verify_hint.into()); + + next_folded + } +} + impl Pcs for TwoAdicFriPcs where @@ -366,7 +432,6 @@ where )>, proof: &Self::Proof, challenger: &mut Challenger, - script_manager: &mut Vec, ) -> Result<(), Self::Error> { // Batch combination challenge let alpha: Challenge = challenger.sample(); @@ -385,8 +450,7 @@ where &self.fri, proof, &fri_challenges, - script_manager, - |index, input_proof, sm| { + |index, input_proof| { // TODO: separate this out into functions // log_height -> (alpha_pow, reduced_opening) @@ -430,7 +494,6 @@ where for (z, ps_at_z) in mat_points_and_values { let mut acc = Challenge::zero(); - let prev_alpha_pow = *alpha_pow; for (&p_at_x, &p_at_z) in izip!(mat_opening, ps_at_z) { // // Compute the value of ro: @@ -444,23 +507,8 @@ where acc += *alpha_pow * (-p_at_z + p_at_x); *alpha_pow *= alpha; } - let final_alpha_pow = *alpha_pow; - let prev_ro = *ro; - let final_ro = prev_ro + acc / (-*z + x); + let final_ro = *ro + acc / (-*z + x); *ro = final_ro; - - let compute_acc = accmulator_script( - alpha, - prev_alpha_pow, - mat_opening.clone(), - ps_at_z.clone(), - final_alpha_pow, - acc.clone(), - ); - let compute_ro = - ro_mul_x_minus_z_script(prev_ro, final_ro, x.clone(), *z, acc); - sm.push(compute_acc); - sm.push(compute_ro); } } } @@ -479,6 +527,138 @@ where } } +impl + PcsExpr for TwoAdicFriPcs +where + Val: BfField, + Dft: TwoAdicSubgroupDft, + InputMmcs: BFMmcs>, + FriMmcs: BFMmcs>, + Challenge: BfField + ExtensionField, + Challenger: CanObserve + CanSample + BfGrindingChallenger, +{ + fn generate_verify_expr( + &self, + // For each round: + rounds: Vec<( + Self::Commitment, + // for each matrix: + Vec<( + // its domain, + Self::Domain, + // for each point: + Vec<( + // the point, + Challenge, + // values at the point + Vec, + )>, + )>, + )>, + proof: &Self::Proof, + challenger: &mut Challenger, + ) -> Result { + // Batch combination challenge + let alpha: Challenge = challenger.sample(); + + let log_global_max_height = proof.commit_phase_commits.len() + self.fri.log_blowup; + + let g: TwoAdicFriGenericConfigForMmcs = + TwoAdicFriGenericConfig(PhantomData); + + let fri_challenges = + verifier::verify_shape_and_sample_challenges(&g, &self.fri, proof, challenger) + .expect("failed verify shape and sample"); + + let manager_assign = script_verifier::bf_verify_challenges( + &g, + &self.fri, + proof, + &fri_challenges, + |index, input_proof, mut manager| { + // TODO: separate this out into functions + + let mut reduced_openings_expr = + BTreeMap::, Dsl)>::new(); + + for (batch_opening, (batch_commit, mats)) in izip!(input_proof, &rounds) { + let batch_heights = mats + .iter() + .map(|(domain, _)| domain.size() << self.fri.log_blowup) + .collect_vec(); + + let batch_max_height = batch_heights.iter().max().expect("Empty batch?"); + let log_batch_max_height = log2_strict_usize(*batch_max_height); + let bits_reduced = log_global_max_height - log_batch_max_height; + let _reduced_index = index >> bits_reduced; + + self.mmcs.verify_batch( + &batch_opening.opened_values, + &batch_opening.opening_proof, + batch_commit, + )?; + + // mat_opening places vec![p_1(k),p_2(k)] + // mat_points_and_values places vec![ vec![(z_1,p_1(z_1)),(z_2,p_1(z_2))], vec![(z_3,p_2(z_3))]] + for (mat_opening, (mat_domain, mat_points_and_values)) in + izip!(&batch_opening.opened_values, mats) + { + let log_height = log2_strict_usize(mat_domain.size()) + self.fri.log_blowup; + + let bits_reduced = log_global_max_height - log_height; + let rev_reduced_index = reverse_bits_len(index >> bits_reduced, log_height); + + // todo: this should be field script expression + let x: Val = Val::generator() + * Val::two_adic_generator(log_height).exp_u64(rev_reduced_index as u64); // calculate k + + let (alpha_pow_expr, ro_expr) = reduced_openings_expr + .entry(log_height) + .or_insert((Dsl::::one(), Dsl::::zero())); + for (z, ps_at_z) in mat_points_and_values { + let mut acc = Dsl::constant_f(Challenge::zero()); + // let prev_alpha_pow = *alpha_pow_expr; + for (&p_at_x, &p_at_z) in izip!(mat_opening, ps_at_z) { + // + // Compute the value of ro: + // + // Original formula: + // ro = alpha^0 * (p(x)_{0} - p(z)_{0}) / (x - z) + alpha^1 * (p(x)_{1} -p(z)_{1}) / (x - z) + ... + alpha^i * (p(x)_{i} -p(z)_{i}) / (x - z) + // + // Optimized formula: + // ro = (alpha^0 * (p(x)_{0} - p(z)_{0}) + alpha^1 * (p(x)_{1} -p(z)_{1}) + ... + alpha^i * (p(x)_{i} -p(z)_{i})) / (x - z) + // + // acc += alpha_pow_expr.clone() + // * (Dsl::::constant_f(-p_at_z) + // .add_base(Dsl::::constant_f(p_at_x))); + acc += alpha_pow_expr.clone() + * (manager + .assign_input_f::(-p_at_z) + .add_base(manager.assign_input_f::(p_at_x))); + *alpha_pow_expr *= alpha; + } + + let x_minus_z_inv = + manager.assign_input_f::((-*z + x).inverse()); + *ro_expr = ro_expr.clone() + acc * x_minus_z_inv; + } + } + } + + // Return reduced openings descending by log_height. + Ok(reduced_openings_expr + .into_iter() + .rev() + .map(|(log_height, (_alpha_pow, ro))| (log_height, ro)) + .collect()) + }, + ) + .expect("fri err"); + + Ok(manager_assign) + } +} + #[instrument(skip_all)] fn compute_inverse_denominators, M: Matrix>( mats_and_points: &[(Vec, &Vec>)], @@ -523,3 +703,10 @@ fn compute_inverse_denominators, M: Matri }) .collect() } + +#[cfg(test)] +mod tests { + + #[test] + fn test_for_pcs_expr() {} +} diff --git a/fri/src/verifier.rs b/fri/src/verifier.rs index 2379012..ba615d9 100644 --- a/fri/src/verifier.rs +++ b/fri/src/verifier.rs @@ -14,6 +14,7 @@ use primitives::mmcs::point::{Point, PointsLeaf}; use primitives::mmcs::taptree_mmcs::CommitProof; use script_manager::script_info::ScriptInfo; use scripts::execute_script_with_inputs; +use tracing::trace; use crate::error::FriError; use crate::{BfQueryProof, FriConfig, FriGenericConfig, FriProof}; @@ -71,12 +72,7 @@ pub fn verify_challenges( config: &FriConfig, proof: &FriProof, challenges: &FriChallenges, - script_manager: &mut Vec, - open_input: impl Fn( - usize, - &G::InputProof, - &mut Vec, - ) -> Result, G::InputError>, + open_input: impl Fn(usize, &G::InputProof) -> Result, G::InputError>, ) -> Result<(), FriError> where F: BfField, @@ -85,8 +81,8 @@ where { let log_max_height = proof.commit_phase_commits.len() + config.log_blowup; for (&index, query_proof) in izip!(&challenges.query_indices, &proof.query_proofs,) { - let ro = open_input(index, &query_proof.input_proof, script_manager) - .map_err(|e| FriError::InputError(e))?; + let ro = + open_input(index, &query_proof.input_proof).map_err(|e| FriError::InputError(e))?; let folded_eval = verify_query( g, config, @@ -135,20 +131,22 @@ where let index_pair = index >> 1; if let Some((_, ro)) = ro_iter.next_if(|(lh, _)| *lh == log_folded_height + 1) { - println!("ro:{}", ro); + trace!("ro:{}", ro); folded_eval += ro; } - println!( + trace!( "ch point index:{}, sib point index:{}, index_pair:{}", - point_index, index_sibling, index_pair + point_index, + index_sibling, + index_pair ); let open_leaf: PointsLeaf = step.points_leaf.clone(); let challenge_point: Point = open_leaf.get_point_by_index(point_index).unwrap().clone(); let sibling_point: Point = open_leaf.get_point_by_index(index_sibling).unwrap().clone(); - println!("challenge_point.y:{}", challenge_point.y); - println!("sibling_point.y:{}", sibling_point.y); + trace!("challenge_point.y:{}", challenge_point.y); + trace!("sibling_point.y:{}", sibling_point.y); if log_folded_height < log_max_height - 1 { assert_eq!(folded_eval, challenge_point.y); } diff --git a/fri/tests/fri.rs b/fri/tests/fri.rs index 0c24879..64d65f5 100644 --- a/fri/tests/fri.rs +++ b/fri/tests/fri.rs @@ -1,368 +1,463 @@ -use core::cmp::Reverse; -use std::marker::PhantomData; - -use fri::prover::bf_prove; -// use super::*; -use fri::script_verifier::bf_verify_challenges; -use fri::two_adic_pcs::TwoAdicFriGenericConfig; -use fri::{verifier, FriConfig}; -use itertools::Itertools; -use p3_baby_bear::BabyBear; -use p3_challenger::CanSampleBits; -use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; -use p3_field::extension::BinomialExtensionField; -use p3_field::AbstractField; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::util::reverse_matrix_index_bits; -use p3_matrix::Matrix; -use p3_symmetric::{CryptographicPermutation, Permutation}; -use p3_util::log2_strict_usize; -use primitives::challenger::chan_field::U32; -use primitives::challenger::{BfChallenger, Blake3Permutation}; -use primitives::mmcs::taptree_mmcs::TapTreeMmcs; -use rand::SeedableRng; -use rand_chacha::ChaCha20Rng; -use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; -use script_manager::script_info::ScriptInfo; -use tracing_subscriber::fmt; - -type PF = U32; -const WIDTH: usize = 16; -type SpongeState = [PF; WIDTH]; -type F = BabyBear; -#[derive(Clone)] -struct TestPermutation {} - -impl Permutation for TestPermutation { - fn permute(&self, mut input: SpongeState) -> SpongeState { - self.permute_mut(&mut input); - input - } +#[cfg(test)] +mod tests0 { + + use core::cmp::Reverse; + use std::marker::PhantomData; + + use fri::prover::bf_prove; + // use super::*; + use fri::script_verifier::bf_verify_challenges; + use fri::two_adic_pcs::TwoAdicFriGenericConfig; + use fri::{verifier, FriConfig}; + use itertools::Itertools; + use p3_baby_bear::BabyBear; + use p3_challenger::CanSampleBits; + use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; + use p3_field::extension::BinomialExtensionField; + use p3_field::AbstractField; + use p3_matrix::dense::RowMajorMatrix; + use p3_matrix::util::reverse_matrix_index_bits; + use p3_matrix::Matrix; + use p3_symmetric::{CryptographicPermutation, Permutation}; + use p3_util::log2_strict_usize; + use primitives::challenger::chan_field::U32; + use primitives::challenger::{BfChallenger, Blake3Permutation}; + use primitives::field::BfField; + use primitives::mmcs::taptree_mmcs::TapTreeMmcs; + use rand::SeedableRng; + use rand_chacha::ChaCha20Rng; + use script_expr::{InputManager, ManagerAssign}; + use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; + use script_manager::script_info::ScriptInfo; - fn permute_mut(&self, input: &mut SpongeState) { - input.reverse(); + extern crate alloc; + use alloc::collections::BTreeMap; + + use bitcoin_script_stack::stack::StackTracker; + type PF = U32; + const WIDTH: usize = 16; + type SpongeState = [PF; WIDTH]; + type F = BabyBear; + #[derive(Clone)] + struct TestPermutation {} + + impl Permutation for TestPermutation { + fn permute(&self, mut input: SpongeState) -> SpongeState { + self.permute_mut(&mut input); + input + } + + fn permute_mut(&self, input: &mut SpongeState) { + input.reverse(); + } } -} -impl CryptographicPermutation for TestPermutation {} -type Val = BabyBear; -type ValMmcs = TapTreeMmcs; -type MyFriConfig = FriConfig; -#[test] -fn test_compelte_fri_process() { - let mut script_manager: Vec = Vec::new(); - let permutation = TestPermutation {}; - let mut challenger = BfChallenger::::new(permutation).unwrap(); - let mmcs = ValMmcs::new(); - let fri_config = FriConfig { - log_blowup: 1, - num_queries: 10, - proof_of_work_bits: 8, - mmcs, - }; - - let dft = Radix2Dit::default(); - - let shift = Val::generator(); - let mut rng = ChaCha20Rng::seed_from_u64(0); - - let ldes: Vec> = (1..10) - .map(|deg_bits| { - let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); - let mut lde = dft.coset_lde_batch(evals, 1, shift); - reverse_matrix_index_bits(&mut lde); - lde - }) - .collect(); - - let alpha = BabyBear::one(); - let input: [_; 32] = core::array::from_fn(|log_height| { - let matrices_with_log_height: Vec<&RowMajorMatrix> = ldes - .iter() - .filter(|m| log2_strict_usize(m.height()) == log_height) + impl CryptographicPermutation for TestPermutation {} + type Val = BabyBear; + type ValMmcs = TapTreeMmcs; + #[test] + fn test_compelte_fri_process() { + let mut script_manager: Vec = Vec::new(); + let permutation = TestPermutation {}; + let mut challenger = + BfChallenger::::new(permutation).unwrap(); + let mmcs = ValMmcs::new(); + let fri_config = FriConfig { + log_blowup: 1, + num_queries: 10, + proof_of_work_bits: 8, + mmcs, + }; + + let dft = Radix2Dit::default(); + + let shift = Val::generator(); + let mut rng = ChaCha20Rng::seed_from_u64(0); + + let ldes: Vec> = (1..10) + .map(|deg_bits| { + let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); + let mut lde = dft.coset_lde_batch(evals, 1, shift); + reverse_matrix_index_bits(&mut lde); + lde + }) .collect(); - if matrices_with_log_height.is_empty() { - None - } else { - let reduced: Vec = (0..(1 << log_height)) - .map(|r| { - alpha - .powers() - .zip(matrices_with_log_height.iter().flat_map(|m| m.row(r))) - .map(|(alpha_pow, v)| alpha_pow * v) - .sum() - }) + + let alpha = BabyBear::one(); + let input: [_; 32] = core::array::from_fn(|log_height| { + let matrices_with_log_height: Vec<&RowMajorMatrix> = ldes + .iter() + .filter(|m| log2_strict_usize(m.height()) == log_height) .collect(); - Some(reduced) - } - }); - - let input: Vec> = input.into_iter().rev().flatten().collect(); - let log_max_height = log2_strict_usize(input[0].len()); - - let proof = bf_prove( - &TwoAdicFriGenericConfig::, ()>(PhantomData), - &fri_config, - input.clone(), - &mut challenger, - |idx| { - // As our "input opening proof", just pass through the literal reduced openings. - let mut ro = vec![]; - for v in &input { - let log_height = log2_strict_usize(v.len()); - ro.push((log_height, v[idx >> (log_max_height - log_height)])); + if matrices_with_log_height.is_empty() { + None + } else { + let reduced: Vec = (0..(1 << log_height)) + .map(|r| { + alpha + .powers() + .zip(matrices_with_log_height.iter().flat_map(|m| m.row(r))) + .map(|(alpha_pow, v)| alpha_pow * v) + .sum() + }) + .collect(); + Some(reduced) } - ro.sort_by_key(|(lh, _)| Reverse(*lh)); - ro - }, - ); - let p_sample = challenger.sample_bits(8); - - let v_permutation = TestPermutation {}; - let mut v_challenger = - BfChallenger::::new(v_permutation).unwrap(); - let fri_challenges = verifier::verify_shape_and_sample_challenges( - &TwoAdicFriGenericConfig::, ()>(PhantomData), - &fri_config, - &proof, - &mut v_challenger, - ) - .expect("failed verify shape and sample"); - - verifier::verify_challenges( - &TwoAdicFriGenericConfig::, ()>(PhantomData), - &fri_config, - &proof, - &fri_challenges, - &mut script_manager, - |_index, proof, sm| Ok(proof.clone()), - ) - .expect("failed verify challenges"); - - assert_eq!( - p_sample, - v_challenger.sample_bits(8), - "prover and verifier transcript have same state after FRI" - ); -} + }); -#[test] -fn test_script_verifier() { - let mut script_manager: Vec = Vec::new(); - let permutation = TestPermutation {}; - let mut challenger = BfChallenger::::new(permutation).unwrap(); - let mmcs = ValMmcs::new(); - let fri_config = FriConfig { - log_blowup: 1, - num_queries: 10, - proof_of_work_bits: 8, - mmcs, - }; - - let mut assign = DefaultBCAssignment::new(); - - let dft = Radix2Dit::default(); - - let shift = Val::generator(); - let mut rng = ChaCha20Rng::seed_from_u64(0); - - let ldes: Vec> = (4..5) - .map(|deg_bits| { - let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); - let mut lde = dft.coset_lde_batch(evals, 1, shift); - reverse_matrix_index_bits(&mut lde); - lde - }) - .collect(); - - let alpha = BabyBear::one(); - let input: [_; 32] = core::array::from_fn(|log_height| { - let matrices_with_log_height: Vec<&RowMajorMatrix> = ldes + let input: Vec> = input.into_iter().rev().flatten().collect(); + let log_max_height = log2_strict_usize(input[0].len()); + + let proof = bf_prove( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + input.clone(), + &mut challenger, + |idx| { + // As our "input opening proof", just pass through the literal reduced openings. + let mut ro = vec![]; + for v in &input { + let log_height = log2_strict_usize(v.len()); + ro.push((log_height, v[idx >> (log_max_height - log_height)])); + } + ro.sort_by_key(|(lh, _)| Reverse(*lh)); + ro + }, + ); + let p_sample = challenger.sample_bits(8); + + let v_permutation = TestPermutation {}; + let mut v_challenger = + BfChallenger::::new(v_permutation).unwrap(); + let fri_challenges = verifier::verify_shape_and_sample_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + &proof, + &mut v_challenger, + ) + .expect("failed verify shape and sample"); + + verifier::verify_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + &proof, + &fri_challenges, + |_index, proof| Ok(proof.clone()), + ) + .expect("failed verify challenges"); + + assert_eq!( + p_sample, + v_challenger.sample_bits(8), + "prover and verifier transcript have same state after FRI" + ); + } + + #[test] + fn test_script_verifier() { + let mut script_manager: Vec = Vec::new(); + let permutation = TestPermutation {}; + let mut challenger = + BfChallenger::::new(permutation).unwrap(); + let mmcs = ValMmcs::new(); + let fri_config = FriConfig { + log_blowup: 1, + num_queries: 10, + proof_of_work_bits: 8, + mmcs, + }; + + let mut assign = DefaultBCAssignment::new(); + + let dft = Radix2Dit::default(); + + let shift = Val::generator(); + let mut rng = ChaCha20Rng::seed_from_u64(0); + + let ldes: Vec> = vec![2] .iter() - .filter(|m| log2_strict_usize(m.height()) == log_height) + .map(|deg_bits| { + let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); + let mut lde = dft.coset_lde_batch(evals, 1, shift); + reverse_matrix_index_bits(&mut lde); + lde + }) .collect(); - if matrices_with_log_height.is_empty() { - None - } else { - let reduced: Vec = (0..(1 << log_height)) - .map(|r| { - alpha - .powers() - .zip(matrices_with_log_height.iter().flat_map(|m| m.row(r))) - .map(|(alpha_pow, v)| alpha_pow * v) - .sum() - }) + + let alpha = BabyBear::one(); + let input: [_; 32] = core::array::from_fn(|log_height| { + let matrices_with_log_height: Vec<&RowMajorMatrix> = ldes + .iter() + .filter(|m| log2_strict_usize(m.height()) == log_height) .collect(); - Some(reduced) - } - }); - - let input: Vec> = input.into_iter().rev().flatten().collect(); - let log_max_height = log2_strict_usize(input[0].len()); - - let proof = bf_prove( - &TwoAdicFriGenericConfig::, ()>(PhantomData), - &fri_config, - input.clone(), - &mut challenger, - |idx| { - // As our "input opening proof", just pass through the literal reduced openings. - let mut ro = vec![]; - for v in &input { - let log_height = log2_strict_usize(v.len()); - ro.push((log_height, v[idx >> (log_max_height - log_height)])); + if matrices_with_log_height.is_empty() { + None + } else { + let reduced: Vec = (0..(1 << log_height)) + .map(|r| { + alpha + .powers() + .zip(matrices_with_log_height.iter().flat_map(|m| m.row(r))) + .map(|(alpha_pow, v)| alpha_pow * v) + .sum() + }) + .collect(); + Some(reduced) } - ro.sort_by_key(|(lh, _)| Reverse(*lh)); - ro - }, - ); - - let p_sample = challenger.sample_bits(8); - - let v_permutation = TestPermutation {}; - let mut v_challenger = - BfChallenger::::new(v_permutation).unwrap(); - let fri_challenges = verifier::verify_shape_and_sample_challenges( - &TwoAdicFriGenericConfig::, ()>(PhantomData), - &fri_config, - &proof, - &mut v_challenger, - ) - .expect("failed verify shape and sample"); - - verifier::verify_challenges( - &TwoAdicFriGenericConfig::, ()>(PhantomData), - &fri_config, - &proof, - &fri_challenges, - &mut script_manager, - |_index, proof, sm| Ok(proof.clone()), - ) - .expect("failed verify challenges"); - - bf_verify_challenges( - &TwoAdicFriGenericConfig::, ()>(PhantomData), - &mut assign, - &fri_config, - &proof, - &fri_challenges, - &mut script_manager, - |_index, proof, sm| Ok(proof.clone()), - ) - .expect("failed verify challenges"); - assert_eq!( - p_sample, - v_challenger.sample_bits(8), - "prover and verifier transcript have same state after FRI" - ); -} + }); + + let input: Vec> = input.into_iter().rev().flatten().collect(); + let log_max_height = log2_strict_usize(input[0].len()); + + let proof = bf_prove( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + input.clone(), + &mut challenger, + |idx| { + // As our "input opening proof", just pass through the literal reduced openings. + let mut ro = vec![]; + for v in &input { + let log_height = log2_strict_usize(v.len()); + ro.push((log_height, v[idx >> (log_max_height - log_height)])); + } + ro.sort_by_key(|(lh, _)| Reverse(*lh)); + ro + }, + ); + + let p_sample = challenger.sample_bits(8); + + let v_permutation = TestPermutation {}; + let mut v_challenger = + BfChallenger::::new(v_permutation).unwrap(); + let fri_challenges = verifier::verify_shape_and_sample_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + &proof, + &mut v_challenger, + ) + .expect("failed verify shape and sample"); + + verifier::verify_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + &proof, + &fri_challenges, + |_index, proof| Ok(proof.clone()), + ) + .expect("failed verify challenges"); + + let manager_assign = bf_verify_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + &proof, + &fri_challenges, + |_index, proof, mut manager| { + Ok(proof + .iter() + // .map(|(lh, v)| (*lh, Dsl::constant_f(v.clone()))) + .map(|(lh, v)| { + let v_dsl = manager.assign_input_f::(v.clone()); + (*lh, v_dsl) + }) + .collect()) + }, + ) + .expect("failed verify challenges"); -#[test] -fn test_bf_prove_with_blake3_permutation() { - // tracing_subscriber::registry().with(fmt::layer()).init(); // open some log information - - let mut script_manager: Vec = Vec::new(); - let permutation = Blake3Permutation {}; - let mut challenger: BfChallenger = - BfChallenger::::new(permutation).unwrap(); - let mmcs = ValMmcs::new(); - let fri_config = FriConfig { - log_blowup: 1, - num_queries: 10, - proof_of_work_bits: 8, - mmcs, - }; - - let dft = Radix2Dit::default(); - - let shift = Val::generator(); - let mut rng = ChaCha20Rng::seed_from_u64(0); - - let ldes: Vec> = (5..6) - .map(|deg_bits| { - let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); - let mut lde = dft.coset_lde_batch(evals, 1, shift); - reverse_matrix_index_bits(&mut lde); - lde - }) - .collect(); - - let alpha = BabyBear::one(); - let input: [_; 32] = core::array::from_fn(|log_height| { - let matrices_with_log_height: Vec<&RowMajorMatrix> = ldes + manager_assign + .managers() .iter() - .filter(|m| log2_strict_usize(m.height()) == log_height) + .enumerate() + .for_each(|(manager_index, manager)| { + manager.lock().unwrap().embed_hint_verify::(); + manager.lock().unwrap().run(false); + println!( + "||optimize script_len {}-kb ||", + manager.lock().unwrap().get_script_len() / 1024 + ); + }); + assert_eq!( + p_sample, + v_challenger.sample_bits(8), + "prover and verifier transcript have same state after FRI" + ); + } +} + +#[cfg(test)] +mod tests1 { + + use core::cmp::Reverse; + use std::marker::PhantomData; + + use fri::prover::bf_prove; + // use super::*; + use fri::script_verifier::bf_verify_challenges; + use fri::two_adic_pcs::TwoAdicFriGenericConfig; + use fri::{verifier, FriConfig}; + use itertools::Itertools; + use p3_baby_bear::BabyBear; + use p3_challenger::CanSampleBits; + use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; + use p3_field::extension::BinomialExtensionField; + use p3_field::AbstractField; + use p3_matrix::dense::RowMajorMatrix; + use p3_matrix::util::reverse_matrix_index_bits; + use p3_matrix::Matrix; + use p3_symmetric::{CryptographicPermutation, Permutation}; + use p3_util::log2_strict_usize; + use primitives::challenger::chan_field::U32; + use primitives::challenger::{BfChallenger, Blake3Permutation}; + use primitives::field::BfField; + use primitives::mmcs::taptree_mmcs::TapTreeMmcs; + use rand::SeedableRng; + use rand_chacha::ChaCha20Rng; + use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; + use script_manager::script_info::ScriptInfo; + + extern crate alloc; + use alloc::collections::BTreeMap; + + use bitcoin_script_stack::stack::StackTracker; + type PF = U32; + const WIDTH: usize = 16; + type SpongeState = [PF; WIDTH]; + type F = BabyBear; + // impl CryptographicPermutation for TestPermutation {} + type Val = BabyBear; + type ValMmcs = TapTreeMmcs; + + #[test] + fn test_bf_prove_with_blake3_permutation() { + let permutation = Blake3Permutation {}; + let mut challenger: BfChallenger = + BfChallenger::::new(permutation).unwrap(); + let mmcs = ValMmcs::new(); + let fri_config = FriConfig { + log_blowup: 1, + num_queries: 10, + proof_of_work_bits: 8, + mmcs, + }; + + let dft = Radix2Dit::default(); + + let shift = Val::generator(); + let mut rng = ChaCha20Rng::seed_from_u64(0); + + let ldes: Vec> = (5..6) + .map(|deg_bits| { + let evals = RowMajorMatrix::::rand_nonzero(&mut rng, 1 << deg_bits, 1); + let mut lde = dft.coset_lde_batch(evals, 1, shift); + reverse_matrix_index_bits(&mut lde); + lde + }) .collect(); - if matrices_with_log_height.is_empty() { - None - } else { - let reduced: Vec = (0..(1 << log_height)) - .map(|r| { - alpha - .powers() - .zip(matrices_with_log_height.iter().flat_map(|m| m.row(r))) - .map(|(alpha_pow, v)| alpha_pow * v) - .sum() - }) + + let alpha = BabyBear::one(); + let input: [_; 32] = core::array::from_fn(|log_height| { + let matrices_with_log_height: Vec<&RowMajorMatrix> = ldes + .iter() + .filter(|m| log2_strict_usize(m.height()) == log_height) .collect(); - Some(reduced) - } - }); - - let input: Vec> = input.into_iter().rev().flatten().collect(); - let log_max_height = log2_strict_usize(input[0].len()); - - let proof = bf_prove( - &TwoAdicFriGenericConfig::, ()>(PhantomData), - &fri_config, - input.clone(), - &mut challenger, - |idx| { - // As our "input opening proof", just pass through the literal reduced openings. - let mut ro = vec![]; - for v in &input { - let log_height = log2_strict_usize(v.len()); - ro.push((log_height, v[idx >> (log_max_height - log_height)])); + if matrices_with_log_height.is_empty() { + None + } else { + let reduced: Vec = (0..(1 << log_height)) + .map(|r| { + alpha + .powers() + .zip(matrices_with_log_height.iter().flat_map(|m| m.row(r))) + .map(|(alpha_pow, v)| alpha_pow * v) + .sum() + }) + .collect(); + Some(reduced) } - ro.sort_by_key(|(lh, _)| Reverse(*lh)); - ro - }, - ); - - let permutation = Blake3Permutation {}; - let mut v_challenger: BfChallenger = - BfChallenger::::new(permutation).unwrap(); - let fri_challenges = verifier::verify_shape_and_sample_challenges( - &TwoAdicFriGenericConfig::, ()>(PhantomData), - &fri_config, - &proof, - &mut v_challenger, - ) - .expect("failed verify shape and sample"); - - verifier::verify_challenges( - &TwoAdicFriGenericConfig::, ()>(PhantomData), - &fri_config, - &proof, - &fri_challenges, - &mut script_manager, - |_index, proof, sm| Ok(proof.clone()), - ) - .expect("failed verify challenges"); + }); + + let input: Vec> = input.into_iter().rev().flatten().collect(); + let log_max_height = log2_strict_usize(input[0].len()); + + let proof = bf_prove( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + input.clone(), + &mut challenger, + |idx| { + // As our "input opening proof", just pass through the literal reduced openings. + let mut ro = vec![]; + for v in &input { + let log_height = log2_strict_usize(v.len()); + ro.push((log_height, v[idx >> (log_max_height - log_height)])); + } + ro.sort_by_key(|(lh, _)| Reverse(*lh)); + ro + }, + ); + + let permutation = Blake3Permutation {}; + let mut v_challenger: BfChallenger = + BfChallenger::::new(permutation).unwrap(); + let fri_challenges = verifier::verify_shape_and_sample_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + &proof, + &mut v_challenger, + ) + .expect("failed verify shape and sample"); + + let manager_assign = bf_verify_challenges( + &TwoAdicFriGenericConfig::, ()>(PhantomData), + &fri_config, + &proof, + &fri_challenges, + |_index, proof, mut manager| { + Ok(proof + .iter() + .map(|(lh, v)| { + let v_dsl = manager.assign_input_f::(v.clone()); + (*lh, v_dsl) + }) + .collect()) + }, + ) + .expect("failed verify challenges"); + + manager_assign + .managers() + .iter() + .enumerate() + .for_each(|(manager_index, manager)| { + manager.lock().unwrap().embed_hint_verify::(); + manager.lock().unwrap().run(false); + println!( + "||optimize script_len {}-kb ||", + manager.lock().unwrap().get_script_len() / 1024 + ); + }); + } } #[cfg(test)] mod tests2 { + use core::cmp::Reverse; use std::marker::PhantomData; + use fri::prover::bf_prove; + use fri::script_verifier::bf_verify_challenges; use fri::two_adic_pcs::TwoAdicFriGenericConfig; + use fri::{verifier, FriConfig}; use itertools::Itertools; use p3_baby_bear::BabyBear; use p3_challenger::CanSampleBits; use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; use p3_field::extension::BinomialExtensionField; use p3_field::AbstractField; + use p3_matrix::dense::RowMajorMatrix; use p3_matrix::util::reverse_matrix_index_bits; use p3_matrix::Matrix; use p3_symmetric::{CryptographicPermutation, Permutation}; @@ -372,12 +467,13 @@ mod tests2 { use primitives::mmcs::taptree_mmcs::{TapTreeMmcs, ROOT_WIDTH}; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; + use script_expr::Dsl; use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; use script_manager::script_info::ScriptInfo; use tracing_subscriber::fmt; use super::*; - use crate::{bf_verify_challenges, verifier}; + // use crate::{bf_verify_challenges, verifier}; type PF = U32; const WIDTH: usize = 16; @@ -490,8 +586,7 @@ mod tests2 { &fri_config, &proof, &fri_challenges, - &mut script_manager, - |_index, proof, sm| Ok(proof.clone()), + |_index, proof| Ok(proof.clone()), ) .expect("failed verify challenges"); @@ -593,21 +688,40 @@ mod tests2 { &fri_config, &proof, &fri_challenges, - &mut script_manager, - |_index, proof, sm| Ok(proof.clone()), + |_index, proof| Ok(proof.clone()), ) .expect("failed verify challenges"); - bf_verify_challenges( + let manager_assign = bf_verify_challenges( &TwoAdicFriGenericConfig::, ()>(PhantomData), - &mut assign, &fri_config, &proof, &fri_challenges, - &mut script_manager, - |_index, proof, sm| Ok(proof.clone()), + |_index, proof, mut manager| { + Ok(proof + .iter() + // .map(|(lh, v)| (*lh, Dsl::constant_f(v.clone()))) + .map(|(lh, v)| { + let v_dsl = manager.assign_input_f::(v.clone()); + (*lh, v_dsl) + }) + .collect()) + }, ) .expect("failed verify challenges"); + + manager_assign + .managers() + .iter() + .enumerate() + .for_each(|(manager_index, manager)| { + manager.lock().unwrap().embed_hint_verify::(); + manager.lock().unwrap().run(false); + println!( + "||optimize script_len {}-kb ||", + manager.lock().unwrap().get_script_len() / 1024 + ); + }); assert_eq!( p_sample, v_challenger.sample_bits(8), diff --git a/fri/tests/pcs.rs b/fri/tests/pcs.rs index 99e5a8d..e455c0c 100644 --- a/fri/tests/pcs.rs +++ b/fri/tests/pcs.rs @@ -7,7 +7,7 @@ use p3_dft::Radix2DitParallel; use p3_field::extension::BinomialExtensionField; use p3_field::{ExtensionField, Field}; use p3_matrix::dense::RowMajorMatrix; -use primitives::bf_pcs::Pcs; +use primitives::bf_pcs::{Pcs, PcsExpr}; use primitives::challenger::chan_field::U32; use primitives::challenger::{BfChallenger, Blake3Permutation}; use primitives::field::BfField; @@ -15,8 +15,9 @@ use primitives::mmcs::taptree_mmcs::TapTreeMmcs; use rand::distributions::{Distribution, Standard}; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; -use script_manager::bc_assignment::DefaultBCAssignment; -use scripts::execute_script_with_inputs; +use script_expr::{Dsl, Expression, ManagerAssign}; + +extern crate alloc; fn seeded_rng() -> impl Rng { ChaCha20Rng::seed_from_u64(0) @@ -26,9 +27,9 @@ fn do_test_fri_pcs( (pcs, challenger): &(P, Challenger), log_degrees_by_round: &[&[usize]], ) where - P: Pcs, + P: PcsExpr, P::Domain: PolynomialSpace, - Val: Field, + Val: Field + BfField, Standard: Distribution, Challenge: BfField + ExtensionField, Challenger: Clone + CanObserve + CanSample, @@ -96,23 +97,22 @@ fn do_test_fri_pcs( .collect_vec(); assert_eq!(commits_and_claims_by_round.len(), num_rounds); - let mut script_manager = vec![]; - pcs.verify( - commits_and_claims_by_round, - &proof, - &mut v_challenger, - &mut script_manager, - ) - .unwrap(); - - let mut bc_assigner = DefaultBCAssignment::new(); - // execute script verifier - for item in script_manager.iter_mut() { - item.gen(&mut bc_assigner); - let res = execute_script_with_inputs(item.get_eq_script(), item.witness()); - // println!("res: {:?}", res); - assert!(res.success); - } + let manager_assign = + pcs.generate_verify_expr(commits_and_claims_by_round, &proof, &mut v_challenger); + + manager_assign + .unwrap() + .managers() + .iter() + .enumerate() + .for_each(|(manager_index, manager)| { + manager.lock().unwrap().embed_hint_verify::(); + manager.lock().unwrap().run(false); + println!( + "||optimize script_len {}-kb ||", + manager.lock().unwrap().get_script_len() / 1024 + ); + }); } // Set it up so we create tests inside a module for each pcs, so we get nice error reports @@ -141,15 +141,6 @@ macro_rules! make_tests_for_pcs { } } - // #[test] - // fn many_different() { - // let p = $p; - // for i in 2..4 { - // let degrees = (3..3 + i).collect::>(); - // $crate::do_test_fri_pcs(&p, &[°rees]); - // } - // } - #[test] fn many_different_rev() { let p = $p; @@ -194,13 +185,13 @@ mod babybear_fri_pcs { let challenge_mmscs = ChallengeMmcs::new(); let fri_config = FriConfig { log_blowup, - num_queries: 10, + num_queries: 1, proof_of_work_bits: 8, mmcs: challenge_mmscs, }; let permutation = Blake3Permutation {}; - let mut challenger = Challenger::new(permutation).unwrap(); + let challenger = Challenger::new(permutation).unwrap(); let pcs = MyPcs::new(Dft {}, val_mmcs, fri_config); (pcs, challenger) } @@ -208,6 +199,7 @@ mod babybear_fri_pcs { mod blowup_1 { make_tests_for_pcs!(super::get_pcs(1)); } + mod blowup_2 { make_tests_for_pcs!(super::get_pcs(2)); } diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 7fae2ec..09cd3a5 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -34,4 +34,4 @@ script_manager = {path = "../script_manager"} [dev-dependencies] p3-interpolation = { git = "https://github.com/Plonky3/Plonky3.git" } p3-dft = { git = "https://github.com/Plonky3/Plonky3.git" } -p3-maybe-rayon ={ git = "https://github.com/Plonky3/Plonky3.git" } +p3-maybe-rayon ={ git = "https://github.com/Plonky3/Plonky3.git" } \ No newline at end of file diff --git a/primitives/src/bf_pcs.rs b/primitives/src/bf_pcs.rs index 27c6152..6b23d92 100644 --- a/primitives/src/bf_pcs.rs +++ b/primitives/src/bf_pcs.rs @@ -83,10 +83,35 @@ where )>, proof: &Self::Proof, challenger: &mut Challenger, - script_managers: &mut Vec, ) -> Result<(), Self::Error>; } +pub trait PcsExpr: Pcs +where + Challenge: ExtensionField>, +{ + fn generate_verify_expr( + &self, + // For each round: + rounds: Vec<( + Self::Commitment, + // for each matrix: + Vec<( + // its domain, + Self::Domain, + // for each point: + Vec<( + // the point, + Challenge, + // values at the point + Vec, + )>, + )>, + )>, + proof: &Self::Proof, + challenger: &mut Challenger, + ) -> Result; +} pub type OpenedValues = Vec>; pub type OpenedValuesForRound = Vec>; pub type OpenedValuesForMatrix = Vec>; diff --git a/script_expr/Cargo.toml b/script_expr/Cargo.toml index 4d130f0..a73b4af 100644 --- a/script_expr/Cargo.toml +++ b/script_expr/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git"} +bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git", branch = "bf-stark"} bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } @@ -19,6 +19,9 @@ p3-util = { git = "https://github.com/Plonky3/Plonky3.git" } primitives = { path = "../primitives" } scripts = {path = "../scripts"} common ={ path = "../common" } +lazy_static = "1.4" +tracing = "0.1.37" +tracing-subscriber = { version = "0.3.17", features = ["std", "env-filter"] } [dev-dependencies] p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } \ No newline at end of file diff --git a/script_expr/src/alias.rs b/script_expr/src/alias.rs new file mode 100644 index 0000000..c595562 --- /dev/null +++ b/script_expr/src/alias.rs @@ -0,0 +1,1364 @@ +use std::collections::BTreeMap; +use std::iter::{Product, Sum}; +use std::marker::PhantomData; +use std::ops::{Add, AddAssign, Deref, DerefMut, Mul, MulAssign, Neg, Sub, SubAssign}; +// #[macro_use] +// extern crate lazy_static; +use std::sync::Mutex; +use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; +use std::usize; + +use bitcoin_script_stack::stack::{StackTracker, StackVariable}; +use common::{AbstractField, BabyBear}; +use lazy_static::lazy_static; +use primitives::field::BfField; + +use crate::{ + CustomOpcode, Expression, IdCount, InputManager, ManagerAssign, ScriptExprError, + StandardOpcode, StandardOpcodeId, Variable, DYNAMIC_INPUT_OR_OUTPUT, +}; +lazy_static! { + static ref OPID: Mutex = Mutex::new(0); +} + +pub(crate) fn get_opid() -> u32 { + let mut id = OPID.lock().unwrap(); + *id += 1; + *id +} + +pub type ExprPtr = Arc>>; +pub type ExprRead<'a> = RwLockReadGuard<'a, Box>; +pub type ExprWrite<'a> = RwLockWriteGuard<'a, Box>; + +#[derive(Debug)] +pub struct Dsl(ExprPtr, PhantomData); +impl Deref for Dsl { + type Target = ExprPtr; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Dsl { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl Clone for Dsl { + fn clone(&self) -> Self { + Self(self.0.clone(), PhantomData::) + } +} + +impl Dsl { + pub(crate) fn get_var_size(&self) -> u32 { + self.read().unwrap().var_size() + } + + pub(crate) fn get_id(&self) -> u32 { + self.read().unwrap().get_id() + } + + pub(crate) fn new(expr: ExprPtr) -> Dsl { + Dsl(expr, PhantomData::) + } + + pub(crate) fn new_equal(lhs: Self, rhs: Self) -> Dsl { + Self( + Arc::new(RwLock::new(Box::new(StandardOpcode::<2, 1>::new( + get_opid(), + vec![lhs.into(), rhs.into()], + 1, // the var size must be 1 for equal op_code + StandardOpcodeId::Equal, + )))), + PhantomData::, + ) + } + + pub(crate) fn new_expconst(lhs: Self, power: u32) -> Dsl { + let var_size = lhs.read().unwrap().var_size(); + Self( + Arc::new(RwLock::new(Box::new(CustomOpcode::<1, 1, F>::new( + get_opid(), + vec![vec![power]], + vec![lhs.into()], + var_size, // the var size must be 1 for equal op_code + StandardOpcodeId::ExpConst, + )))), + PhantomData::, + ) + } + + pub fn index_to_rou(index: u32, sub_group_bits: u32) -> Self { + assert_eq!(F::U32_SIZE, 1); + Self( + Arc::new(RwLock::new(Box::new(CustomOpcode::<1, 1, F>::new( + get_opid(), + vec![vec![sub_group_bits]], + vec![Self::constant_u32(index).into()], + F::U32_SIZE as u32, // the var size must be 1 for equal op_code + StandardOpcodeId::IndexToRou, + )))), + PhantomData::, + ) + } + + pub fn index_to_rou_ext(index: u32, sub_group_bits: u32) -> Self { + assert_eq!(Base::U32_SIZE, 1); + assert_eq!(F::U32_SIZE, 4); + Self( + Arc::new(RwLock::new(Box::new(CustomOpcode::<1, 1, F>::new( + get_opid(), + vec![vec![sub_group_bits]], + vec![Dsl::::constant_u32(index).into()], + F::U32_SIZE as u32, // the var size must be 1 for equal op_code + StandardOpcodeId::IndexToRou, + )))), + PhantomData::, + ) + } + + pub(crate) fn new_equal_verify(lhs: Self, rhs: Self) -> Dsl { + Self( + Arc::new(RwLock::new(Box::new(StandardOpcode::<2, 0>::new( + get_opid(), + vec![lhs.into(), rhs.into()], + 0, + StandardOpcodeId::EqualVerify, + )))), + PhantomData::, + ) + } + + pub fn square(self) -> Self { + let var_size = self.read().unwrap().var_size(); + Self( + Arc::new(RwLock::new(Box::new(StandardOpcode::<1, 1>::new( + get_opid(), + vec![self.into()], + var_size, + StandardOpcodeId::Square, + )))), + PhantomData, + ) + } + + pub fn double(self) -> Self { + let var_size = self.read().unwrap().var_size(); + Self( + Arc::new(RwLock::new(Box::new(StandardOpcode::<1, 1>::new( + get_opid(), + vec![self.into()], + var_size, + StandardOpcodeId::Double, + )))), + PhantomData, + ) + } + + pub fn exp_constant(self, power: u32) -> Self { + Self::new_expconst(self, power) + } + + pub fn num_to_field(self) -> Self { + Self( + Arc::new(RwLock::new(Box::new(StandardOpcode::<1, 1>::new( + get_opid(), + vec![self.into()], + F::U32_SIZE as u32, + StandardOpcodeId::NumToField, + )))), + PhantomData::, + ) + } + + pub fn lookup(self, index: u32, len: usize) -> Self { + let index = Self::constant_u32(index); + Self( + Arc::new(RwLock::new(Box::new(CustomOpcode::<2, 1, F>::new( + get_opid(), + vec![vec![len as u32]], + vec![self.into(), index.into()], + F::U32_SIZE as u32, + StandardOpcodeId::Lookup, + )))), + PhantomData::, + ) + } + + pub fn from_table(table: &[F]) -> Self { + let vs = table.iter().map(|f| f.as_u32_vec()).collect::>(); + Self( + Arc::new(RwLock::new(Box::new(CustomOpcode::< + 0, + DYNAMIC_INPUT_OR_OUTPUT, + F, + >::new( + get_opid(), + vs, + vec![], + F::U32_SIZE as u32, + StandardOpcodeId::Table, + )))), + PhantomData::, + ) + } + + pub fn add_ext(self, rhs: Dsl) -> Dsl { + assert_eq!(F::U32_SIZE, 1); + assert_eq!(EF::U32_SIZE, 4); + Dsl::( + Arc::new(RwLock::new(Box::new(StandardOpcode::<2, 1>::new( + get_opid(), + vec![self.into(), rhs.into()], + EF::U32_SIZE as u32, + StandardOpcodeId::Add, + )))), + PhantomData, + ) + } + + pub fn add_base(self, rhs: Dsl) -> Self { + assert_eq!(F::U32_SIZE, 4); + assert_eq!(Base::U32_SIZE, 1); + Self( + Arc::new(RwLock::new(Box::new(StandardOpcode::<2, 1>::new( + get_opid(), + vec![self.into(), rhs.into()], + F::U32_SIZE as u32, + StandardOpcodeId::Add, + )))), + PhantomData, + ) + } + + pub fn mul_ext(self, rhs: Dsl) -> Dsl { + assert_eq!(F::U32_SIZE, 1); + assert_eq!(EF::U32_SIZE, 4); + Dsl::( + Arc::new(RwLock::new(Box::new(StandardOpcode::<2, 1>::new( + get_opid(), + vec![self.into(), rhs.into()], + EF::U32_SIZE as u32, + StandardOpcodeId::Mul, + )))), + PhantomData, + ) + } + + pub fn mul_base(self, rhs: Dsl) -> Self { + assert_eq!(F::U32_SIZE, 4); + assert_eq!(Base::U32_SIZE, 1); + Self( + Arc::new(RwLock::new(Box::new(StandardOpcode::<2, 1>::new( + get_opid(), + vec![self.into(), rhs.into()], + F::U32_SIZE as u32, + StandardOpcodeId::Mul, + )))), + PhantomData, + ) + } + + pub fn sub_ext(self, rhs: Dsl) -> Dsl { + assert_eq!(F::U32_SIZE, 1); + assert_eq!(EF::U32_SIZE, 4); + Dsl::( + Arc::new(RwLock::new(Box::new(StandardOpcode::<2, 1>::new( + get_opid(), + vec![self.into(), rhs.into()], + EF::U32_SIZE as u32, + StandardOpcodeId::Sub, + )))), + PhantomData, + ) + } + + pub fn sub_base(self, rhs: Dsl) -> Self { + assert_eq!(F::U32_SIZE, 4); + assert_eq!(Base::U32_SIZE, 1); + Self( + Arc::new(RwLock::new(Box::new(StandardOpcode::<2, 1>::new( + get_opid(), + vec![self.into(), rhs.into()], + F::U32_SIZE as u32, + StandardOpcodeId::Sub, + )))), + PhantomData, + ) + } + + pub fn equal(self, other: Self) -> Self { + Self::new_equal(self, other) + } + + pub fn equal_for_f(self, other: F) -> Self { + Self::new_equal(self, Self::constant(other.as_u32_vec())) + } + + pub fn equal_verify(self, other: Self) -> Self { + Self::new_equal_verify(self, other) + } + + pub fn equal_verify_for_f(self, other: F) -> Self { + Self::new_equal_verify(self, Self::constant(other.as_u32_vec())) + } + + pub fn constant(values: Vec) -> Self { + Self( + Arc::new(RwLock::new(Box::new(CustomOpcode::<0, 1, F>::new( + get_opid(), + vec![values.clone()], + vec![], + values.len() as u32, + StandardOpcodeId::Constant, + )))), + PhantomData::, + ) + } + + pub fn constant_f(value: F) -> Self { + Self::constant(value.as_u32_vec()) + } + + pub fn constant_u32(value: u32) -> Self { + Self::constant(vec![value]) + } +} + +impl Dsl { + pub fn read(&self) -> Result { + self.0.read().map_err(|_| ScriptExprError::ReadLockError) + } + + pub fn write(&self) -> Result { + self.0.write().map_err(|_| ScriptExprError::WriteLockError) + } + + pub fn opcode(&self) -> StandardOpcodeId { + self.read().unwrap().opcode() + } + + pub fn debug(self) -> Self { + self.read().unwrap().set_debug(); + self + } + + pub fn set_debug(&self) { + self.read().unwrap().set_debug(); + } + + pub fn simulate_express(&self, id_mapper: &mut BTreeMap) { + self.read().unwrap().simulate_express(id_mapper) + } + + pub fn express_to_script( + &self, + stack: &mut StackTracker, + bmap: &BTreeMap, + id_mapper: &mut BTreeMap, + optimize: bool, + ) -> Vec { + self.read() + .unwrap() + .express_to_script(stack, bmap, id_mapper, optimize) + } + + pub fn express( + &self, + stack: &mut StackTracker, + var_getter: &BTreeMap, + ) -> (Vec, BTreeMap) { + let mut id_mapper = BTreeMap::new(); + self.read().unwrap().simulate_express(&mut id_mapper); + ( + self.express_to_script(stack, &var_getter, &mut id_mapper, true), + id_mapper, + ) + } + + pub fn express1( + &self, + stack: &mut StackTracker, + var_getter: &BTreeMap, + optimize: bool, + ) -> (Vec, BTreeMap) { + let mut id_mapper = BTreeMap::new(); + self.read().unwrap().simulate_express(&mut id_mapper); + ( + self.express_to_script(stack, &var_getter, &mut id_mapper, optimize), + id_mapper, + ) + } + + pub fn express_with_optimize( + &self, + ) -> ( + StackTracker, + BTreeMap, + BTreeMap, + ) { + let mut stack = StackTracker::new(); + let var_getter = BTreeMap::new(); + let mut id_mapper = BTreeMap::new(); + self.read().unwrap().simulate_express(&mut id_mapper); + self.express_to_script(&mut stack, &var_getter, &mut id_mapper, true); + (stack, var_getter, id_mapper) + } + + pub fn express_without_optimize( + &self, + ) -> ( + StackTracker, + BTreeMap, + BTreeMap, + ) { + let mut stack = StackTracker::new(); + let var_getter = BTreeMap::new(); + let mut id_mapper = BTreeMap::new(); + self.read().unwrap().simulate_express(&mut id_mapper); + self.express_to_script(&mut stack, &var_getter, &mut id_mapper, false); + (stack, var_getter, id_mapper) + } +} + +impl From for Dsl { + fn from(expr: F) -> Self { + Self::constant_f(expr) + } +} + +impl From> for ExprPtr { + fn from(expr: Dsl) -> Self { + expr.0 + } +} + +impl Default for Dsl { + fn default() -> Self { + Self::constant_f(F::zero()) + } +} + +impl AbstractField for Dsl { + type F = F; + + fn zero() -> Self { + Self::constant_f(F::zero()) + } + fn one() -> Self { + Self::constant_f(F::one()) + } + fn two() -> Self { + Self::constant_f(F::two()) + } + fn neg_one() -> Self { + Self::constant_f(F::neg_one()) + } + + #[inline] + fn from_f(f: Self::F) -> Self { + Self::constant_f(f) + } + + fn from_bool(b: bool) -> Self { + Self::constant_f(F::from_bool(b)) + } + + fn from_canonical_u8(n: u8) -> Self { + Self::constant_f(F::from_canonical_u8(n)) + } + + fn from_canonical_u16(n: u16) -> Self { + Self::constant_f(F::from_canonical_u16(n)) + } + + fn from_canonical_u32(n: u32) -> Self { + Self::constant_f(F::from_canonical_u32(n)) + } + + fn from_canonical_u64(n: u64) -> Self { + Self::constant_f(F::from_canonical_u64(n)) + } + + fn from_canonical_usize(n: usize) -> Self { + Self::constant_f(F::from_canonical_usize(n)) + } + + fn from_wrapped_u32(n: u32) -> Self { + Self::constant_f(F::from_wrapped_u32(n)) + } + + fn from_wrapped_u64(n: u64) -> Self { + Self::constant_f(F::from_wrapped_u64(n)) + } + + fn generator() -> Self { + Self::constant_f(F::generator()) + } +} + +impl Add for Dsl { + type Output = Dsl; + fn add(self, other: Dsl) -> Self::Output { + let var_size = self + .read() + .unwrap() + .var_size() + .max(other.read().unwrap().var_size()); + + Self( + Arc::new(RwLock::new(Box::new(StandardOpcode::<2, 1>::new( + get_opid(), + vec![self.into(), other.into()], + var_size, + StandardOpcodeId::Add, + )))), + PhantomData::, + ) + } +} + +impl Add<&Self> for Dsl { + type Output = Dsl; + fn add(self, other: &Dsl) -> Self::Output { + let var_size = self + .read() + .unwrap() + .var_size() + .max(other.read().unwrap().var_size()); + + Self( + Arc::new(RwLock::new(Box::new(StandardOpcode::<2, 1>::new( + get_opid(), + vec![self.into(), other.clone().into()], + var_size, + StandardOpcodeId::Add, + )))), + PhantomData::, + ) + } +} + +impl Add for Dsl { + type Output = Dsl; + fn add(self, other: F) -> Self::Output { + self + Self::constant_f(other) + } +} + +impl AddAssign for Dsl { + fn add_assign(&mut self, rhs: Self) { + let c: Dsl = self.clone(); + *self = c + rhs; + } +} + +impl AddAssign for Dsl { + fn add_assign(&mut self, rhs: F) { + *self += Self::constant_f(rhs); + } +} + +impl Sum for Dsl { + fn sum>(iter: I) -> Self { + iter.reduce(|x, y| x + y).unwrap_or(Self::zero()) + } +} + +impl Sub for Dsl { + type Output = Dsl; + fn sub(self, other: Dsl) -> Self::Output { + let var_size = self + .read() + .unwrap() + .var_size() + .max(other.read().unwrap().var_size()); + + Self( + Arc::new(RwLock::new(Box::new(StandardOpcode::<2, 1>::new( + get_opid(), + vec![self.into(), other.into()], + var_size, + StandardOpcodeId::Sub, + )))), + PhantomData::, + ) + } +} + +impl Sub for Dsl { + type Output = Dsl; + fn sub(self, other: F) -> Self::Output { + self - Self::constant(other.as_u32_vec()) + } +} + +impl SubAssign for Dsl { + fn sub_assign(&mut self, rhs: Self) { + let c: Dsl = self.clone(); + *self = c - rhs; + } +} + +impl SubAssign for Dsl { + fn sub_assign(&mut self, rhs: ExprPtr) { + *self -= Self::new(rhs); + } +} + +impl Mul for Dsl { + type Output = Dsl; + fn mul(self, other: Dsl) -> Self::Output { + let var_size = self + .read() + .unwrap() + .var_size() + .max(other.read().unwrap().var_size()); + + Self( + Arc::new(RwLock::new(Box::new(StandardOpcode::<2, 1>::new( + get_opid(), + vec![self.into(), other.into()], + var_size, + StandardOpcodeId::Mul, + )))), + PhantomData::, + ) + } +} + +impl Mul for Dsl { + type Output = Dsl; + fn mul(self, other: F) -> Self::Output { + self * Self::constant(other.as_u32_vec()) + } +} + +impl MulAssign for Dsl { + fn mul_assign(&mut self, rhs: Self) { + let c: Dsl = self.clone(); + *self = c * rhs; + } +} + +impl MulAssign for Dsl { + fn mul_assign(&mut self, rhs: F) { + *self *= Self::constant(rhs.as_u32_vec()); + } +} + +impl Neg for Dsl { + type Output = Dsl; + fn neg(self) -> Self::Output { + let var_size = self.read().unwrap().var_size(); + + Self( + Arc::new(RwLock::new(Box::new(StandardOpcode::<1, 1>::new( + get_opid(), + vec![self.into()], + var_size, + StandardOpcodeId::Neg, + )))), + PhantomData, + ) + } +} + +impl Product for Dsl { + fn product>(iter: I) -> Self { + iter.reduce(|x, y| x * y).unwrap_or(Self::one()) + } +} + +impl Product for Dsl { + fn product>(iter: I) -> Self { + iter.map(|x| Self::new(x)).product() + } +} + +#[cfg(test)] +mod tests { + use alloc::boxed::Box; + use alloc::collections::BTreeMap; + use alloc::sync::Arc; + use alloc::vec::Vec; + use core::cell::{self, Cell}; + + use bitcoin_script_stack::stack::{self, StackTracker, StackVariable}; + use common::{AbstractField, BabyBear, BinomialExtensionField}; + use p3_air::AirBuilder; + use p3_field::TwoAdicField; + use p3_matrix::Matrix; + use primitives::field::BfField; + use scripts::treepp::*; + use scripts::u31_lib::{u31_equalverify, u31ext_equalverify, BabyBear4}; + + use super::{Dsl, Expression, Variable, *}; + use crate::InputManager; + type F = BabyBear; + type EF = BinomialExtensionField; + + #[test] + fn test_expr_double() { + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a_value = BabyBear::two(); + let b_value = a_value.clone() + a_value; + + let a = Dsl::constant_f(a_value); + let b = a.double(); + let equal = b.equal_verify_for_f(b_value); + equal.express(&mut stack, &bmap); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a_value = EF::two(); + let b_value = a_value.clone() + a_value; + let a = Dsl::constant_f(a_value); + let b = a.double(); + let equal = b.equal_verify_for_f(b_value); + equal.express(&mut stack, &bmap); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + } + + #[test] + fn test_expr_square() { + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a_value = BabyBear::two(); + let b_value = a_value.exp_u64(2); + + let a = Dsl::constant_f(a_value); + let b = a.square(); + let equal = b.equal_verify_for_f(b_value); + equal.express(&mut stack, &bmap); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a_value = EF::two(); + let b_value = a_value.exp_u64(2); + let a = Dsl::constant_f(a_value); + let b = a.square(); + let equal = b.equal_verify_for_f(b_value); + equal.express(&mut stack, &bmap); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + } + + #[test] + fn test_expr_expconst() { + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a_value = BabyBear::two(); + let b_value = a_value.exp_u64(2); + let a = Dsl::constant_f(a_value); + let b = a.exp_constant(2); + let equal = b.equal_verify_for_f(b_value); + equal.express(&mut stack, &bmap); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a_value = EF::two(); + let b_value = a_value.exp_u64(2); + let a = Dsl::constant_f(a_value); + let b = a.exp_constant(2); + let equal = b.equal_verify_for_f(b_value); + equal.express(&mut stack, &bmap); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + } + + #[test] + fn test_index_to_rou() { + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let sub_group_bits = 10u32; + let generator = BabyBear::two_adic_generator(sub_group_bits as usize); + let index = 7u32; + let res = generator.exp_u64(index as u64); + + let b = Dsl::::index_to_rou(index, sub_group_bits); + // b.set_debug(); + let res_expr = Dsl::constant_f(res); + let equal = b.equal_verify(res_expr); + equal.express(&mut stack, &bmap); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let sub_group_bits = 10u32; + let generator = EF::two_adic_generator(sub_group_bits as usize); + let index = 7u32; + let res = generator.exp_u64(index as u64); + + let b = Dsl::::index_to_rou_ext::(index, sub_group_bits); + let res_dsl = Dsl::constant_f(res); + assert_eq!(b.get_var_size(), res_dsl.get_var_size()); + // assert_eq!(b.get) + let equal = b.equal_verify(res_dsl); + equal.express(&mut stack, &bmap); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + } + + #[test] + fn test_num_to_field() { + let num = 182712u32; + + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = Dsl::constant_u32(num); + let b = a.num_to_field(); + let res = BabyBear::from_canonical_u32(num); + let equal = b.equal_verify_for_f(res); + equal.express(&mut stack, &bmap); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + } + + #[test] + fn test_script_expression_add() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = Dsl::constant_f(BabyBear::one()); + let b = Dsl::constant_f(BabyBear::two()); + let c = a + b; + c.set_debug(); + + let d = Dsl::constant_f(BabyBear::two()); + let e = Dsl::constant_f(BabyBear::two()); + let f = d + e; + + let g = c + f; // 4 + 3 = 7 + let script = g.express(&mut stack, &bmap); + stack.number(BabyBear::from_canonical_u32(7u32).as_u32_vec()[0]); + stack.op_equal(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_u31add_u31ext() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = Dsl::constant_f(BabyBear::one()); + let b = Dsl::constant_f(EF::two()); + let c = a.add_ext(b); + + let d = Dsl::constant_f(BabyBear::two()); + let e = Dsl::constant_f(EF::two()); + let f = e.add_base(d); + + let g = c + f; // 4 + 3 = 7 + let h = g.equal_verify_for_f(EF::from_canonical_u32(7u32)); + let script = h.express(&mut stack, &bmap); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_u31sub_u31ext() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = Dsl::constant_f(BabyBear::one()); + let b = Dsl::constant_f(EF::two()); + let c = a.sub_ext(b); + + let d = Dsl::constant_f(BabyBear::two()); + let e = Dsl::constant_f(EF::from_canonical_u32(4)); + let f = e.sub_base(d); + let g = c + f; // 4 + 3 = 7 + let script = g.express(&mut stack, &bmap); + stack.bignumber(EF::from_canonical_u32(1u32).as_u32_vec()); + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "u31ext_equalverify", + ); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_u31mul_u31ext() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = Dsl::constant_f(BabyBear::one()); + let b = Dsl::constant_f(EF::two()); + b.set_debug(); + // let c = a.mul_ext(b); + let c = b.mul_base(a); + c.set_debug(); + let d = Dsl::constant_f(BabyBear::two()); + let e = Dsl::constant_f(EF::from_canonical_u32(4)); + let f = e.mul_base(d); + f.set_debug(); + let g = c * f; + let equal = g.equal_for_f(EF::from_canonical_u32(16)); + equal.express(&mut stack, &bmap); + let res = stack.run(); + println!("{:?}", res.error); + println!("{:?}", res.error_msg); + assert!(res.success); + } + + #[test] + fn test_ext_constant() { + let mut stack = StackTracker::new(); + let bmap = BTreeMap::new(); + let a = Dsl::constant_f(EF::one()); + a.express(&mut stack, &bmap); + let res = EF::one(); + + stack.bignumber(res.as_u32_vec()); + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "u31ext_equalverify", + ); + + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expr_with_input() { + let mut input_manager = InputManager::new(); + let var1_wrap = + input_manager.assign_input::(BabyBear::from_canonical_u32(1u32).as_u32_vec()); + let var2_wrap = + input_manager.assign_input::(BabyBear::from_canonical_u32(2u32).as_u32_vec()); + let var3_wrap = + input_manager.assign_input::(BabyBear::from_canonical_u32(3u32).as_u32_vec()); + let var4_wrap = + input_manager.assign_input::(BabyBear::from_canonical_u32(4u32).as_u32_vec()); + let (mut stack, input_getter) = input_manager.simulate_input(); + + let res1 = var1_wrap + var2_wrap; + let res2 = var3_wrap + var4_wrap; + + let res = res1 + res2; + res.express(&mut stack, &input_getter); + + stack.number(BabyBear::from_canonical_u32(10u32).as_u32_vec()[0]); + stack.op_equalverify(); + + stack.debug(); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + + { + let mut input_manager = InputManager::new(); + let var1_wrap = input_manager.assign_input(EF::from_canonical_u32(1u32).as_u32_vec()); + let var2_wrap = input_manager.assign_input(EF::from_canonical_u32(2u32).as_u32_vec()); + let var3_wrap = input_manager.assign_input(EF::from_canonical_u32(3u32).as_u32_vec()); + let var4_wrap = input_manager.assign_input(EF::from_canonical_u32(4u32).as_u32_vec()); + let (mut stack, input_getter) = input_manager.simulate_input(); + + let res1 = var1_wrap + var2_wrap; + let res2 = var3_wrap + var4_wrap; + + let res = res1 + res2; + let equal = res.equal_for_f(EF::from_canonical_u32(10)); + equal.debug().express(&mut stack, &input_getter); + let res = stack.run(); + assert!(res.success); + } + } + + #[test] + fn test_script_expression_extadd() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = Dsl::constant_f(EF::one()); + let b = Dsl::constant_f(EF::two()); + let c = a + b; + + let script = c.express(&mut stack, &bmap); + stack.debug(); + let res = EF::one() + EF::two(); + + stack.bignumber(res.as_u32_vec()); + stack.debug(); + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "u31ext_equalverify", + ); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_sub() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = Dsl::constant_f(BabyBear::one()); + let b = Dsl::constant_f(BabyBear::two()); + let c = b - a; // 1 + + let d = Dsl::constant_f(BabyBear::two()); + let e = Dsl::constant_f(BabyBear::from_canonical_u32(8)); + let f = e - d; // 6 + + let g = f - c; // 5 + let script = g.express(&mut stack, &bmap); + stack.number(BabyBear::from_canonical_u32(5u32).as_u32_vec()[0]); + stack.op_equal(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_extsub() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = Dsl::constant_f(EF::one()); + let b = Dsl::constant_f(EF::two()); + let c = b - a; // 1 + + let d = Dsl::constant_f(EF::two()); + let e = Dsl::constant_f(EF::from_canonical_u32(8)); + let f = e - d; // 6 + let g = f - c; // 5 + let script = g.express(&mut stack, &bmap); + stack.bignumber(EF::from_canonical_u32(5u32).as_u32_vec()); + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "u31ext_equalverify", + ); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_mul() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = Dsl::constant_f(BabyBear::one()); + let b = Dsl::constant_f(BabyBear::two()); + let c = b * a; // 2 + + let d = Dsl::constant_f(BabyBear::two()); + let e = Dsl::constant_f(BabyBear::from_canonical_u32(8)); + let f = e * d * BabyBear::one(); // 16 + stack.show_stack(); + let g = f * c; // 32 + let script = g.express(&mut stack, &bmap); + stack.number(BabyBear::from_canonical_u32(32u32).as_u32_vec()[0]); + stack.op_equal(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_extmul() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = Dsl::constant_f(EF::one()); + let b = Dsl::constant_f(EF::two()); + let c = b * a; // 2 + + let d = Dsl::constant_f(EF::two()); + let e = Dsl::constant_f(EF::from_canonical_u32(8)); + let f = e * d; // 16 + let g = f * c; // 32 + g.express(&mut stack, &bmap); + + stack.show_stack(); + + stack.bignumber(EF::from_canonical_u32(32u32).as_u32_vec()); + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "u31ext_equalverify", + ); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_neg() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = Dsl::constant_f(BabyBear::one()); + let b = -a * BabyBear::two(); + let script = b.express(&mut stack, &bmap); + stack.number(BabyBear::from_canonical_u32(BabyBear::MOD - 2).as_u32_vec()[0]); + stack.op_equal(); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_script_expression_extneg() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = Dsl::constant_f(EF::one()); + let b = -a * EF::two(); + let equal = b.equal_for_f(EF::from_canonical_u32(EF::MOD - 2)); + let script = equal.express(&mut stack, &bmap); + // let res = stack.run(); + // assert!(res.success); + } + #[test] + fn test_ext_equal() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = Dsl::constant_f(EF::two()); + let exp = a.equal_for_f(EF::two()); + let script = exp.express(&mut stack, &bmap); + let res = stack.run(); + assert!(res.success); + + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = Dsl::constant_f(BabyBear::two()); + let exp = a.equal_for_f(BabyBear::two()); + let script = exp.express(&mut stack, &bmap); + let res = stack.run(); + assert!(res.success); + } + + #[test] + fn test_lookup() { + let vec = vec![ + BabyBear::from_canonical_u32(1 as u32), + BabyBear::from_canonical_u32(2 as u32), + BabyBear::from_canonical_u32(3 as u32), + BabyBear::from_canonical_u32(4 as u32), + BabyBear::from_canonical_u32(5 as u32), + ]; + let mut stack = StackTracker::new(); + let bmap = BTreeMap::new(); + + let table = Dsl::from_table(&vec); + + let index = 4; + + let m = table.lookup(index, vec.len()); + + let script = m.express(&mut stack, &bmap); + + stack.number(5 as u32); + + stack.custom(u31_equalverify(), 2, false, 0, "u31_equalverify"); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } +} + +#[cfg(test)] +mod tests2 { + use alloc::boxed::Box; + use alloc::collections::BTreeMap; + use alloc::sync::Arc; + use alloc::vec::Vec; + use core::cell::{self, Cell}; + use std::borrow::Borrow; + + use bitcoin_script_stack::stack::{self, StackTracker, StackVariable}; + use common::{AbstractField, BabyBear, BinomialExtensionField}; + use p3_air::AirBuilder; + use p3_field::TwoAdicField; + use p3_matrix::Matrix; + use primitives::field::BfField; + use scripts::treepp::*; + use scripts::u31_lib::{u31ext_equalverify, BabyBear4}; + + use super::{Dsl, Expression, Variable, *}; + use crate::opcode::Opcode; + type EF = BinomialExtensionField; + + #[test] + fn test_mul_express_optimize() { + let a_value = BabyBear::two(); + let b_value = BabyBear::one(); + let c_value = BabyBear::from_canonical_u32(13232); + let d_value = a_value + b_value; + let e_value = d_value * c_value; + + let f_value = e_value * d_value; + let g_value = f_value * e_value; + let h_value = g_value * e_value; + + let a = Dsl::constant_f(a_value); + let b = Dsl::constant_f(b_value); + + let c = Dsl::constant_f(c_value); + let d = a + b; + let e = d.clone() * c; + let f = e.clone() * d; + let g = e.clone() * f; + let h = g * e.clone(); + + let equal = h.equal_for_f(h_value); + { + let res = equal.express_without_optimize(); + println!("no optimize script len {:?}", res.0.get_script().len()); + let res = res.0.run(); + assert!(res.success); + } + { + let res = equal.express_with_optimize(); + println!("optimize script len {:?}", res.0.get_script().len()); + let res = res.0.run(); + assert!(res.success); + } + } + + /** + * a b + * c d + * e + */ + + #[test] + fn test_add_express_optimize() { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let a = Dsl::constant_f(BabyBear::one()); + // let b = Dsl::constant_f(BabyBear::one()); + let b = a.clone(); + // let c = b.clone(); + + let c = a + b; + let d = c.clone(); + // let res = res1 + c; + let e = c + d; + let e_copy = e.clone(); + + let e1 = e_copy.clone(); + + let e_clone = e.clone(); + + let g = e1 + e.clone() + e_clone + e.clone(); + + let equal_check = g.equal_for_f(BabyBear::from_canonical_u32(16)); + let vars = equal_check.express(&mut stack, &bmap); + stack.debug(); + let success = stack.run().success; + assert!(success); + } + + #[test] + fn test_dsl_clone() { + // let bmap = BTreeMap::new(); + // let mut stack = StackTracker::new(); + let a = Dsl::constant_f(BabyBear::one()); + let b = a.clone() + a.clone(); + let c = b.clone() + b.clone(); + let equal_check = c.equal_for_f(BabyBear::from_canonical_u32(4)); + let res = equal_check.express_with_optimize(); + let success = res.0.run().success; + println!("optimize script len: {:?}", res.0.get_script().len()); + assert!(success); + + let res = equal_check.express_without_optimize(); + let success = res.0.run().success; + println!("script len: {:?}", res.0.get_script().len()); + assert!(success); + } + + #[test] + fn test_index_to_rou_bug() { + // todo: the test below happens bug, to fix + // { + // let bmap = BTreeMap::new(); + // let mut stack = StackTracker::new(); + // let sub_group_bits = 10u32; + // let generator = BabyBear::two_adic_generator(sub_group_bits as usize); + // let index = 7u32; + // let res = generator.exp_u64(index as u64); + + // let b = Dsl::::index_to_rou(index, sub_group_bits); + // b.set_debug(); + // let b_2 = b.clone() * b; + // // let b_2 = b.square(); + // let res_expr = Dsl::constant_f(res * res); + // let equal = b_2.equal_verify(res_expr); + // equal.express1(&mut stack, &bmap,false); + // stack.op_true(); + // let res = stack.run(); + // assert!(res.success); + // println!("script_len: {:?}", stack.get_script_len()); + // } + + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let sub_group_bits = 10u32; + let generator = BabyBear::two_adic_generator(sub_group_bits as usize); + let index = 7u32; + let res = generator.exp_u64(index as u64); + + let b = Dsl::::index_to_rou(index, sub_group_bits); + let b_2 = b.clone() * b; + let res_expr = Dsl::constant_f(res * res); + let equal = b_2.equal_verify(res_expr); + equal.express(&mut stack, &bmap); + stack.op_true(); + + let res = stack.run(); + assert!(res.success); + println!("script_len: {:?}", stack.get_script_len()); + } + } +} diff --git a/script_expr/src/field_script_expr.rs b/script_expr/src/field_script_expr.rs index 50e5437..e3fedb9 100644 --- a/script_expr/src/field_script_expr.rs +++ b/script_expr/src/field_script_expr.rs @@ -7,8 +7,11 @@ use core::cell::Cell; use core::fmt::Debug; use core::iter::{Product, Sum}; use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use std::cell::RefCell; use std::ops::Div; +use std::sync::{Mutex, RwLock}; +use bitcoin::consensus::serde::hex::Case; use bitcoin_script_stack::stack::{StackTracker, StackVariable}; use common::AbstractField; use p3_util::log2_strict_usize; @@ -20,239 +23,50 @@ use scripts::u31_lib::{ u32_to_u31, BabyBear4, BabyBearU31, }; -use super::num_script_expr::NumScriptExpression; use super::variable::{ValueVariable, Variable}; use super::Expression; +use crate::opcode::Opcode; +use crate::script_gen::StandardOpcodeId; use crate::script_helper::{index_to_rou, value_exp_n}; -use crate::Fraction; +use crate::{ + op_mul, CopyVar, CustomOpcode, CustomOpcodeId, Dsl, ExprPtr, IdCount, InputOpcode, ScriptExprError, StandardOpcode, StandardOpcodeId +}; pub enum FieldScriptExpression { - ValueVariable { - v: ValueVariable, - debug: Cell, - var: StackVariable, - }, - InputVariable { - sv: Variable, - debug: Cell, - var: StackVariable, - }, - Constant { - f: F, - debug: Cell, - var: StackVariable, - }, Table { table: Vec, debug: Cell, var: StackVariable, }, - Add { - x: Arc>, - y: Arc>, - var: StackVariable, - debug: Cell, - }, - Sub { - x: Arc>, - y: Arc>, - var: StackVariable, - debug: Cell, - }, - Neg { - x: Arc>, - var: StackVariable, - debug: Cell, - }, - Mul { - x: Arc>, - y: Arc>, - var: StackVariable, - debug: Cell, - }, - EqualVerify { - x: Arc>, - y: Arc>, - debug: Cell, - }, - ExpConstant { - x: Arc>, - y: u32, - var: StackVariable, - debug: Cell, - }, - IndexToROU { - // calculate generator^index - index: Arc>, // u32 -> NumberScriptExpression - sub_group_bits: u32, - var: StackVariable, - debug: Cell, - }, - NumToField { - x: Arc>, - var: StackVariable, - debug: Cell, - }, - Lookup { - x: Arc>, - y: Arc>, - len: usize, - var: StackVariable, - debug: Cell, - }, } -impl FieldScriptExpression { - pub fn add_ext( - &self, - rhs: FieldScriptExpression, - ) -> FieldScriptExpression { - assert_eq!(F::U32_SIZE, 1); - assert_eq!(EF::U32_SIZE, 4); - FieldScriptExpression::::Add { - x: Arc::new(Box::new(self.clone())), - y: Arc::new(Box::new(rhs)), - var: StackVariable::null(), - debug: Cell::new(false), - } - } - - pub fn add_base(&self, rhs: FieldScriptExpression) -> Self { - assert_eq!(F::U32_SIZE, 4); - assert_eq!(Base::U32_SIZE, 1); - FieldScriptExpression::Add { - x: Arc::new(Box::new(self.clone())), - y: Arc::new(Box::new(rhs)), - var: StackVariable::null(), - debug: Cell::new(false), - } - } - - pub fn mul_ext( - &self, - rhs: FieldScriptExpression, - ) -> FieldScriptExpression { - assert_eq!(F::U32_SIZE, 1); - assert_eq!(EF::U32_SIZE, 4); - FieldScriptExpression::::Mul { - x: Arc::new(Box::new(self.clone())), - y: Arc::new(Box::new(rhs)), - var: StackVariable::null(), - debug: Cell::new(false), - } - } - - pub fn mul_base(&self, rhs: FieldScriptExpression) -> Self { - assert_eq!(F::U32_SIZE, 4); - assert_eq!(Base::U32_SIZE, 1); - FieldScriptExpression::Mul { - x: Arc::new(Box::new(self.clone())), - y: Arc::new(Box::new(rhs)), - var: StackVariable::null(), - debug: Cell::new(false), - } - } - - pub fn sub_ext( - &self, - rhs: FieldScriptExpression, - ) -> FieldScriptExpression { - assert_eq!(F::U32_SIZE, 1); - assert_eq!(EF::U32_SIZE, 4); - FieldScriptExpression::::Sub { - x: Arc::new(Box::new(self.clone())), - y: Arc::new(Box::new(rhs)), - var: StackVariable::null(), - debug: Cell::new(false), - } - } - - pub fn sub_base(&self, rhs: FieldScriptExpression) -> Self { - assert_eq!(F::U32_SIZE, 4); - assert_eq!(Base::U32_SIZE, 1); - FieldScriptExpression::Sub { - x: Arc::new(Box::new(self.clone())), - y: Arc::new(Box::new(rhs)), - var: StackVariable::null(), - debug: Cell::new(false), - } - } - - pub fn exp_constant(&self, power: u32) -> Self { - FieldScriptExpression::ExpConstant { - x: Arc::new(Box::new(self.clone())), - y: power, - var: StackVariable::null(), - debug: Cell::new(false), +impl Debug for FieldScriptExpression { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + FieldScriptExpression::Table { table, debug, var } => { + write!(f, "Table: {:?}, Debug: {:?}, Var: {:?}", table, debug, var) + } } } +} - pub fn equal_verify(&self, rhs: Self) -> Self { - FieldScriptExpression::EqualVerify { - x: Arc::new(Box::new(self.clone())), - y: Arc::new(Box::new(rhs.clone())), - debug: Cell::new(false), - } - } +impl Expression for FieldScriptExpression { - pub fn equal_verify_for_f(&self, rhs: F) -> Self { - FieldScriptExpression::EqualVerify { - x: Arc::new(Box::new(self.clone())), - y: Arc::new(Box::new(Self::from(rhs))), - debug: Cell::new(false), + fn opcode(&self) -> StandardOpcodeId { + match self { + Self::Table { table, debug, var } => StandardOpcodeId::Table, } } - pub fn index_to_rou(index: u32, sub_group_bits: u32) -> Self { - FieldScriptExpression::IndexToROU { - index: Arc::new(Box::new(NumScriptExpression::from(index))), - sub_group_bits: sub_group_bits, - var: StackVariable::null(), - debug: Cell::new(false), - } + fn as_expr_ptr(self) -> ExprPtr { + Arc::new(RwLock::new(Box::new(self))) } -} -impl Expression for FieldScriptExpression { fn set_debug(&self) { match self { - FieldScriptExpression::ValueVariable { debug, .. } => { - debug.set(true); - } - FieldScriptExpression::InputVariable { debug, .. } => { - debug.set(true); - } - FieldScriptExpression::Constant { debug, .. } => debug.set(true), FieldScriptExpression::Table { debug, .. } => { debug.set(true); } - FieldScriptExpression::Add { debug, .. } => { - debug.set(true); - } - FieldScriptExpression::Sub { debug, .. } => { - debug.set(true); - } - FieldScriptExpression::Neg { debug, .. } => { - debug.set(true); - } - FieldScriptExpression::Mul { debug, .. } => { - debug.set(true); - } - FieldScriptExpression::EqualVerify { debug, .. } => { - debug.set(true); - } - FieldScriptExpression::ExpConstant { debug, .. } => { - debug.set(true); - } - FieldScriptExpression::IndexToROU { debug, .. } => { - debug.set(true); - } - FieldScriptExpression::NumToField { debug, .. } => { - debug.set(true); - } - FieldScriptExpression::Lookup { debug, .. } => { - debug.set(true); - } }; } @@ -260,808 +74,37 @@ impl Expression for FieldScriptExpression { &self, stack: &mut StackTracker, input_variables: &BTreeMap, - ) -> Script { + id_mapper: &mut BTreeMap, + optimize: bool, + ) -> Vec { match self { - FieldScriptExpression::ValueVariable { v, debug, mut var } => { - let intput_var = input_variables.get(v.get_var()).unwrap(); - var = stack.copy_var(intput_var.clone()); - if debug.get() == true { - stack.debug(); - } - if v.get_var().get_var_size().is_some() { - assert_eq!(var.size(), v.get_var().get_var_size().unwrap()); - } - } - FieldScriptExpression::InputVariable { sv, debug, mut var } => { - let intput_var = input_variables.get(sv).unwrap(); - var = stack.copy_var(intput_var.clone()); - if debug.get() == true { - stack.debug(); - } - if sv.get_var_size().is_some() { - assert_eq!(var.size(), sv.get_var_size().unwrap()); - } - } - FieldScriptExpression::Constant { f, mut var, debug } => { - let v = f.as_u32_vec(); - var = stack.bignumber(v); - if debug.get() == true { - stack.debug(); - } - } + FieldScriptExpression::Table { table, mut var, debug, } => { //push table + let mut vars = vec![]; for f in table.iter().rev() { let v = f.as_u32_vec(); - var = stack.bignumber(v); - } - if debug.get() == true { - stack.debug(); - } - } - FieldScriptExpression::Add { - x, - y, - debug, - mut var, - } => { - x.express_to_script(stack, input_variables); // F - y.express_to_script(stack, input_variables); // EF - if x.var_size() == y.var_size() { - let vars = stack - .custom1( - script! { - if x.var_size() == 1{ - {u31_add::()} - }else{ - {u31ext_add::()} - } - }, - 2, - 1, - 0, - F::U32_SIZE as u32, - "ExprADD_Result", - ) - .unwrap(); - var = vars[0]; - assert_eq!(var.size(), x.var_size() as u32); - } else { - let mut script = Script::default(); - if x.var_size() > y.var_size() { - script = script! { - {u31ext_add_u31::()} - }; - } else { - script = script! { - 4 OP_ROLL - {u31ext_add_u31::()} - }; - } - let output_var_size = x.var_size().max(y.var_size()); - let vars = stack - .custom1( - script, - 2, // consumes 2 variable, one size is 4 and the other size is 1 - 1, // the output variable size is 4 - 0, - output_var_size, - "ExprADD_Result", - ) - .unwrap(); - var = vars[0]; - assert_eq!(var.size(), output_var_size as u32); - } - if debug.get() == true { - stack.debug(); - } - } - FieldScriptExpression::Sub { - x, - y, - debug, - mut var, - } => { - x.express_to_script(stack, input_variables); - y.express_to_script(stack, input_variables); - if x.var_size() == y.var_size() { - let vars = stack - .custom1( - script! { - if F::U32_SIZE == 1{ - {u31_sub::()} - }else{ - {u31ext_sub::()} - } - }, - 2, - 1, - 0, - F::U32_SIZE as u32, - "ExprSUB_Result", - ) - .unwrap(); - var = vars[0]; - } else { - let mut script = Script::default(); - if debug.get() == true { - stack.debug(); - } - - if x.var_size() > y.var_size() { - script = script! { - {u31ext_sub_u31::()} - }; - } else { - script = script! { - 4 OP_ROLL - {u31_sub_u31ext::()} - }; - } - let vars = stack - .custom1( - script, - 2, // consumes 2 variable, one size is 4 and the other size is 1 - 1, // the size of output variable is 4 - 0, - F::U32_SIZE as u32, - "ExprSUB_Result", - ) - .unwrap(); - var = vars[0]; - } - - if debug.get() == true { - stack.debug(); - } - assert_eq!(var.size(), F::U32_SIZE as u32); - } - FieldScriptExpression::Neg { x, debug, mut var } => { - x.express_to_script(stack, input_variables); - let vars = stack - .custom1( - script! { - if F::U32_SIZE == 1{ - {u31_neg::()} - }else{ - {u31ext_neg::()} - } - }, - 1, - 1, - 0, - F::U32_SIZE as u32, - "ExprNEG_Result", - ) - .unwrap(); - var = vars[0]; - if debug.get() == true { - stack.debug(); - } - assert_eq!(var.size(), F::U32_SIZE as u32); - } - FieldScriptExpression::Mul { - x, - y, - debug, - mut var, - } => { - x.express_to_script(stack, input_variables); - y.express_to_script(stack, input_variables); - if x.var_size() == y.var_size() { - let vars = stack - .custom1( - script! { - if F::U32_SIZE == 1{ - {u31_mul::()} - }else{ - {u31ext_mul::()} - } - }, - 2, - 1, - 0, - F::U32_SIZE as u32, - "ExprMUL_Result", - ) - .unwrap(); - var = vars[0]; - } else { - let mut script = Script::default(); - - if x.var_size() > y.var_size() { - script = script! { - {u31ext_mul_u31::()} - }; - } else { - script = script! { - 4 OP_ROLL - {u31ext_mul_u31::()} - }; - } - let vars = stack - .custom1( - script, - 2, // consumes 2 variable, one size is 4 and the other size is 1 - 1, // the size of output variable is 4 - 0, - F::U32_SIZE as u32, - "ExprMUL_Result", - ) - .unwrap(); - var = vars[0]; + vars.push(stack.bignumber(v)); } if debug.get() == true { stack.debug(); } - assert_eq!(var.size(), F::U32_SIZE as u32); + vars } - FieldScriptExpression::EqualVerify { x, y, debug } => { - x.express_to_script(stack, input_variables); - y.express_to_script(stack, input_variables); - assert_eq!(x.var_size(), y.var_size()); - if x.var_size() == 1 { - stack.op_equalverify(); - } else { - stack.custom( - u31ext_equalverify::(), - 2, - false, - 0, - "u31ext_equalverify", - ); - } - if debug.get() == true { - stack.debug(); - } - } - FieldScriptExpression::ExpConstant { - x, - y, - debug, - mut var, - } => { - x.express_to_script(stack, input_variables); - - let vars = stack - .custom1( - value_exp_n::(log2_strict_usize(*y as usize)), - 1, - 1, - 0, - x.var_size(), - "FieldExpr::ExpConstant", - ) - .unwrap(); - var = vars[0]; - - if debug.get() == true { - stack.debug(); - } - assert_eq!(var.size(), F::U32_SIZE as u32); - } - FieldScriptExpression::IndexToROU { - index, - debug, - mut var, - sub_group_bits, - } => { - index.express_to_script(stack, input_variables); - - let vars = stack - .custom1( - index_to_rou::(*sub_group_bits), - 1, - 1, - 0, - F::U32_SIZE as u32, - "FieldExpr::IndexToROU", - ) - .unwrap(); - var = vars[0]; - - if debug.get() == true { - stack.debug(); - } - assert_eq!(var.size(), F::U32_SIZE as u32); - } - FieldScriptExpression::NumToField { x, mut var, debug } => { - x.express_to_script(stack, input_variables); - let vars = stack - .custom1( - script! { - if F::U32_SIZE == 1 { - {u32_to_u31()} - } else { - {u32_to_u31()} - {u31_to_u31ext::()} - } - }, - 1, - 1, - 0, - F::U32_SIZE as u32, - "FieldExpr::NumToField", - ) - .unwrap(); - var = vars[0]; - - if debug.get() == true { - stack.debug(); - } - assert_eq!(var.size(), F::U32_SIZE as u32); - } - FieldScriptExpression::Lookup { - x, - y, - len, - debug, - mut var, - } => { - x.express_to_script(stack, input_variables); - // todo: check y is the NumScriptExpression - y.express_to_script(stack, input_variables); - let vars = stack.custom1( - script! { - OP_PICK - }, - 1, - 1, - 0, - F::U32_SIZE as u32, - "ExprLookup_Result", - ); - stack.to_altstack(); - for _ in 0..(*len) { - stack.op_drop(); - } - var = stack.from_altstack(); - - assert_eq!(var.size(), F::U32_SIZE as u32); - } - }; - stack.get_script() + } } fn var_size(&self) -> u32 { F::U32_SIZE as u32 } - - fn get_var(&self) -> Option> { - match self { - FieldScriptExpression::ValueVariable { var, .. } => Some(vec![var]), - FieldScriptExpression::InputVariable { var, .. } => Some(vec![var]), - FieldScriptExpression::Constant { var, .. } => Some(vec![var]), - FieldScriptExpression::Table { var, .. } => Some(vec![var]), - FieldScriptExpression::Add { var, .. } => Some(vec![var]), - FieldScriptExpression::Sub { var, .. } => Some(vec![var]), - FieldScriptExpression::Neg { var, .. } => Some(vec![var]), - FieldScriptExpression::Mul { var, .. } => Some(vec![var]), - FieldScriptExpression::EqualVerify { .. } => None, - FieldScriptExpression::ExpConstant { var, .. } => Some(vec![var]), - FieldScriptExpression::IndexToROU { var, .. } => Some(vec![var]), - FieldScriptExpression::NumToField { var, .. } => Some(vec![var]), - FieldScriptExpression::Lookup { var, .. } => Some(vec![var]), - } - } -} - -impl Default for FieldScriptExpression { - fn default() -> Self { - Self::zero() - } } -impl From for FieldScriptExpression { - fn from(value: F) -> Self { - Self::Constant { - f: value, - debug: Cell::new(false), - var: StackVariable::null(), - } - } -} - -impl Debug for FieldScriptExpression { - fn fmt(&self, fm: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - FieldScriptExpression::ValueVariable { v, .. } => fm - .debug_struct("ScriptExpression::ValueVariable") - .field("var", v) - .finish(), - FieldScriptExpression::InputVariable { sv, .. } => fm - .debug_struct("ScriptExpression::InputVariable") - .field("sv", sv) - .finish(), - FieldScriptExpression::Constant { f, .. } => fm - .debug_struct("ScriptExpression::Constant") - .field("f", f) - .finish(), - FieldScriptExpression::Table { table, .. } => fm - .debug_struct("ScriptExpression::Table") - .field("table", table) - .finish(), - FieldScriptExpression::Add { x, y, debug, var } => fm - .debug_struct("ScriptExpression::Add") - .field("variable", var) - .finish(), - FieldScriptExpression::Sub { x, y, debug, var } => fm - .debug_struct("ScriptExpression::Sub") - .field("variable", var) - .finish(), - FieldScriptExpression::Mul { x, y, debug, var } => fm - .debug_struct("ScriptExpression::Mul") - .field("variable", var) - .finish(), - FieldScriptExpression::Neg { x, debug, var } => fm - .debug_struct("ScriptExpression::Neg") - .field("variable", var) - .finish(), - FieldScriptExpression::EqualVerify { x, y, debug } => { - fm.debug_struct("ScriptExpression::Equal").finish() - } - FieldScriptExpression::ExpConstant { x, y, debug, var } => fm - .debug_struct("ScriptExpression::Exp") - .field("variable", var) - .finish(), - FieldScriptExpression::IndexToROU { debug, var, .. } => fm - .debug_struct("ScriptExpression::Exp") - .field("variable", var) - .finish(), - FieldScriptExpression::NumToField { debug, var, .. } => fm - .debug_struct("ScriptExpression::Exp") - .field("variable", var) - .finish(), - FieldScriptExpression::Lookup { - x, - y, - len, - debug, - var, - } => fm - .debug_struct("ScriptExpression::Lookup") - .field("variable", var) - .finish(), - } - } -} - -impl Clone for FieldScriptExpression { - fn clone(&self) -> Self { - match self { - FieldScriptExpression::ValueVariable { v, debug, var } => { - FieldScriptExpression::ValueVariable { - v: v.clone(), - debug: debug.clone(), - var: var.clone(), - } - } - FieldScriptExpression::InputVariable { sv, debug, var } => { - FieldScriptExpression::InputVariable { - sv: sv.clone(), - debug: debug.clone(), - var: var.clone(), - } - } - FieldScriptExpression::Constant { f, debug, var } => FieldScriptExpression::Constant { - f: f.clone(), - debug: debug.clone(), - var: var.clone(), - }, - FieldScriptExpression::Table { table, debug, var } => FieldScriptExpression::Table { - table: table.clone(), - debug: debug.clone(), - var: var.clone(), - }, - FieldScriptExpression::Add { x, y, debug, var } => FieldScriptExpression::Add { - x: x.clone(), - y: y.clone(), - debug: debug.clone(), - var: var.clone(), - }, - FieldScriptExpression::Mul { x, y, debug, var } => FieldScriptExpression::Mul { - x: x.clone(), - y: y.clone(), - debug: debug.clone(), - var: var.clone(), - }, - FieldScriptExpression::Sub { x, y, debug, var } => FieldScriptExpression::Sub { - x: x.clone(), - y: y.clone(), - debug: debug.clone(), - var: var.clone(), - }, - FieldScriptExpression::Neg { x, debug, var } => FieldScriptExpression::Neg { - x: x.clone(), - debug: debug.clone(), - var: var.clone(), - }, - FieldScriptExpression::EqualVerify { x, y, debug } => { - FieldScriptExpression::EqualVerify { - x: x.clone(), - y: y.clone(), - debug: debug.clone(), - } - } - FieldScriptExpression::ExpConstant { x, y, debug, var } => { - FieldScriptExpression::ExpConstant { - x: x.clone(), - y: y.clone(), - debug: debug.clone(), - var: var.clone(), - } - } - FieldScriptExpression::IndexToROU { - index, - debug, - var, - sub_group_bits, - } => FieldScriptExpression::IndexToROU { - index: index.clone(), - debug: debug.clone(), - var: var.clone(), - sub_group_bits: *sub_group_bits, - }, - FieldScriptExpression::NumToField { x, debug, var } => { - FieldScriptExpression::NumToField { - x: x.clone(), - debug: debug.clone(), - var: var.clone(), - } - } - FieldScriptExpression::Lookup { - x, - y, - len, - debug, - var, - } => FieldScriptExpression::Lookup { - x: x.clone(), - y: y.clone(), - len: len.clone(), - debug: debug.clone(), - var: var.clone(), - }, - } - } -} - -impl AbstractField for FieldScriptExpression { - type F = F; - - fn zero() -> Self { - Self::from(F::zero()) - } - fn one() -> Self { - Self::from(F::one()) - } - fn two() -> Self { - Self::from(F::two()) - } - fn neg_one() -> Self { - Self::from(F::neg_one()) - } - - #[inline] - fn from_f(f: Self::F) -> Self { - f.into() - } - - fn from_bool(b: bool) -> Self { - Self::from(F::from_bool(b)) - } - - fn from_canonical_u8(n: u8) -> Self { - Self::from(F::from_canonical_u8(n)) - } - - fn from_canonical_u16(n: u16) -> Self { - Self::from(F::from_canonical_u16(n)) - } - - fn from_canonical_u32(n: u32) -> Self { - Self::from(F::from_canonical_u32(n)) - } - - fn from_canonical_u64(n: u64) -> Self { - Self::from(F::from_canonical_u64(n)) - } - - fn from_canonical_usize(n: usize) -> Self { - Self::from(F::from_canonical_usize(n)) - } - - fn from_wrapped_u32(n: u32) -> Self { - Self::from(F::from_wrapped_u32(n)) - } - - fn from_wrapped_u64(n: u64) -> Self { - Self::from(F::from_wrapped_u64(n)) - } - - fn generator() -> Self { - Self::from(F::generator()) - } -} - -impl Add for FieldScriptExpression { - type Output = Self; - - fn add(self, rhs: F) -> Self { - Self::Add { - x: Arc::new(Box::new(self)), - y: Arc::new(Box::new(Self::from(rhs))), - debug: Cell::new(false), - var: StackVariable::null(), - } - // self + Self::from(rhs) - } -} - -impl Add for FieldScriptExpression { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - Self::Add { - x: Arc::new(Box::new(self)), - y: Arc::new(Box::new(rhs)), - debug: Cell::new(false), - var: StackVariable::null(), - } - } -} - -impl Add<&Self> for FieldScriptExpression { - type Output = Self; - - fn add(self, rhs: &Self) -> Self { - Self::Add { - x: Arc::new(Box::new(self)), - y: Arc::new(Box::new(rhs.clone())), - debug: Cell::new(false), - var: StackVariable::null(), - } - } -} - -impl AddAssign for FieldScriptExpression { - fn add_assign(&mut self, rhs: Self) { - *self = self.clone() + rhs; - } -} - -impl AddAssign for FieldScriptExpression { - fn add_assign(&mut self, rhs: F) { - *self += Self::from(rhs); - } -} - -impl Sum for FieldScriptExpression { - fn sum>(iter: I) -> Self { - iter.reduce(|x, y| x + y).unwrap_or(Self::zero()) - } -} - -impl Sum for FieldScriptExpression { - fn sum>(iter: I) -> Self { - iter.map(|x| Self::from(x)).sum() - } -} - -impl Sub for FieldScriptExpression { - type Output = Self; - - fn sub(self, rhs: Self) -> Self { - Self::Sub { - x: Arc::new(Box::new(self)), - y: Arc::new(Box::new(rhs)), - debug: Cell::new(false), - var: StackVariable::null(), - } - } -} - -impl Sub for FieldScriptExpression { - type Output = Self; - - fn sub(self, rhs: F) -> Self { - self - Self::from(rhs) - } -} - -impl SubAssign for FieldScriptExpression { - fn sub_assign(&mut self, rhs: Self) { - *self = self.clone() - rhs; - } -} - -impl SubAssign for FieldScriptExpression { - fn sub_assign(&mut self, rhs: F) { - *self -= Self::from(rhs); - } -} - -impl Neg for FieldScriptExpression { - type Output = Self; - - fn neg(self) -> Self { - Self::Neg { - x: Arc::new(Box::new(self)), - debug: Cell::new(false), - var: StackVariable::null(), - } - } -} - -impl Mul for FieldScriptExpression { - type Output = Self; - - fn mul(self, rhs: Self) -> Self { - #[allow(clippy::suspicious_arithmetic_impl)] - Self::Mul { - x: Arc::new(Box::new(self)), - y: Arc::new(Box::new(rhs)), - debug: Cell::new(false), - var: StackVariable::null(), - } - } -} - -impl Mul for FieldScriptExpression { - type Output = Self; - - fn mul(self, rhs: F) -> Self { - self * Self::from(rhs) - } -} - -impl Div for FieldScriptExpression { - type Output = Fraction; - - fn div(self, rhs: Self) -> Fraction { - Fraction::::new(self, rhs) - } -} - -impl MulAssign for FieldScriptExpression { - fn mul_assign(&mut self, rhs: Self) { - *self = self.clone() * rhs; - } -} - -impl MulAssign for FieldScriptExpression { - fn mul_assign(&mut self, rhs: F) { - *self *= Self::from(rhs); - } -} - -impl Product for FieldScriptExpression { - fn product>(iter: I) -> Self { - iter.reduce(|x, y| x * y).unwrap_or(Self::one()) - } -} - -impl Product for FieldScriptExpression { - fn product>(iter: I) -> Self { - iter.map(|x| Self::from(x)).product() - } -} impl FieldScriptExpression { - pub fn lookup(self, index: u32, len: usize) -> Self { - let index = NumScriptExpression::from(index); - Self::Lookup { - x: Arc::new(Box::new(self)), - y: Arc::new(Box::new(index)), - len: len, - debug: Cell::new(false), - var: StackVariable::null(), - } - } pub fn from_table(table: &[F]) -> Self { Self::Table { table: table.into(), @@ -1070,614 +113,3 @@ impl FieldScriptExpression { } } } - -#[cfg(test)] -mod tests { - use alloc::boxed::Box; - use alloc::collections::BTreeMap; - use alloc::sync::Arc; - use alloc::vec::Vec; - use core::cell::{self, Cell}; - - use bitcoin_script_stack::stack::{self, StackTracker, StackVariable}; - use common::{AbstractField, BabyBear, BinomialExtensionField}; - use p3_air::AirBuilder; - use p3_field::TwoAdicField; - use p3_matrix::Matrix; - use primitives::field::BfField; - use scripts::treepp::*; - use scripts::u31_lib::{u31_equalverify, u31ext_equalverify, BabyBear4}; - - use super::{Expression, FieldScriptExpression, Variable, *}; - type EF = BinomialExtensionField; - - #[test] - fn test_field_expr_expconst() { - { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a_value = BabyBear::two(); - let b_value = a_value.exp_u64(2); - let a = FieldScriptExpression::from(a_value); - let b = a.exp_constant(2); - let equal = b.equal_verify_for_f(b_value); - equal.express_to_script(&mut stack, &bmap); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } - - { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a_value = EF::two(); - let b_value = a_value.exp_u64(2); - let a = FieldScriptExpression::from(a_value); - let b = a.exp_constant(2); - let equal = b.equal_verify_for_f(b_value); - equal.express_to_script(&mut stack, &bmap); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } - } - - #[test] - fn test_field_expr_index_to_rou() { - { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let sub_group_bits = 10u32; - let generator = BabyBear::two_adic_generator(sub_group_bits as usize); - let index = 7u32; - let res = generator.exp_u64(index as u64); - - let b = FieldScriptExpression::index_to_rou(index, sub_group_bits); - // b.set_debug(); - let res_expr = FieldScriptExpression::from(res); - let equal = b.equal_verify(res_expr); - equal.express_to_script(&mut stack, &bmap); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } - - { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let sub_group_bits = 10u32; - let generator = EF::two_adic_generator(sub_group_bits as usize); - let index = 7u32; - let res = generator.exp_u64(index as u64); - - let b = FieldScriptExpression::index_to_rou(index, sub_group_bits); - let equal = b.equal_verify_for_f(res); - equal.express_to_script(&mut stack, &bmap); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } - } - - #[test] - fn test_num_to_field() { - let num = 182712u32; - - { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a = NumScriptExpression::from(num); - let b = a.num_to_field(); - let res = BabyBear::from_canonical_u32(num); - let equal = b.equal_verify_for_f(res); - equal.express_to_script(&mut stack, &bmap); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } - - { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a = NumScriptExpression::from(num); - let b = a.num_to_field(); - let res = EF::from_canonical_u32(num); - let equal = b.equal_verify_for_f(res); - equal.express_to_script(&mut stack, &bmap); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } - } - - #[test] - fn test_script_expression_add() { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a = FieldScriptExpression::from(BabyBear::one()); - let b = FieldScriptExpression::from(BabyBear::two()); - let c = a + b; - c.set_debug(); - - let d = FieldScriptExpression::from(BabyBear::two()); - let e = FieldScriptExpression::from(BabyBear::two()); - let f = d + e; - - let g = c + f; // 4 + 3 = 7 - let script = g.express_to_script(&mut stack, &bmap); - stack.number(BabyBear::from_canonical_u32(7u32).as_u32_vec()[0]); - stack.op_equal(); - let res = stack.run(); - assert!(res.success); - } - - #[test] - fn test_script_expression_u31add_u31ext() { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a = FieldScriptExpression::from(BabyBear::one()); - let b = FieldScriptExpression::from(EF::two()); - let c = a.add_ext(b); - - let d = FieldScriptExpression::from(BabyBear::two()); - let e = FieldScriptExpression::from(EF::two()); - let f = e.add_base(d); - - let g = c + f; // 4 + 3 = 7 - let h = g.equal_verify_for_f(EF::from_canonical_u32(7u32)); - let script = h.express_to_script(&mut stack, &bmap); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } - - #[test] - fn test_script_expression_u31sub_u31ext() { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a = FieldScriptExpression::from(BabyBear::one()); - let b = FieldScriptExpression::from(EF::two()); - let c = a.sub_ext(b); - - let d = FieldScriptExpression::from(BabyBear::two()); - let e = FieldScriptExpression::from(EF::from_canonical_u32(4)); - let f = e.sub_base(d); - let g = c + f; // 4 + 3 = 7 - let script = g.express_to_script(&mut stack, &bmap); - stack.bignumber(EF::from_canonical_u32(1u32).as_u32_vec()); - stack.custom( - u31ext_equalverify::(), - 2, - false, - 0, - "u31ext_equalverify", - ); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } - - #[test] - fn test_script_expression_u31mul_u31ext() { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a = FieldScriptExpression::from(BabyBear::one()); - let b = FieldScriptExpression::from(EF::two()); - let c = FieldScriptExpression::::Mul { - x: Arc::new(Box::new(a)), - y: Arc::new(Box::new(b)), - debug: Cell::new(false), - var: StackVariable::null(), - }; - - let d = FieldScriptExpression::from(BabyBear::two()); - let e = FieldScriptExpression::from(EF::from_canonical_u32(4)); - let f = FieldScriptExpression::::Mul { - x: Arc::new(Box::new(e)), - y: Arc::new(Box::new(d)), - debug: Cell::new(false), - var: StackVariable::null(), - }; - - let g = c * f; - let script = g.express_to_script(&mut stack, &bmap); - stack.bignumber(EF::from_canonical_u32(16).as_u32_vec()); - stack.custom( - u31ext_equalverify::(), - 2, - false, - 0, - "equal result", - ); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } - - #[test] - fn test_ext_constant() { - let mut stack = StackTracker::new(); - let bmap = BTreeMap::new(); - let a = FieldScriptExpression::from(EF::one()); - a.express_to_script(&mut stack, &bmap); - let res = EF::one(); - - stack.bignumber(res.as_u32_vec()); - stack.custom( - u31ext_equalverify::(), - 2, - false, - 0, - "u31ext_equalverify", - ); - - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } - - #[test] - fn test_script_expr_with_input() { - let var1 = Variable::new(0, 0); - let var2 = Variable::new(0, 1); - let var3 = Variable::new(1, 0); - let var4 = Variable::new(1, 1); - - let mut stack = StackTracker::new(); - let mut bmap = BTreeMap::new(); - bmap.insert( - var1, - stack.var( - 1, - script! { {BabyBear::from_canonical_u32(1u32).as_u32_vec()[0]}}, - "input 1", - ), - ); - bmap.insert( - var2, - stack.var( - 1, - script! { {BabyBear::from_canonical_u32(2u32).as_u32_vec()[0]}}, - "input 2", - ), - ); - bmap.insert( - var3, - stack.var( - 1, - script! {{BabyBear::from_canonical_u32(3u32).as_u32_vec()[0]}}, - "input 3", - ), - ); - bmap.insert( - var4, - stack.var( - 1, - script! {{BabyBear::from_canonical_u32(4u32).as_u32_vec()[0]}}, - "input 4", - ), - ); - - let var1_wrap = FieldScriptExpression::InputVariable { - sv: var1, - debug: Cell::new(false), - var: StackVariable::null(), - }; - let var2_wrap = FieldScriptExpression::::InputVariable { - sv: var2, - debug: Cell::new(false), - var: StackVariable::null(), - }; - let var3_wrap = FieldScriptExpression::InputVariable { - sv: var3, - debug: Cell::new(false), - var: StackVariable::null(), - }; - let var4_wrap = FieldScriptExpression::::InputVariable { - sv: var4, - debug: Cell::new(false), - var: StackVariable::null(), - }; - let res1 = var1_wrap + var2_wrap; - let res2 = var3_wrap + var4_wrap; - - let res = res1 + res2; - res.express_to_script(&mut stack, &bmap); - - stack.number(BabyBear::from_canonical_u32(10u32).as_u32_vec()[0]); - stack.op_equalverify(); - - stack.drop(*bmap.get(&var4).unwrap()); - stack.drop(*bmap.get(&var3).unwrap()); - stack.drop(*bmap.get(&var2).unwrap()); - stack.drop(*bmap.get(&var1).unwrap()); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } - - #[test] - fn test_script_expr_with_extinput() { - let var1 = Variable::new(0, 0); - let var2 = Variable::new(0, 1); - let var3 = Variable::new(1, 0); - let var4 = Variable::new(1, 1); - - let mut stack = StackTracker::new(); - let mut bmap = BTreeMap::new(); - bmap.insert( - var1, - stack.var( - 4, - script! { - {EF::from_canonical_u32(1u32).as_u32_vec()[3]} - {EF::from_canonical_u32(1u32).as_u32_vec()[2]} - {EF::from_canonical_u32(1u32).as_u32_vec()[1]} - {EF::from_canonical_u32(1u32).as_u32_vec()[0]} - }, - "input 1", - ), - ); - bmap.insert( - var2, - stack.var( - 4, - script! { - {EF::from_canonical_u32(2u32).as_u32_vec()[3]} - {EF::from_canonical_u32(2u32).as_u32_vec()[2]} - {EF::from_canonical_u32(2u32).as_u32_vec()[1]} - {EF::from_canonical_u32(2u32).as_u32_vec()[0]} - }, - "input 2", - ), - ); - bmap.insert( - var3, - stack.var( - 4, - script! {{EF::from_canonical_u32(3u32).as_u32_vec()[3]} {EF::from_canonical_u32(3u32).as_u32_vec()[2]} {EF::from_canonical_u32(3u32).as_u32_vec()[1]} {EF::from_canonical_u32(3u32).as_u32_vec()[0]}}, - "input 3", - ), - ); - bmap.insert( - var4, - stack.var( - 4, - script! {{EF::from_canonical_u32(4u32).as_u32_vec()[3]} {EF::from_canonical_u32(4u32).as_u32_vec()[2]} {EF::from_canonical_u32(4u32).as_u32_vec()[1]} {EF::from_canonical_u32(4u32).as_u32_vec()[0]}}, - "input 4", - ), - ); - - let var1_wrap = FieldScriptExpression::::InputVariable { - sv: var1, - debug: Cell::new(false), - var: StackVariable::null(), - }; - let var2_wrap = FieldScriptExpression::InputVariable { - sv: var2, - debug: Cell::new(false), - var: StackVariable::null(), - }; - let var3_wrap = FieldScriptExpression::InputVariable { - sv: var3, - debug: Cell::new(false), - var: StackVariable::null(), - }; - let var4_wrap = FieldScriptExpression::InputVariable { - sv: var4, - debug: Cell::new(false), - var: StackVariable::null(), - }; - stack.debug(); - let res1 = var1_wrap + var2_wrap; - let res2 = var3_wrap + var4_wrap; - - let res = res1 + res2 + EF::from_canonical_u32(3); - res.express_to_script(&mut stack, &bmap); - - // stack.debug(); - stack.bignumber(EF::from_canonical_u32(13u32).as_u32_vec()); - stack.custom( - u31ext_equalverify::(), - 2, - false, - 0, - "u31ext_equalverify", - ); - stack.debug(); - - stack.drop(*bmap.get(&var4).unwrap()); - stack.drop(*bmap.get(&var3).unwrap()); - stack.drop(*bmap.get(&var2).unwrap()); - stack.drop(*bmap.get(&var1).unwrap()); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } - - #[test] - fn test_script_expression_extadd() { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a = FieldScriptExpression::from(EF::one()); - let b = FieldScriptExpression::from(EF::two()); - let c = a + b; - - let script = c.express_to_script(&mut stack, &bmap); - stack.debug(); - let res = EF::one() + EF::two(); - - stack.bignumber(res.as_u32_vec()); - stack.debug(); - stack.custom( - u31ext_equalverify::(), - 2, - false, - 0, - "u31ext_equalverify", - ); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } - - #[test] - fn test_script_expression_sub() { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a = FieldScriptExpression::from(BabyBear::one()); - let b = FieldScriptExpression::from(BabyBear::two()); - let c = b - a; // 1 - - let d = FieldScriptExpression::from(BabyBear::two()); - let e = FieldScriptExpression::from(BabyBear::from_canonical_u32(8)); - let f = e - d; // 6 - - let g = f - c; // 5 - let script = g.express_to_script(&mut stack, &bmap); - stack.number(BabyBear::from_canonical_u32(5u32).as_u32_vec()[0]); - stack.op_equal(); - let res = stack.run(); - assert!(res.success); - } - - #[test] - fn test_script_expression_extsub() { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a = FieldScriptExpression::from(EF::one()); - let b = FieldScriptExpression::from(EF::two()); - let c = b - a; // 1 - - let d = FieldScriptExpression::from(EF::two()); - let e = FieldScriptExpression::from(EF::from_canonical_u32(8)); - let f = e - d; // 6 - let g = f - c; // 5 - let script = g.express_to_script(&mut stack, &bmap); - stack.bignumber(EF::from_canonical_u32(5u32).as_u32_vec()); - stack.custom( - u31ext_equalverify::(), - 2, - false, - 0, - "u31ext_equalverify", - ); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } - - #[test] - fn test_script_expression_mul() { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a = FieldScriptExpression::from(BabyBear::one()); - let b = FieldScriptExpression::from(BabyBear::two()); - let c = b * a; // 2 - - let d = FieldScriptExpression::from(BabyBear::two()); - let e = FieldScriptExpression::from(BabyBear::from_canonical_u32(8)); - let f = e * d * BabyBear::one(); // 16 - stack.show_stack(); - let g = f * c; // 32 - let script = g.express_to_script(&mut stack, &bmap); - stack.number(BabyBear::from_canonical_u32(32u32).as_u32_vec()[0]); - stack.op_equal(); - let res = stack.run(); - assert!(res.success); - } - - #[test] - fn test_script_expression_extmul() { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a = FieldScriptExpression::from(EF::one()); - let b = FieldScriptExpression::from(EF::two()); - let c = b * a; // 2 - - let d = FieldScriptExpression::from(EF::two()); - let e = FieldScriptExpression::from(EF::from_canonical_u32(8)); - let f = e * d; // 16 - let g = f * c; // 32 - let script = g.express_to_script(&mut stack, &bmap); - - stack.show_stack(); - - stack.bignumber(EF::from_canonical_u32(32u32).as_u32_vec()); - stack.custom( - u31ext_equalverify::(), - 2, - false, - 0, - "u31ext_equalverify", - ); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } - - #[test] - fn test_script_expression_neg() { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a = FieldScriptExpression::from(BabyBear::one()); - let b = -a * BabyBear::two(); - let script = b.express_to_script(&mut stack, &bmap); - stack.number(BabyBear::from_canonical_u32(BabyBear::MOD - 2).as_u32_vec()[0]); - stack.op_equal(); - let res = stack.run(); - assert!(res.success); - } - - #[test] - fn test_script_expression_extneg() { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a = FieldScriptExpression::from(EF::one()); - let b = -a * EF::two(); - let script = b.express_to_script(&mut stack, &bmap); - stack.bignumber(EF::from_canonical_u32(EF::MOD - 2).as_u32_vec()); - stack.custom( - u31ext_equalverify::(), - 2, - false, - 0, - "u31ext_equalverify", - ); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } - - #[test] - fn test_lookup() { - let vec = vec![ - BabyBear::from_canonical_u32(1 as u32), - BabyBear::from_canonical_u32(2 as u32), - BabyBear::from_canonical_u32(3 as u32), - BabyBear::from_canonical_u32(4 as u32), - BabyBear::from_canonical_u32(5 as u32), - ]; - let mut stack = StackTracker::new(); - let bmap = BTreeMap::new(); - - let table = FieldScriptExpression::Table { - table: vec.clone(), - debug: Cell::new(false), - var: StackVariable::null(), - }; - - let index = 4; - - let m = table.lookup(index, vec.len()); - - let script = m.express_to_script(&mut stack, &bmap); - - stack.number(5 as u32); - - stack.custom(u31_equalverify(), 2, false, 0, "u31_equalverify"); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } -} diff --git a/script_expr/src/input_manager.rs b/script_expr/src/input_manager.rs new file mode 100644 index 0000000..39f72ab --- /dev/null +++ b/script_expr/src/input_manager.rs @@ -0,0 +1,360 @@ +use std::cell::{Cell, Ref, RefCell}; +use std::collections::BTreeMap; +use std::fmt::Debug; +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; +use std::sync::{Arc, Mutex, RwLock}; + +use bitcoin_script_stack::stack::StackTracker; +use lazy_static::lazy_static; +use primitives::field::BfField; +use tracing::warn; + +use crate::script_gen::*; +use crate::variable::VarWithValue; +use crate::{ + get_opid, Dsl, ExprPtr, Expression, IdCount, InputOpcode, ScriptExprError, StackVariable, + ValueVariable, Variable, DYNAMIC_INPUT_OR_OUTPUT, +}; + +pub struct ManagerAssign { + managers: Vec>>>, + current_index: Option, +} + +impl IntoIterator for ManagerAssign { + type Item = Arc>>; + type IntoIter = std::vec::IntoIter; + fn into_iter(self) -> Self::IntoIter { + self.managers.into_iter() + } +} + +impl ManagerAssign { + pub fn new() -> Self { + Self { + managers: vec![], + current_index: None, + } + } + + pub fn managers(&self) -> Vec>>> { + self.managers.clone() + } + + pub fn clear(&mut self) { + self.managers = vec![]; + self.current_index = None; + } + + pub fn add_manager(&mut self) -> Arc>> { + let manager: Arc>> = + Arc::new(Mutex::new(Box::new(InputManager::new()))); + self.managers.push(manager.clone()); + manager + } + + pub fn next_manager(&mut self) -> Arc>> { + if self.current_index.is_none() { + self.current_index = Some(0); + } else { + self.current_index = Some(self.current_index.unwrap() + 1); + } + self.add_manager() + } + + pub fn current_manager(&self) -> Arc>> { + self.managers + .get(self.current_index.unwrap()) + .unwrap() + .clone() + } + + pub fn move_current_index(&mut self, index: usize) -> Arc>> { + assert!(index < self.managers.len()); + self.current_index = Some(index); + self.managers.get(index).unwrap().clone() + } + + pub fn get_manager(&mut self, index: usize) -> Arc>> { + assert!(index < self.managers.len()); + self.managers.get(index).unwrap().clone() + } + + pub fn next(&mut self) { + if self.current_index.is_none() { + panic!("current_index no set"); + } else { + self.current_index = Some(self.current_index.unwrap() + 1); + } + assert!(self.current_index.unwrap() <= self.managers.len()); + } + + pub fn assign_input(&self, value: Vec) -> Dsl { + self.current_manager().lock().unwrap().assign_input(value) + } + + pub fn assign_input_f(&self, value: EF) -> Dsl { + self.current_manager() + .lock() + .unwrap() + .assign_input(value.as_u32_vec()) + } + + pub fn simulate_input(&self) -> (StackTracker, BTreeMap) { + let binding = self.current_manager(); + let (stack, var_getter) = binding.lock().unwrap().simulate_input(); + (stack, var_getter) + } +} + +pub struct InputManager { + counter: usize, + input_var: Vec, + input_hint: Vec, + exec_dsl: Option, + hint: Vec, + var_getter: BTreeMap, + id_mapper: BTreeMap, + stack: StackTracker, +} + +impl InputManager { + pub(crate) fn new() -> Self { + Self { + counter: 0, + input_var: vec![], + input_hint: vec![], + exec_dsl: None, + hint: vec![], + var_getter: BTreeMap::new(), + stack: StackTracker::new(), + id_mapper: BTreeMap::new(), + } + } + + pub fn set_exec_dsl(&mut self, exec_dsl: ExprPtr) { + self.exec_dsl = Some(exec_dsl); + } + + pub(crate) fn assign_input_hint(&mut self, value: Vec) -> Variable { + let input_var = VarWithValue::new(value, 5, self.counter); + self.counter += 1; + self.input_hint.push(input_var.clone()); + input_var.var + } + + pub(crate) fn assign_input_var(&mut self, value: Vec) -> Variable { + let input_var = VarWithValue::new(value, 5, self.counter); + self.counter += 1; + self.input_var.push(input_var.clone()); + input_var.var + } + + pub(crate) fn assign_input_opcode(&mut self, value: Vec) -> InputOpcode<0, 1> { + InputOpcode::new( + get_opid(), + self.assign_input_var(value.clone()), + vec![], + value.len() as u32, + StandardOpcodeId::InputVarMove, + ) + } + + pub(crate) fn assign_input_hint_opcode(&mut self, value: Vec) -> InputOpcode<0, 1> { + InputOpcode::new( + get_opid(), + self.assign_input_hint(value.clone()), + vec![], + value.len() as u32, + StandardOpcodeId::InputVarMove, + ) + } + + pub fn assign_input(&mut self, value: Vec) -> Dsl { + Dsl::::new(Arc::new(RwLock::new(Box::new( + self.assign_input_opcode(value), + )))) + } + + pub fn assign_input_f(&mut self, value: EF) -> Dsl { + self.assign_input(value.as_u32_vec()) + } + + pub(crate) fn assign_hint_input(&mut self, value: Vec) -> Dsl { + Dsl::::new(Arc::new(RwLock::new(Box::new( + self.assign_input_hint_opcode(value), + )))) + } + + pub fn assign_hint_input_f(&mut self, value: EF) -> Dsl { + self.assign_hint_input(value.as_u32_vec()) + } + + pub fn add_hint_verify(&mut self, expr: ExprPtr) { + self.hint.push(expr); + } + + pub fn embed_hint_verify(&mut self) { + self.hint.iter().for_each(|hint| { + self.exec_dsl = Some( + Dsl::::new(self.exec_dsl.clone().unwrap()) + .equal(Dsl::::new(hint.clone())) + .into(), + ); + }) + } + + pub(crate) fn simulate_input(&mut self) -> (StackTracker, BTreeMap) { + self.input_var.iter().rev().for_each(|var| { + let stack_var = self.stack.bignumber(var.value.clone()); + self.var_getter.insert(var.var, stack_var); + }); + + self.input_hint.iter().rev().for_each(|var| { + let stack_var = self.stack.bignumber(var.value.clone()); + self.var_getter.insert(var.var, stack_var); + }); + (self.stack.clone(), self.var_getter.clone()) + } + + pub fn run(&mut self, debug: bool) { + if self.exec_dsl.is_none() { + warn!("No expression to run"); + return; + } + self.simulate_input(); + self.exec_dsl + .clone() + .unwrap() + .read() + .unwrap() + .simulate_express(&mut self.id_mapper); + self.exec_dsl + .clone() + .unwrap() + .read() + .unwrap() + .express_to_script(&mut self.stack, &self.var_getter, &mut self.id_mapper, true); + + if debug { + self.stack.debug(); + } + assert!(self.stack.run().success); + } + + pub fn get_script_len(&self) -> usize { + if self.exec_dsl.is_none() { + warn!("No expression to run"); + return 0; + } + self.stack.get_script().len() + } + + // pub(crate) fn assign_public_exprs(&mut self, value: Vec) -> Dsl { + // Dsl::new(Arc::new(RwLock::new(Box::new( + // self.assign_input_opcode(value), + // )))) + // } + + // pub(crate) fn assign_trace_exprs(&mut self, local: Vec, next: Vec) { + // let width = local.len(); + // let main_variables: Vec> = [local, next] + // .into_iter() + // .enumerate() + // .flat_map(|(row_index, row_values)| { + // (0..width).map(move |column_index| { + // ValueVariable::new( + // Variable::new(row_index, column_index), + // row_values[column_index], + // ) + // }) + // }) + // .collect(); + // self.trace_open = main_variables; + // } + + // pub(crate) fn end(&mut self, stack: &mut StackTracker){ + // self.input_vars.iter().for_each(|var|{ + // let stack_var = self.var_getter.get(&var.var).unwrap(); + // println!("Dropping {:?}",stack_var); + // stack.drop(stack_var.clone()); + // }); + // } + + fn generate_input(&self) {} +} + +#[cfg(test)] +mod tests { + use common::{BabyBear, BinomialExtensionField}; + use p3_field::AbstractField; + use primitives::field::BfField; + use scripts::u31_lib::BabyBearU31; + + use super::InputManager; + use crate::{Dsl, ManagerAssign}; + + #[test] + fn test_input_manager_assign() { + let mut input_manager = InputManager::new(); + let val = BabyBear::from_u32(3); + let val_inv = BabyBear::one() / val; + let a = input_manager.assign_input::(val.as_u32_vec()); + let b = input_manager.assign_input::(BabyBear::from_u32(3).as_u32_vec()); + let c = input_manager.assign_input::(BabyBear::from_u32(100).as_u32_vec()); + + let c = (a.clone() + b.clone() + b.square()) * c; + let equal = c.equal_for_f(BabyBear::from_canonical_u32(1500)); + input_manager.set_exec_dsl(equal.into()); + + let val_inv_dsl = input_manager.assign_hint_input_f::(val_inv); + let hint1 = a * val_inv_dsl; + input_manager.add_hint_verify(hint1.into()); + + input_manager.embed_hint_verify::(); + input_manager.run(false); + } + + #[test] + fn test_manager_assign() { + type EF = BinomialExtensionField; + let mut manager_assign = ManagerAssign::new(); + for _ in 0..10 { + manager_assign.next_manager(); + let a = manager_assign.assign_input::(BabyBear::from_u32(3).as_u32_vec()); + let b = manager_assign.assign_input::(BabyBear::from_u32(3).as_u32_vec()); + let c = manager_assign.assign_input_f::(BabyBear::from_u32(100)); + let (mut stack, var_getter) = manager_assign.simulate_input(); + + let c = (a + b.clone() + b.square()) * c + BabyBear::from_u32(1); + let d = c.mul_ext(Dsl::::from(EF::from_u32(2))); + let equal = d.equal_for_f(EF::from_u32(3002)); + let res = equal.express1(&mut stack, &var_getter, true); + assert!(stack.run().success); + } + + for _ in 0..10 { + let cur_manager = manager_assign.next_manager(); + let a = cur_manager + .lock() + .unwrap() + .assign_input::(BabyBear::from_u32(3).as_u32_vec()); + let b = cur_manager + .lock() + .unwrap() + .assign_input::(BabyBear::from_u32(3).as_u32_vec()); + let c = cur_manager + .lock() + .unwrap() + .assign_input_f::(BabyBear::from_u32(100)); + let (mut stack, var_getter) = cur_manager.lock().unwrap().simulate_input(); + + let c = (a + b.clone() + b.square()) * c + BabyBear::from_u32(1); + let d = c.mul_ext(Dsl::::from(EF::from_u32(2))); + let equal = d.equal_for_f(EF::from_u32(3002)); + equal.express1(&mut stack, &var_getter, true); + assert!(stack.run().success); + } + } +} diff --git a/script_expr/src/lagrange.rs b/script_expr/src/lagrange.rs index b668305..9b53106 100644 --- a/script_expr/src/lagrange.rs +++ b/script_expr/src/lagrange.rs @@ -2,13 +2,13 @@ use common::TwoAdicField; use p3_field::ExtensionField; use primitives::field::BfField; -use super::FieldScriptExpression; +use super::Dsl; pub struct LagrangeSelectorsExpr { - pub is_first_row: FieldScriptExpression, - pub is_last_row: FieldScriptExpression, - pub is_transition: FieldScriptExpression, - pub z_h: FieldScriptExpression, + pub is_first_row: Dsl, + pub is_last_row: Dsl, + pub is_transition: Dsl, + pub z_h: Dsl, } pub fn selectors_at_point_expr + BfField, Val: TwoAdicField + BfField>( @@ -17,20 +17,21 @@ pub fn selectors_at_point_expr + BfField, Val: TwoAdicF log_n: usize, ) -> LagrangeSelectorsExpr { let unshifted_point = point * shift.inverse(); - let mut unshifted_point_expr = FieldScriptExpression::::default(); + let mut unshifted_point_expr = Dsl::::default(); if shift == Val::one() { - unshifted_point_expr = FieldScriptExpression::::from(unshifted_point); + unshifted_point_expr = Dsl::::constant_f(unshifted_point); } else { - unshifted_point_expr = FieldScriptExpression::from(point) - .mul_base(FieldScriptExpression::from(shift.inverse())); + unshifted_point_expr = Dsl::constant_f(point).mul_base(Dsl::constant_f(shift.inverse())); } let z_h = unshifted_point.exp_power_of_2(log_n) - Ext::one(); // (x-w^0)...(x-w^n-1) - let z_h_expr = unshifted_point_expr.exp_constant(2 ^ log_n as u32); + let z_h_expr = unshifted_point_expr.clone().exp_constant(2 ^ log_n as u32); LagrangeSelectorsExpr { - is_first_row: (z_h / (unshifted_point - Ext::one())).into(), // hint - is_last_row: (z_h / (unshifted_point - Val::two_adic_generator(log_n).inverse())).into(), // hint + is_first_row: Dsl::constant_f(z_h / (unshifted_point - Ext::one())), // hint + is_last_row: Dsl::constant_f( + z_h / (unshifted_point - Val::two_adic_generator(log_n).inverse()), + ), // hint is_transition: unshifted_point_expr - .sub_base(Val::two_adic_generator(log_n).inverse().into()), + .sub_base(Dsl::constant_f(Val::two_adic_generator(log_n).inverse())), z_h: z_h_expr, // } } diff --git a/script_expr/src/lib.rs b/script_expr/src/lib.rs index 74a210a..e90a926 100644 --- a/script_expr/src/lib.rs +++ b/script_expr/src/lib.rs @@ -4,44 +4,204 @@ use alloc::boxed::Box; use alloc::collections::BTreeMap; use alloc::sync::Arc; use alloc::vec::Vec; -use core::cell::Cell; +use std::fmt::Debug; +use bitcoin_script_stack::debugger::StepResult; use bitcoin_script_stack::stack::{StackTracker, StackVariable}; -use num_script_expr::NumScriptExpression; use primitives::field::BfField; -use scripts::treepp::*; - +use script_gen::StandardOpcodeId; +use tracing::{error, info, instrument, trace, warn}; mod script_builder; mod variable; pub use variable::{ValueVariable, Variable}; -mod num_script_expr; -pub use num_script_expr::*; -mod field_script_expr; -pub use field_script_expr::*; mod script_helper; pub use script_builder::*; -mod fraction_expr; -pub use fraction_expr::*; mod lagrange; pub use lagrange::*; -pub struct Executor { - to_exec_expr: FieldScriptExpression, - bmap: BTreeMap, - stack: StackTracker, +pub mod opcode; +pub use opcode::*; +pub mod script_gen; +pub use script_gen::*; +pub mod alias; +pub use alias::*; +pub mod input_manager; +pub use input_manager::*; + +#[derive(Debug, Clone, Copy)] +pub enum ScriptExprError { + DoubleCopy, + ReadLockError, + WriteLockError, + InvalidExpression, + InvalidScript, +} +#[derive(Debug, Clone)] +pub struct IdCount { + count: u32, + copied: u32, + stack_var: Option, +} + +impl IdCount { + fn new(count: u32) -> Self { + Self { + count, + copied: 0, + stack_var: None, + } + } } -pub trait Expression { +pub(crate) const DYNAMIC_INPUT_OR_OUTPUT: usize = 4294967295; + +pub trait Expression: Debug { + fn as_expr_ptr(self) -> ExprPtr; + + #[instrument] + fn simulate_express(&self, id_mapper: &mut BTreeMap) { + let id = self.get_id(); + let count = id_mapper + .entry(id) + .and_modify(|count| (*count).count += 1) + .or_insert(IdCount::new(1)) + .count; + trace!("insert id:{:?}; count:{:?}", id, count); + if count > 1 { + trace!("insert id:{:?} and find the same op_id, just copy", id); + } else { + // 1. simulate execution + self.get_ops().iter().for_each(|op| { + op.as_ref().read().unwrap().simulate_express(id_mapper); + }); + } + } + + #[instrument] fn express_to_script( &self, stack: &mut StackTracker, - input_variables: &BTreeMap, - ) -> Script; + var_getter: &BTreeMap, + id_mapper: &mut BTreeMap, + optimize: bool, + ) -> Vec { + let id = self.get_id(); + if optimize && self.get_output_number() == 1 { + let mut id_count = id_mapper.get(&id).unwrap().clone(); + if id_count.count > 1 && id_count.stack_var.is_some() { + if id_count.copied == id_count.count - 2 { + trace!("id:{:?} copy and drop form stack_var {:?}", id, id_count); + let top_var = stack.move_var_from_altstack(id_count.stack_var.unwrap()); + stack.rename(top_var, "move_var"); + let id_count = id_mapper.get(&id).unwrap().clone(); + trace!( + "id:{:?} copy and drop ending {:?} get the new stack_var {:?}", + id, + id_count, + top_var + ); + return vec![top_var]; + } else { + trace!("id:{:?} copy form stack_var {:?}", id, id_count); + let top_var = stack.copy_var_from_altstack(id_count.stack_var.unwrap()); + id_count.copied += 1; + id_mapper.insert(id, id_count.clone()); + let id_count = id_mapper.get(&id).unwrap().clone(); + trace!( + "id:{:?} copy and drop ending {:?} get the new stack_var {:?}", + id, + id_count, + top_var + ); + return vec![top_var]; + } + } + } + + self.check_input_number(); + + // 2. express + let vars_size: Vec = self + .get_ops() + .iter() + .map(|op| { + op.as_ref() + .read() + .unwrap() + .express_to_script(stack, var_getter, id_mapper, optimize); + op.as_ref().read().unwrap().var_size() + }) + .collect(); + + // 3. generate script + let mut vars = (self.generate_script_fn())(vars_size, stack, var_getter); + + self.check_output_number(vars.len()); + // 4. set copy var to copy + if optimize && self.get_output_number() == 1 { + let id_count = id_mapper.get_mut(&id).unwrap(); + if id_count.count > 1 && id_count.stack_var.is_none() && id_count.copied == 0 { + stack.copy_var(vars[0]); + let copy_var = stack.to_altstack(); + (*id_count).stack_var = Some(copy_var); + vars = vec![vars[0]]; + } + } + + if self.is_debug() == true { + stack.debug(); + } + vars + } + + fn get_input_number(&self) -> usize; + fn get_output_number(&self) -> usize; + + fn check_input_number(&self) { + let num = self.get_input_number(); + if num == DYNAMIC_INPUT_OR_OUTPUT { + // for dynamic input + } else { + assert_eq!(self.get_ops().len(), num); + } + } + + fn check_output_number(&self, output_num: usize) { + let num = self.get_output_number(); + if num == DYNAMIC_INPUT_OR_OUTPUT { + // for dynamic output + } else { + assert_eq!(output_num, num); + } + } + fn get_ops(&self) -> &Vec; + fn generate_script_fn(&self) -> Arc>; fn var_size(&self) -> u32; + fn get_id(&self) -> u32; #[allow(unused)] fn set_debug(&self); - fn get_var(&self) -> Option>; + fn is_debug(&self) -> bool; + + fn opcode(&self) -> StandardOpcodeId; +} + +pub fn run_dsl(expr: Dsl, value: F) -> StepResult { + let assert_expr = expr.equal_for_f(value); + let mut stack = StackTracker::new(); + let mut inputs = BTreeMap::new(); + assert_expr.express(&mut stack, &mut inputs); + stack.run() +} + +pub fn assert_dsl(expr: Dsl, value: F) { + let res = run_dsl(expr, value); + assert!(res.success); +} + +pub fn debug_assert_dsl(expr: Dsl, value: F) { + let res = run_dsl(expr, value); + debug_assert!(res.success); } diff --git a/script_expr/src/num_script_expr.rs b/script_expr/src/num_script_expr.rs deleted file mode 100644 index 9c024c4..0000000 --- a/script_expr/src/num_script_expr.rs +++ /dev/null @@ -1,828 +0,0 @@ -use alloc::boxed::Box; -use alloc::collections::BTreeMap; -use alloc::sync::Arc; -use alloc::vec::Vec; -use alloc::{format, vec}; -use core::cell::Cell; -use core::fmt::Debug; -use core::iter::{Product, Sum}; -use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; - -use bitcoin_script_stack::stack::{StackTracker, StackVariable}; -use primitives::field::BfField; -use scripts::treepp::*; - -use super::variable::{ValueVariable, Variable}; -use super::{Expression, FieldScriptExpression}; -use crate::script_helper::value_to_bits_format; - -pub enum NumScriptExpression { - InputVariable { - sv: Variable, - debug: Cell, - var: StackVariable, - }, - Constant { - values: Vec, - debug: Cell, - var: StackVariable, - }, - Add { - x: Arc>, - y: Arc>, - var: StackVariable, - debug: Cell, - }, - Sub { - x: Arc>, - y: Arc>, - var: StackVariable, - debug: Cell, - }, - Neg { - x: Arc>, - var: StackVariable, - debug: Cell, - }, - Mul { - x: Arc>, - y: Arc>, - var: StackVariable, - debug: Cell, - }, - EqualVerify { - x: Arc>, - y: Arc>, - debug: Cell, - }, - Equal { - x: Arc>, - y: Arc>, - debug: Cell, - var: StackVariable, - }, - Double { - x: Arc>, - debug: Cell, - var: StackVariable, - }, - Square { - x: Arc>, - debug: Cell, - var: StackVariable, - }, - ToBits { - x: Arc>, - debug: Cell, - var: StackVariable, - bits_len: u32, - }, - ToBitsVec { - x: Arc>, - debug: Cell, - var: Vec, - bits_len: u32, - }, - // Exp{ - // x: Arc>, - // y: Arc>, - // var: StackVariable, - // debug: Cell, - // }, -} - -impl NumScriptExpression { - pub fn zero() -> Self { - Self::from(0u32) - } - - pub fn one() -> Self { - Self::from(1u32) - } - - pub fn two() -> Self { - Self::from(2u32) - } - - pub fn euqal_verify(&self, rhs: NumScriptExpression) -> Self { - Self::EqualVerify { - x: Arc::new(Box::new(self.clone())), - y: Arc::new(Box::new(rhs)), - debug: Cell::new(false), - } - } - - pub fn euqal(&self, rhs: NumScriptExpression) -> Self { - Self::Equal { - x: Arc::new(Box::new(self.clone())), - y: Arc::new(Box::new(rhs)), - debug: Cell::new(false), - var: StackVariable::null(), - } - } - - pub fn to_bits(&self) -> Self { - Self::ToBits { - x: Arc::new(Box::new(self.clone())), - debug: Cell::new(false), - var: StackVariable::null(), - bits_len: 32, - } - } - - pub fn to_custom_bits(&self, bits_len: u32) -> Self { - Self::ToBits { - x: Arc::new(Box::new(self.clone())), - debug: Cell::new(false), - var: StackVariable::null(), - bits_len: bits_len, - } - } - - pub fn num_to_field(&self) -> FieldScriptExpression { - FieldScriptExpression::NumToField { - x: Arc::new(Box::new(self.clone())), - debug: Cell::new(false), - var: StackVariable::null(), - } - } -} - -impl Expression for NumScriptExpression { - fn set_debug(&self) { - match self { - NumScriptExpression::InputVariable { debug, .. } => { - debug.set(true); - } - NumScriptExpression::Constant { debug, .. } => debug.set(true), - NumScriptExpression::Add { debug, .. } => { - debug.set(true); - } - NumScriptExpression::Sub { debug, .. } => { - debug.set(true); - } - NumScriptExpression::Neg { debug, .. } => { - debug.set(true); - } - NumScriptExpression::Mul { debug, .. } => { - debug.set(true); - } - NumScriptExpression::EqualVerify { debug, .. } => { - debug.set(true); - } - NumScriptExpression::Equal { debug, .. } => { - debug.set(true); - } - NumScriptExpression::Double { debug, .. } => { - debug.set(true); - } - NumScriptExpression::Square { debug, .. } => { - debug.set(true); - } - NumScriptExpression::ToBits { debug, .. } => { - debug.set(true); - } - NumScriptExpression::ToBitsVec { debug, .. } => { - debug.set(true); - } - }; - } - - fn express_to_script( - &self, - stack: &mut StackTracker, - input_variables: &BTreeMap, - ) -> Script { - match self { - NumScriptExpression::InputVariable { sv, debug, mut var } => { - let intput_var = input_variables.get(sv).unwrap(); - var = stack.copy_var(intput_var.clone()); - if debug.get() == true { - stack.debug(); - } - if sv.get_var_size().is_some() { - assert_eq!(var.size(), sv.get_var_size().unwrap()); - } - } - NumScriptExpression::Constant { - values, - mut var, - debug, - } => { - var = stack.bignumber(values.clone()); - if debug.get() == true { - stack.debug(); - } - } - NumScriptExpression::Add { - x, - y, - debug, - mut var, - } => { - assert_eq!(x.var_size(), 1); - assert_eq!(y.var_size(), 1); - x.express_to_script(stack, input_variables); // F - y.express_to_script(stack, input_variables); // EF - - var = stack.op_add(); // Bitcoin OP_ADD - - if debug.get() == true { - stack.debug(); - } - } - NumScriptExpression::Sub { - x, - y, - debug, - mut var, - } => { - x.express_to_script(stack, input_variables); // F - y.express_to_script(stack, input_variables); // EF - assert_eq!(x.var_size(), 1); - assert_eq!(y.var_size(), 1); - - var = stack.op_sub(); - - if debug.get() == true { - stack.debug(); - } - } - NumScriptExpression::Neg { x, debug, mut var } => { - x.express_to_script(stack, input_variables); // F - assert_eq!(x.var_size(), 1); - - var = stack.op_negate(); - - if debug.get() == true { - stack.debug(); - } - } - NumScriptExpression::Mul { - x, - y, - debug, - mut var, - } => { - // todo: support mul - assert_eq!(0, 1); - } - NumScriptExpression::EqualVerify { x, y, debug } => { - x.express_to_script(stack, input_variables); // F - y.express_to_script(stack, input_variables); // EF - assert_eq!(x.var_size(), 1); - assert_eq!(y.var_size(), 1); - - stack.op_equalverify(); - - if debug.get() == true { - stack.debug(); - } - } - NumScriptExpression::Equal { - x, - y, - debug, - mut var, - } => { - assert_eq!(x.var_size(), 1); - assert_eq!(y.var_size(), 1); - x.express_to_script(stack, input_variables); // F - y.express_to_script(stack, input_variables); // EF - - var = stack.op_equal(); - - if debug.get() == true { - stack.debug(); - } - } - NumScriptExpression::Double { x, debug, mut var } => { - assert_eq!(x.var_size(), 1); - x.express_to_script(stack, input_variables); // F - stack.copy_var(x.get_var().unwrap()[0].clone()); - stack.op_add(); - - if debug.get() == true { - stack.debug(); - } - } - NumScriptExpression::Square { x, debug, mut var } => { - x.express_to_script(stack, input_variables); // F - assert_eq!(x.var_size(), 1); - // todo: support square - assert_eq!(0, 1); - // var = stack.op_negate(); - - if debug.get() == true { - stack.debug(); - } - } - NumScriptExpression::ToBits { - x, - debug, - mut var, - bits_len, - } => { - x.express_to_script(stack, input_variables); // F - assert_eq!(x.var_size(), 1); - let vars = stack - .custom1( - value_to_bits_format(*bits_len), - x.var_size(), - 1, - 0, - *bits_len, - "NumExpr::ToBits", - ) - .unwrap(); - var = vars[0]; - - if debug.get() == true { - stack.debug(); - } - } - NumScriptExpression::ToBitsVec { x, debug, .. } => { - // todo: support ToBitsVec - assert_eq!(1, 2); - // var = stack.custom1(value_to_bits_format(*bits_len), x.var_size(), *bits_len, 0, 1, "NumExpr::ToBitsVec").unwrap(); - } - }; - stack.get_script() - } - - fn var_size(&self) -> u32 { - match self { - NumScriptExpression::ToBits { bits_len, .. } => *bits_len, - NumScriptExpression::ToBitsVec { .. } => 1, - _ => 1, - } - } - - fn get_var(&self) -> Option> { - match self { - NumScriptExpression::InputVariable { var, .. } => Some(vec![var]), - NumScriptExpression::Constant { var, .. } => Some(vec![var]), - NumScriptExpression::Add { var, .. } => Some(vec![var]), - NumScriptExpression::Sub { var, .. } => Some(vec![var]), - NumScriptExpression::Neg { var, .. } => Some(vec![var]), - NumScriptExpression::Mul { var, .. } => Some(vec![var]), - NumScriptExpression::EqualVerify { .. } => None, - NumScriptExpression::Equal { var, .. } => Some(vec![var]), - NumScriptExpression::Double { var, .. } => Some(vec![var]), - NumScriptExpression::Square { var, .. } => Some(vec![var]), - NumScriptExpression::ToBits { var, .. } => Some(vec![var]), - NumScriptExpression::ToBitsVec { var, .. } => { - let vec = var.iter().map(|item| item).collect(); - Some(vec) - } - } - } -} - -impl Default for NumScriptExpression { - fn default() -> Self { - Self::zero() - } -} - -impl From for NumScriptExpression { - fn from(value: u32) -> Self { - Self::Constant { - values: vec![value], - debug: Cell::new(false), - var: StackVariable::null(), - } - } -} - -impl From> for NumScriptExpression { - fn from(values: Vec) -> Self { - Self::Constant { - values, - debug: Cell::new(false), - var: StackVariable::null(), - } - } -} - -impl Debug for NumScriptExpression { - fn fmt(&self, fm: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - NumScriptExpression::InputVariable { sv, .. } => fm - .debug_struct("ScriptExpression::InputVariable") - .field("sv", sv) - .finish(), - NumScriptExpression::Constant { values, .. } => fm - .debug_struct("ScriptExpression::Constant") - .field("f", values) - .finish(), - NumScriptExpression::Add { x, y, debug, var } => fm - .debug_struct("ScriptExpression::Add") - .field("variable", var) - .finish(), - NumScriptExpression::Sub { x, y, debug, var } => fm - .debug_struct("ScriptExpression::Sub") - .field("variable", var) - .finish(), - NumScriptExpression::Mul { x, y, debug, var } => fm - .debug_struct("ScriptExpression::Mul") - .field("variable", var) - .finish(), - NumScriptExpression::Neg { x, debug, var } => fm - .debug_struct("ScriptExpression::Neg") - .field("variable", var) - .finish(), - NumScriptExpression::EqualVerify { x, y, debug } => { - fm.debug_struct("ScriptExpression::EqualVerify").finish() - } - NumScriptExpression::Equal { x, y, debug, var } => fm - .debug_struct("ScriptExpression::Equal") - .field("variable", var) - .finish(), - NumScriptExpression::Double { x, debug, var } => fm - .debug_struct("ScriptExpression::Double") - .field("variable", var) - .finish(), - NumScriptExpression::Square { x, debug, var } => fm - .debug_struct("ScriptExpression::Square") - .field("variable", var) - .finish(), - NumScriptExpression::ToBits { x, debug, var, .. } => fm - .debug_struct("ScriptExpression::ToBits") - .field("variable", var) - .finish(), - NumScriptExpression::ToBitsVec { x, debug, var, .. } => fm - .debug_struct("ScriptExpression::ToBits") - .field("variable", var) - .finish(), - } - } -} - -impl Clone for NumScriptExpression { - fn clone(&self) -> Self { - match self { - NumScriptExpression::InputVariable { sv, debug, var } => { - NumScriptExpression::InputVariable { - sv: sv.clone(), - debug: debug.clone(), - var: var.clone(), - } - } - NumScriptExpression::Constant { values, debug, var } => NumScriptExpression::Constant { - values: values.clone(), - debug: debug.clone(), - var: var.clone(), - }, - NumScriptExpression::Add { x, y, debug, var } => NumScriptExpression::Add { - x: x.clone(), - y: y.clone(), - debug: debug.clone(), - var: var.clone(), - }, - NumScriptExpression::Mul { x, y, debug, var } => NumScriptExpression::Mul { - x: x.clone(), - y: y.clone(), - debug: debug.clone(), - var: var.clone(), - }, - NumScriptExpression::Sub { x, y, debug, var } => NumScriptExpression::Sub { - x: x.clone(), - y: y.clone(), - debug: debug.clone(), - var: var.clone(), - }, - NumScriptExpression::Neg { x, debug, var } => NumScriptExpression::Neg { - x: x.clone(), - debug: debug.clone(), - var: var.clone(), - }, - NumScriptExpression::EqualVerify { x, y, debug } => NumScriptExpression::EqualVerify { - x: x.clone(), - y: y.clone(), - debug: debug.clone(), - }, - NumScriptExpression::Equal { x, y, debug, var } => NumScriptExpression::Equal { - x: x.clone(), - y: y.clone(), - debug: debug.clone(), - var: var.clone(), - }, - NumScriptExpression::Double { x, debug, var } => NumScriptExpression::Double { - x: x.clone(), - debug: debug.clone(), - var: var.clone(), - }, - NumScriptExpression::Square { x, debug, var } => NumScriptExpression::Square { - x: x.clone(), - debug: debug.clone(), - var: var.clone(), - }, - NumScriptExpression::ToBits { - x, - debug, - var, - bits_len, - } => NumScriptExpression::ToBits { - x: x.clone(), - debug: debug.clone(), - var: var.clone(), - bits_len: *bits_len, - }, - NumScriptExpression::ToBitsVec { - x, - debug, - var, - bits_len, - } => NumScriptExpression::ToBitsVec { - x: x.clone(), - debug: debug.clone(), - var: var.clone(), - bits_len: *bits_len, - }, - } - } -} - -impl Add for NumScriptExpression { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - Self::Add { - x: Arc::new(Box::new(self)), - y: Arc::new(Box::new(rhs)), - debug: Cell::new(false), - var: StackVariable::null(), - } - } -} - -impl Add<&Self> for NumScriptExpression { - type Output = Self; - - fn add(self, rhs: &Self) -> Self { - Self::Add { - x: Arc::new(Box::new(self)), - y: Arc::new(Box::new(rhs.clone())), - debug: Cell::new(false), - var: StackVariable::null(), - } - } -} - -impl AddAssign for NumScriptExpression { - fn add_assign(&mut self, rhs: Self) { - *self = self.clone() + rhs; - } -} - -impl AddAssign for NumScriptExpression { - fn add_assign(&mut self, rhs: u32) { - *self += Self::from(rhs); - } -} - -impl AddAssign> for NumScriptExpression { - fn add_assign(&mut self, rhs: Vec) { - *self += Self::from(rhs); - } -} - -impl Sum for NumScriptExpression { - fn sum>(iter: I) -> Self { - iter.reduce(|x, y| x + y).unwrap_or(Self::zero()) - } -} - -impl Sum for NumScriptExpression { - fn sum>(iter: I) -> Self { - iter.map(|x| Self::from(x)).sum() - } -} - -impl Sub for NumScriptExpression { - type Output = Self; - - fn sub(self, rhs: Self) -> Self { - Self::Sub { - x: Arc::new(Box::new(self)), - y: Arc::new(Box::new(rhs)), - debug: Cell::new(false), - var: StackVariable::null(), - } - } -} - -impl Sub for NumScriptExpression { - type Output = Self; - - fn sub(self, rhs: u32) -> Self { - self - Self::from(rhs) - } -} - -impl SubAssign for NumScriptExpression { - fn sub_assign(&mut self, rhs: Self) { - *self = self.clone() - rhs; - } -} - -impl SubAssign for NumScriptExpression { - fn sub_assign(&mut self, rhs: u32) { - *self -= Self::from(rhs); - } -} - -impl Neg for NumScriptExpression { - type Output = Self; - - fn neg(self) -> Self { - Self::Neg { - x: Arc::new(Box::new(self)), - debug: Cell::new(false), - var: StackVariable::null(), - } - } -} - -impl Mul for NumScriptExpression { - type Output = Self; - - fn mul(self, rhs: Self) -> Self { - #[allow(clippy::suspicious_arithmetic_impl)] - Self::Mul { - x: Arc::new(Box::new(self)), - y: Arc::new(Box::new(rhs)), - debug: Cell::new(false), - var: StackVariable::null(), - } - } -} - -impl Mul for NumScriptExpression { - type Output = Self; - - fn mul(self, rhs: u32) -> Self { - self * Self::from(rhs) - } -} - -impl MulAssign for NumScriptExpression { - fn mul_assign(&mut self, rhs: Self) { - *self = self.clone() * rhs; - } -} - -impl MulAssign for NumScriptExpression { - fn mul_assign(&mut self, rhs: u32) { - *self *= Self::from(rhs); - } -} - -impl Product for NumScriptExpression { - fn product>(iter: I) -> Self { - iter.reduce(|x, y| x * y).unwrap_or(Self::one()) - } -} - -impl Product for NumScriptExpression { - fn product>(iter: I) -> Self { - iter.map(|x| Self::from(x)).product() - } -} - -#[cfg(test)] -mod tests { - use alloc::collections::BTreeMap; - use core::cell::{self, Cell}; - - use bitcoin_script_stack::stack::{StackTracker, StackVariable}; - use scripts::treepp::*; - - use super::{Expression, NumScriptExpression, Variable, *}; - - #[test] - fn test_script_expression_add() { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a = NumScriptExpression::from(1); - let b = NumScriptExpression::from(2); - let c = a + b; - c.set_debug(); - - let d = NumScriptExpression::from(2); - let e = NumScriptExpression::from(2); - let f = d + e; - - let g: NumScriptExpression = c + f; // 4 + 3 = 7 - let h = g.euqal(NumScriptExpression::from(7)); - let script = h.express_to_script(&mut stack, &bmap); - let res = stack.run(); - assert!(res.success); - } - - #[test] - fn test_script_expr_with_input() { - let var1 = Variable::new(0, 0); - let var2 = Variable::new(0, 1); - let var3 = Variable::new(1, 0); - let var4 = Variable::new(1, 1); - - let mut stack = StackTracker::new(); - let mut bmap = BTreeMap::new(); - bmap.insert(var1, stack.var(1, script! { 1 }, "input 1")); - bmap.insert(var2, stack.var(1, script! { 2}, "input 2")); - bmap.insert(var3, stack.var(1, script! {3}, "input 3")); - bmap.insert(var4, stack.var(1, script! {4}, "input 4")); - - let var1_wrap = NumScriptExpression::InputVariable { - sv: var1, - debug: Cell::new(false), - var: StackVariable::null(), - }; - let var2_wrap = NumScriptExpression::InputVariable { - sv: var2, - debug: Cell::new(false), - var: StackVariable::null(), - }; - let var3_wrap = NumScriptExpression::InputVariable { - sv: var3, - debug: Cell::new(false), - var: StackVariable::null(), - }; - let var4_wrap = NumScriptExpression::InputVariable { - sv: var4, - debug: Cell::new(false), - var: StackVariable::null(), - }; - let res1 = var1_wrap + var2_wrap; - let res2 = var3_wrap + var4_wrap; - - let res = res1 + res2; - res.express_to_script(&mut stack, &bmap); - - stack.number(10); - stack.op_equalverify(); - - stack.drop(*bmap.get(&var4).unwrap()); - stack.drop(*bmap.get(&var3).unwrap()); - stack.drop(*bmap.get(&var2).unwrap()); - stack.drop(*bmap.get(&var1).unwrap()); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - } - - #[test] - fn test_script_expression_sub() { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a = NumScriptExpression::from(1); - let b = NumScriptExpression::from(2); - let c = b - a; // 1 - - let d = NumScriptExpression::from(2); - let e = NumScriptExpression::from(8); - let f = e - d; // 6 - - let g = f - c; // 5 - let script = g.express_to_script(&mut stack, &bmap); - stack.number(5); - stack.op_equal(); - let res = stack.run(); - assert!(res.success); - } - - // #[test] - // fn test_script_expression_mul() { - // let bmap = BTreeMap::new(); - // let mut stack = StackTracker::new(); - // let a = NumScriptExpression::from(BabyBear::one()); - // let b = NumScriptExpression::from(BabyBear::two()); - // let c = b * a; // 2 - - // let d = NumScriptExpression::from(BabyBear::two()); - // let e = NumScriptExpression::from(BabyBear::from_canonical_u32(8)); - // let f = e * d * BabyBear::one(); // 16 - // stack.show_stack(); - // let g = f * c; // 32 - // let script = g.express_to_script(&mut stack, &bmap); - // stack.number(BabyBear::from_canonical_u32(32u32).as_u32_vec()[0]); - // stack.op_equal(); - // let res = stack.run(); - // assert!(res.success); - // } - - #[test] - fn test_script_expression_neg() { - let bmap = BTreeMap::new(); - let mut stack = StackTracker::new(); - let a = NumScriptExpression::from(1); - let b = -a + NumScriptExpression::two(); - let script = b.express_to_script(&mut stack, &bmap); - stack.number(1); - stack.op_equal(); - let res = stack.run(); - assert!(res.success); - } -} diff --git a/script_expr/src/opcode.rs b/script_expr/src/opcode.rs new file mode 100644 index 0000000..b4ddb7f --- /dev/null +++ b/script_expr/src/opcode.rs @@ -0,0 +1,446 @@ +use std::cell::{Cell, Ref, RefCell}; +use std::collections::BTreeMap; +use std::fmt::Debug; +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; +use std::sync::{Arc, RwLock}; + +use bitcoin_script_stack::stack::StackTracker; +use primitives::field::BfField; + +use crate::script_gen::*; +use crate::variable::VarWithValue; +use crate::{ + get_opid, Dsl, ExprPtr, Expression, IdCount, ScriptExprError, StackVariable, ValueVariable, + Variable, DYNAMIC_INPUT_OR_OUTPUT, +}; + +fn to_copy( + low_var: StackVariable, + stack: &mut StackTracker, + copy_ref: Ref>>>>, +) -> Option { + if copy_ref.is_none() { + return None; + } + let top_var = stack.copy_var(low_var); + Some(top_var) +} + +pub(crate) struct Opcode { + id: u32, + name: RefCell>, + var_size: u32, + ops: Vec, + debug: Cell, +} + +impl Debug for Opcode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Opcode") + .field("id", &self.id) + .field("var_size", &self.var_size) + .field("ops", &self.ops.len()) + .field("debug", &self.debug) + .finish() + } +} + +impl Clone for Opcode { + fn clone(&self) -> Self { + Self { + id: self.id.clone(), + name: self.name.clone(), + var_size: self.var_size, + ops: self.ops.clone(), + debug: self.debug.clone(), + } + } +} + +impl Opcode { + pub(crate) fn new(id: u32, ops: Vec>>>, var_size: u32) -> Self { + Self { + id: id, + name: RefCell::new(None), + ops: ops, + var_size: var_size, + debug: Cell::new(false), + } + } + + pub(crate) fn get_id(&self) -> u32 { + self.id + } + + pub(crate) fn get_name(&self) -> Option { + self.name.borrow().deref().clone() + } + + pub(crate) fn set_id(&mut self, id: u32) { + self.id = id; + } + + pub(crate) fn set_name(&self, name: String) { + *self.name.borrow_mut() = Some(name); + } + + pub(crate) fn get_op_expr_ptr(&self, index: usize) -> ExprPtr { + self.ops[index].clone() + } + + fn check_input_num(&self) { + assert_eq!(self.ops.len(), INPUT_NUM); + } + + fn var_size(&self) -> u32 { + if self.var_size == 1 || self.var_size == 4 { + self.var_size + } else { + panic!("Invalid var_size") + } + } + + fn set_debug(&self) { + self.debug.set(true); + } +} + +impl Expression for Opcode { + fn as_expr_ptr(self) -> ExprPtr { + Arc::new(RwLock::new(Box::new(self))) + } + + fn get_input_number(&self) -> usize { + INPUT_NUM + } + + fn get_output_number(&self) -> usize { + OUTPUT_NUM + } + + fn get_ops(&self) -> &Vec { + &self.ops + } + + fn generate_script_fn(&self) -> Arc> { + unimplemented!() + } + + fn var_size(&self) -> u32 { + if self.var_size == 1 || self.var_size == 4 { + self.var_size + } else { + panic!("Invalid var_size") + } + } + + fn get_id(&self) -> u32 { + self.id + } + + fn set_debug(&self) { + self.debug.set(true); + } + + fn is_debug(&self) -> bool { + self.debug.get() + } + + fn opcode(&self) -> StandardOpcodeId { + unimplemented!() + } +} + +pub(crate) struct StandardOpcode { + opcode: Opcode, + opcode_id: StandardOpcodeId, + script_gen: Arc>, +} + +impl StandardOpcode { + pub(crate) fn new( + id: u32, + ops: Vec>>>, + var_size: u32, + opcode: StandardOpcodeId, + ) -> Self { + Self { + opcode: Opcode::new(id, ops, var_size), + opcode_id: opcode, + script_gen: Arc::new(standard_script_genreator(opcode)), + } + } + + fn check_input_num(&self) { + self.opcode.check_input_num(); + } +} + +impl Debug + for StandardOpcode +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("StandardOpcode") + .field("opcode", &self.opcode) + .field("opcode_Id", &self.opcode_id) + .finish() + } +} + +impl Clone + for StandardOpcode +{ + fn clone(&self) -> Self { + Self { + opcode: self.opcode.clone(), + opcode_id: self.opcode_id, + script_gen: self.script_gen.clone(), + } + } +} + +impl Expression + for StandardOpcode +{ + fn as_expr_ptr(self) -> ExprPtr { + Arc::new(RwLock::new(Box::new(self))) + } + + fn get_input_number(&self) -> usize { + INPUT_NUM + } + + fn get_output_number(&self) -> usize { + OUTPUT_NUM + } + + fn get_ops(&self) -> &Vec { + &self.opcode.ops + } + + fn generate_script_fn(&self) -> Arc> { + self.script_gen.clone() + } + + fn var_size(&self) -> u32 { + if self.opcode.var_size == 1 || self.opcode.var_size == 4 { + self.opcode.var_size + } else { + panic!("Invalid var_size") + } + } + + fn get_id(&self) -> u32 { + self.opcode.get_id() + } + + fn set_debug(&self) { + self.opcode.debug.set(true); + } + + fn is_debug(&self) -> bool { + self.opcode.debug.get() + } + + fn opcode(&self) -> StandardOpcodeId { + self.opcode_id.into() + } +} + +pub(crate) struct CustomOpcode { + opcode: Opcode, + custom: Vec>, + opcode_id: StandardOpcodeId, + script_gen: Arc>, + _marker: PhantomData, +} +impl + CustomOpcode +{ + pub(crate) fn new( + id: u32, + custom_data: Vec>, + ops: Vec>>>, + var_size: u32, + opcode: StandardOpcodeId, + ) -> Self { + Self { + custom: custom_data.clone(), + opcode: Opcode::new(id, ops, var_size), + opcode_id: opcode, + script_gen: Arc::new(custom_script_generator::(opcode, custom_data)), + _marker: PhantomData, + } + } + + fn check_input_num(&self) { + self.opcode.check_input_num(); + } +} + +impl Debug + for CustomOpcode +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ValueOpcode") + .field("opcode", &self.opcode) + .field("opcode_Id", &self.opcode_id) + .finish() + } +} + +impl Clone + for CustomOpcode +{ + fn clone(&self) -> Self { + Self { + custom: self.custom.clone(), + opcode: self.opcode.clone(), + opcode_id: self.opcode_id, + script_gen: self.script_gen.clone(), + _marker: PhantomData, + } + } +} + +impl Expression + for CustomOpcode +{ + fn as_expr_ptr(self) -> ExprPtr { + Arc::new(RwLock::new(Box::new(self))) + } + + fn get_input_number(&self) -> usize { + INPUT_NUM + } + fn get_output_number(&self) -> usize { + OUTPUT_NUM + } + + fn get_ops(&self) -> &Vec { + &self.opcode.ops + } + + fn generate_script_fn(&self) -> Arc> { + self.script_gen.clone() + } + + fn var_size(&self) -> u32 { + if self.opcode.var_size == 1 || self.opcode.var_size == 4 || self.opcode.var_size == 0 { + self.opcode.var_size + } else { + panic!("Invalid var_size") + } + } + + fn get_id(&self) -> u32 { + self.opcode.get_id() + } + + fn set_debug(&self) { + self.opcode.debug.set(true); + } + + fn is_debug(&self) -> bool { + self.opcode.debug.get() + } + + fn opcode(&self) -> StandardOpcodeId { + self.opcode_id.into() + } +} + +pub(crate) struct InputOpcode { + opcode: Opcode, + input_var: Variable, + opcode_id: StandardOpcodeId, + script_gen: Arc>, +} +impl InputOpcode { + pub(crate) fn new( + id: u32, + input_var: Variable, + ops: Vec>>>, + var_size: u32, + opcode: StandardOpcodeId, + ) -> Self { + Self { + input_var: input_var, + opcode: Opcode::new(id, ops, var_size), + opcode_id: opcode, + script_gen: Arc::new(input_script_generator(opcode, input_var)), + } + } + + fn check_input_num(&self) { + self.opcode.check_input_num(); + } +} + +impl Debug for InputOpcode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ValueOpcode") + .field("opcode", &self.opcode) + .field("opcode_id", &self.opcode_id) + .finish() + } +} + +impl Clone for InputOpcode { + fn clone(&self) -> Self { + Self { + input_var: self.input_var.clone(), + opcode: self.opcode.clone(), + opcode_id: self.opcode_id, + script_gen: self.script_gen.clone(), + } + } +} + +impl Expression + for InputOpcode +{ + fn as_expr_ptr(self) -> ExprPtr { + Arc::new(RwLock::new(Box::new(self))) + } + + fn get_input_number(&self) -> usize { + INPUT_NUM + } + fn get_output_number(&self) -> usize { + OUTPUT_NUM + } + + fn get_ops(&self) -> &Vec { + &self.opcode.ops + } + + fn generate_script_fn(&self) -> Arc> { + self.script_gen.clone() + } + + fn var_size(&self) -> u32 { + if self.opcode.var_size == 1 || self.opcode.var_size == 4 || self.opcode.var_size == 0 { + self.opcode.var_size + } else { + panic!("Invalid var_size") + } + } + + fn get_id(&self) -> u32 { + self.opcode.get_id() + } + + fn set_debug(&self) { + self.opcode.debug.set(true); + } + + fn is_debug(&self) -> bool { + self.opcode.debug.get() + } + + fn opcode(&self) -> StandardOpcodeId { + self.opcode_id.into() + } +} diff --git a/script_expr/src/script_builder.rs b/script_expr/src/script_builder.rs index a63465a..3be30f7 100644 --- a/script_expr/src/script_builder.rs +++ b/script_expr/src/script_builder.rs @@ -8,16 +8,16 @@ use p3_matrix::dense::RowMajorMatrix; use primitives::field::BfField; use scripts::treepp::*; -use super::{FieldScriptExpression, ValueVariable, Variable}; +use super::{Dsl, ValueVariable, Variable}; pub struct ScriptConstraintBuilder { pub main: RowMajorMatrix>, pub public_values: Vec, - pub is_first_row: FieldScriptExpression, - pub is_last_row: FieldScriptExpression, - pub is_transition: FieldScriptExpression, - pub constraints: Vec>, - pub alpha: FieldScriptExpression, + pub is_first_row: Dsl, + pub is_last_row: Dsl, + pub is_transition: Dsl, + pub constraints: Vec>, + pub alpha: Dsl, } impl ScriptConstraintBuilder { @@ -34,10 +34,10 @@ impl ScriptConstraintBuilder { local, next, num_public_values, - FieldScriptExpression::from(is_first_row), - FieldScriptExpression::from(is_last_row), - FieldScriptExpression::from(is_transition), - FieldScriptExpression::from(alpha), + Dsl::constant_f(is_first_row), + Dsl::constant_f(is_last_row), + Dsl::constant_f(is_transition), + Dsl::constant_f(alpha), ) } @@ -45,10 +45,10 @@ impl ScriptConstraintBuilder { local: Vec, next: Vec, num_public_values: usize, - is_first_row: FieldScriptExpression, - is_last_row: FieldScriptExpression, - is_transition: FieldScriptExpression, - alpha: FieldScriptExpression, + is_first_row: Dsl, + is_last_row: Dsl, + is_transition: Dsl, + alpha: Dsl, ) -> Self { let width = local.len(); let main_variables: Vec> = [local, next] @@ -57,7 +57,7 @@ impl ScriptConstraintBuilder { .flat_map(|(row_index, row_values)| { (0..width).map(move |column_index| { ValueVariable::new( - Variable::new(row_index, column_index), + Variable::new_with_size(row_index, column_index, F::U32_SIZE as u32), row_values[column_index], ) }) @@ -80,7 +80,7 @@ impl ScriptConstraintBuilder { } } - pub fn get_accmulator_expr(&self) -> FieldScriptExpression { + pub fn get_accmulator_expr(&self) -> Dsl { let mut acc = self.constraints[0].clone(); for i in 1..self.constraints.len() { acc = acc * self.alpha.clone() + self.constraints[i].clone(); @@ -116,7 +116,7 @@ impl ScriptConstraintBuilder { F::U32_SIZE as u32, script! { {u32_vec[3]} {u32_vec[2]} {u32_vec[1]} {u32_vec[0]} }, &format!( - "main_trace row index={} column_value={}", + "main_trace row_index={} column_index={}", i / self.main().width, i % self.main().width ), @@ -142,7 +142,7 @@ impl ScriptConstraintBuilder { impl AirBuilder for ScriptConstraintBuilder { type F = F; - type Expr = FieldScriptExpression; + type Expr = Dsl; type Var = ValueVariable; type M = RowMajorMatrix; diff --git a/script_expr/src/script_gen.rs b/script_expr/src/script_gen.rs new file mode 100644 index 0000000..550edb8 --- /dev/null +++ b/script_expr/src/script_gen.rs @@ -0,0 +1,570 @@ +use std::collections::BTreeMap; + +use bitcoin_script::script; +use bitcoin_script_stack::stack::StackTracker; +use p3_util::log2_strict_usize; +use primitives::field::BfField; +use scripts::treepp::*; +use scripts::u31_lib::{ + u31_add, u31_double, u31_mul, u31_neg, u31_square, u31_sub, u31_sub_u31ext, u31_to_u31ext, + u31ext_add, u31ext_add_u31, u31ext_double, u31ext_equalverify, u31ext_mul, u31ext_mul_u31, + u31ext_neg, u31ext_square, u31ext_sub, u31ext_sub_u31, u32_to_u31, BabyBear4, BabyBearU31, +}; + +use crate::script_helper::{index_to_rou, value_exp_n}; +use crate::{StackVariable, Variable}; + +#[derive(Debug, Clone, Copy)] +pub(crate) enum StandardOpcodeId { + Add, + Mul, + Sub, + Neg, + Equal, + EqualVerify, + NumToField, + Constant, + ExpConst, + IndexToRou, + Lookup, + InputVarMove, + InputVarCopy, + Table, + Square, + Double, +} + +pub(crate) type StandardOpScriptGen = dyn Fn(Vec, &mut StackTracker, &BTreeMap) -> Vec + + 'static; + +pub(crate) fn standard_script_genreator(opid: StandardOpcodeId) -> Box { + match opid { + StandardOpcodeId::Add => Box::new(op_add), + StandardOpcodeId::Mul => Box::new(op_mul), + StandardOpcodeId::Sub => Box::new(op_sub), + StandardOpcodeId::Neg => Box::new(op_neg), + StandardOpcodeId::EqualVerify => Box::new(op_euqalverify), + StandardOpcodeId::Equal => Box::new(op_euqal), + StandardOpcodeId::NumToField => Box::new(op_num_to_field), + StandardOpcodeId::Square => Box::new(op_square), + StandardOpcodeId::Double => Box::new(op_double), + _ => panic!("not support"), + } +} + +pub(crate) fn custom_script_generator( + opid: StandardOpcodeId, + custom_data: Vec>, +) -> Box { + match opid { + StandardOpcodeId::ExpConst => Box::new( + move |vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap| { + op_expconst::(custom_data.clone(), vars_size, stack, var_getter) + }, + ), + StandardOpcodeId::IndexToRou => Box::new( + move |vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap| { + op_indextorou::(custom_data.clone(), vars_size, stack, var_getter) + }, + ), + StandardOpcodeId::Constant => Box::new( + move |vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap| { + op_constant(custom_data.clone(), vars_size, stack, var_getter) + }, + ), + StandardOpcodeId::Lookup => Box::new( + move |vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap| { + op_lookup::(custom_data.clone(), vars_size, stack, var_getter) + }, + ), + StandardOpcodeId::Table => Box::new( + move |vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap| { + op_table(custom_data.clone(), vars_size, stack, var_getter) + }, + ), + _ => panic!("not support"), + } +} + +pub(crate) fn input_script_generator( + opid: StandardOpcodeId, + input_var: Variable, +) -> Box { + match opid { + StandardOpcodeId::InputVarMove => Box::new( + move |vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap| { + op_inputvar_move(input_var, vars_size, stack, var_getter) + }, + ), + StandardOpcodeId::InputVarCopy => Box::new( + move |vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap| { + op_inputvar_copy(input_var, vars_size, stack, var_getter) + }, + ), + _ => panic!("not support"), + } +} + +pub(crate) fn op_inputvar_copy( + input_var: Variable, + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(vars_size.len(), 0); + let stack_var = var_getter.get(&input_var).unwrap(); + let var = stack.copy_var(stack_var.clone()); + vec![var] +} + +pub(crate) fn op_inputvar_move( + input_var: Variable, + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(vars_size.len(), 0); + let stack_var = var_getter.get(&input_var).unwrap(); + + let var = stack.move_var(stack_var.clone()); + vec![var] +} + +pub(crate) fn op_num_to_field( + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(vars_size.len(), 1); + let vars = stack + .custom1( + script! { + if vars_size[0] == 1 { + {u32_to_u31()} + } else { + {u32_to_u31()} + {u31_to_u31ext::()} + } + }, + 1, + 1, + 0, + vars_size[0], + "FieldExpr::NumToField", + ) + .unwrap(); + + vars +} + +pub(crate) fn op_lookup( + len: Vec>, + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(len[0].len(), 1); + assert_eq!(vars_size[0], 1); // the size of index is must 1 + assert!(F::U32_SIZE != 4); // no support extension + let vars = stack.custom1( + script! { + OP_PICK + }, + 1, + 1, + 0, + F::U32_SIZE as u32, + "ExprLookup_Result", + ); + stack.to_altstack(); + for _ in 0..(len[0][0]) { + stack.op_drop(); + } + let var = stack.from_altstack(); + + vec![var] +} + +pub(crate) fn op_table( + table: Vec>, + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + //push table + let mut vars = vec![]; + for f in table.iter().rev() { + let v = f.clone(); + vars.push(stack.bignumber(v)); + } + vars +} + +pub(crate) fn op_indextorou( + sub_group_bits: Vec>, + _vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(sub_group_bits[0].len(), 1); + let vars = stack + .custom1( + index_to_rou::(sub_group_bits[0][0]), + 1, + 1, + 0, + F::U32_SIZE as u32, + "FieldExpr::IndexToROU", + ) + .unwrap(); + + vars +} + +pub(crate) fn op_expconst( + const_exp_power: Vec>, + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(const_exp_power[0].len(), 1); + let vars = stack + .custom1( + value_exp_n::(log2_strict_usize(const_exp_power[0][0] as usize)), + 1, + 1, + 0, + vars_size[0], + "FieldExpr::ExpConstant", + ) + .unwrap(); + + assert_eq!(vars[0].size(), vars_size[0]); + vars +} + +pub(crate) fn op_constant( + value: Vec>, + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(value.len(), 1); + let var = stack.bignumber(value[0].clone()); + vec![var] +} + +pub(crate) fn op_euqal( + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(vars_size[0], vars_size[1]); + assert_eq!(vars_size.len(), 2); + + if vars_size[0] == 1 { + let var = stack.op_equal(); + vec![var] + } else { + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "u31ext_equalverify", + ); + let var = stack.op_true(); + vec![var] + } +} + +pub(crate) fn op_euqalverify( + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(vars_size[0], vars_size[1]); + assert_eq!(vars_size.len(), 2); + if vars_size[0] == 1 { + stack.op_equalverify(); + } else { + stack.custom( + u31ext_equalverify::(), + 2, + false, + 0, + "u31ext_equalverify", + ); + } + vec![] +} +pub(crate) fn op_neg( + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(vars_size.len(), 1); + let vars = stack + .custom1( + script! { + if vars_size[0] == 1 { + {u31_neg::()} + }else{ + {u31ext_neg::()} + } + }, + 1, + 1, + 0, + vars_size[0], + "ExprNEG_Result", + ) + .unwrap(); + vars +} + +pub(crate) fn op_sub( + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(vars_size.len(), 2); + let mut vars = vec![]; + if vars_size[0] == vars_size[1] { + vars = stack + .custom1( + script! { + if vars_size[0] == 1{ + {u31_sub::()} + }else{ + {u31ext_sub::()} + } + }, + 2, + 1, + 0, + vars_size[0], + "ExprMUL_Result", + ) + .unwrap() + } else { + let mut script = Script::default(); + + if vars_size[0] > vars_size[1] { + script = script! { + {u31ext_sub_u31::()} + }; + } else { + script = script! { + 4 OP_ROLL + {u31_sub_u31ext::()} + }; + } + vars = stack + .custom1( + script, + 2, // consumes 2 variable, one size is 4 and the other size is 1 + 1, // the size of output variable is 4 + 0, + vars_size[0].max(vars_size[1]), + "ExprMUL_Result", + ) + .unwrap(); + } + + vars +} + +pub(crate) fn op_add( + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(vars_size.len(), 2); + let mut vars = vec![]; + if vars_size[0] == vars_size[1] { + vars = stack + .custom1( + script! { + if vars_size[0] == 1{ + {u31_add::()} + }else{ + {u31ext_add::()} + } + }, + 2, + 1, + 0, + vars_size[0], + "ExprMUL_Result", + ) + .unwrap() + } else { + let mut script = Script::default(); + + if vars_size[0] > vars_size[1] { + script = script! { + {u31ext_add_u31::()} + }; + } else { + script = script! { + 4 OP_ROLL + {u31ext_add_u31::()} + }; + } + vars = stack + .custom1( + script, + 2, // consumes 2 variable, one size is 4 and the other size is 1 + 1, // the size of output variable is 4 + 0, + vars_size[0].max(vars_size[1]), + "ExprMUL_Result", + ) + .unwrap(); + } + + vars +} + +pub(crate) fn op_double( + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(vars_size.len(), 1); + let mut vars = vec![]; + + if vars_size[0] == 1 { + vars = stack + .custom1( + script! { + {u31_double::()} + }, + 1, + 1, + 0, + vars_size[0], + "op_double", + ) + .unwrap() + } else { + vars = stack + .custom1( + script! { + {u31ext_double::()} + }, + 1, + 1, + 0, + vars_size[0], + "op_double", + ) + .unwrap() + } + vars +} + +pub(crate) fn op_square( + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(vars_size.len(), 1); + let mut vars = vec![]; + + if vars_size[0] == 1 { + vars = stack + .custom1( + script! { + {u31_square()} + }, + 1, + 1, + 0, + vars_size[0], + "op_square", + ) + .unwrap() + } else { + vars = stack + .custom1( + script! { + {u31ext_square()} + }, + 1, + 1, + 0, + vars_size[0], + "op_square", + ) + .unwrap() + } + vars +} + +pub(crate) fn op_mul( + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(vars_size.len(), 2); + let mut vars = vec![]; + + if vars_size[0] == vars_size[1] { + vars = stack + .custom1( + script! { + if vars_size[0] == 1{ + {u31_mul::()} + }else{ + {u31ext_mul::()} + } + }, + 2, + 1, + 0, + vars_size[0], + "ExprMUL_Result", + ) + .unwrap() + } else { + let mut script = Script::default(); + + if vars_size[0] > vars_size[1] { + script = script! { + {u31ext_mul_u31::()} + }; + } else { + script = script! { + 4 OP_ROLL + {u31ext_mul_u31::()} + }; + } + vars = stack + .custom1( + script, + 2, // consumes 2 variable, one size is 4 and the other size is 1 + 1, // the size of output variable is 4 + 0, + vars_size[0].max(vars_size[1]), + "ExprMUL_Result", + ) + .unwrap(); + } + vars +} diff --git a/script_expr/src/script_helper.rs b/script_expr/src/script_helper.rs index 57a4e55..c14fda2 100644 --- a/script_expr/src/script_helper.rs +++ b/script_expr/src/script_helper.rs @@ -24,7 +24,7 @@ pub fn compress_bits(bits: usize) -> Script { } /// decompress num to a vector of bits, from lowest bit to highest bit -pub fn decompress(num: u32, bits: usize) -> Vec { +fn decompress(num: u32, bits: usize) -> Vec { let mut res = vec![]; for index in 0..bits { res.push(((num >> index) & 0x1) as u8); @@ -33,7 +33,7 @@ pub fn decompress(num: u32, bits: usize) -> Vec { } /// input: [index, b_{0}, b_{1}, ..., b_{bits-1}] -pub fn reverse_bits_len_script(bits: usize) -> Script { +fn reverse_bits_len_script(bits: usize) -> Script { let script = script! { for i in 0..bits { {i*2} OP_PICK @@ -49,18 +49,16 @@ pub fn reverse_bits_len_script(bits: usize) -> Script { script } -// the input stack: +// input stack: +// index <-- top +// output stack: // rev_index <-- top -// index pub fn reverse_bits_len_script_with_input(input_index: u32, bits: usize) -> Script { script! { - OP_TOALTSTACK for bit in decompress(input_index, bits) { {bit} } {reverse_bits_len_script(bits)} - OP_FROMALTSTACK - OP_EQUAL } } @@ -290,6 +288,28 @@ mod tests { use super::*; type EF = BinomialExtensionField; + // #[test] + // fn test_reverse_bits_20() { + // for bits in 1..31 { + // for _ in 0..30 { + // let x: u32 = rand::thread_rng().gen(); + // let x = x % (1 << bits); + // let script = script! { + // {x} + // for bit in decompress(x, bits) { + // {bit} + // } + // {reverse_bits_len_script(bits)} + // {reverse_bits_len(x as usize, bits)} + // OP_EQUAL + // }; + // let res = execute_script(script); + // // println!("{:?}", res); + // assert_eq!(res.success, true); + // } + // } + // } + #[test] fn test_index_to_rou() { let index: u64 = 7; // 111 ; // 7= 4 + 3=(2+1) diff --git a/script_expr/src/variable.rs b/script_expr/src/variable.rs index 3526941..44cff56 100644 --- a/script_expr/src/variable.rs +++ b/script_expr/src/variable.rs @@ -1,11 +1,11 @@ -use core::cell::Cell; use core::fmt::Debug; use core::ops::{Add, Mul, Sub}; +use std::sync::{Arc, RwLock}; -use bitcoin_script_stack::stack::StackVariable; use primitives::field::BfField; -use super::FieldScriptExpression; +use super::Dsl; +use crate::{get_opid, InputOpcode, StandardOpcodeId}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct ValueVariable { @@ -15,6 +15,7 @@ pub struct ValueVariable { impl ValueVariable { pub fn new(var: Variable, value: F) -> Self { + assert_eq!(var.expect_var_size.unwrap(), F::U32_SIZE as u32); Self { var, value: Some(value), @@ -30,41 +31,43 @@ impl ValueVariable { } } -impl From> for FieldScriptExpression { +impl From> for Dsl { fn from(var: ValueVariable) -> Self { - Self::ValueVariable { - v: var, - debug: Cell::new(false), - var: StackVariable::null(), - } + Dsl::new(Arc::new(RwLock::new(Box::new(InputOpcode::<0, 1>::new( + get_opid(), + var.into(), + vec![], + F::U32_SIZE as u32, + StandardOpcodeId::InputVarCopy, + ))))) } } impl Add for ValueVariable { - type Output = FieldScriptExpression; + type Output = Dsl; fn add(self, rhs: Self) -> Self::Output { - FieldScriptExpression::::from(self) + FieldScriptExpression::::from(rhs) + Dsl::::from(self) + Dsl::::from(rhs) } } impl Add for ValueVariable { - type Output = FieldScriptExpression; + type Output = Dsl; fn add(self, rhs: F) -> Self::Output { - FieldScriptExpression::::from(self) + FieldScriptExpression::::from(rhs) + Dsl::::from(self) + Dsl::::constant_f(rhs) } } -impl Add> for ValueVariable { - type Output = FieldScriptExpression; +impl Add> for ValueVariable { + type Output = Dsl; - fn add(self, rhs: FieldScriptExpression) -> Self::Output { - FieldScriptExpression::from(self) + rhs + fn add(self, rhs: Dsl) -> Self::Output { + Dsl::from(self) + rhs } } -impl Add> for FieldScriptExpression { +impl Add> for Dsl { type Output = Self; fn add(self, rhs: ValueVariable) -> Self::Output { @@ -73,30 +76,30 @@ impl Add> for FieldScriptExpression { } impl Sub for ValueVariable { - type Output = FieldScriptExpression; + type Output = Dsl; fn sub(self, rhs: Self) -> Self::Output { - FieldScriptExpression::::from(self) - FieldScriptExpression::::from(rhs) + Dsl::::from(self) - Dsl::::from(rhs) } } impl Sub for ValueVariable { - type Output = FieldScriptExpression; + type Output = Dsl; fn sub(self, rhs: F) -> Self::Output { - FieldScriptExpression::::from(self) - FieldScriptExpression::::from(rhs) + Dsl::::from(self) - Dsl::::constant_f(rhs) } } -impl Sub> for ValueVariable { - type Output = FieldScriptExpression; +impl Sub> for ValueVariable { + type Output = Dsl; - fn sub(self, rhs: FieldScriptExpression) -> Self::Output { - FieldScriptExpression::::from(self) - rhs + fn sub(self, rhs: Dsl) -> Self::Output { + Dsl::::from(self) - rhs } } -impl Sub> for FieldScriptExpression { +impl Sub> for Dsl { type Output = Self; fn sub(self, rhs: ValueVariable) -> Self::Output { @@ -105,30 +108,30 @@ impl Sub> for FieldScriptExpression { } impl Mul for ValueVariable { - type Output = FieldScriptExpression; + type Output = Dsl; fn mul(self, rhs: Self) -> Self::Output { - FieldScriptExpression::::from(self) * FieldScriptExpression::::from(rhs) + Dsl::::from(self) * Dsl::::from(rhs) } } impl Mul for ValueVariable { - type Output = FieldScriptExpression; + type Output = Dsl; fn mul(self, rhs: F) -> Self::Output { - FieldScriptExpression::::from(self) * FieldScriptExpression::::from(rhs) + Dsl::::from(self) * Dsl::::constant_f(rhs) } } -impl Mul> for ValueVariable { - type Output = FieldScriptExpression; +impl Mul> for ValueVariable { + type Output = Dsl; - fn mul(self, rhs: FieldScriptExpression) -> Self::Output { - FieldScriptExpression::::from(self) * rhs + fn mul(self, rhs: Dsl) -> Self::Output { + Dsl::::from(self) * rhs } } -impl Mul> for FieldScriptExpression { +impl Mul> for Dsl { type Output = Self; fn mul(self, rhs: ValueVariable) -> Self::Output { @@ -137,12 +140,51 @@ impl Mul> for FieldScriptExpression { } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +// Assume the trace matrix height is k, the row 0~k uses to record Matrix open +// the u32::Max row use to record public inputs +// the u32::Max-1 row uses to record other inputs pub struct Variable { pub row_index: usize, pub column_index: usize, pub expect_var_size: Option, } +#[derive(Debug, Clone)] +pub struct VarWithValue { + pub var: Variable, + pub value: Vec, +} + +impl VarWithValue { + pub fn new(value: Vec, row_index: usize, column_index: usize) -> Self { + VarWithValue { + var: Variable::new(row_index, column_index), + value: value, + } + } +} + +impl From> for VarWithValue { + fn from(value: ValueVariable) -> Self { + Self::new( + value.value.unwrap().as_u32_vec(), + value.var.row_index, + value.var.column_index, + ) + } +} + +impl From> for Variable { + fn from(value: ValueVariable) -> Self { + let var = Self::new_with_size( + value.var.row_index, + value.var.column_index, + F::U32_SIZE as u32, + ); + var + } +} + impl Variable { pub fn new(row_index: usize, column_index: usize) -> Self { Variable { @@ -181,33 +223,38 @@ impl Variable { } } -impl From for FieldScriptExpression { +impl From for Dsl { fn from(var: Variable) -> Self { - Self::InputVariable { - sv: var, - debug: Cell::new(false), - var: StackVariable::null(), + if let Some(size) = var.expect_var_size { + assert_eq!(size, F::U32_SIZE as u32); } + Self::new(Arc::new(RwLock::new(Box::new(InputOpcode::<0, 1>::new( + get_opid(), + var, + vec![], + F::U32_SIZE as u32, + StandardOpcodeId::InputVarCopy, + ))))) } } impl Add for Variable { - type Output = FieldScriptExpression; + type Output = Dsl; fn add(self, rhs: F) -> Self::Output { - FieldScriptExpression::::from(self) + FieldScriptExpression::::from(rhs) + Dsl::::from(self) + Dsl::::constant_f(rhs) } } -impl Add> for Variable { - type Output = FieldScriptExpression; +impl Add> for Variable { + type Output = Dsl; - fn add(self, rhs: FieldScriptExpression) -> Self::Output { - FieldScriptExpression::from(self) + rhs + fn add(self, rhs: Dsl) -> Self::Output { + Dsl::from(self) + rhs } } -impl Add for FieldScriptExpression { +impl Add for Dsl { type Output = Self; fn add(self, rhs: Variable) -> Self::Output { @@ -216,22 +263,22 @@ impl Add for FieldScriptExpression { } impl Sub for Variable { - type Output = FieldScriptExpression; + type Output = Dsl; fn sub(self, rhs: F) -> Self::Output { - FieldScriptExpression::::from(self) - FieldScriptExpression::::from(rhs) + Dsl::::from(self) - Dsl::::constant_f(rhs) } } -impl Sub> for Variable { - type Output = FieldScriptExpression; +impl Sub> for Variable { + type Output = Dsl; - fn sub(self, rhs: FieldScriptExpression) -> Self::Output { - FieldScriptExpression::::from(self) - rhs + fn sub(self, rhs: Dsl) -> Self::Output { + Dsl::::from(self) - rhs } } -impl Sub for FieldScriptExpression { +impl Sub for Dsl { type Output = Self; fn sub(self, rhs: Variable) -> Self::Output { @@ -240,22 +287,22 @@ impl Sub for FieldScriptExpression { } impl Mul for Variable { - type Output = FieldScriptExpression; + type Output = Dsl; fn mul(self, rhs: F) -> Self::Output { - FieldScriptExpression::::from(self) * FieldScriptExpression::::from(rhs) + Dsl::::from(self) * Dsl::::constant_f(rhs) } } -impl Mul> for Variable { - type Output = FieldScriptExpression; +impl Mul> for Variable { + type Output = Dsl; - fn mul(self, rhs: FieldScriptExpression) -> Self::Output { - FieldScriptExpression::::from(self) * rhs + fn mul(self, rhs: Dsl) -> Self::Output { + Dsl::::from(self) * rhs } } -impl Mul for FieldScriptExpression { +impl Mul for Dsl { type Output = Self; fn mul(self, rhs: Variable) -> Self::Output { diff --git a/scripts/src/lib.rs b/scripts/src/lib.rs index 14e8d6c..baa6edb 100644 --- a/scripts/src/lib.rs +++ b/scripts/src/lib.rs @@ -33,6 +33,22 @@ pub mod u31_lib { BabyBear as BabyBearU31, BabyBear4, U31Config, U31ExtConfig, }; + use crate::pseudo::OP_4DUP; + + pub fn u31_square() -> Script { + script! { + OP_DUP + {u31_mul::()} + } + } + + pub fn u31ext_square() -> Script { + script! { + OP_4DUP + {u31ext_mul::()} + } + } + pub fn u31_equalverify() -> Script { script! { OP_EQUALVERIFY diff --git a/uni-stark/Cargo.toml b/uni-stark/Cargo.toml index e2a5a0c..b934522 100644 --- a/uni-stark/Cargo.toml +++ b/uni-stark/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "MIT OR Apache-2.0" [dependencies] -bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git"} +bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git", branch = "bf-stark"} bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } diff --git a/uni-stark/src/config.rs b/uni-stark/src/config.rs index 452a8ee..658b3ff 100644 --- a/uni-stark/src/config.rs +++ b/uni-stark/src/config.rs @@ -4,8 +4,10 @@ use p3_challenger::{CanObserve, CanSample, FieldChallenger}; use p3_commit::PolynomialSpace; use p3_field::{ExtensionField, Field}; use primitives::bf_pcs; -use primitives::bf_pcs::Pcs; +use primitives::bf_pcs::{Pcs, PcsExpr}; use primitives::challenger::BfGrindingChallenger; +use primitives::field::BfField; +use script_expr::{Dsl, ManagerAssign}; pub type PcsError = <::Pcs as Pcs< ::Challenge, @@ -30,10 +32,10 @@ pub type PackedChallenge = pub trait StarkGenericConfig { /// The PCS used to commit to trace polynomials. - type Pcs: Pcs; + type Pcs: PcsExpr; /// The field from which most random challenges are drawn. - type Challenge: ExtensionField>; + type Challenge: ExtensionField> + BfField; /// The challenger (Fiat-Shamir) implementation used. // type Challenger: FieldChallenger> @@ -66,8 +68,8 @@ impl StarkConfig { impl StarkGenericConfig for StarkConfig where - Challenge: ExtensionField<::Val>, - Pcs: bf_pcs::Pcs, + Challenge: ExtensionField<::Val> + BfField, + Pcs: PcsExpr, Challenger: BfGrindingChallenger + CanObserve<>::Commitment> + CanSample, diff --git a/uni-stark/src/expr_helper.rs b/uni-stark/src/expr_helper.rs index 39f0c12..9bb7cf3 100644 --- a/uni-stark/src/expr_helper.rs +++ b/uni-stark/src/expr_helper.rs @@ -4,53 +4,49 @@ use std::sync::Arc; use bitcoin_script_stack::stack::StackVariable; use p3_field::{AbstractField, Field}; use primitives::field::BfField; -use script_expr::{FieldScriptExpression, ValueVariable, Variable}; +use script_expr::{Dsl, ValueVariable, Variable}; use crate::symbolic_variable::SymbolicVariable; use crate::{Entry, SymbolicExpression}; -impl From<&SymbolicExpression> for FieldScriptExpression { - fn from(value: &SymbolicExpression) -> Self { - match value { - SymbolicExpression::Variable(v) => FieldScriptExpression::InputVariable { - sv: v.into(), - debug: Cell::new(false), - var: StackVariable::null(), - }, - SymbolicExpression::IsFirstRow => FieldScriptExpression::one(), - SymbolicExpression::IsLastRow => FieldScriptExpression::one(), - SymbolicExpression::IsTransition => FieldScriptExpression::one(), - SymbolicExpression::Constant(f) => FieldScriptExpression::Constant { - f: f.clone(), - debug: Cell::new(false), - var: StackVariable::null(), - }, - SymbolicExpression::Add { x, y, .. } => FieldScriptExpression::Add { - x: Arc::new(Box::new(FieldScriptExpression::from(&*x.clone()))), - y: Arc::new(Box::new(FieldScriptExpression::from(&*y.clone()))), - debug: Cell::new(false), - var: StackVariable::null(), - }, - SymbolicExpression::Sub { x, y, .. } => FieldScriptExpression::Sub { - x: Arc::new(Box::new(FieldScriptExpression::from(&*x.clone()))), - y: Arc::new(Box::new(FieldScriptExpression::from(&*y.clone()))), - debug: Cell::new(false), - var: StackVariable::null(), - }, - SymbolicExpression::Neg { x, .. } => FieldScriptExpression::Neg { - x: Arc::new(Box::new(FieldScriptExpression::from(&*x.clone()))), - debug: Cell::new(false), - var: StackVariable::null(), - }, - SymbolicExpression::Mul { x, y, .. } => FieldScriptExpression::Mul { - x: Arc::new(Box::new(FieldScriptExpression::from(&*x.clone()))), - y: Arc::new(Box::new(FieldScriptExpression::from(&*y.clone()))), - debug: Cell::new(false), - var: StackVariable::null(), - }, - } - } -} +// impl From<&SymbolicExpression> for Dsl { +// fn from(value: &SymbolicExpression) -> Self { +// match value { +// SymbolicExpression::Variable(v) => Dsl::InputVariable { +// sv: v.into(), +// debug: Cell::new(false), +// var: StackVariable::null(), +// }, +// SymbolicExpression::IsFirstRow => Dsl::one(), +// SymbolicExpression::IsLastRow => Dsl::one(), +// SymbolicExpression::IsTransition => Dsl::one(), +// SymbolicExpression::Constant(f) => Dsl::constant_f(f.clone()), +// SymbolicExpression::Add { x, y, .. } => Dsl::Add { +// x: Arc::new(Box::new(Dsl::from(&*x.clone()))), +// y: Arc::new(Box::new(Dsl::from(&*y.clone()))), +// debug: Cell::new(false), +// var: StackVariable::null(), +// }, +// SymbolicExpression::Sub { x, y, .. } => Dsl::Sub { +// x: Arc::new(Box::new(Dsl::from(&*x.clone()))), +// y: Arc::new(Box::new(Dsl::from(&*y.clone()))), +// debug: Cell::new(false), +// var: StackVariable::null(), +// }, +// SymbolicExpression::Neg { x, .. } => Dsl::Neg { +// x: Arc::new(Box::new(Dsl::from(&*x.clone()))), +// debug: Cell::new(false), +// var: StackVariable::null(), +// }, +// SymbolicExpression::Mul { x, y, .. } => Dsl::Mul { +// x: Arc::new(Box::new(Dsl::from(&*x.clone()))), +// y: Arc::new(Box::new(Dsl::from(&*y.clone()))), +// debug: Cell::new(false), +// var: StackVariable::null(), +// }, +// } +// } +// } impl From> for Variable { fn from(value: SymbolicVariable) -> Self { @@ -105,27 +101,27 @@ mod tests { use common::{BabyBear, BinomialExtensionField}; use p3_air::AirBuilder; use p3_matrix::Matrix; - use script_expr::{FieldScriptExpression, *}; + use script_expr::{Dsl, *}; type EF = BinomialExtensionField; use crate::SymbolicAirBuilder; - #[test] - fn test_symbolic_expr_constraints() { - let air_width: usize = 2; - let mut builder = SymbolicAirBuilder::::new(0, air_width, 0); - let main_values = builder.main(); - let (local, next) = (main_values.row_slice(0), main_values.row_slice(1)); - let mut when_transition = builder.when_transition(); - // a' <- b - when_transition.assert_eq(local[0], local[1]); + // #[test] + // fn test_symbolic_expr_constraints() { + // let air_width: usize = 2; + // let mut builder = SymbolicAirBuilder::::new(0, air_width, 0); + // let main_values = builder.main(); + // let (local, next) = (main_values.row_slice(0), main_values.row_slice(1)); + // let mut when_transition = builder.when_transition(); + // // a' <- b + // when_transition.assert_eq(local[0], local[1]); - // b' <- a + b - when_transition.assert_eq(local[0] + local[1], next[1]); + // // b' <- a + b + // when_transition.assert_eq(local[0] + local[1], next[1]); - let cs = builder.constraints(); - let script_exp: Vec> = cs - .iter() - .map(|cons| FieldScriptExpression::from(cons)) - .collect(); - } + // let cs = builder.constraints(); + // let script_exp: Vec> = cs + // .iter() + // .map(|cons| Dsl::from(cons)) + // .collect(); + // } } diff --git a/uni-stark/src/lib.rs b/uni-stark/src/lib.rs index dcc764f..30297e3 100644 --- a/uni-stark/src/lib.rs +++ b/uni-stark/src/lib.rs @@ -9,6 +9,7 @@ mod expr_helper; mod folder; mod proof; mod prover; +mod script_verifier; mod scripts; mod symbolic_builder; mod symbolic_expression; @@ -25,6 +26,7 @@ pub use config::*; pub use folder::*; pub use proof::*; pub use prover::*; +pub use script_verifier::*; pub use scripts::*; pub use symbolic_builder::*; pub use symbolic_expression::*; diff --git a/uni-stark/src/script_verifier.rs b/uni-stark/src/script_verifier.rs new file mode 100644 index 0000000..74c9b5e --- /dev/null +++ b/uni-stark/src/script_verifier.rs @@ -0,0 +1,277 @@ +use alloc::collections::BTreeMap; +use alloc::vec; +use alloc::vec::Vec; + +use bitcoin_script_stack::stack::StackTracker; +use itertools::Itertools; +use p3_air::{Air, BaseAir}; +use p3_challenger::{CanObserve, CanSample}; +use p3_commit::PolynomialSpace; +use p3_field::{AbstractExtensionField, AbstractField, Field, TwoAdicField}; +use p3_matrix::dense::{RowMajorMatrix, RowMajorMatrixView}; +use p3_matrix::stack::VerticalPair; +use p3_util::log2_strict_usize; +use primitives::bf_pcs::{Pcs, PcsExpr}; +use primitives::field::BfField; +use script_expr::{ + selectors_at_point_expr, Dsl, InputManager, ManagerAssign, ScriptConstraintBuilder, +}; +use tracing::instrument; + +use crate::symbolic_builder::{self, get_log_quotient_degree, SymbolicAirBuilder}; +use crate::{ + compute_quotient_expr, PcsError, Proof, StarkGenericConfig, Val, VerifierConstraintFolder, +}; + +#[instrument(skip_all)] +pub fn generate_script_verifier( + config: &SC, + air: &A, + challenger: &mut SC::Challenger, + proof: &Proof, + public_values: &Vec>, +) -> Result<(), VerificationError>> +where + SC: StarkGenericConfig, + A: Air>> + + for<'a> Air> + + Air>, + Val: BfField, + SC::Challenge: BfField, +{ + let Proof { + commitments, + opened_values, + opening_proof, + degree_bits, + } = proof; + + let degree = 1 << degree_bits; + let log_quotient_degree = get_log_quotient_degree::, A>(air, 0, public_values.len()); + let quotient_degree = 1 << log_quotient_degree; + + let pcs = config.pcs(); + let trace_domain = pcs.natural_domain_for_degree(degree); + let quotient_domain = + trace_domain.create_disjoint_domain(1 << (degree_bits + log_quotient_degree)); + let quotient_chunks_domains = quotient_domain.split_domains(quotient_degree); + + let air_width = >>::width(air); + let valid_shape = opened_values.trace_local.len() == air_width + && opened_values.trace_next.len() == air_width + && opened_values.quotient_chunks.len() == quotient_degree + && opened_values + .quotient_chunks + .iter() + .all(|qc| qc.len() == >>::D); + if !valid_shape { + return Err(VerificationError::InvalidProofShape); + } + + // Observe the instance. // TODO: recover observe when we have CanObserve trait + // challenger.observe(Val::::from_canonical_usize(proof.degree_bits)); + // TODO: Might be best practice to include other instance data here in the transcript, like some + // encoding of the AIR. This protects against transcript collisions between distinct instances. + // Practically speaking though, the only related known attack is from failing to include public + // values. It's not clear if failing to include other instance data could enable a transcript + // collision, since most such changes would completely change the set of satisfying witnesses. + + challenger.observe(commitments.trace.clone()); + // challenger.observe_slice(public_values); + let alpha: SC::Challenge = challenger.sample(); + challenger.observe(commitments.quotient_chunks.clone()); + + let zeta: SC::Challenge = challenger.sample(); + let zeta_next = trace_domain.next_point(zeta).unwrap(); + + let mut manager_assign = pcs + .generate_verify_expr( + vec![ + ( + commitments.trace.clone(), + vec![( + trace_domain, + vec![ + (zeta, opened_values.trace_local.clone()), + (zeta_next, opened_values.trace_next.clone()), + ], + )], + ), + ( + commitments.quotient_chunks.clone(), + quotient_chunks_domains + .iter() + .zip(&opened_values.quotient_chunks) + .map(|(domain, values)| (*domain, vec![(zeta, values.clone())])) + .collect_vec(), + ), + ], + opening_proof, + challenger, + ) + .map_err(VerificationError::InvalidOpeningArgument)?; + + println!( + "[Counter Trace u32-Len] local {}-u32 next {}-u32", + opened_values.trace_local.len() * 4, + opened_values.trace_next.len() * 4 + ); + opened_values + .quotient_chunks + .iter() + .enumerate() + .for_each(|(index, chunk)| { + println!( + "[Counter quotient_chunk-{} u32-Len] local {}-u32 next {}-u32", + index, + chunk.len() * 4, + chunk.len() * 4 + ); + }); + + let zps = quotient_chunks_domains + .iter() + .enumerate() + .map(|(i, domain)| { + quotient_chunks_domains + .iter() + .enumerate() + .filter(|(j, _)| *j != i) + .map(|(_, other_domain)| { + other_domain.zp_at_point(zeta) + * other_domain + .zp_at_point(domain.first_point()) + .inverse() + .into() + }) + .product::() + }) + .collect_vec(); + + let quotient = opened_values + .quotient_chunks + .iter() + .enumerate() + .map(|(ch_i, ch)| { + ch.iter() + .enumerate() + .map(|(e_i, &c)| zps[ch_i] * SC::Challenge::monomial(e_i) * c) + .sum::() + }) + .sum::(); + let denomiator_inverse = quotient_chunks_domains + .iter() + .enumerate() + .map(|(i, domain)| { + quotient_chunks_domains + .iter() + .enumerate() + .filter(|(j, _)| *j != i) + .map(|(_, other_domain)| { + other_domain + .zp_at_point(domain.first_point()) + .inverse() + .into() + }) + .product::>() + }) + .collect_vec(); + let generator = Val::::two_adic_generator(degree_bits + log_quotient_degree); + + let quotient_chunk_nums = quotient_chunks_domains.len(); + + let manager_for_quotient = manager_assign.next_manager(); + { + let manager = manager_for_quotient.lock().unwrap(); + compute_quotient_expr::, SC::Challenge>( + zeta, + degree, + generator, + quotient_chunk_nums, + opened_values.quotient_chunks.clone(), + denomiator_inverse, + quotient, + manager, + ); + } + + manager_assign + .managers() + .iter() + .enumerate() + .for_each(|(manager_index, manager)| { + manager.lock().unwrap().embed_hint_verify::>(); + manager.lock().unwrap().run(false); + println!( + "||optimize script_len {}-kb ||", + manager.lock().unwrap().get_script_len() / 1024 + ); + }); + + let sels = trace_domain.selectors_at_point(zeta); + + let main = VerticalPair::new( + RowMajorMatrixView::new_row(&opened_values.trace_local), + RowMajorMatrixView::new_row(&opened_values.trace_next), + ); + + let mut folder = VerifierConstraintFolder { + main, + public_values, + is_first_row: sels.is_first_row, + is_last_row: sels.is_last_row, + is_transition: sels.is_transition, + alpha, + accumulator: SC::Challenge::zero(), + }; + air.eval(&mut folder); + let folded_constraints = folder.accumulator; + + // Finally, check that + // folded_constraints(zeta) / Z_H(zeta) = quotient(zeta) + if folded_constraints * sels.inv_zeroifier != quotient { + return Err(VerificationError::OodEvaluationMismatch); + } + + let log_n = log2_strict_usize(degree); + let sels_expr = selectors_at_point_expr(Val::::one(), zeta, log_n); + let mut script_folder = ScriptConstraintBuilder::new_with_expr( + opened_values.trace_local.clone(), + opened_values.trace_next.clone(), + public_values.len(), + sels_expr.is_first_row, + sels_expr.is_last_row, + sels_expr.is_transition, + alpha.into(), + ); + + air.eval(&mut script_folder); + let mut stack = StackTracker::new(); + let mut var_getter = BTreeMap::new(); + let mut optimize = BTreeMap::new(); + script_folder.set_variable_values(public_values, &mut var_getter, &mut stack); + + let acc_expr = script_folder.get_accmulator_expr(); + let equal_expr = acc_expr.equal_verify_for_f(folder.accumulator); + equal_expr.simulate_express(&mut optimize); + equal_expr.express_to_script(&mut stack, &mut var_getter, &mut optimize, true); + script_folder.drop_variable_values(&mut var_getter, &mut stack); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + println!( + "[compute trace open] optimize script: {:?}-kb", + stack.get_script().len() / 1024 + ); + Ok(()) +} + +#[derive(Debug)] +pub enum VerificationError { + InvalidProofShape, + /// An error occurred while verifying the claimed openings. + InvalidOpeningArgument(PcsErr), + /// Out-of-domain evaluation mismatch, i.e. `constraints(zeta)` did not match + /// `quotient(zeta) Z_H(zeta)`. + OodEvaluationMismatch, +} diff --git a/uni-stark/src/scripts/bf_unistark.rs b/uni-stark/src/scripts/bf_unistark.rs index 3cac16c..0849b9f 100644 --- a/uni-stark/src/scripts/bf_unistark.rs +++ b/uni-stark/src/scripts/bf_unistark.rs @@ -1,12 +1,12 @@ use std::cell::Cell; use std::collections::BTreeMap; -use std::sync::Arc; +use std::sync::{Arc, MutexGuard}; use bitcoin_script_stack::stack::{StackTracker, StackVariable}; use itertools::Itertools; use p3_field::ExtensionField; use primitives::field::BfField; -use script_expr::{Expression, FieldScriptExpression}; +use script_expr::{Dsl, Expression, InputManager}; use scripts::u31_lib::u31_equalverify; use crate::get_table; @@ -20,9 +20,8 @@ pub fn compute_quotient_expr>, //hint denominator_inverse: Vec, -) -> ( - FieldScriptExpression, - Vec>, + quotient_res: Challenge, + mut manager: MutexGuard>, ) { assert_eq!(open_values.len(), quotient_chunk_nums); assert_eq!(denominator_inverse.len(), quotient_chunk_nums); @@ -32,25 +31,27 @@ pub fn compute_quotient_expr( challenger: &mut SC::Challenger, proof: &Proof, public_values: &Vec>, - script_managers: &mut Vec, ) -> Result<(), VerificationError>> where SC: StarkGenericConfig, - A: Air>> - + for<'a> Air> - + Air>, + A: Air>> + for<'a> Air>, Val: BfField, SC::Challenge: BfField, { @@ -108,7 +103,6 @@ where ], opening_proof, challenger, - script_managers, ) .map_err(VerificationError::InvalidOpeningArgument)?; @@ -169,34 +163,6 @@ where if folded_constraints * sels.inv_zeroifier != quotient { return Err(VerificationError::OodEvaluationMismatch); } - - let log_n = log2_strict_usize(degree); - let sels_expr = selectors_at_point_expr(Val::::one(), zeta, log_n); - let mut script_folder = ScriptConstraintBuilder::new_with_expr( - opened_values.trace_local.clone(), - opened_values.trace_next.clone(), - public_values.len(), - sels_expr.is_first_row, - sels_expr.is_last_row, - sels_expr.is_transition, - alpha.into(), - ); - - air.eval(&mut script_folder); - let mut stack = StackTracker::new(); - let mut bmap = BTreeMap::new(); - script_folder.set_variable_values(public_values, &mut bmap, &mut stack); - - let acc_expr = script_folder.get_accmulator_expr(); - - let equal_expr = acc_expr.equal_verify_for_f(folder.accumulator); - equal_expr.express_to_script(&mut stack, &bmap); - - stack.debug(); - script_folder.drop_variable_values(&mut bmap, &mut stack); - stack.op_true(); - let res = stack.run(); - assert!(res.success); Ok(()) } diff --git a/uni-stark/tests/fib_air.rs b/uni-stark/tests/fib_air.rs index b2b6c98..fdb0cd4 100644 --- a/uni-stark/tests/fib_air.rs +++ b/uni-stark/tests/fib_air.rs @@ -22,12 +22,13 @@ use primitives::field::BfField; use primitives::mmcs::taptree_mmcs::TapTreeMmcs; use rand::{thread_rng, Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; -use script_expr::Expression; +use script_expr::{Expression, ManagerAssign}; use script_manager::bc_assignment::DefaultBCAssignment; use scripts::execute_script_with_inputs; use scripts::u31_lib::{u31ext_equalverify, BabyBear4}; use uni_stark::{ - compute_quotient_expr, get_log_quotient_degree, prove, verify, Proof, StarkConfig, + compute_quotient_expr, generate_script_verifier, get_log_quotient_degree, prove, verify, Proof, + StarkConfig, }; /// For testing the public values feature @@ -153,16 +154,36 @@ fn test_public_value() { let permutation = Blake3Permutation {}; let mut challenger = Challenger::new(permutation).unwrap(); - let mut script_manager = vec![]; - verify( - &config, - &FibonacciAir {}, - &mut challenger, - &proof, - &pis, - &mut script_manager, - ) - .expect("verification failed"); + verify(&config, &FibonacciAir {}, &mut challenger, &proof, &pis).expect("verification failed"); +} + +#[test] +fn test_generate_script_expr() { + let val_mmcs = ValMmcs::new(); + let challenge_mmcs = ChallengeMmcs::new(); + let dft = Dft {}; + let trace = generate_trace_rows::(0, 1, 1 << 3); + let fri_config = FriConfig { + log_blowup: 2, + num_queries: 28, + proof_of_work_bits: 8, + mmcs: challenge_mmcs, + }; + let pcs = MyPcs::new(dft, val_mmcs, fri_config); + let config = MyConfig::new(pcs); + let permutation = Blake3Permutation {}; + let mut challenger = Challenger::new(permutation).unwrap(); + let pis = vec![ + BabyBear::from_canonical_u64(0), + BabyBear::from_canonical_u64(1), + BabyBear::from_canonical_u64(21), + ]; + let proof = prove(&config, &FibonacciAir {}, &mut challenger, trace, &pis); + + let permutation = Blake3Permutation {}; + let mut challenger = Challenger::new(permutation).unwrap(); + generate_script_verifier(&config, &FibonacciAir {}, &mut challenger, &proof, &pis) + .expect("verification failed"); } #[test] @@ -270,52 +291,27 @@ fn test_quotient_zeta() { }) .collect_vec(); - let (q_zeta, _hint_verify) = compute_quotient_expr::( + let mut manager_assign = ManagerAssign::new(); + let manager = manager_assign.next_manager(); + + compute_quotient_expr::( zeta, degree, generator, quotient_chunk_nums, opened_values.quotient_chunks, denomiator_inverse, + quotient, + manager.lock().unwrap(), ); - let mut stack = StackTracker::new(); - let bmap = BTreeMap::new(); - let script = q_zeta.express_to_script(&mut stack, &bmap); - - stack.bignumber(quotient.as_u32_vec()); - - stack.custom( - u31ext_equalverify::(), - 2, - false, - 0, - "u31ext_equalverify", - ); - stack.op_true(); - let res = stack.run(); - assert!(res.success); - - // let mut bc_assigner = DefaultBCAssignment::new(); - // let mut exec_script_info = compute_quotient_zeta_script::( - // quotient_chunk_nums, - // zps, - // opened_values.quotient_chunks, - // quotient, - // ); - - // exec_script_info.gen(&mut bc_assigner); - - // let res = - // execute_script_with_inputs(exec_script_info.get_eq_script(), exec_script_info.witness()); - // assert!(res.success); - - // let res = execute_script_with_inputs( - // exec_script_info.get_neq_script(), - // exec_script_info.witness(), - // ); - // assert!(!res.success); + { + let mut m = manager.lock().unwrap(); + m.embed_hint_verify::(); + m.run(false); + } } + // #[cfg(debug_assertions)] // #[test] // #[should_panic(expected = "assertion `left == right` failed: constraints had nonzero value")] From e427d6e723fb4e842b1040b2b844a182985d7d25 Mon Sep 17 00:00:00 2001 From: 0xhhh <52317293+cyl19970726@users.noreply.github.com> Date: Wed, 7 Aug 2024 20:30:54 +0800 Subject: [PATCH 17/25] Update README.md --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 66876aa..0e81e8c 100644 --- a/README.md +++ b/README.md @@ -15,17 +15,18 @@ Bf-Stark does not need to depend on the implementation of OP_CAT. - [x] compute selector script_expr - [x] compute quotient script_expr - [x] compute constraints script_expr -- [ ] two-adic-pcs script_expr -- [ ] fri script_expr +- [x] two-adic-pcs script_expr +- [x] fri script_expr - [ ] challenge script_expr ### ScriptExpr - [x] support input variable -- [ ] automatic management of input variables -- [ ] implement copy variable to optimize the compiler +- [x] automatic management of input variables + - [ ] automatic computation of the number of inputs +- [x] implement copy variable to optimize the compiler - [ ] Implementing automatic segmentation tool - [ ] bitcommitment assign - [ ] extract intermidiate value -- [ ] add verify hint gadget +- [x] add verify hint gadget From 212429f27dec11ef48244dbd841f37527ce7495c Mon Sep 17 00:00:00 2001 From: cyl19970726 <15258378443@163.com> Date: Fri, 16 Aug 2024 12:00:48 +0800 Subject: [PATCH 18/25] add value_manager --- fri/src/script_verifier.rs | 6 +- script_expr/src/input_manager.rs | 93 +++++++++++++++++-------------- script_expr/src/lib.rs | 2 + script_expr/src/script_builder.rs | 15 +++++ script_expr/src/value_manager.rs | 39 +++++++++++++ uni-stark/src/script_verifier.rs | 34 ++++++----- uni-stark/tests/fib_air.rs | 19 +++++-- 7 files changed, 145 insertions(+), 63 deletions(-) create mode 100644 script_expr/src/value_manager.rs diff --git a/fri/src/script_verifier.rs b/fri/src/script_verifier.rs index e865540..500c79b 100644 --- a/fri/src/script_verifier.rs +++ b/fri/src/script_verifier.rs @@ -38,7 +38,8 @@ where let log_max_height = proof.commit_phase_commits.len() + config.log_blowup; let mut manager_assign = ManagerAssign::new(); for (&index, query_proof) in izip!(&challenges.query_indices, &proof.query_proofs,) { - let cur_manager = manager_assign.next_manager(); + let cur_manager = manager_assign + .next_manager_with_name(format!("[fri-pcs-verify query_index:{}] ", index)); let ro = { let mut manager: std::sync::MutexGuard> = cur_manager.lock().unwrap(); open_input(index, &query_proof.input_proof, manager) @@ -58,7 +59,8 @@ where { let mut manager = cur_manager.lock().unwrap(); - manager.set_exec_dsl(folded_eval.equal_for_f(proof.final_poly).into()); + let final_poly_input = manager.assign_input_f::(proof.final_poly); + manager.set_exec_dsl(folded_eval.equal(final_poly_input).into()); } } diff --git a/script_expr/src/input_manager.rs b/script_expr/src/input_manager.rs index 39f72ab..57bbdb6 100644 --- a/script_expr/src/input_manager.rs +++ b/script_expr/src/input_manager.rs @@ -5,6 +5,7 @@ use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::sync::{Arc, Mutex, RwLock}; +use bitcoin::hashes::serde::de::value; use bitcoin_script_stack::stack::StackTracker; use lazy_static::lazy_static; use primitives::field::BfField; @@ -14,7 +15,7 @@ use crate::script_gen::*; use crate::variable::VarWithValue; use crate::{ get_opid, Dsl, ExprPtr, Expression, IdCount, InputOpcode, ScriptExprError, StackVariable, - ValueVariable, Variable, DYNAMIC_INPUT_OR_OUTPUT, + ValueCounter, ValueVariable, Variable, DYNAMIC_INPUT_OR_OUTPUT, }; pub struct ManagerAssign { @@ -54,6 +55,13 @@ impl ManagerAssign { manager } + pub fn add_manager_with_name(&mut self, name: String) -> Arc>> { + let manager: Arc>> = + Arc::new(Mutex::new(Box::new(InputManager::new_with_name(name)))); + self.managers.push(manager.clone()); + manager + } + pub fn next_manager(&mut self) -> Arc>> { if self.current_index.is_none() { self.current_index = Some(0); @@ -63,6 +71,15 @@ impl ManagerAssign { self.add_manager() } + pub fn next_manager_with_name(&mut self, name: String) -> Arc>> { + if self.current_index.is_none() { + self.current_index = Some(0); + } else { + self.current_index = Some(self.current_index.unwrap() + 1); + } + self.add_manager_with_name(name) + } + pub fn current_manager(&self) -> Arc>> { self.managers .get(self.current_index.unwrap()) @@ -81,15 +98,6 @@ impl ManagerAssign { self.managers.get(index).unwrap().clone() } - pub fn next(&mut self) { - if self.current_index.is_none() { - panic!("current_index no set"); - } else { - self.current_index = Some(self.current_index.unwrap() + 1); - } - assert!(self.current_index.unwrap() <= self.managers.len()); - } - pub fn assign_input(&self, value: Vec) -> Dsl { self.current_manager().lock().unwrap().assign_input(value) } @@ -106,9 +114,21 @@ impl ManagerAssign { let (stack, var_getter) = binding.lock().unwrap().simulate_input(); (stack, var_getter) } + + pub fn set_value_count(&self, value_count: &mut ValueCounter) { + self.managers.iter().for_each(|manager| { + let manager = manager.lock().unwrap(); + manager.input_var.iter().for_each(|var| { + var.value.iter().for_each(|value| { + value_count.get_or_set(*value); + }); + }); + }); + } } pub struct InputManager { + name: String, counter: usize, input_var: Vec, input_hint: Vec, @@ -121,7 +141,12 @@ pub struct InputManager { impl InputManager { pub(crate) fn new() -> Self { + Self::new_with_name("".to_string()) + } + + pub(crate) fn new_with_name(name: String) -> Self { Self { + name: name, counter: 0, input_var: vec![], input_hint: vec![], @@ -133,6 +158,10 @@ impl InputManager { } } + fn set_name(&mut self, name: String) { + self.name = name; + } + pub fn set_exec_dsl(&mut self, exec_dsl: ExprPtr) { self.exec_dsl = Some(exec_dsl); } @@ -251,38 +280,11 @@ impl InputManager { self.stack.get_script().len() } - // pub(crate) fn assign_public_exprs(&mut self, value: Vec) -> Dsl { - // Dsl::new(Arc::new(RwLock::new(Box::new( - // self.assign_input_opcode(value), - // )))) - // } - - // pub(crate) fn assign_trace_exprs(&mut self, local: Vec, next: Vec) { - // let width = local.len(); - // let main_variables: Vec> = [local, next] - // .into_iter() - // .enumerate() - // .flat_map(|(row_index, row_values)| { - // (0..width).map(move |column_index| { - // ValueVariable::new( - // Variable::new(row_index, column_index), - // row_values[column_index], - // ) - // }) - // }) - // .collect(); - // self.trace_open = main_variables; - // } - - // pub(crate) fn end(&mut self, stack: &mut StackTracker){ - // self.input_vars.iter().for_each(|var|{ - // let stack_var = self.var_getter.get(&var.var).unwrap(); - // println!("Dropping {:?}",stack_var); - // stack.drop(stack_var.clone()); - // }); - // } - - fn generate_input(&self) {} + pub fn print_script_len(&self) -> usize { + let sl = self.get_script_len() / 1024; + println!("name:{} ; script_len: {}-kb", self.name, sl); + sl + } } #[cfg(test)] @@ -293,7 +295,7 @@ mod tests { use scripts::u31_lib::BabyBearU31; use super::InputManager; - use crate::{Dsl, ManagerAssign}; + use crate::{Dsl, ManagerAssign, ValueCounter}; #[test] fn test_input_manager_assign() { @@ -356,5 +358,10 @@ mod tests { equal.express1(&mut stack, &var_getter, true); assert!(stack.run().success); } + + let mut vc = ValueCounter::new(); + manager_assign.set_value_count(&mut vc); + println!("value count: {}", vc.get_value_num()); + assert_eq!(vc.get_value_num(), 2); } } diff --git a/script_expr/src/lib.rs b/script_expr/src/lib.rs index e90a926..28794b4 100644 --- a/script_expr/src/lib.rs +++ b/script_expr/src/lib.rs @@ -27,6 +27,8 @@ pub mod alias; pub use alias::*; pub mod input_manager; pub use input_manager::*; +pub mod value_manager; +pub use value_manager::*; #[derive(Debug, Clone, Copy)] pub enum ScriptExprError { diff --git a/script_expr/src/script_builder.rs b/script_expr/src/script_builder.rs index 3be30f7..ea4d6c0 100644 --- a/script_expr/src/script_builder.rs +++ b/script_expr/src/script_builder.rs @@ -9,6 +9,7 @@ use primitives::field::BfField; use scripts::treepp::*; use super::{Dsl, ValueVariable, Variable}; +use crate::ValueCounter; pub struct ScriptConstraintBuilder { pub main: RowMajorMatrix>, @@ -125,6 +126,20 @@ impl ScriptConstraintBuilder { } } + pub fn set_value_count(&self, vc: &mut ValueCounter) { + // for i in 0..self.public_values().len() { + // let value = self.var + // vc.get_or_set(self.public_values()[i].as_u32()); + // } + + for i in 0..self.main().values.len() { + let fvalue = self.main.values[i].get_value().unwrap().as_u32_vec(); + for j in 0..fvalue.len() { + vc.get_or_set(fvalue[j]); + } + } + } + pub fn drop_variable_values( &self, bmap: &mut BTreeMap, diff --git a/script_expr/src/value_manager.rs b/script_expr/src/value_manager.rs new file mode 100644 index 0000000..f86bbaf --- /dev/null +++ b/script_expr/src/value_manager.rs @@ -0,0 +1,39 @@ +use std::collections::HashMap; + +pub struct ValueCounter { + value_num: u32, + value_register: HashMap, +} + +impl ValueCounter { + pub fn new() -> Self { + ValueCounter { + value_num: 0, + value_register: HashMap::new(), + } + } + + fn set_value_bitcomm(&mut self, value: u32) { + self.value_num += 1; + let res = self.value_register.insert(value, true); + assert!(res.is_none()); + } + + fn get_value_bitcomm(&self, value: u32) -> Option<&bool> { + self.value_register.get(&value) + } + + pub(crate) fn get_or_set(&mut self, value: u32) -> bool { + let exist = self.get_value_bitcomm(value); + if exist.is_some() { + *exist.unwrap() + } else { + self.set_value_bitcomm(value); + true + } + } + + pub fn get_value_num(&self) -> u32 { + self.value_num + } +} diff --git a/uni-stark/src/script_verifier.rs b/uni-stark/src/script_verifier.rs index 74c9b5e..41f88d9 100644 --- a/uni-stark/src/script_verifier.rs +++ b/uni-stark/src/script_verifier.rs @@ -15,7 +15,9 @@ use primitives::bf_pcs::{Pcs, PcsExpr}; use primitives::field::BfField; use script_expr::{ selectors_at_point_expr, Dsl, InputManager, ManagerAssign, ScriptConstraintBuilder, + ValueCounter, }; +use serde::de::value; use tracing::instrument; use crate::symbolic_builder::{self, get_log_quotient_degree, SymbolicAirBuilder}; @@ -180,7 +182,8 @@ where let quotient_chunk_nums = quotient_chunks_domains.len(); - let manager_for_quotient = manager_assign.next_manager(); + let manager_for_quotient = + manager_assign.next_manager_with_name("[compute quotient]".to_string()); { let manager = manager_for_quotient.lock().unwrap(); compute_quotient_expr::, SC::Challenge>( @@ -195,18 +198,20 @@ where ); } - manager_assign - .managers() - .iter() - .enumerate() - .for_each(|(manager_index, manager)| { - manager.lock().unwrap().embed_hint_verify::>(); - manager.lock().unwrap().run(false); - println!( - "||optimize script_len {}-kb ||", - manager.lock().unwrap().get_script_len() / 1024 - ); - }); + let total_script_len = + manager_assign + .managers() + .iter() + .enumerate() + .fold(0, |acc, (manager_index, manager)| { + manager.lock().unwrap().embed_hint_verify::>(); + manager.lock().unwrap().run(false); + acc + manager.lock().unwrap().print_script_len() + }); + println!("total script: {:?}-kb", total_script_len); + let mut value_count = ValueCounter::new(); + manager_assign.set_value_count(&mut value_count); + println!("u32_count: {}", value_count.get_value_num()); let sels = trace_domain.selectors_at_point(zeta); @@ -263,6 +268,9 @@ where "[compute trace open] optimize script: {:?}-kb", stack.get_script().len() / 1024 ); + + script_folder.set_value_count(&mut value_count); + println!("value_count: {}", value_count.get_value_num()); Ok(()) } diff --git a/uni-stark/tests/fib_air.rs b/uni-stark/tests/fib_air.rs index fdb0cd4..e886c17 100644 --- a/uni-stark/tests/fib_air.rs +++ b/uni-stark/tests/fib_air.rs @@ -145,11 +145,16 @@ fn test_public_value() { let config = MyConfig::new(pcs); let permutation = Blake3Permutation {}; let mut challenger = Challenger::new(permutation).unwrap(); + + let len = trace.values.len(); + let output = trace.values[len - 1].clone(); let pis = vec![ BabyBear::from_canonical_u64(0), BabyBear::from_canonical_u64(1), - BabyBear::from_canonical_u64(21), + output, ]; + + // assert_eq!(BabyBear::from_canonical_u64(21),trace.clone().values[len-1]); let proof = prove(&config, &FibonacciAir {}, &mut challenger, trace, &pis); let permutation = Blake3Permutation {}; @@ -164,20 +169,24 @@ fn test_generate_script_expr() { let dft = Dft {}; let trace = generate_trace_rows::(0, 1, 1 << 3); let fri_config = FriConfig { - log_blowup: 2, - num_queries: 28, - proof_of_work_bits: 8, + log_blowup: 4, + num_queries: 16, + proof_of_work_bits: 26, mmcs: challenge_mmcs, }; let pcs = MyPcs::new(dft, val_mmcs, fri_config); let config = MyConfig::new(pcs); let permutation = Blake3Permutation {}; let mut challenger = Challenger::new(permutation).unwrap(); + + let len = trace.values.len(); + let output = trace.values[len - 1].clone(); let pis = vec![ BabyBear::from_canonical_u64(0), BabyBear::from_canonical_u64(1), - BabyBear::from_canonical_u64(21), + output, ]; + let proof = prove(&config, &FibonacciAir {}, &mut challenger, trace, &pis); let permutation = Blake3Permutation {}; From d1b82d1203d79be3cec3ac207b9db7fa134367cd Mon Sep 17 00:00:00 2001 From: 0xhhh <52317293+cyl19970726@users.noreply.github.com> Date: Mon, 19 Aug 2024 17:36:59 +0800 Subject: [PATCH 19/25] fix test (#31) --- uni-stark/tests/fib_air.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uni-stark/tests/fib_air.rs b/uni-stark/tests/fib_air.rs index e886c17..0407b3f 100644 --- a/uni-stark/tests/fib_air.rs +++ b/uni-stark/tests/fib_air.rs @@ -169,9 +169,9 @@ fn test_generate_script_expr() { let dft = Dft {}; let trace = generate_trace_rows::(0, 1, 1 << 3); let fri_config = FriConfig { - log_blowup: 4, + log_blowup: 2, num_queries: 16, - proof_of_work_bits: 26, + proof_of_work_bits: 8, mmcs: challenge_mmcs, }; let pcs = MyPcs::new(dft, val_mmcs, fri_config); From e76ad7273963bde366ae24d2c796bd094d9854cb Mon Sep 17 00:00:00 2001 From: dylanCai9 <22110240060@m.fudan.edu.cn> Date: Mon, 26 Aug 2024 14:55:27 +0800 Subject: [PATCH 20/25] blake3 challenger expr (#30) * blake3 challenger expr * add PermutationField * reverse_bits_len dsl version * compute x_hint * remove index hint for bit_reverse_len * verify hint of challenger --- fri/Cargo.toml | 3 +- fri/src/script_verifier.rs | 15 +- primitives/src/challenger/mod.rs | 3 + script_expr/Cargo.toml | 5 +- script_expr/src/alias.rs | 118 +++++++++++ script_expr/src/challenger_expr.rs | 299 +++++++++++++++++++++++++++ script_expr/src/lib.rs | 3 + script_expr/src/script_gen.rs | 151 +++++++++++++- script_expr/src/script_helper.rs | 44 +++- scripts/src/lib.rs | 12 +- uni-stark/Cargo.toml | 2 +- uni-stark/src/config.rs | 17 +- uni-stark/src/script_verifier.rs | 30 ++- uni-stark/src/scripts/bf_unistark.rs | 4 +- uni-stark/tests/fib_air.rs | 20 +- 15 files changed, 697 insertions(+), 29 deletions(-) create mode 100644 script_expr/src/challenger_expr.rs diff --git a/fri/Cargo.toml b/fri/Cargo.toml index 7fdb803..bb878c0 100644 --- a/fri/Cargo.toml +++ b/fri/Cargo.toml @@ -8,7 +8,8 @@ license = "MIT OR Apache-2.0" bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } -bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git"} +#bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git"} +bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git", branch = "bf-stark"} p3-commit ={ git = "https://github.com/Plonky3/Plonky3.git" } p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git" } diff --git a/fri/src/script_verifier.rs b/fri/src/script_verifier.rs index 500c79b..1c93482 100644 --- a/fri/src/script_verifier.rs +++ b/fri/src/script_verifier.rs @@ -1,9 +1,11 @@ use alloc::vec; use alloc::vec::Vec; use core::panic; +use std::collections::BTreeMap; use std::sync::{Arc, Mutex, MutexGuard}; use bitcoin::taproot::TapLeaf; +use bitcoin_script_stack::stack::StackTracker; use itertools::izip; use p3_field::AbstractField; use p3_util::reverse_bits_len; @@ -12,7 +14,8 @@ use primitives::mmcs::bf_mmcs::BFMmcs; use primitives::mmcs::point::{Point, PointsLeaf}; use primitives::mmcs::taptree_mmcs::CommitProof; use script_expr::{Dsl, InputManager, ManagerAssign}; -use scripts::execute_script_with_inputs; +use scripts::u31_lib::{u31_equalverify, u31ext_equalverify, BabyBear4}; +use scripts::{execute_script_with_inputs, BabyBear}; use tracing::{instrument, trace}; use crate::error::{FriError, SVError}; @@ -85,13 +88,15 @@ where { let mut ro_iter = reduced_openings.into_iter().peekable(); let mut folded_eval = Dsl::::zero(); - // todo: replace the rust version of reverse_bits_len as dsl version - let rev_index = reverse_bits_len(index, log_max_height); - // todo: active dsl::index_to_rou() - // let mut x = Dsl::::index_to_rou(rev_index as u32, log_max_height as u32 ); + // //TODO: fix index to rou bug and use dsl version + // let rev_index = Dsl::::reverse_bits_len::(index as u32, log_max_height as u32); + + // let mut x = rev_index.index_to_rou_dsl(log_max_height as u32); + let rev_index = reverse_bits_len(index, log_max_height); let mut x_hint = F::two_adic_generator(log_max_height).exp_u64(rev_index as u64); + let mut x = manager .lock() .unwrap() diff --git a/primitives/src/challenger/mod.rs b/primitives/src/challenger/mod.rs index 29a4cd4..389bd25 100644 --- a/primitives/src/challenger/mod.rs +++ b/primitives/src/challenger/mod.rs @@ -298,6 +298,9 @@ where panic!("the type of base or f is invalid") } // no other implementation yet self.record_sample(&sample_input, &res); + + //TODO:adapt our challenger expr implementation + //self.output_buffer.clear(); res } } diff --git a/script_expr/Cargo.toml b/script_expr/Cargo.toml index a73b4af..1d1968e 100644 --- a/script_expr/Cargo.toml +++ b/script_expr/Cargo.toml @@ -16,6 +16,8 @@ p3-dft = { git = "https://github.com/Plonky3/Plonky3.git" } p3-matrix = { git = "https://github.com/Plonky3/Plonky3.git" } p3-maybe-rayon = { git = "https://github.com/Plonky3/Plonky3.git" } p3-util = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-symmetric ={ git = "https://github.com/Plonky3/Plonky3.git" } primitives = { path = "../primitives" } scripts = {path = "../scripts"} common ={ path = "../common" } @@ -23,5 +25,4 @@ lazy_static = "1.4" tracing = "0.1.37" tracing-subscriber = { version = "0.3.17", features = ["std", "env-filter"] } -[dev-dependencies] -p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } \ No newline at end of file +[dev-dependencies] \ No newline at end of file diff --git a/script_expr/src/alias.rs b/script_expr/src/alias.rs index c595562..cb71fc7 100644 --- a/script_expr/src/alias.rs +++ b/script_expr/src/alias.rs @@ -120,6 +120,33 @@ impl Dsl { ) } + pub fn index_to_rou_dsl(self, sub_group_bits: u32) -> Self { + //assert_eq!(F::U32_SIZE, 1); + Self( + Arc::new(RwLock::new(Box::new(CustomOpcode::<1, 1, F>::new( + get_opid(), + vec![vec![sub_group_bits]], + vec![self.into()], + F::U32_SIZE as u32, // the var size must be 1 for equal op_code + StandardOpcodeId::IndexToRou, + )))), + PhantomData::, + ) + } + + pub fn reverse_bits_len(index: u32, bit_len: u32) -> Self { + Self( + Arc::new(RwLock::new(Box::new(CustomOpcode::<1, 1, F>::new( + get_opid(), + vec![vec![bit_len]], + vec![Dsl::::constant_u32(index).into()], + 1, // the var size must be 1 for equal op_code + StandardOpcodeId::ReverseBitslen, + )))), + PhantomData::, + ) + } + pub(crate) fn new_equal_verify(lhs: Self, rhs: Self) -> Dsl { Self( Arc::new(RwLock::new(Box::new(StandardOpcode::<2, 0>::new( @@ -206,6 +233,24 @@ impl Dsl { ) } + pub fn sponge_state_init() -> Self { + let vs = (0..32).map(|x| vec![0]).collect::>(); + Self( + Arc::new(RwLock::new(Box::new(CustomOpcode::< + 0, + DYNAMIC_INPUT_OR_OUTPUT, + F, + >::new( + get_opid(), + vs, + vec![], + 1, + StandardOpcodeId::Table, + )))), + PhantomData::, + ) + } + pub fn add_ext(self, rhs: Dsl) -> Dsl { assert_eq!(F::U32_SIZE, 1); assert_eq!(EF::U32_SIZE, 4); @@ -326,6 +371,55 @@ impl Dsl { pub fn constant_u32(value: u32) -> Self { Self::constant(vec![value]) } + + pub fn blake3(state: &[Self]) -> Self { + let state = state.iter().map(|x| x.clone().into()).collect::>(); + Self( + Arc::new(RwLock::new(Box::new(StandardOpcode::<33, 32>::new( + get_opid(), + state, + F::U32_SIZE as u32, + StandardOpcodeId::Blake3Perm, + )))), + PhantomData, + ) + } + + pub fn to_sample(self) -> Self { + Self( + Arc::new(RwLock::new(Box::new(StandardOpcode::<1, 8>::new( + get_opid(), + vec![self.into()], + F::U32_SIZE as u32, + StandardOpcodeId::ToSample, + )))), + PhantomData, + ) + } + + pub fn sample_base(self) -> Self { + Self( + Arc::new(RwLock::new(Box::new(StandardOpcode::<1, 1>::new( + get_opid(), + vec![self.into()], + 1, + StandardOpcodeId::SampleBase, + )))), + PhantomData, + ) + } + + pub fn sample_ext(self) -> Self { + Self( + Arc::new(RwLock::new(Box::new(StandardOpcode::<1, 1>::new( + get_opid(), + vec![self.into()], + 4, + StandardOpcodeId::SampleExt, + )))), + PhantomData, + ) + } } impl Dsl { @@ -692,6 +786,7 @@ mod tests { use p3_air::AirBuilder; use p3_field::TwoAdicField; use p3_matrix::Matrix; + use p3_util::reverse_bits_len; use primitives::field::BfField; use scripts::treepp::*; use scripts::u31_lib::{u31_equalverify, u31ext_equalverify, BabyBear4}; @@ -1203,6 +1298,29 @@ mod tests { let res = stack.run(); assert!(res.success); } + + #[test] + fn test_reverse_bits_len() { + let index = 6892339; + let bit_len = 25; + let mut stack = StackTracker::new(); + let bmap = BTreeMap::new(); + + let rev_index = Dsl::::reverse_bits_len::(index, bit_len.clone()); + + let script = rev_index.express(&mut stack, &bmap); + + let expected = reverse_bits_len(index as usize, bit_len as usize); + + stack.number(expected as u32); + + stack.debug(); + + stack.custom(u31_equalverify(), 2, false, 0, "u31_equalverify"); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + } } #[cfg(test)] diff --git a/script_expr/src/challenger_expr.rs b/script_expr/src/challenger_expr.rs new file mode 100644 index 0000000..7fedfd4 --- /dev/null +++ b/script_expr/src/challenger_expr.rs @@ -0,0 +1,299 @@ +use std::any::TypeId; +use std::marker::PhantomData; + +use common::BinomialExtensionField; +use p3_baby_bear::BabyBear; +use p3_challenger::{CanObserve, CanSample}; +use p3_field::AbstractField; +use p3_symmetric::Hash; +use primitives::challenger::chan_field::{PermutationField, U32}; +use primitives::challenger::BitExtractor; +use primitives::field::BfField; +use scripts::blake3; + +use crate::Dsl; + +// BASE is the base field of F when F is a extension field +// And BASE is exactly same with F when F is a prime field +#[derive(Clone, Debug)] +pub struct BfChallengerExpr +where + F: BfField, + PF: PermutationField<4>, +{ + sponge_state: Vec>, + input_buffer: Vec>, + output_buffer: Vec>, + + pub grind_bits: Option, + pub grind_output: F, + pub sample_input: Vec>>, + pub sample_output: Vec>, + phantom_data: PhantomData, +} + +impl BfChallengerExpr +where + F: BfField, + PF: PermutationField<4>, +{ + pub fn new() -> Result { + let mut u8_state = vec![]; + for _ in 0..32 { + u8_state.push(Dsl::constant_u32(0)); + } + //last 32bytes init as one dsl to adapt blake3_res dsl + u8_state.push(Dsl::sponge_state_init()); + Ok(Self { + sponge_state: u8_state, + input_buffer: vec![], + output_buffer: vec![], + + grind_bits: None, + grind_output: F::default(), + sample_input: vec![], + sample_output: vec![], + phantom_data: PhantomData::default(), + }) + } + + pub fn record_sample(&mut self, input: &Vec>, output: &Dsl) { + self.sample_input.push(input.clone()); + self.sample_output.push(output.clone()); + } +} + +impl BfChallengerExpr +where + F: BfField, + PF: PermutationField<4>, +{ + fn duplexing(&mut self) { + assert!(self.input_buffer.len() <= WIDTH / 2); + + for i in 0..self.input_buffer.len() { + self.sponge_state[i] = self.input_buffer[i].clone(); + } + self.input_buffer.clear(); + + //reverse for permutation bytes order + self.sponge_state.reverse(); + + // Apply blake3 permutation. + let blake3_res = Dsl::blake3(&self.sponge_state); + + self.sponge_state.clear(); + for _ in 0..32 { + self.sponge_state.push(Dsl::constant_u32(0)); + } + self.sponge_state.push(blake3_res.clone()); + + self.output_buffer.push(blake3_res.to_sample()); + } +} + +impl CanObserve for BfChallengerExpr +where + F: BfField, + PF: PermutationField<4>, +{ + fn observe(&mut self, value: PF) { + // Any buffered output is now invalid. + self.output_buffer.clear(); + + for elem in value.as_u8_array() { + self.input_buffer.push(Dsl::constant_u32(elem as u32)); + } + + if self.input_buffer.len() == 32 { + self.duplexing(); + } + } +} + +impl CanObserve<[PF; N]> + for BfChallengerExpr +where + F: BfField, + PF: PermutationField<4>, +{ + fn observe(&mut self, values: [PF; N]) { + for value in values { + self.observe(value); + } + } +} + +// for TrivialPcs +impl CanObserve>> for BfChallengerExpr +where + F: BfField, + PF: PermutationField<4>, +{ + fn observe(&mut self, valuess: Vec>) { + for values in valuess { + for value in values { + self.observe(value); + } + } + } +} + +impl CanObserve> + for BfChallengerExpr +where + F: BfField + BitExtractor, + PF: PermutationField<4>, +{ + fn observe(&mut self, values: Hash) { + for pf_val in values { + self.observe(pf_val); + } + } +} + +impl CanSample> for BfChallengerExpr +where + F: BfField, + PF: PermutationField<4>, +{ + fn sample(&mut self) -> Dsl { + // if BASE is the same with F + let mut sample_input = vec![]; + let res; + if TypeId::of::() == TypeId::of::() { + // If we have buffered inputs, we must perform a duplexing so that the challenge will + // reflect them. Or if we've run out of outputs, we must perform a duplexing to get more. + if !self.input_buffer.is_empty() || self.output_buffer.is_empty() { + self.duplexing(); + } + + let value = self + .output_buffer + .pop() + .expect("Output buffer should be non-empty"); + + sample_input.push(value.clone()); + + let output = value.sample_base(); + + res = output; + } + // else, F would be a extension field of Babybear + else if TypeId::of::() == TypeId::of::>() { + // If we have buffered inputs, we must perform a duplexing so that the challenge will + // reflect them. Or if we've run out of outputs, we must perform a duplexing to get more. + if !self.input_buffer.is_empty() || self.output_buffer.is_empty() { + self.duplexing(); + } + let value = self + .output_buffer + .pop() + .expect("Output buffer should be non-empty"); + + sample_input.push(value.clone()); + + let output = value.sample_ext(); + + res = output; + } else { + panic!("the type of base or f is invalid") + } // no other implementation yet + + res + } +} + +#[cfg(test)] +mod tests { + use std::collections::BTreeMap; + + use bitcoin_script_stack::stack::StackTracker; + use common::BinomialExtensionField; + use p3_baby_bear::BabyBear; + use p3_challenger::{CanObserve, CanSample}; + use primitives::challenger::chan_field::U32; + use primitives::challenger::{BfChallenger, Blake3Permutation}; + + use crate::challenger_expr::BfChallengerExpr; + + #[test] + fn test_challenger_expr() { + { + let mut stack = StackTracker::new(); + let mut var_getter = BTreeMap::new(); + let mut optimize = BTreeMap::new(); + + let mut challenger = BfChallengerExpr::::new().unwrap(); + + let value = [1 as u8; 4]; + challenger.observe(value.clone()); + + let t = challenger.sample(); + + // t.simulate_express(&mut optimize); + // t.express_to_script(&mut stack, &mut var_getter, &mut optimize, true); + + challenger.observe(value.clone()); + + let t1 = challenger.sample(); + + t1.simulate_express(&mut optimize); + t1.express_to_script(&mut stack, &mut var_getter, &mut optimize, true); + + stack.number(1103171332 as u32); + stack.debug(); + stack.op_equal(); + + stack.debug(); + let res = stack.run(); + assert!(res.success); + } + + { + let mut stack = StackTracker::new(); + let mut var_getter = BTreeMap::new(); + let mut optimize = BTreeMap::new(); + + let mut challenger = + BfChallengerExpr::, U32, 64>::new().unwrap(); + + let value = [1 as u8, 2 as u8, 3 as u8, 4 as u8]; + challenger.observe(value.clone()); + + let _t = challenger.sample(); + + challenger.observe(value.clone()); + + let t1 = challenger.sample(); + + //t1.express_to_script(&mut stack, &bmap); + + let permutation = Blake3Permutation {}; + let mut challenger = BfChallenger::< + BinomialExtensionField, + U32, + Blake3Permutation, + 16, + >::new(permutation) + .unwrap(); + let value = [1 as u8, 2 as u8, 3 as u8, 4 as u8]; + + challenger.observe(value.clone()); + let _t_value = challenger.sample(); + + challenger.observe(value); + let t1_value = challenger.sample(); + + let equal = t1.equal_for_f(t1_value); + + equal.simulate_express(&mut optimize); + equal.express_to_script(&mut stack, &mut var_getter, &mut optimize, true); + + stack.debug(); + + let res = stack.run(); + assert!(res.success); + } + } +} diff --git a/script_expr/src/lib.rs b/script_expr/src/lib.rs index 28794b4..8ce64c8 100644 --- a/script_expr/src/lib.rs +++ b/script_expr/src/lib.rs @@ -30,6 +30,9 @@ pub use input_manager::*; pub mod value_manager; pub use value_manager::*; +mod challenger_expr; +pub use challenger_expr::BfChallengerExpr; + #[derive(Debug, Clone, Copy)] pub enum ScriptExprError { DoubleCopy, diff --git a/script_expr/src/script_gen.rs b/script_expr/src/script_gen.rs index 550edb8..83842ba 100644 --- a/script_expr/src/script_gen.rs +++ b/script_expr/src/script_gen.rs @@ -2,16 +2,21 @@ use std::collections::BTreeMap; use bitcoin_script::script; use bitcoin_script_stack::stack::StackTracker; -use p3_util::log2_strict_usize; +use p3_util::{log2_strict_usize, reverse_bits_len}; use primitives::field::BfField; +use scripts::blake3::blake3; +use scripts::pseudo::{OP_4DROP, OP_4FROMALTSTACK, OP_4ROLL, OP_4TOALTSTACK}; use scripts::treepp::*; use scripts::u31_lib::{ u31_add, u31_double, u31_mul, u31_neg, u31_square, u31_sub, u31_sub_u31ext, u31_to_u31ext, u31ext_add, u31ext_add_u31, u31ext_double, u31ext_equalverify, u31ext_mul, u31ext_mul_u31, u31ext_neg, u31ext_square, u31ext_sub, u31ext_sub_u31, u32_to_u31, BabyBear4, BabyBearU31, }; +use scripts::u32_std::u32_compress; -use crate::script_helper::{index_to_rou, value_exp_n}; +use crate::script_helper::{ + index_to_reverse_index, index_to_rou, reverse_bits_len_script_with_input, value_exp_n, +}; use crate::{StackVariable, Variable}; #[derive(Debug, Clone, Copy)] @@ -32,6 +37,11 @@ pub(crate) enum StandardOpcodeId { Table, Square, Double, + Blake3Perm, + ToSample, + SampleBase, + SampleExt, + ReverseBitslen, } pub(crate) type StandardOpScriptGen = dyn Fn(Vec, &mut StackTracker, &BTreeMap) -> Vec @@ -48,6 +58,10 @@ pub(crate) fn standard_script_genreator(opid: StandardOpcodeId) -> Box Box::new(op_num_to_field), StandardOpcodeId::Square => Box::new(op_square), StandardOpcodeId::Double => Box::new(op_double), + StandardOpcodeId::Blake3Perm => Box::new(op_blake3), + StandardOpcodeId::ToSample => Box::new(op_tosample), + StandardOpcodeId::SampleBase => Box::new(op_samplebase), + StandardOpcodeId::SampleExt => Box::new(op_sampleext), _ => panic!("not support"), } } @@ -71,6 +85,13 @@ pub(crate) fn custom_script_generator( op_indextorou::(custom_data.clone(), vars_size, stack, var_getter) }, ), + StandardOpcodeId::ReverseBitslen => Box::new( + move |vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap| { + op_reversebitslen::(custom_data.clone(), vars_size, stack, var_getter) + }, + ), StandardOpcodeId::Constant => Box::new( move |vars_size: Vec, stack: &mut StackTracker, @@ -234,6 +255,25 @@ pub(crate) fn op_indextorou( vars } +pub(crate) fn op_reversebitslen( + bits_len: Vec>, + _vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + //assert_eq!(indexandbits[0].len(), 1); + let vars = stack + .custom1( + index_to_reverse_index(bits_len[0][0]), + 1, + 1, + 0, + 1, + "FieldExpr::ReverseBitsLen", + ) + .unwrap(); + vars +} pub(crate) fn op_expconst( const_exp_power: Vec>, @@ -299,6 +339,7 @@ pub(crate) fn op_euqalverify( ) -> Vec { assert_eq!(vars_size[0], vars_size[1]); assert_eq!(vars_size.len(), 2); + stack.debug(); if vars_size[0] == 1 { stack.op_equalverify(); } else { @@ -568,3 +609,109 @@ pub(crate) fn op_mul( } vars } + +pub(crate) fn op_blake3( + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(vars_size.len(), 33); + let mut vars = vec![]; + vars = stack + .custom1( + script! { + {blake3()} + for i in 0..7{ + {(i+1)*4} OP_4ROLL + } + }, + 64, + 32, + 0, + 1, + "ExprBlake3Perm_Result", + ) + .unwrap(); + vars +} + +pub(crate) fn op_samplebase( + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(vars_size[0], 1); + let mut vars = vec![]; + vars = stack + .custom1( + script! { + OP_TOALTSTACK + for _ in 0..7 { + OP_DROP + } + OP_FROMALTSTACK + }, + 8 as u32, + 1, + 0, + 1, + "ExprSampleF_Result", + ) + .unwrap(); + vars +} + +pub(crate) fn op_sampleext( + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + let mut vars = vec![]; + vars = stack + .custom1( + script! { + OP_4TOALTSTACK + OP_4DROP + OP_4FROMALTSTACK + }, + 8 as u32, + 1, + 0, + 4, + "ExprSampleEF_Result", + ) + .unwrap(); + vars +} + +pub(crate) fn op_tosample( + vars_size: Vec, + stack: &mut StackTracker, + var_getter: &BTreeMap, +) -> Vec { + assert_eq!(vars_size.len(), 1); + let mut vars = vec![]; + vars = stack + .custom1( + script! { + for _ in 0..8 { + {u32_compress()} + {u32_to_u31()} + OP_TOALTSTACK + } + for _ in 0..8 { + OP_FROMALTSTACK + } + for i in 0..7{ + {i+1} OP_ROLL + } + }, + 32 as u32, + 8, + 0, + 1, + "ExprToF_Result", + ) + .unwrap(); + vars +} diff --git a/script_expr/src/script_helper.rs b/script_expr/src/script_helper.rs index c14fda2..9543c77 100644 --- a/script_expr/src/script_helper.rs +++ b/script_expr/src/script_helper.rs @@ -1,6 +1,7 @@ use alloc::vec::Vec; use alloc::{format, vec}; +use bitcoin::opcodes::{OP_FROMALTSTACK, OP_TOALTSTACK}; use primitives::field::BfField; use scripts::pseudo::{OP_4DUP, OP_4FROMALTSTACK, OP_4MUL, OP_4PICK, OP_4TOALTSTACK}; use scripts::treepp::*; @@ -13,6 +14,7 @@ use scripts::u31_lib::{ /// constraint: bits <= 31 /// input: [b_{0}, b_{1}, ..., b_{bits-1}] pub fn compress_bits(bits: usize) -> Script { + println!("bits len{:?}", bits); assert!(bits <= 31); let script = script! { for _ in 0..bits-1 { @@ -62,6 +64,25 @@ pub fn reverse_bits_len_script_with_input(input_index: u32, bits: usize) -> Scri } } +// input stack: +// index <-- top +// output stack: +// rev_index <-- top +pub(crate) fn index_to_reverse_index(bits_len: u32) -> Script { + script! { + {value_to_bits_format(bits_len)} + for i in 0..bits_len { + {i*2} OP_PICK + } + {compress_bits(bits_len as usize)} + OP_TOALTSTACK + for _ in 0..bits_len { + OP_DROP + } + OP_FROMALTSTACK + } +} + fn push_two_adic_generator_table() -> Script { script! { for i in (0..28).rev(){ @@ -119,12 +140,13 @@ pub(crate) fn value_to_bits_format(bits_len_conf: u32) -> Script { for i in (0..bits_len_conf).rev(){ {value_bit_to_altstack(i)} } - + OP_DROP for _ in 0..bits_len_conf{ OP_FROMALTSTACK } } } +//11 // value_bits_len fn value_bit_to_altstack(bits: u32) -> Script { @@ -281,6 +303,7 @@ pub(crate) fn value_exp_n(log_n: usize) -> Script { #[cfg(test)] mod tests { + use bitcoin::opcodes::{OP_DROP, OP_EQUAL}; use p3_baby_bear::BabyBear; use p3_field::extension::BinomialExtensionField; use p3_field::{AbstractField, TwoAdicField}; @@ -289,7 +312,7 @@ mod tests { type EF = BinomialExtensionField; // #[test] - // fn test_reverse_bits_20() { + // fn test_ts_20() { // for bits in 1..31 { // for _ in 0..30 { // let x: u32 = rand::thread_rng().gen(); @@ -310,6 +333,23 @@ mod tests { // } // } + #[test] + fn test_value_to_bits() { + let index = 6; + let bits_len = 3; + let script = script! { + {index as u32} + // {index_to_reverse_index(3)} + {value_to_bits_format(bits_len)} + {compress_bits(bits_len as usize)} + {6} + OP_EQUAL + }; + let res = execute_script(script); + println!("{:?}", res); + assert_eq!(res.success, true); + } + #[test] fn test_index_to_rou() { let index: u64 = 7; // 111 ; // 7= 4 + 3=(2+1) diff --git a/scripts/src/lib.rs b/scripts/src/lib.rs index baa6edb..1835150 100644 --- a/scripts/src/lib.rs +++ b/scripts/src/lib.rs @@ -57,8 +57,16 @@ pub mod u31_lib { pub fn u32_to_u31() -> Script { script! { - {BabyBearU31::MOD} - {u31_sub::()} + OP_DUP + 0 OP_LESSTHAN + OP_IF + OP_ABS + {BabyBearU31::MOD} + {u31_sub::()} + {0x80000000 as u32 - 0x78000001} OP_ADD + OP_ENDIF + {BabyBearU31::MOD} + {u31_sub::()} } } } diff --git a/uni-stark/Cargo.toml b/uni-stark/Cargo.toml index b934522..8f2865b 100644 --- a/uni-stark/Cargo.toml +++ b/uni-stark/Cargo.toml @@ -17,6 +17,7 @@ p3-dft = { git = "https://github.com/Plonky3/Plonky3.git" } p3-matrix = { git = "https://github.com/Plonky3/Plonky3.git" } p3-maybe-rayon = { git = "https://github.com/Plonky3/Plonky3.git" } p3-util = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } itertools = "0.13.0" tracing = "0.1.37" serde = { version = "1.0", default-features = false, features = ["derive", "alloc"] } @@ -29,7 +30,6 @@ common = {path = "../common"} script_expr = {path = "../script_expr"} [dev-dependencies] -p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } p3-circle = { git = "https://github.com/Plonky3/Plonky3.git" } p3-fri = { git = "https://github.com/Plonky3/Plonky3.git" } p3-keccak = { git = "https://github.com/Plonky3/Plonky3.git" } diff --git a/uni-stark/src/config.rs b/uni-stark/src/config.rs index 658b3ff..12d5809 100644 --- a/uni-stark/src/config.rs +++ b/uni-stark/src/config.rs @@ -46,18 +46,23 @@ pub trait StarkGenericConfig { type Challenger: BfGrindingChallenger + CanObserve<>::Commitment> + CanSample; + + type ChallengerDsl: CanObserve<>::Commitment> + + CanSample>; // + CanObserve<<>::Domain as PolynomialSpace>::Val> fn pcs(&self) -> &Self::Pcs; } #[derive(Debug)] -pub struct StarkConfig { +pub struct StarkConfig { pcs: Pcs, - _phantom: PhantomData<(Challenge, Challenger)>, + _phantom: PhantomData<(Challenge, Challenger, ChallengerDsl)>, } -impl StarkConfig { +impl + StarkConfig +{ pub const fn new(pcs: Pcs) -> Self { Self { pcs, @@ -66,17 +71,21 @@ impl StarkConfig { } } -impl StarkGenericConfig for StarkConfig +impl StarkGenericConfig + for StarkConfig where Challenge: ExtensionField<::Val> + BfField, Pcs: PcsExpr, Challenger: BfGrindingChallenger + CanObserve<>::Commitment> + CanSample, + ChallengerDsl: CanObserve<>::Commitment> + + CanSample>, { type Pcs = Pcs; type Challenge = Challenge; type Challenger = Challenger; + type ChallengerDsl = ChallengerDsl; fn pcs(&self) -> &Self::Pcs { &self.pcs diff --git a/uni-stark/src/script_verifier.rs b/uni-stark/src/script_verifier.rs index 41f88d9..5f09c20 100644 --- a/uni-stark/src/script_verifier.rs +++ b/uni-stark/src/script_verifier.rs @@ -12,9 +12,10 @@ use p3_matrix::dense::{RowMajorMatrix, RowMajorMatrixView}; use p3_matrix::stack::VerticalPair; use p3_util::log2_strict_usize; use primitives::bf_pcs::{Pcs, PcsExpr}; +use primitives::challenger::chan_field::U32; use primitives::field::BfField; use script_expr::{ - selectors_at_point_expr, Dsl, InputManager, ManagerAssign, ScriptConstraintBuilder, + selectors_at_point_expr, BfChallengerExpr, Dsl, InputManager, ManagerAssign, ScriptConstraintBuilder, ValueCounter, }; use serde::de::value; @@ -30,6 +31,7 @@ pub fn generate_script_verifier( config: &SC, air: &A, challenger: &mut SC::Challenger, + challenger_dsl: &mut SC::ChallengerDsl, proof: &Proof, public_values: &Vec>, ) -> Result<(), VerificationError>> @@ -53,7 +55,7 @@ where let quotient_degree = 1 << log_quotient_degree; let pcs = config.pcs(); - let trace_domain = pcs.natural_domain_for_degree(degree); + let trace_domain = pcs.natural_domain_for_degree(degree.clone()); let quotient_domain = trace_domain.create_disjoint_domain(1 << (degree_bits + log_quotient_degree)); let quotient_chunks_domains = quotient_domain.split_domains(quotient_degree); @@ -72,6 +74,7 @@ where // Observe the instance. // TODO: recover observe when we have CanObserve trait // challenger.observe(Val::::from_canonical_usize(proof.degree_bits)); + // TODO: Might be best practice to include other instance data here in the transcript, like some // encoding of the AIR. This protects against transcript collisions between distinct instances. // Practically speaking though, the only related known attack is from failing to include public @@ -79,13 +82,24 @@ where // collision, since most such changes would completely change the set of satisfying witnesses. challenger.observe(commitments.trace.clone()); + challenger_dsl.observe(commitments.trace.clone()); // challenger.observe_slice(public_values); let alpha: SC::Challenge = challenger.sample(); + let alpha_dsl = challenger_dsl.sample(); + challenger.observe(commitments.quotient_chunks.clone()); + challenger_dsl.observe(commitments.quotient_chunks.clone()); let zeta: SC::Challenge = challenger.sample(); + let zeta_dsl = challenger_dsl.sample(); + let zeta_next = trace_domain.next_point(zeta).unwrap(); + let zeta_next_dsl = zeta_dsl.clone().mul_base(Dsl::>::index_to_rou( + 1, + (*degree_bits).try_into().unwrap(), + )); + let mut manager_assign = pcs .generate_verify_expr( vec![ @@ -187,7 +201,7 @@ where { let manager = manager_for_quotient.lock().unwrap(); compute_quotient_expr::, SC::Challenge>( - zeta, + zeta_dsl.clone(), degree, generator, quotient_chunk_nums, @@ -198,6 +212,16 @@ where ); } + //verify hint of challenger equal to challenger_dsl + let manager_for_challenger = manager_assign.next_manager(); + { + let mut manager = manager_for_challenger.lock().unwrap(); + let hint_zeta = zeta_dsl.equal_for_f(zeta); + let hint_zeta_next = zeta_next_dsl.equal_for_f(zeta_next); + manager.add_hint_verify(hint_zeta.into()); + manager.add_hint_verify(hint_zeta_next.into()); + manager.set_exec_dsl(alpha_dsl.equal_for_f(alpha).into()); + } let total_script_len = manager_assign .managers() diff --git a/uni-stark/src/scripts/bf_unistark.rs b/uni-stark/src/scripts/bf_unistark.rs index 0849b9f..2524cbf 100644 --- a/uni-stark/src/scripts/bf_unistark.rs +++ b/uni-stark/src/scripts/bf_unistark.rs @@ -12,7 +12,7 @@ use scripts::u31_lib::u31_equalverify; use crate::get_table; pub fn compute_quotient_expr>( - zeta: Challenge, + zeta_dsl: Dsl, trace_degree: usize, generator: Val, quotient_chunk_nums: usize, @@ -42,7 +42,7 @@ pub fn compute_quotient_expr; type Dft = Radix2DitParallel; type MyPcs = TwoAdicFriPcs; -type MyConfig = StarkConfig; +type MyConfig = StarkConfig>; #[test] fn test_public_value() { @@ -181,6 +181,8 @@ fn test_generate_script_expr() { let len = trace.values.len(); let output = trace.values[len - 1].clone(); + let mut challenger_dsl = BfChallengerExpr::::new().unwrap(); + let pis = vec![ BabyBear::from_canonical_u64(0), BabyBear::from_canonical_u64(1), @@ -191,8 +193,15 @@ fn test_generate_script_expr() { let permutation = Blake3Permutation {}; let mut challenger = Challenger::new(permutation).unwrap(); - generate_script_verifier(&config, &FibonacciAir {}, &mut challenger, &proof, &pis) - .expect("verification failed"); + generate_script_verifier( + &config, + &FibonacciAir {}, + &mut challenger, + &mut challenger_dsl, + &proof, + &pis, + ) + .expect("verification failed"); } #[test] @@ -303,8 +312,9 @@ fn test_quotient_zeta() { let mut manager_assign = ManagerAssign::new(); let manager = manager_assign.next_manager(); + let zeta_dsl = Dsl::from(zeta); compute_quotient_expr::( - zeta, + zeta_dsl, degree, generator, quotient_chunk_nums, From 08ddcb98535165ad798558bfd6b21957e0e65bfa Mon Sep 17 00:00:00 2001 From: dylanCai9 <22110240060@m.fudan.edu.cn> Date: Thu, 29 Aug 2024 11:54:19 +0800 Subject: [PATCH 21/25] Fix index_to_rou bug (#32) * fix index_to_rou bug * optimize index 0 case * add comment --- fri/src/script_verifier.rs | 13 +++--- script_expr/src/alias.rs | 80 ++++++++++++++++++++++++-------- script_expr/src/script_helper.rs | 70 +++++++++++----------------- 3 files changed, 93 insertions(+), 70 deletions(-) diff --git a/fri/src/script_verifier.rs b/fri/src/script_verifier.rs index 1c93482..47c6599 100644 --- a/fri/src/script_verifier.rs +++ b/fri/src/script_verifier.rs @@ -89,18 +89,17 @@ where let mut ro_iter = reduced_openings.into_iter().peekable(); let mut folded_eval = Dsl::::zero(); - // //TODO: fix index to rou bug and use dsl version - // let rev_index = Dsl::::reverse_bits_len::(index as u32, log_max_height as u32); + let rev_index_dsl = Dsl::::reverse_bits_len::(index as u32, log_max_height as u32); - // let mut x = rev_index.index_to_rou_dsl(log_max_height as u32); + let mut x = rev_index_dsl.index_to_rou_dsl(log_max_height as u32); let rev_index = reverse_bits_len(index, log_max_height); let mut x_hint = F::two_adic_generator(log_max_height).exp_u64(rev_index as u64); - let mut x = manager - .lock() - .unwrap() - .assign_input::(x_hint.as_u32_vec()); + // let mut x = manager + // .lock() + // .unwrap() + // .assign_input::(x_hint.as_u32_vec()); for (log_folded_height, commit, step, &beta) in izip!( (0..log_max_height).rev(), diff --git a/script_expr/src/alias.rs b/script_expr/src/alias.rs index cb71fc7..f1f2ab0 100644 --- a/script_expr/src/alias.rs +++ b/script_expr/src/alias.rs @@ -1438,27 +1438,26 @@ mod tests2 { #[test] fn test_index_to_rou_bug() { // todo: the test below happens bug, to fix - // { - // let bmap = BTreeMap::new(); - // let mut stack = StackTracker::new(); - // let sub_group_bits = 10u32; - // let generator = BabyBear::two_adic_generator(sub_group_bits as usize); - // let index = 7u32; - // let res = generator.exp_u64(index as u64); - - // let b = Dsl::::index_to_rou(index, sub_group_bits); - // b.set_debug(); - // let b_2 = b.clone() * b; - // // let b_2 = b.square(); - // let res_expr = Dsl::constant_f(res * res); - // let equal = b_2.equal_verify(res_expr); - // equal.express1(&mut stack, &bmap,false); - // stack.op_true(); - // let res = stack.run(); - // assert!(res.success); - // println!("script_len: {:?}", stack.get_script_len()); - // } + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let sub_group_bits = 10u32; + let generator = BabyBear::two_adic_generator(sub_group_bits as usize); + let index = 7u32; + let res = generator.exp_u64(index as u64); + let b = Dsl::::index_to_rou(index, sub_group_bits); + b.set_debug(); + let b_2 = b.clone() * b; + // let b_2 = b.square(); + let res_expr = Dsl::constant_f(res * res); + let equal = b_2.equal_verify(res_expr); + equal.express1(&mut stack, &bmap,false); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + println!("script_len: {:?}", stack.get_script_len()); + } { let bmap = BTreeMap::new(); let mut stack = StackTracker::new(); @@ -1467,6 +1466,47 @@ mod tests2 { let index = 7u32; let res = generator.exp_u64(index as u64); + let b = Dsl::::index_to_rou(index, sub_group_bits); + b.set_debug(); + //let b_2 = b.clone() * b; + // let b_2 = b.square(); + let res_expr = Dsl::constant_f(res); + let equal = res_expr.equal_verify(b); + equal.express1(&mut stack, &bmap,false); + stack.op_true(); + let res = stack.run(); + assert!(res.success); + println!("script_len: {:?}", stack.get_script_len()); + } + + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let sub_group_bits = 10u32; + let generator = BabyBear::two_adic_generator(sub_group_bits as usize); + let index = 7u32; + let res = generator.exp_u64(index as u64); + + let b = Dsl::::index_to_rou(index, sub_group_bits); + let b_2 = b.clone() * b; + let res_expr = Dsl::constant_f(res * res); + let equal = b_2.equal_verify(res_expr); + equal.express(&mut stack, &bmap); + stack.op_true(); + + let res = stack.run(); + assert!(res.success); + println!("script_len: {:?}", stack.get_script_len()); + } + + { + let bmap = BTreeMap::new(); + let mut stack = StackTracker::new(); + let sub_group_bits = 10u32; + let generator = BabyBear::two_adic_generator(sub_group_bits as usize); + let index = 0u32; + let res = generator.exp_u64(index as u64); + let b = Dsl::::index_to_rou(index, sub_group_bits); let b_2 = b.clone() * b; let res_expr = Dsl::constant_f(res * res); diff --git a/script_expr/src/script_helper.rs b/script_expr/src/script_helper.rs index 9543c77..8eed7e1 100644 --- a/script_expr/src/script_helper.rs +++ b/script_expr/src/script_helper.rs @@ -229,53 +229,37 @@ pub fn index_to_rou(sub_group_bits: u32) -> Script { assert!(sub_group_bits <= 27); // 0..27 script! { + for i in (0..sub_group_bits).rev(){ + {value_to_generator_bit_altstack(i, sub_group_bits)} + } - OP_DUP - 0 - OP_EQUAL - OP_IF - // case: deal index is equal to 0 - OP_DROP - for j in (0..F::U32_SIZE).rev(){ - {F::one().as_u32_vec()[j]} - } - OP_ELSE - for i in (0..sub_group_bits).rev(){ - {value_to_generator_bit_altstack(i,sub_group_bits)} - } + // drop the 0 + OP_0 + OP_EQUALVERIFY - // drop the 0 - OP_0 - OP_EQUALVERIFY + //init res acc to F::one() + for j in (0..F::U32_SIZE).rev(){ + {F::one().as_u32_vec()[j]} + } - for _i in 0..sub_group_bits{ - OP_FROMALTSTACK + for _i in 0..sub_group_bits{ + OP_FROMALTSTACK - // bit-size - OP_DUP - {33} - OP_EQUAL - OP_IF - OP_DROP - OP_ELSE - {get_generator::()} - if F::U32_SIZE == 1{ - OP_DEPTH - OP_2 - OP_EQUAL - OP_IF - {u31_mul::()} - }else{ - OP_DEPTH - OP_8 - OP_EQUAL - OP_IF - {u31ext_mul::()} - } - OP_ENDIF - OP_ENDIF - } - OP_ENDIF + // bit-size + OP_DUP + {33} + OP_EQUAL + OP_IF + OP_DROP + OP_ELSE + {get_generator::()} + if F::U32_SIZE == 1{ + {u31_mul::()} + }else{ + {u31ext_mul::()} + } + OP_ENDIF + } } } From b651fffe4106a99316795378147f37ac28c33b54 Mon Sep 17 00:00:00 2001 From: dylanCai9 <22110240060@m.fudan.edu.cn> Date: Thu, 29 Aug 2024 21:39:37 +0800 Subject: [PATCH 22/25] Proof Serialize and Deserialize (#33) --- fri/src/proof.rs | 22 ++- fri/src/two_adic_pcs.rs | 4 +- primitives/Cargo.toml | 2 +- primitives/src/bf_pcs.rs | 4 +- primitives/src/challenger/chan_field.rs | 4 +- primitives/src/mmcs/bf_mmcs.rs | 10 +- primitives/src/mmcs/point.rs | 10 +- primitives/src/mmcs/taptree_mmcs.rs | 7 +- scripts/Cargo.toml | 1 + scripts/src/bit_comm/bit_comm.rs | 3 +- scripts/src/bit_comm/bit_comm_u32.rs | 3 +- scripts/src/bit_comm/winternitz.rs | 3 +- uni-stark/src/proof.rs | 41 ++-- uni-stark/src/script_verifier.rs | 4 +- uni-stark/tests/fib_air.rs | 248 ++++++++++++------------ 15 files changed, 184 insertions(+), 182 deletions(-) diff --git a/fri/src/proof.rs b/fri/src/proof.rs index 4a79c17..3af2a94 100644 --- a/fri/src/proof.rs +++ b/fri/src/proof.rs @@ -2,16 +2,16 @@ use alloc::vec::Vec; use bitcoin::taproot::LeafNode; use primitives::field::BfField; -// use serde::{Deserialize, Serialize}; use primitives::mmcs::bf_mmcs::BFMmcs; use primitives::mmcs::point::PointsLeaf; use primitives::mmcs::taptree_mmcs::CommitProof; -// #[derive(Serialize, Deserialize)] -// #[serde(bound( -// serialize = "Witness: Serialize", -// deserialize = "Witness: Deserialize<'de>" -// ))] -#[derive(Clone)] +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone)] +#[serde(bound( + serialize = "Witness: Serialize, InputProof: Serialize", + deserialize = "Witness: Deserialize<'de>, InputProof: Deserialize<'de>" +))] pub struct FriProof, Witness, InputProof> { pub(crate) commit_phase_commits: Vec, pub(crate) query_proofs: Vec>, @@ -21,9 +21,11 @@ pub struct FriProof, Witness, InputProof> { pub(crate) pow_witness: Witness, } -// #[derive(Serialize, Deserialize)] -// #[serde(bound = "")] -#[derive(Clone)] +#[derive(Serialize, Deserialize, Clone)] +#[serde(bound( + serialize = "InputProof: Serialize", + deserialize = "InputProof: Deserialize<'de>", +))] pub struct BfQueryProof { pub input_proof: InputProof, /// For each commit phase commitment, this contains openings of a commit phase codeword at the diff --git a/fri/src/two_adic_pcs.rs b/fri/src/two_adic_pcs.rs index 5c73b31..233a740 100644 --- a/fri/src/two_adic_pcs.rs +++ b/fri/src/two_adic_pcs.rs @@ -28,6 +28,7 @@ use primitives::field::BfField; use primitives::mmcs::bf_mmcs::BFMmcs; use primitives::mmcs::taptree_mmcs::{CommitProof, TapTreeMmcs}; use script_expr::{Dsl, InputManager, ManagerAssign}; +use serde::{Deserialize, Serialize}; use tracing::{debug_span, info_span, instrument}; use crate::error::{self, FriError}; @@ -62,7 +63,8 @@ impl TwoAdicFriPcs { } } -#[derive(Clone)] +#[derive(Serialize, Deserialize, Clone)] +#[serde(bound = "")] pub struct BatchOpening>> { pub opened_values: Vec>, pub opening_proof: >::Proof, diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 09cd3a5..b840281 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } -bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } +bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark", features = ["serde"]} bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } lazy_static = "1.4.0" itertools = "0.12.0" diff --git a/primitives/src/bf_pcs.rs b/primitives/src/bf_pcs.rs index 6b23d92..a404b7b 100644 --- a/primitives/src/bf_pcs.rs +++ b/primitives/src/bf_pcs.rs @@ -22,13 +22,13 @@ where type Domain: PolynomialSpace; /// The commitment that's sent to the verifier. - type Commitment: Clone; + type Commitment: Clone + Serialize + DeserializeOwned; /// Data that the prover stores for committed polynomials, to help the prover with opening. type ProverData; /// The opening argument. - type Proof: Clone; + type Proof: Clone + Serialize + DeserializeOwned; type Error: Debug; diff --git a/primitives/src/challenger/chan_field.rs b/primitives/src/challenger/chan_field.rs index 68a999d..c3a3f19 100644 --- a/primitives/src/challenger/chan_field.rs +++ b/primitives/src/challenger/chan_field.rs @@ -2,6 +2,8 @@ use core::array; use p3_baby_bear::BabyBear; use p3_field::PrimeField32; +use serde::de::DeserializeOwned; +use serde::Serialize; pub trait ChallengeField: PrimeField32 + Clone + Default + Copy + Ord { fn u8_num() -> usize { U8_NUM @@ -20,7 +22,7 @@ impl ChallengeField<4> for BabyBear {} // the PremutationField only support U8_NUM<=8 // Use LittleEndian pub trait PermutationField: - Clone + Default + Copy + Ord + Sized + Send + Sync + Clone + Default + Copy + Ord + Sized + Send + Sync + Serialize + DeserializeOwned { fn u8_num() -> usize { U8_NUM diff --git a/primitives/src/mmcs/bf_mmcs.rs b/primitives/src/mmcs/bf_mmcs.rs index 18d0382..43059ef 100644 --- a/primitives/src/mmcs/bf_mmcs.rs +++ b/primitives/src/mmcs/bf_mmcs.rs @@ -4,8 +4,8 @@ use core::fmt::Debug; use std::borrow::Borrow; use p3_matrix::dense::RowMajorMatrix; -// use serde::de::DeserializeOwned; -// use serde::Serialize; +use serde::de::DeserializeOwned; +use serde::Serialize; /// A "Mixed Matrix Commitment Scheme" (MMCS) is a generalization of a vector commitment scheme; it /// supports committing to matrices and then opening rows. It is also batch-oriented; one can commit @@ -17,10 +17,8 @@ use p3_matrix::dense::RowMajorMatrix; /// useful in the FRI protocol. See the documentation for `open_batch` for more details. pub trait BFMmcs: Clone { type ProverData; - // type Commitment: Clone + Serialize + DeserializeOwned; - // type Proof: Clone + Serialize + DeserializeOwned; - type Commitment: Clone; - type Proof: Clone; + type Commitment: Clone + Serialize + DeserializeOwned; + type Proof: Clone + Serialize + DeserializeOwned; type Error: Debug; fn commit(&self, inputs: Vec>) -> (Self::Commitment, Self::ProverData); diff --git a/primitives/src/mmcs/point.rs b/primitives/src/mmcs/point.rs index 761cab6..687a2fb 100644 --- a/primitives/src/mmcs/point.rs +++ b/primitives/src/mmcs/point.rs @@ -5,11 +5,13 @@ use bitcoin_script::{define_pushable, script}; use script_manager::bc_assignment::DefaultBCAssignment; use scripts::bit_comm::bit_comm::BitCommitment; use scripts::secret_generator::ConstantSecretGen; +use serde::{Deserialize, Serialize}; use crate::field::BfField; define_pushable!(); -#[derive(Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(bound = "")] pub struct PointsLeaf { leaf_index: usize, leaf_evals: Points, @@ -62,7 +64,8 @@ impl PointsLeaf { } } -#[derive(Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(bound = "")] pub struct Points { pub points: Vec>, } @@ -99,7 +102,8 @@ impl Points { } } -#[derive(Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(bound = "")] pub struct Point { pub x: F, pub y: F, diff --git a/primitives/src/mmcs/taptree_mmcs.rs b/primitives/src/mmcs/taptree_mmcs.rs index e87d05f..7e68756 100644 --- a/primitives/src/mmcs/taptree_mmcs.rs +++ b/primitives/src/mmcs/taptree_mmcs.rs @@ -8,6 +8,8 @@ use p3_matrix::dense::RowMajorMatrix; use p3_matrix::Matrix; use p3_util::log2_strict_usize; use scripts::execute_script_with_inputs; +use serde::ser::SerializeStruct; +use serde::{Deserialize, Serialize, Serializer}; use super::bf_mmcs::BFMmcs; use super::error::BfError; @@ -22,7 +24,7 @@ pub const DEFAULT_MATRIX_WIDTH: usize = 2; pub const LOG_DEFAULT_MATRIX_WIDTH: usize = 1; pub const ROOT_WIDTH: usize = 8; -#[derive(Clone, Debug, PartialEq, PartialOrd)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)] pub struct TapTreeMmcs { _marker: PhantomData, } @@ -35,7 +37,8 @@ impl TapTreeMmcs { } } -#[derive(Clone)] +#[derive(Serialize, Deserialize, Clone)] +#[serde(bound = "")] pub struct CommitProof { pub points_leaf: PointsLeaf, pub leaf_node: LeafNode, diff --git a/scripts/Cargo.toml b/scripts/Cargo.toml index 33e0a9a..6bb32de 100644 --- a/scripts/Cargo.toml +++ b/scripts/Cargo.toml @@ -19,6 +19,7 @@ p3-util = { git = "https://github.com/Plonky3/Plonky3.git" } once_cell = "1.8.0" hex = "0.4.3" itertools = "0.12.1" +serde = { version = "1.0", default-features = false, features = ["derive", "alloc", "rc"] } common = {path = "../common"} diff --git a/scripts/src/bit_comm/bit_comm.rs b/scripts/src/bit_comm/bit_comm.rs index ea5541b..491fe1d 100644 --- a/scripts/src/bit_comm/bit_comm.rs +++ b/scripts/src/bit_comm/bit_comm.rs @@ -5,6 +5,7 @@ use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; use common::AsU32Vec; use itertools::Itertools; +use serde::{Deserialize, Serialize}; use super::bit_comm_u32::BitCommitmentU32; use super::secret_generator::{SecretGen, ThreadSecretGen}; @@ -17,7 +18,7 @@ use crate::u31_lib::{u31_equalverify, u31ext_equalverify, BabyBear4}; // 2. after run this `execute_script_with_input(bc.check_and_recover(), bc.witness())`, // the u32 values should be placed on the stack for any bc. -#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq)] pub struct BitCommitment { pub u32_values: Vec, pub commitments: Vec, diff --git a/scripts/src/bit_comm/bit_comm_u32.rs b/scripts/src/bit_comm/bit_comm_u32.rs index 8a0d097..920c48c 100644 --- a/scripts/src/bit_comm/bit_comm_u32.rs +++ b/scripts/src/bit_comm/bit_comm_u32.rs @@ -1,12 +1,13 @@ use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; +use serde::{Deserialize, Serialize}; use super::winternitz::*; use crate::bit_comm::winternitz; use crate::u32_std::u32_compress; define_pushable!(); -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] pub struct BitCommitmentU32 { pub value: u32, pub winternitz: Winternitz, diff --git a/scripts/src/bit_comm/winternitz.rs b/scripts/src/bit_comm/winternitz.rs index 2d8f5aa..51b2042 100644 --- a/scripts/src/bit_comm/winternitz.rs +++ b/scripts/src/bit_comm/winternitz.rs @@ -17,6 +17,7 @@ // pub use bitcoin_script::{define_pushable, script}; +use serde::{Deserialize, Serialize}; pub use crate::execute_script; @@ -54,7 +55,7 @@ pub const N1: usize = 2; // // Helper functions // -#[derive(Default, Debug, Clone, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)] pub struct Winternitz { secret_key: String, pub_key: Vec>, diff --git a/uni-stark/src/proof.rs b/uni-stark/src/proof.rs index 8561d4d..5b46ae7 100644 --- a/uni-stark/src/proof.rs +++ b/uni-stark/src/proof.rs @@ -1,8 +1,8 @@ use alloc::vec::Vec; use primitives::bf_pcs::Pcs; +use serde::{Deserialize, Serialize}; -// use serde::{Deserialize, Serialize}; use crate::StarkGenericConfig; type Com = <::Pcs as Pcs< @@ -14,37 +14,24 @@ type PcsProof = <::Pcs as Pcs< ::Challenger, >>::Proof; -// #[derive(Serialize, Deserialize)] -// #[serde(bound = "")] -#[derive(Clone)] +#[derive(Serialize, Deserialize)] +#[serde(bound = "")] pub struct Proof { - // pub(crate) commitments: Commitments>, - // pub(crate) opened_values: OpenedValues, - // pub(crate) opening_proof: PcsProof, - // pub(crate) degree_bits: usize, - //remove crate for test - pub commitments: Commitments>, - pub opened_values: OpenedValues, - pub opening_proof: PcsProof, - pub degree_bits: usize, + pub(crate) commitments: Commitments>, + pub(crate) opened_values: OpenedValues, + pub(crate) opening_proof: PcsProof, + pub(crate) degree_bits: usize, } -// #[derive(Debug, Serialize, Deserialize)] -#[derive(Clone)] +#[derive(Debug, Serialize, Deserialize)] pub struct Commitments { - // pub(crate) trace: Com, - // pub(crate) quotient_chunks: Com, - pub trace: Com, - pub quotient_chunks: Com, + pub(crate) trace: Com, + pub(crate) quotient_chunks: Com, } -// #[derive(Debug, Serialize, Deserialize)] -#[derive(Clone)] +#[derive(Debug, Serialize, Deserialize)] pub struct OpenedValues { - // pub(crate) trace_local: Vec, - // pub(crate) trace_next: Vec, - // pub(crate) quotient_chunks: Vec>, - pub trace_local: Vec, - pub trace_next: Vec, - pub quotient_chunks: Vec>, + pub(crate) trace_local: Vec, + pub(crate) trace_next: Vec, + pub(crate) quotient_chunks: Vec>, } diff --git a/uni-stark/src/script_verifier.rs b/uni-stark/src/script_verifier.rs index 5f09c20..5d6a325 100644 --- a/uni-stark/src/script_verifier.rs +++ b/uni-stark/src/script_verifier.rs @@ -15,8 +15,8 @@ use primitives::bf_pcs::{Pcs, PcsExpr}; use primitives::challenger::chan_field::U32; use primitives::field::BfField; use script_expr::{ - selectors_at_point_expr, BfChallengerExpr, Dsl, InputManager, ManagerAssign, ScriptConstraintBuilder, - ValueCounter, + selectors_at_point_expr, BfChallengerExpr, Dsl, InputManager, ManagerAssign, + ScriptConstraintBuilder, ValueCounter, }; use serde::de::value; use tracing::instrument; diff --git a/uni-stark/tests/fib_air.rs b/uni-stark/tests/fib_air.rs index b7b501c..5eb56a6 100644 --- a/uni-stark/tests/fib_air.rs +++ b/uni-stark/tests/fib_air.rs @@ -204,132 +204,132 @@ fn test_generate_script_expr() { .expect("verification failed"); } -#[test] -fn test_quotient_zeta() { - let val_mmcs = ValMmcs::new(); - let challenge_mmcs = ChallengeMmcs::new(); - let dft = Dft {}; - let trace = generate_trace_rows::(0, 1, 1 << 3); - let fri_config = FriConfig { - log_blowup: 2, - num_queries: 28, - proof_of_work_bits: 8, - mmcs: challenge_mmcs, - }; - let pcs = MyPcs::new(dft, val_mmcs, fri_config); - let config = MyConfig::new(pcs); - let permutation = Blake3Permutation {}; - let mut challenger = Challenger::new(permutation).unwrap(); +// #[test] +// fn test_quotient_zeta() { +// let val_mmcs = ValMmcs::new(); +// let challenge_mmcs = ChallengeMmcs::new(); +// let dft = Dft {}; +// let trace = generate_trace_rows::(0, 1, 1 << 3); +// let fri_config = FriConfig { +// log_blowup: 2, +// num_queries: 28, +// proof_of_work_bits: 8, +// mmcs: challenge_mmcs, +// }; +// let pcs = MyPcs::new(dft, val_mmcs, fri_config); +// let config = MyConfig::new(pcs); +// let permutation = Blake3Permutation {}; +// let mut challenger = Challenger::new(permutation).unwrap(); - let pis = vec![ - BabyBear::from_canonical_u64(0), - BabyBear::from_canonical_u64(1), - BabyBear::from_canonical_u64(21), - ]; - let proof = prove(&config, &FibonacciAir {}, &mut challenger, trace, &pis); +// let pis = vec![ +// BabyBear::from_canonical_u64(0), +// BabyBear::from_canonical_u64(1), +// BabyBear::from_canonical_u64(21), +// ]; +// let proof = prove(&config, &FibonacciAir {}, &mut challenger, trace, &pis); + +// let Proof { +// commitments, +// opened_values, +// opening_proof, +// degree_bits, +// } = proof; + +// let degree = 1 << degree_bits; +// let log_quotient_degree = +// get_log_quotient_degree::(&FibonacciAir {}, 0, pis.len()); +// let quotient_degree = 1 << log_quotient_degree; + +// let trace_domain = TwoAdicMultiplicativeCoset { +// log_n: degree_bits, +// shift: Val::one(), +// }; +// let quotient_domain = +// trace_domain.create_disjoint_domain(1 << (degree_bits + log_quotient_degree)); +// let quotient_chunks_domains = quotient_domain.split_domains(quotient_degree); + +// let mut rng = ChaCha20Rng::seed_from_u64(0u64); + +// let zeta = rng.gen::(); + +// let a = Val::generator().try_inverse().unwrap(); + +// let generator = Val::two_adic_generator(quotient_domain.log_n); + +// let quotient_chunk_nums = quotient_chunks_domains.len(); + +// let zps = quotient_chunks_domains +// .iter() +// .enumerate() +// .map(|(i, domain)| { +// quotient_chunks_domains +// .iter() +// .enumerate() +// .filter(|(j, _)| *j != i) +// .map(|(_, other_domain)| { +// other_domain.zp_at_point(zeta) +// * other_domain.zp_at_point(domain.first_point()).inverse() +// }) +// .product::() +// }) +// .collect_vec(); + +// let quotient = opened_values +// .quotient_chunks +// .iter() +// .enumerate() +// .map(|(ch_i, ch)| { +// ch.iter() +// .enumerate() +// .map(|(e_i, &c)| { +// zps[ch_i] +// * as AbstractExtensionField< +// BabyBear, +// >>::monomial(e_i) +// * c +// }) +// .sum::() +// }) +// .sum::(); +// let denomiator_inverse = quotient_chunks_domains +// .iter() +// .enumerate() +// .map(|(i, domain)| { +// quotient_chunks_domains +// .iter() +// .enumerate() +// .filter(|(j, _)| *j != i) +// .map(|(_, other_domain)| { +// other_domain +// .zp_at_point(domain.first_point()) +// .inverse() +// .into() +// }) +// .product::() +// }) +// .collect_vec(); + +// let mut manager_assign = ManagerAssign::new(); +// let manager = manager_assign.next_manager(); + +// let zeta_dsl = Dsl::from(zeta); +// compute_quotient_expr::( +// zeta_dsl, +// degree, +// generator, +// quotient_chunk_nums, +// opened_values.quotient_chunks, +// denomiator_inverse, +// quotient, +// manager.lock().unwrap(), +// ); - let Proof { - commitments, - opened_values, - opening_proof, - degree_bits, - } = proof; - - let degree = 1 << degree_bits; - let log_quotient_degree = - get_log_quotient_degree::(&FibonacciAir {}, 0, pis.len()); - let quotient_degree = 1 << log_quotient_degree; - - let trace_domain = TwoAdicMultiplicativeCoset { - log_n: degree_bits, - shift: Val::one(), - }; - let quotient_domain = - trace_domain.create_disjoint_domain(1 << (degree_bits + log_quotient_degree)); - let quotient_chunks_domains = quotient_domain.split_domains(quotient_degree); - - let mut rng = ChaCha20Rng::seed_from_u64(0u64); - - let zeta = rng.gen::(); - - let a = Val::generator().try_inverse().unwrap(); - - let generator = Val::two_adic_generator(quotient_domain.log_n); - - let quotient_chunk_nums = quotient_chunks_domains.len(); - - let zps = quotient_chunks_domains - .iter() - .enumerate() - .map(|(i, domain)| { - quotient_chunks_domains - .iter() - .enumerate() - .filter(|(j, _)| *j != i) - .map(|(_, other_domain)| { - other_domain.zp_at_point(zeta) - * other_domain.zp_at_point(domain.first_point()).inverse() - }) - .product::() - }) - .collect_vec(); - - let quotient = opened_values - .quotient_chunks - .iter() - .enumerate() - .map(|(ch_i, ch)| { - ch.iter() - .enumerate() - .map(|(e_i, &c)| { - zps[ch_i] - * as AbstractExtensionField< - BabyBear, - >>::monomial(e_i) - * c - }) - .sum::() - }) - .sum::(); - let denomiator_inverse = quotient_chunks_domains - .iter() - .enumerate() - .map(|(i, domain)| { - quotient_chunks_domains - .iter() - .enumerate() - .filter(|(j, _)| *j != i) - .map(|(_, other_domain)| { - other_domain - .zp_at_point(domain.first_point()) - .inverse() - .into() - }) - .product::() - }) - .collect_vec(); - - let mut manager_assign = ManagerAssign::new(); - let manager = manager_assign.next_manager(); - - let zeta_dsl = Dsl::from(zeta); - compute_quotient_expr::( - zeta_dsl, - degree, - generator, - quotient_chunk_nums, - opened_values.quotient_chunks, - denomiator_inverse, - quotient, - manager.lock().unwrap(), - ); - - { - let mut m = manager.lock().unwrap(); - m.embed_hint_verify::(); - m.run(false); - } -} +// { +// let mut m = manager.lock().unwrap(); +// m.embed_hint_verify::(); +// m.run(false); +// } +// } // #[cfg(debug_assertions)] // #[test] From aba642e42b1fc60ccd2d53a9e30d80e2c397577c Mon Sep 17 00:00:00 2001 From: 0xhhh <52317293+cyl19970726@users.noreply.github.com> Date: Fri, 30 Aug 2024 10:09:42 +0800 Subject: [PATCH 23/25] Adapter bitcoin verifier (#34) * update cargo.toml && cargo fix * cargo fix test --- Cargo.toml | 23 +++++++++ fri/Cargo.toml | 6 +-- fri/src/config.rs | 2 +- fri/src/error.rs | 1 - fri/src/fold_even_odd.rs | 2 +- fri/src/fri_scripts/fiat_shamir_subtree.rs | 29 ++++------- fri/src/fri_scripts/leaf.rs | 12 ++--- fri/src/fri_scripts/pcs.rs | 32 +++++------- fri/src/fri_scripts/verify_folding.rs | 17 +++--- fri/src/proof.rs | 2 - fri/src/prover.rs | 3 +- fri/src/script_verifier.rs | 8 +-- fri/src/two_adic_pcs.rs | 13 ++--- fri/src/verifier.rs | 4 -- fri/tests/fri.rs | 60 +++++++++++----------- fri/tests/pcs.rs | 8 +-- primitives/Cargo.toml | 4 +- primitives/src/bf_pcs.rs | 2 - primitives/src/challenger/mod.rs | 8 +-- primitives/src/mmcs/bf_mmcs.rs | 1 - primitives/src/mmcs/point.rs | 1 - primitives/src/mmcs/taptree.rs | 23 +++------ primitives/src/mmcs/taptree_mmcs.rs | 5 +- script_expr/Cargo.toml | 6 +-- script_expr/src/alias.rs | 39 +++++--------- script_expr/src/challenger_expr.rs | 4 +- script_expr/src/input_manager.rs | 10 +--- script_expr/src/lib.rs | 2 +- script_expr/src/opcode.rs | 9 +--- script_expr/src/script_gen.rs | 6 +-- script_expr/src/script_helper.rs | 10 +--- script_manager/Cargo.toml | 4 +- script_manager/src/bc_assignment.rs | 7 +-- script_manager/src/planner.rs | 16 +++--- script_manager/src/script_info.rs | 7 +-- scripts/Cargo.toml | 6 +-- scripts/src/bit_comm/bit_comm.rs | 13 ++--- scripts/src/bit_comm/mod.rs | 1 - scripts/src/bit_comm/secret_generator.rs | 2 +- scripts/src/bit_comm/winternitz.rs | 2 - scripts/src/u32/u32_std.rs | 2 +- segment/Cargo.toml | 4 +- uni-stark/Cargo.toml | 6 +-- uni-stark/src/config.rs | 2 +- uni-stark/src/expr_helper.rs | 20 +++----- uni-stark/src/script_verifier.rs | 8 ++- uni-stark/src/scripts/bf_unistark.rs | 8 +-- uni-stark/src/scripts/utils.rs | 11 ++-- uni-stark/src/verifier.rs | 10 +--- uni-stark/src/zerofier_coset.rs | 2 +- uni-stark/tests/fib_air.rs | 17 ++---- 51 files changed, 191 insertions(+), 309 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 78afecd..09bef38 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,26 @@ members = [ "uni-stark" , "script_expr"] +[patch.crates-io.base58check] +git = "https://github.com/bitlayer-org/rust-bitcoin" +branch = "bitvm" + +[patch.crates-io.bitcoin] +git = "https://github.com/bitlayer-org/rust-bitcoin" +branch = "bitvm" + +[patch.crates-io.bitcoin_hashes] +git = "https://github.com/bitlayer-org/rust-bitcoin" +branch = "bitvm" + +[patch.crates-io.bitcoin-internals] +git = "https://github.com/bitlayer-org/rust-bitcoin" +branch = "bitvm" + +[patch.crates-io.bitcoin-io] +git = "https://github.com/bitlayer-org/rust-bitcoin" +branch = "bitvm" + +[patch.crates-io.bitcoin-units] +git = "https://github.com/bitlayer-org/rust-bitcoin" +branch = "bitvm" diff --git a/fri/Cargo.toml b/fri/Cargo.toml index bb878c0..8e0cc55 100644 --- a/fri/Cargo.toml +++ b/fri/Cargo.toml @@ -6,10 +6,10 @@ license = "MIT OR Apache-2.0" [dependencies] bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } -bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } -bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } +bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bitvm" } +bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec", branch = "bitvm"} #bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git"} -bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git", branch = "bf-stark"} +bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git", branch = "bitvm"} p3-commit ={ git = "https://github.com/Plonky3/Plonky3.git" } p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git" } diff --git a/fri/src/config.rs b/fri/src/config.rs index 70467a8..e3d9a7a 100644 --- a/fri/src/config.rs +++ b/fri/src/config.rs @@ -1,6 +1,6 @@ use alloc::vec::Vec; use core::fmt::Debug; -use std::sync::{Arc, Mutex, MutexGuard}; +use std::sync::MutexGuard; use p3_field::Field; use p3_matrix::Matrix; diff --git a/fri/src/error.rs b/fri/src/error.rs index 8172232..8f201c0 100644 --- a/fri/src/error.rs +++ b/fri/src/error.rs @@ -1,4 +1,3 @@ -use bitcoin::taproot::TaprootBuilderError; use primitives::mmcs::error::BfError; #[derive(Debug, PartialEq, Eq, Clone)] pub enum SVError { diff --git a/fri/src/fold_even_odd.rs b/fri/src/fold_even_odd.rs index 0814920..99d8d5b 100644 --- a/fri/src/fold_even_odd.rs +++ b/fri/src/fold_even_odd.rs @@ -62,7 +62,7 @@ mod tests { use primitives::field::BfField; use rand::{thread_rng, Rng}; use scripts::execute_script; - use scripts::u31_lib::BabyBear4; + use super::*; use crate::fri_scripts::verify_folding::fold_degree; diff --git a/fri/src/fri_scripts/fiat_shamir_subtree.rs b/fri/src/fri_scripts/fiat_shamir_subtree.rs index cc1a7ee..9255859 100644 --- a/fri/src/fri_scripts/fiat_shamir_subtree.rs +++ b/fri/src/fri_scripts/fiat_shamir_subtree.rs @@ -1,15 +1,8 @@ use std::usize; -use bitcoin::opcodes::{ - OP_2SWAP, OP_DROP, OP_ENDIF, OP_EQUALVERIFY, OP_FROMALTSTACK, OP_GREATERTHAN, - OP_GREATERTHANOREQUAL, OP_LESSTHAN, OP_LESSTHANOREQUAL, OP_PICK, OP_RESERVED2, OP_SUB, OP_SWAP, - OP_TOALTSTACK, -}; -use bitcoin::script::{self, scriptint_vec}; use bitcoin::ScriptBuf as Script; -use bitcoin_script::{define_pushable, script}; +use bitcoin_script::script; use itertools::Itertools; -use p3_field::PrimeField32; use primitives::challenger::chan_field::{PermutationField, U32}; use primitives::challenger::{BfChallenger, BitExtractor, Blake3Permutation}; use primitives::field::BfField; @@ -17,9 +10,8 @@ use script_manager::bc_assignment::DefaultBCAssignment; use scripts::bit_comm::bit_comm::BitCommitment; use scripts::bit_comm_u32::*; use scripts::blake3; -use scripts::pseudo::{OP_4DROP, OP_4FROMALTSTACK, OP_4TOALTSTACK}; -use scripts::u32_rrot::{u32_rrot, u8_extract_hbit}; -use scripts::u32_std::{u32_compress, u32_equal, u32_equalverify, u32_push}; +use scripts::pseudo::{OP_4FROMALTSTACK, OP_4TOALTSTACK}; +use scripts::u32_std::{u32_compress, u32_equalverify}; /// fiat shamir subtree contains a series script leafs and coressponding trait SubTree { @@ -223,7 +215,7 @@ fn u32_to_compressed_babybear() -> Script { } fn new_u32_bit_commit(bc_assignment: &mut DefaultBCAssignment, value: U32) -> Commit { - let mut bitcommit = bc_assignment.assign(U32_to_u32(value)); + let bitcommit = bc_assignment.assign(U32_to_u32(value)); let locking = script! { { bitcommit.commitments.get(0).unwrap().checksig_verify_script() } }; @@ -400,11 +392,10 @@ where #[cfg(test)] mod test { - use std::fmt::Debug; + - use bitcoin::opcodes::OP_EQUALVERIFY; - use bitcoin::{OutPoint, ScriptBuf as Script}; - use bitcoin_script::{define_pushable, script}; + use bitcoin::ScriptBuf as Script; + use bitcoin_script::script; use itertools::Itertools; use p3_baby_bear::BabyBear; use p3_challenger::{CanObserve, CanSample, CanSampleBits}; @@ -412,10 +403,10 @@ mod test { use p3_field::{AbstractField, PrimeField32}; use primitives::challenger::chan_field::{PermutationField, U32}; use primitives::challenger::{BfChallenger, BfGrindingChallenger, Blake3Permutation}; - use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; + use script_manager::bc_assignment::DefaultBCAssignment; use scripts::bit_comm::winternitz::{pushable, to_digits}; - use scripts::u31_lib::BabyBear4; - use scripts::{execute_script, execute_script_with_inputs}; + + use scripts::execute_script_with_inputs; use super::{new_challenge_commit, new_u32_bit_commit, Commit, FiatShamirSubTree, SubTree}; diff --git a/fri/src/fri_scripts/leaf.rs b/fri/src/fri_scripts/leaf.rs index b4fce21..e11a8bf 100644 --- a/fri/src/fri_scripts/leaf.rs +++ b/fri/src/fri_scripts/leaf.rs @@ -9,12 +9,10 @@ use std::usize; use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; -use itertools::rev; use p3_field::TwoAdicField; use primitives::field::BfField; use script_manager::bc_assignment::DefaultBCAssignment; use scripts::bit_comm::bit_comm::BitCommitment; -use scripts::bit_comm_u32::BitCommitmentU32; use scripts::execute_script_with_inputs; use scripts::secret_generator::ConstantSecretGen; use scripts::u31_lib::{ @@ -23,8 +21,8 @@ use scripts::u31_lib::{ use segment::SegmentLeaf; use super::verify_folding::{ - cal_neg_x_with_input, fold_degree, fold_degree_with_input, index_to_rou, - reverse_bits_len_script_with_input, value_square_with_input, + cal_neg_x_with_input, fold_degree_with_input, index_to_rou, reverse_bits_len_script_with_input, + value_square_with_input, }; define_pushable!(); @@ -222,7 +220,7 @@ impl IndexToROULeaf { impl SegmentLeaf for IndexToROULeaf { fn input(&self) -> Vec> { - let mut sigs0 = self.x_bc.witness(); + let sigs0 = self.x_bc.witness(); let mut sigs1 = self.index_bc.witness(); sigs1.extend(sigs0); sigs1 @@ -534,8 +532,8 @@ mod test { use p3_field::extension::BinomialExtensionField; use p3_field::{AbstractField, TwoAdicField}; use p3_util::reverse_bits_len; - use primitives::mmcs::taptree::EvaluationLeaf; - use rand::Rng; + + use scripts::execute_script; type AF = BabyBear; diff --git a/fri/src/fri_scripts/pcs.rs b/fri/src/fri_scripts/pcs.rs index 850a84a..fa76266 100644 --- a/fri/src/fri_scripts/pcs.rs +++ b/fri/src/fri_scripts/pcs.rs @@ -1,19 +1,12 @@ -use std::marker::PhantomData; -use std::ops::Add; - -use bitcoin::opcodes::{OP_SUB, OP_TOALTSTACK, OP_TRUE}; -use bitcoin::{script, ScriptBuf as Script}; +use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; use itertools::izip; use primitives::field::BfField; -use script_manager::script_info::{self, ScriptInfo}; -use scripts::pseudo::{ - OP_4DROP, OP_4DUP, OP_4FROMALTSTACK, OP_4MUL, OP_4PICK, OP_4ROLL, OP_4TOALTSTACK, OP_NDUP, -}; +use script_manager::script_info::ScriptInfo; +use scripts::pseudo::{OP_4DROP, OP_4DUP, OP_4FROMALTSTACK, OP_4ROLL, OP_4TOALTSTACK}; use scripts::u31_lib::{ - u31_add, u31_double, u31_mul, u31_sub, u31_sub_u31ext, u31_to_u31ext, u31ext_add, - u31ext_double, u31ext_equalverify, u31ext_mul, u31ext_mul_u31, u31ext_mul_u31_by_constant, - u31ext_sub, u31ext_sub_u31, BabyBear4, BabyBearU31, + u31_mul, u31_sub_u31ext, u31ext_add, u31ext_equalverify, u31ext_mul, u31ext_sub, BabyBear4, + BabyBearU31, }; define_pushable!(); @@ -282,20 +275,19 @@ pub fn verify_quotient(matrix_width: usize) -> #[cfg(test)] mod tests { - use bitcoin::opcodes::{OP_FROMALTSTACK, OP_TRUE}; - use bitcoin::ScriptBuf as Script; + use bitcoin_script::{define_pushable, script}; use itertools::izip; - use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; - use p3_field::{AbstractExtensionField, AbstractField}; - use p3_interpolation::interpolate_coset; - use p3_matrix::dense::RowMajorMatrix; - use p3_matrix::util::reverse_matrix_index_bits; + + use p3_field::AbstractField; + + + use primitives::field::BfField; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; use script_manager::bc_assignment::DefaultBCAssignment; - use scripts::pseudo::{OP_4DROP, OP_4FROMALTSTACK, OP_4TOALTSTACK}; + use scripts::pseudo::{OP_4FROMALTSTACK, OP_4TOALTSTACK}; use scripts::u31_lib::{u31ext_equalverify, BabyBear4}; use scripts::{execute_script, execute_script_with_inputs, BabyBear, BinomialExtensionField}; diff --git a/fri/src/fri_scripts/verify_folding.rs b/fri/src/fri_scripts/verify_folding.rs index b319d38..ad37f3c 100644 --- a/fri/src/fri_scripts/verify_folding.rs +++ b/fri/src/fri_scripts/verify_folding.rs @@ -1,9 +1,7 @@ use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; use primitives::field::BfField; -use scripts::pseudo::{ - OP_4DUP, OP_4FROMALTSTACK, OP_4MUL, OP_4PICK, OP_4ROLL, OP_4TOALTSTACK, OP_NDUP, -}; +use scripts::pseudo::{OP_4DUP, OP_4FROMALTSTACK, OP_4MUL, OP_4PICK, OP_4ROLL, OP_4TOALTSTACK}; use scripts::u31_lib::{ u31_add, u31_double, u31_mul, u31_sub, u31ext_add, u31ext_double, u31ext_equalverify, u31ext_mul, u31ext_sub, BabyBear4, BabyBearU31, @@ -277,15 +275,14 @@ pub fn value_square_with_input() -> Script { #[cfg(test)] mod tests { - use bitcoin::opcodes::{OP_DEPTH, OP_EQUAL}; use p3_baby_bear::BabyBear; use p3_field::extension::BinomialExtensionField; use p3_field::{AbstractField, TwoAdicField}; use p3_util::reverse_bits_len; - use rand::{random, Rng}; + use rand::Rng; type AF = BabyBear; type F = BinomialExtensionField; - use scripts::{execute_script, execute_script_with_inputs}; + use scripts::execute_script; use super::*; @@ -1029,13 +1026,13 @@ pub fn fold_degree_with_input() -> Script { #[cfg(test)] mod tests2 { - use bitcoin::opcodes::{OP_DROP, OP_EQUAL, OP_EQUALVERIFY, OP_FROMALTSTACK, OP_TOALTSTACK}; - use bitcoin::Script; + use p3_baby_bear::BabyBear; use primitives::field::BfField; - use rand::{Rng, SeedableRng}; - use rand_chacha::ChaCha20Rng; + + use scripts::execute_script; + use scripts::pseudo::OP_NDUP; use super::*; diff --git a/fri/src/proof.rs b/fri/src/proof.rs index 3af2a94..57c4827 100644 --- a/fri/src/proof.rs +++ b/fri/src/proof.rs @@ -1,9 +1,7 @@ use alloc::vec::Vec; -use bitcoin::taproot::LeafNode; use primitives::field::BfField; use primitives::mmcs::bf_mmcs::BFMmcs; -use primitives::mmcs::point::PointsLeaf; use primitives::mmcs::taptree_mmcs::CommitProof; use serde::{Deserialize, Serialize}; diff --git a/fri/src/prover.rs b/fri/src/prover.rs index 3e72567..00f2d95 100644 --- a/fri/src/prover.rs +++ b/fri/src/prover.rs @@ -1,6 +1,5 @@ use alloc::vec; use alloc::vec::Vec; -use core::cmp::Reverse; use core::iter; use itertools::{izip, Itertools}; @@ -11,7 +10,7 @@ use p3_util::log2_strict_usize; use primitives::challenger::BfGrindingChallenger; use primitives::field::BfField; use primitives::mmcs::bf_mmcs::BFMmcs; -use primitives::mmcs::taptree_mmcs::{CommitProof, DEFAULT_MATRIX_WIDTH}; +use primitives::mmcs::taptree_mmcs::CommitProof; use tracing::{info_span, instrument}; use crate::{BfQueryProof, FriConfig, FriGenericConfig, FriProof}; diff --git a/fri/src/script_verifier.rs b/fri/src/script_verifier.rs index 47c6599..861c9d4 100644 --- a/fri/src/script_verifier.rs +++ b/fri/src/script_verifier.rs @@ -1,11 +1,8 @@ -use alloc::vec; use alloc::vec::Vec; use core::panic; -use std::collections::BTreeMap; use std::sync::{Arc, Mutex, MutexGuard}; use bitcoin::taproot::TapLeaf; -use bitcoin_script_stack::stack::StackTracker; use itertools::izip; use p3_field::AbstractField; use p3_util::reverse_bits_len; @@ -14,9 +11,8 @@ use primitives::mmcs::bf_mmcs::BFMmcs; use primitives::mmcs::point::{Point, PointsLeaf}; use primitives::mmcs::taptree_mmcs::CommitProof; use script_expr::{Dsl, InputManager, ManagerAssign}; -use scripts::u31_lib::{u31_equalverify, u31ext_equalverify, BabyBear4}; use scripts::{execute_script_with_inputs, BabyBear}; -use tracing::{instrument, trace}; +use tracing::trace; use crate::error::{FriError, SVError}; use crate::verifier::*; @@ -44,7 +40,7 @@ where let cur_manager = manager_assign .next_manager_with_name(format!("[fri-pcs-verify query_index:{}] ", index)); let ro = { - let mut manager: std::sync::MutexGuard> = cur_manager.lock().unwrap(); + let manager: std::sync::MutexGuard> = cur_manager.lock().unwrap(); open_input(index, &query_proof.input_proof, manager) .map_err(|e| FriError::InputError(e))? }; diff --git a/fri/src/two_adic_pcs.rs b/fri/src/two_adic_pcs.rs index 233a740..3d59dbf 100644 --- a/fri/src/two_adic_pcs.rs +++ b/fri/src/two_adic_pcs.rs @@ -3,10 +3,8 @@ use alloc::vec; use alloc::vec::Vec; use core::fmt::Debug; use core::marker::PhantomData; -use std::cell::Cell; -use std::sync::{Arc, Mutex, MutexGuard}; +use std::sync::MutexGuard; -use bitcoin_script_stack::stack::StackTracker; use itertools::{izip, Itertools}; use p3_challenger::{CanObserve, CanSample}; use p3_commit::{OpenedValues, PolynomialSpace, TwoAdicMultiplicativeCoset}; @@ -18,7 +16,7 @@ use p3_field::{ use p3_interpolation::interpolate_coset; use p3_matrix::bitrev::{BitReversableMatrix, BitReversalPerm}; use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::{Dimensions, Matrix}; +use p3_matrix::Matrix; use p3_maybe_rayon::prelude::*; use p3_util::linear_map::LinearMap; use p3_util::{log2_strict_usize, reverse_bits_len, reverse_slice_index_bits, VecExt}; @@ -26,13 +24,12 @@ use primitives::bf_pcs::{Pcs, PcsExpr}; use primitives::challenger::BfGrindingChallenger; use primitives::field::BfField; use primitives::mmcs::bf_mmcs::BFMmcs; -use primitives::mmcs::taptree_mmcs::{CommitProof, TapTreeMmcs}; +use primitives::mmcs::taptree_mmcs::CommitProof; use script_expr::{Dsl, InputManager, ManagerAssign}; use serde::{Deserialize, Serialize}; -use tracing::{debug_span, info_span, instrument}; +use tracing::{info_span, instrument}; -use crate::error::{self, FriError}; -use crate::fri_scripts::pcs::{accmulator_script, ro_mul_x_minus_z_script}; +use crate::error::FriError; use crate::{ prover, script_verifier, verifier, FriConfig, FriGenericConfig, FriGenericConfigWithExpr, FriProof, diff --git a/fri/src/verifier.rs b/fri/src/verifier.rs index ba615d9..3b5a02a 100644 --- a/fri/src/verifier.rs +++ b/fri/src/verifier.rs @@ -2,17 +2,13 @@ use alloc::vec; use alloc::vec::Vec; use bitcoin::taproot::TapLeaf; -use bitcoin::Script; use itertools::izip; use p3_challenger::{CanObserve, CanSample}; -use p3_util::reverse_bits_len; use primitives::challenger::BfGrindingChallenger; use primitives::field::BfField; use primitives::mmcs::bf_mmcs::BFMmcs; -use primitives::mmcs::error::BfError; use primitives::mmcs::point::{Point, PointsLeaf}; use primitives::mmcs::taptree_mmcs::CommitProof; -use script_manager::script_info::ScriptInfo; use scripts::execute_script_with_inputs; use tracing::trace; diff --git a/fri/tests/fri.rs b/fri/tests/fri.rs index 64d65f5..33fe988 100644 --- a/fri/tests/fri.rs +++ b/fri/tests/fri.rs @@ -9,11 +9,11 @@ mod tests0 { use fri::script_verifier::bf_verify_challenges; use fri::two_adic_pcs::TwoAdicFriGenericConfig; use fri::{verifier, FriConfig}; - use itertools::Itertools; + use p3_baby_bear::BabyBear; use p3_challenger::CanSampleBits; use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; - use p3_field::extension::BinomialExtensionField; + use p3_field::AbstractField; use p3_matrix::dense::RowMajorMatrix; use p3_matrix::util::reverse_matrix_index_bits; @@ -21,19 +21,19 @@ mod tests0 { use p3_symmetric::{CryptographicPermutation, Permutation}; use p3_util::log2_strict_usize; use primitives::challenger::chan_field::U32; - use primitives::challenger::{BfChallenger, Blake3Permutation}; - use primitives::field::BfField; + use primitives::challenger::BfChallenger; + use primitives::mmcs::taptree_mmcs::TapTreeMmcs; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; - use script_expr::{InputManager, ManagerAssign}; - use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; + + use script_manager::bc_assignment::DefaultBCAssignment; use script_manager::script_info::ScriptInfo; extern crate alloc; - use alloc::collections::BTreeMap; + - use bitcoin_script_stack::stack::StackTracker; + type PF = U32; const WIDTH: usize = 16; type SpongeState = [PF; WIDTH]; @@ -57,7 +57,7 @@ mod tests0 { type ValMmcs = TapTreeMmcs; #[test] fn test_compelte_fri_process() { - let mut script_manager: Vec = Vec::new(); + let script_manager: Vec = Vec::new(); let permutation = TestPermutation {}; let mut challenger = BfChallenger::::new(permutation).unwrap(); @@ -155,7 +155,7 @@ mod tests0 { #[test] fn test_script_verifier() { - let mut script_manager: Vec = Vec::new(); + let script_manager: Vec = Vec::new(); let permutation = TestPermutation {}; let mut challenger = BfChallenger::::new(permutation).unwrap(); @@ -167,7 +167,7 @@ mod tests0 { mmcs, }; - let mut assign = DefaultBCAssignment::new(); + let assign = DefaultBCAssignment::new(); let dft = Radix2Dit::default(); @@ -297,30 +297,30 @@ mod tests1 { use fri::script_verifier::bf_verify_challenges; use fri::two_adic_pcs::TwoAdicFriGenericConfig; use fri::{verifier, FriConfig}; - use itertools::Itertools; + use p3_baby_bear::BabyBear; - use p3_challenger::CanSampleBits; + use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; - use p3_field::extension::BinomialExtensionField; + use p3_field::AbstractField; use p3_matrix::dense::RowMajorMatrix; use p3_matrix::util::reverse_matrix_index_bits; use p3_matrix::Matrix; - use p3_symmetric::{CryptographicPermutation, Permutation}; + use p3_util::log2_strict_usize; use primitives::challenger::chan_field::U32; use primitives::challenger::{BfChallenger, Blake3Permutation}; - use primitives::field::BfField; + use primitives::mmcs::taptree_mmcs::TapTreeMmcs; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; - use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; - use script_manager::script_info::ScriptInfo; + + extern crate alloc; - use alloc::collections::BTreeMap; + - use bitcoin_script_stack::stack::StackTracker; + type PF = U32; const WIDTH: usize = 16; type SpongeState = [PF; WIDTH]; @@ -451,7 +451,7 @@ mod tests2 { use fri::script_verifier::bf_verify_challenges; use fri::two_adic_pcs::TwoAdicFriGenericConfig; use fri::{verifier, FriConfig}; - use itertools::Itertools; + use p3_baby_bear::BabyBear; use p3_challenger::CanSampleBits; use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; @@ -463,16 +463,16 @@ mod tests2 { use p3_symmetric::{CryptographicPermutation, Permutation}; use p3_util::log2_strict_usize; use primitives::challenger::chan_field::U32; - use primitives::challenger::{BfChallenger, Blake3Permutation}; - use primitives::mmcs::taptree_mmcs::{TapTreeMmcs, ROOT_WIDTH}; + use primitives::challenger::BfChallenger; + use primitives::mmcs::taptree_mmcs::TapTreeMmcs; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; - use script_expr::Dsl; - use script_manager::bc_assignment::{BCAssignment, DefaultBCAssignment}; + + use script_manager::bc_assignment::DefaultBCAssignment; use script_manager::script_info::ScriptInfo; - use tracing_subscriber::fmt; + - use super::*; + // use crate::{bf_verify_challenges, verifier}; type PF = U32; @@ -500,7 +500,7 @@ mod tests2 { #[test] fn test_compelte_fri_process_with_ext_babybear() { - let mut script_manager: Vec = Vec::new(); + let script_manager: Vec = Vec::new(); let permutation = TestPermutation {}; let mut challenger = BfChallenger::::new(permutation).unwrap(); @@ -599,7 +599,7 @@ mod tests2 { #[test] fn test_script_verifier() { - let mut script_manager: Vec = Vec::new(); + let script_manager: Vec = Vec::new(); let permutation = TestPermutation {}; let mut challenger = BfChallenger::::new(permutation).unwrap(); @@ -611,7 +611,7 @@ mod tests2 { mmcs, }; - let mut assign = DefaultBCAssignment::new(); + let assign = DefaultBCAssignment::new(); let dft = Radix2Dit::default(); diff --git a/fri/tests/pcs.rs b/fri/tests/pcs.rs index e455c0c..592a08b 100644 --- a/fri/tests/pcs.rs +++ b/fri/tests/pcs.rs @@ -1,8 +1,8 @@ use fri::{FriConfig, TwoAdicFriPcs}; use itertools::{izip, Itertools}; -use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; -use p3_challenger::{CanObserve, CanSample, DuplexChallenger, FieldChallenger}; -use p3_commit::{ExtensionMmcs, PolynomialSpace}; +use p3_baby_bear::BabyBear; +use p3_challenger::{CanObserve, CanSample}; +use p3_commit::PolynomialSpace; use p3_dft::Radix2DitParallel; use p3_field::extension::BinomialExtensionField; use p3_field::{ExtensionField, Field}; @@ -15,7 +15,7 @@ use primitives::mmcs::taptree_mmcs::TapTreeMmcs; use rand::distributions::{Distribution, Standard}; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; -use script_expr::{Dsl, Expression, ManagerAssign}; +use script_expr::ManagerAssign; extern crate alloc; diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index b840281..4176618 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -5,8 +5,8 @@ edition = "2021" [dependencies] bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } -bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark", features = ["serde"]} -bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } +bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bitvm", features = ["serde"] } +bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec", branch = "bitvm"} lazy_static = "1.4.0" itertools = "0.12.0" tracing = "0.1.37" diff --git a/primitives/src/bf_pcs.rs b/primitives/src/bf_pcs.rs index a404b7b..fd368c8 100644 --- a/primitives/src/bf_pcs.rs +++ b/primitives/src/bf_pcs.rs @@ -2,12 +2,10 @@ use core::fmt::Debug; -use bitcoin::script; use p3_commit::PolynomialSpace; use p3_field::ExtensionField; use p3_matrix::dense::RowMajorMatrix; use p3_matrix::Matrix; -use script_manager::script_info::ScriptInfo; use serde::de::DeserializeOwned; use serde::Serialize; diff --git a/primitives/src/challenger/mod.rs b/primitives/src/challenger/mod.rs index 389bd25..11f2d2e 100644 --- a/primitives/src/challenger/mod.rs +++ b/primitives/src/challenger/mod.rs @@ -1,16 +1,10 @@ -use core::array; -use core::marker::PhantomData; use std::any::{Any, TypeId}; -use bitcoin::hashes::serde::Serializer; use chan_field::{ChallengeField, PermutationField, U32}; use p3_baby_bear::BabyBear; use p3_challenger::{CanObserve, CanSample, CanSampleBits}; use p3_field::extension::BinomialExtensionField; -use p3_field::{ - AbstractExtensionField, AbstractField, ExtensionField, Field, PackedValue, PrimeField, - PrimeField32, -}; +use p3_field::{AbstractExtensionField, AbstractField, Field, PrimeField32}; use p3_maybe_rayon::prelude::*; use p3_symmetric::{CryptographicPermutation, Hash, Permutation}; use tracing; diff --git a/primitives/src/mmcs/bf_mmcs.rs b/primitives/src/mmcs/bf_mmcs.rs index 43059ef..b6f749a 100644 --- a/primitives/src/mmcs/bf_mmcs.rs +++ b/primitives/src/mmcs/bf_mmcs.rs @@ -1,7 +1,6 @@ // use alloc::vec; // use alloc::vec::Vec; use core::fmt::Debug; -use std::borrow::Borrow; use p3_matrix::dense::RowMajorMatrix; use serde::de::DeserializeOwned; diff --git a/primitives/src/mmcs/point.rs b/primitives/src/mmcs/point.rs index 687a2fb..5a06c96 100644 --- a/primitives/src/mmcs/point.rs +++ b/primitives/src/mmcs/point.rs @@ -181,7 +181,6 @@ impl Point { #[cfg(test)] mod test { use p3_baby_bear::BabyBear; - use p3_field::{AbstractExtensionField, AbstractField, PrimeField32}; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; use scripts::execute_script_with_inputs; diff --git a/primitives/src/mmcs/taptree.rs b/primitives/src/mmcs/taptree.rs index 7e1e654..adf7e5e 100644 --- a/primitives/src/mmcs/taptree.rs +++ b/primitives/src/mmcs/taptree.rs @@ -1,14 +1,13 @@ -use core::ops::{Deref, DerefMut}; -use core::{mem, usize}; +use core::usize; use std::cmp::Reverse; use bitcoin::taproot::LeafVersion::TapScript; use bitcoin::taproot::{LeafNode, LeafNodes, NodeInfo, TaprootMerkleBranch}; use bitcoin::{ScriptBuf, TapNodeHash}; -use itertools::{Chunk, Itertools}; +use itertools::Itertools; use p3_matrix::dense::RowMajorMatrix; use p3_matrix::Matrix; -use p3_util::{log2_ceil_usize, log2_strict_usize, reverse_slice_index_bits}; +use p3_util::{log2_ceil_usize, log2_strict_usize}; use scripts::secret_generator::ThreadSecretGen; use super::error::BfError; @@ -248,7 +247,7 @@ impl TreeBuilder { reminder_node = working_nodes.pop(); } - let mut node_tuples = working_nodes.into_iter().tuples(); + let node_tuples = working_nodes.into_iter().tuples(); let mut todo: Vec = Vec::new(); let mut a_start_idx = 0usize; // will be updated after finishing combining two nodes. @@ -315,8 +314,8 @@ impl BasicTree { // This function only support combine trees with same depth pub fn combine_tree(a: Self, b: Self) -> Self { // perserve indices map before combining two trees. - let mut a_leaf_indices = a.leaf_indices.clone(); - let mut b_leaf_indices = b.leaf_indices.clone(); + let a_leaf_indices = a.leaf_indices.clone(); + let b_leaf_indices = b.leaf_indices.clone(); let (combined_tree, noswap) = combine_two_nodes(a.root_node.unwrap(), b.root_node.unwrap()).unwrap(); @@ -465,14 +464,8 @@ impl Polynomials { mod tests { use p3_baby_bear::BabyBear; - use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; - use p3_field::extension::BinomialExtensionField; - use p3_field::{AbstractExtensionField, AbstractField}; - use p3_interpolation::interpolate_subgroup; - use p3_matrix::dense::RowMajorMatrix; - use rand::distributions::Standard; - use rand::prelude::Distribution; - use rand::{thread_rng, Rng}; + use p3_field::AbstractField; + use rand::Rng; use scripts::execute_script_with_inputs; use super::*; diff --git a/primitives/src/mmcs/taptree_mmcs.rs b/primitives/src/mmcs/taptree_mmcs.rs index 7e68756..df88bb1 100644 --- a/primitives/src/mmcs/taptree_mmcs.rs +++ b/primitives/src/mmcs/taptree_mmcs.rs @@ -5,11 +5,8 @@ use bitcoin::hashes::Hash as Bitcoin_HASH; use bitcoin::taproot::{LeafNode, TapLeaf}; use bitcoin::TapNodeHash; use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; -use p3_util::log2_strict_usize; use scripts::execute_script_with_inputs; -use serde::ser::SerializeStruct; -use serde::{Deserialize, Serialize, Serializer}; +use serde::{Deserialize, Serialize}; use super::bf_mmcs::BFMmcs; use super::error::BfError; diff --git a/script_expr/Cargo.toml b/script_expr/Cargo.toml index 1d1968e..4c0959b 100644 --- a/script_expr/Cargo.toml +++ b/script_expr/Cargo.toml @@ -4,10 +4,10 @@ version = "0.1.0" edition = "2021" [dependencies] -bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git", branch = "bf-stark"} +bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git", branch = "bitvm"} bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } -bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } -bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } +bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bitvm" } +bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec", branch = "bitvm"} p3-air = { git = "https://github.com/Plonky3/Plonky3.git" } p3-field = { git = "https://github.com/Plonky3/Plonky3.git" } p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git" } diff --git a/script_expr/src/alias.rs b/script_expr/src/alias.rs index f1f2ab0..9821458 100644 --- a/script_expr/src/alias.rs +++ b/script_expr/src/alias.rs @@ -9,13 +9,13 @@ use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; use std::usize; use bitcoin_script_stack::stack::{StackTracker, StackVariable}; -use common::{AbstractField, BabyBear}; +use common::AbstractField; use lazy_static::lazy_static; use primitives::field::BfField; use crate::{ - CustomOpcode, Expression, IdCount, InputManager, ManagerAssign, ScriptExprError, - StandardOpcode, StandardOpcodeId, Variable, DYNAMIC_INPUT_OR_OUTPUT, + CustomOpcode, Expression, IdCount, ScriptExprError, StandardOpcode, StandardOpcodeId, Variable, + DYNAMIC_INPUT_OR_OUTPUT, }; lazy_static! { static ref OPID: Mutex = Mutex::new(0); @@ -775,23 +775,17 @@ impl Product for Dsl { #[cfg(test)] mod tests { - use alloc::boxed::Box; + use alloc::collections::BTreeMap; - use alloc::sync::Arc; - use alloc::vec::Vec; - use core::cell::{self, Cell}; - use bitcoin_script_stack::stack::{self, StackTracker, StackVariable}; + use bitcoin_script_stack::stack::StackTracker; use common::{AbstractField, BabyBear, BinomialExtensionField}; - use p3_air::AirBuilder; use p3_field::TwoAdicField; - use p3_matrix::Matrix; use p3_util::reverse_bits_len; use primitives::field::BfField; - use scripts::treepp::*; use scripts::u31_lib::{u31_equalverify, u31ext_equalverify, BabyBear4}; - use super::{Dsl, Expression, Variable, *}; + use super::{Dsl, Expression, *}; use crate::InputManager; type F = BabyBear; type EF = BinomialExtensionField; @@ -1325,24 +1319,15 @@ mod tests { #[cfg(test)] mod tests2 { - use alloc::boxed::Box; + use alloc::collections::BTreeMap; - use alloc::sync::Arc; - use alloc::vec::Vec; - use core::cell::{self, Cell}; - use std::borrow::Borrow; - use bitcoin_script_stack::stack::{self, StackTracker, StackVariable}; + use bitcoin_script_stack::stack::StackTracker; use common::{AbstractField, BabyBear, BinomialExtensionField}; - use p3_air::AirBuilder; use p3_field::TwoAdicField; - use p3_matrix::Matrix; - use primitives::field::BfField; - use scripts::treepp::*; - use scripts::u31_lib::{u31ext_equalverify, BabyBear4}; - use super::{Dsl, Expression, Variable, *}; - use crate::opcode::Opcode; + use super::{Dsl, Expression, *}; + type EF = BinomialExtensionField; #[test] @@ -1452,7 +1437,7 @@ mod tests2 { // let b_2 = b.square(); let res_expr = Dsl::constant_f(res * res); let equal = b_2.equal_verify(res_expr); - equal.express1(&mut stack, &bmap,false); + equal.express1(&mut stack, &bmap, false); stack.op_true(); let res = stack.run(); assert!(res.success); @@ -1472,7 +1457,7 @@ mod tests2 { // let b_2 = b.square(); let res_expr = Dsl::constant_f(res); let equal = res_expr.equal_verify(b); - equal.express1(&mut stack, &bmap,false); + equal.express1(&mut stack, &bmap, false); stack.op_true(); let res = stack.run(); assert!(res.success); diff --git a/script_expr/src/challenger_expr.rs b/script_expr/src/challenger_expr.rs index 7fedfd4..99d5db4 100644 --- a/script_expr/src/challenger_expr.rs +++ b/script_expr/src/challenger_expr.rs @@ -4,12 +4,10 @@ use std::marker::PhantomData; use common::BinomialExtensionField; use p3_baby_bear::BabyBear; use p3_challenger::{CanObserve, CanSample}; -use p3_field::AbstractField; use p3_symmetric::Hash; -use primitives::challenger::chan_field::{PermutationField, U32}; +use primitives::challenger::chan_field::PermutationField; use primitives::challenger::BitExtractor; use primitives::field::BfField; -use scripts::blake3; use crate::Dsl; diff --git a/script_expr/src/input_manager.rs b/script_expr/src/input_manager.rs index 57bbdb6..dbcbf6f 100644 --- a/script_expr/src/input_manager.rs +++ b/script_expr/src/input_manager.rs @@ -1,21 +1,14 @@ -use std::cell::{Cell, Ref, RefCell}; use std::collections::BTreeMap; -use std::fmt::Debug; -use std::marker::PhantomData; -use std::ops::{Deref, DerefMut}; use std::sync::{Arc, Mutex, RwLock}; -use bitcoin::hashes::serde::de::value; use bitcoin_script_stack::stack::StackTracker; -use lazy_static::lazy_static; use primitives::field::BfField; use tracing::warn; use crate::script_gen::*; use crate::variable::VarWithValue; use crate::{ - get_opid, Dsl, ExprPtr, Expression, IdCount, InputOpcode, ScriptExprError, StackVariable, - ValueCounter, ValueVariable, Variable, DYNAMIC_INPUT_OR_OUTPUT, + get_opid, Dsl, ExprPtr, Expression, IdCount, InputOpcode, StackVariable, ValueCounter, Variable, }; pub struct ManagerAssign { @@ -292,7 +285,6 @@ mod tests { use common::{BabyBear, BinomialExtensionField}; use p3_field::AbstractField; use primitives::field::BfField; - use scripts::u31_lib::BabyBearU31; use super::InputManager; use crate::{Dsl, ManagerAssign, ValueCounter}; diff --git a/script_expr/src/lib.rs b/script_expr/src/lib.rs index 8ce64c8..24ad375 100644 --- a/script_expr/src/lib.rs +++ b/script_expr/src/lib.rs @@ -10,7 +10,7 @@ use bitcoin_script_stack::debugger::StepResult; use bitcoin_script_stack::stack::{StackTracker, StackVariable}; use primitives::field::BfField; use script_gen::StandardOpcodeId; -use tracing::{error, info, instrument, trace, warn}; +use tracing::{instrument, trace, warn}; mod script_builder; mod variable; pub use variable::{ValueVariable, Variable}; diff --git a/script_expr/src/opcode.rs b/script_expr/src/opcode.rs index b4ddb7f..7be4172 100644 --- a/script_expr/src/opcode.rs +++ b/script_expr/src/opcode.rs @@ -1,19 +1,14 @@ use std::cell::{Cell, Ref, RefCell}; -use std::collections::BTreeMap; use std::fmt::Debug; use std::marker::PhantomData; -use std::ops::{Deref, DerefMut}; +use std::ops::Deref; use std::sync::{Arc, RwLock}; use bitcoin_script_stack::stack::StackTracker; use primitives::field::BfField; use crate::script_gen::*; -use crate::variable::VarWithValue; -use crate::{ - get_opid, Dsl, ExprPtr, Expression, IdCount, ScriptExprError, StackVariable, ValueVariable, - Variable, DYNAMIC_INPUT_OR_OUTPUT, -}; +use crate::{ExprPtr, Expression, StackVariable, Variable}; fn to_copy( low_var: StackVariable, diff --git a/script_expr/src/script_gen.rs b/script_expr/src/script_gen.rs index 83842ba..e8769f2 100644 --- a/script_expr/src/script_gen.rs +++ b/script_expr/src/script_gen.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use bitcoin_script::script; use bitcoin_script_stack::stack::StackTracker; -use p3_util::{log2_strict_usize, reverse_bits_len}; +use p3_util::log2_strict_usize; use primitives::field::BfField; use scripts::blake3::blake3; use scripts::pseudo::{OP_4DROP, OP_4FROMALTSTACK, OP_4ROLL, OP_4TOALTSTACK}; @@ -14,9 +14,7 @@ use scripts::u31_lib::{ }; use scripts::u32_std::u32_compress; -use crate::script_helper::{ - index_to_reverse_index, index_to_rou, reverse_bits_len_script_with_input, value_exp_n, -}; +use crate::script_helper::{index_to_reverse_index, index_to_rou, value_exp_n}; use crate::{StackVariable, Variable}; #[derive(Debug, Clone, Copy)] diff --git a/script_expr/src/script_helper.rs b/script_expr/src/script_helper.rs index 8eed7e1..5bcaf0d 100644 --- a/script_expr/src/script_helper.rs +++ b/script_expr/src/script_helper.rs @@ -1,15 +1,10 @@ +use alloc::vec; use alloc::vec::Vec; -use alloc::{format, vec}; -use bitcoin::opcodes::{OP_FROMALTSTACK, OP_TOALTSTACK}; use primitives::field::BfField; use scripts::pseudo::{OP_4DUP, OP_4FROMALTSTACK, OP_4MUL, OP_4PICK, OP_4TOALTSTACK}; use scripts::treepp::*; -use scripts::u31_lib::{ - u31_add, u31_mul, u31_neg, u31_sub, u31_sub_u31ext, u31ext_add, u31ext_add_u31, - u31ext_equalverify, u31ext_mul, u31ext_mul_u31, u31ext_neg, u31ext_sub, u31ext_sub_u31, - BabyBear4, BabyBearU31, -}; +use scripts::u31_lib::{u31_mul, u31ext_equalverify, u31ext_mul, BabyBear4, BabyBearU31}; /// constraint: bits <= 31 /// input: [b_{0}, b_{1}, ..., b_{bits-1}] @@ -287,7 +282,6 @@ pub(crate) fn value_exp_n(log_n: usize) -> Script { #[cfg(test)] mod tests { - use bitcoin::opcodes::{OP_DROP, OP_EQUAL}; use p3_baby_bear::BabyBear; use p3_field::extension::BinomialExtensionField; use p3_field::{AbstractField, TwoAdicField}; diff --git a/script_manager/Cargo.toml b/script_manager/Cargo.toml index 47276af..26afdbe 100644 --- a/script_manager/Cargo.toml +++ b/script_manager/Cargo.toml @@ -5,8 +5,8 @@ edition = "2021" [dependencies] bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } -bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } -bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } +bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bitvm" } +bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec", branch = "bitvm" } lazy_static = "1.4.0" scripts = {path = "../scripts"} diff --git a/script_manager/src/bc_assignment.rs b/script_manager/src/bc_assignment.rs index 0f38638..3e4c9bd 100644 --- a/script_manager/src/bc_assignment.rs +++ b/script_manager/src/bc_assignment.rs @@ -70,12 +70,9 @@ impl BCAssignment { #[cfg(test)] mod tests { - use itertools::Itertools; + use p3_baby_bear::BabyBear; - use p3_field::{AbstractField, PackedValue}; - use primitives::field::BfField; - use rand::{Rng, SeedableRng}; - use rand_chacha::ChaCha20Rng; + use p3_field::AbstractField; use scripts::secret_generator::ThreadSecretGen; use super::*; diff --git a/script_manager/src/planner.rs b/script_manager/src/planner.rs index 3b5bfe2..f6efd09 100644 --- a/script_manager/src/planner.rs +++ b/script_manager/src/planner.rs @@ -1,7 +1,4 @@ -use std::collections::VecDeque; - -use bitcoin::opcodes::{OP_RESERVED, OP_TOALTSTACK}; -use bitcoin::{witness, ScriptBuf}; +use bitcoin::ScriptBuf; use bitcoin_script::script; use scripts::pushable; @@ -258,10 +255,9 @@ impl Planner for SimplePlanner { #[cfg(test)] mod test { use bitcoin_script::script; - use rand_chacha::rand_core::le; use scripts::{execute_script_with_inputs, pushable}; - use crate::bc_assignment::{self, DefaultBCAssignment}; + use crate::bc_assignment::DefaultBCAssignment; use crate::planner::{Planner, SimplePlanner}; use crate::script_info; use crate::script_info::ScriptInfo; @@ -270,7 +266,7 @@ mod test { #[test] fn test_simple_planner() { let mut bc_assigner = DefaultBCAssignment::new(); - let mut script1 = script_info!( + let script1 = script_info!( "add1", script! { OP_ADD @@ -280,7 +276,7 @@ mod test { [3] ); - let mut script2 = script_info!( + let script2 = script_info!( "add1", script! { OP_ADD @@ -300,7 +296,7 @@ mod test { #[test] fn test_simple_planner2() { let mut bc_assigner = DefaultBCAssignment::new(); - let mut script1 = script_info!( + let script1 = script_info!( "add1", script! { OP_ADD @@ -310,7 +306,7 @@ mod test { [33] ); - let mut script2 = script_info!( + let script2 = script_info!( "add1", script! { OP_ADD diff --git a/script_manager/src/script_info.rs b/script_manager/src/script_info.rs index 6201f8f..72ec92f 100644 --- a/script_manager/src/script_info.rs +++ b/script_manager/src/script_info.rs @@ -1,8 +1,8 @@ use std::collections::VecDeque; use std::sync::Arc; -use bitcoin::{Script, ScriptBuf}; -use bitcoin_script::{define_pushable, script}; +use bitcoin::ScriptBuf; +use bitcoin_script::script; use scripts::{pushable, unroll, AsU32Vec}; use crate::bc_assignment::DefaultBCAssignment; @@ -212,15 +212,12 @@ macro_rules! script_info { mod test { use std::ops::Mul; - use bitcoin::opcodes::{OP_FROMALTSTACK, OP_TOALTSTACK}; use bitcoin_script::script; use p3_baby_bear::BabyBear; use p3_field::AbstractField; use primitives::field::BinomialExtensionField; - use scripts::bit_comm::bit_comm::BitCommitment; use scripts::bit_comm_u32::pushable; use scripts::execute_script_with_inputs; - use scripts::secret_generator::ThreadSecretGen; use scripts::u31_lib::{u31ext_mul, BabyBear4}; use super::ScriptInfo; diff --git a/scripts/Cargo.toml b/scripts/Cargo.toml index 6bb32de..bf79989 100644 --- a/scripts/Cargo.toml +++ b/scripts/Cargo.toml @@ -5,9 +5,9 @@ edition = "2021" [dependencies] bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } -bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } -bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } -rust-bitcoin-u31-or-u30 ={ git = "https://github.com/bitlayer-org/rust-bitcoin-m31-or-babybear.git", branch = "bf-pcs" } +bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bitvm" } +bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec", branch = "bitvm" } +rust-bitcoin-u31-or-u30 ={ git = "https://github.com/bitlayer-org/rust-bitcoin-m31-or-babybear.git", branch = "bitvm" } lazy_static = "1.4.0" rand_chacha = "0.3.1" diff --git a/scripts/src/bit_comm/bit_comm.rs b/scripts/src/bit_comm/bit_comm.rs index 491fe1d..34fa0e1 100644 --- a/scripts/src/bit_comm/bit_comm.rs +++ b/scripts/src/bit_comm/bit_comm.rs @@ -1,8 +1,7 @@ -use std::marker::PhantomData; use std::sync::Arc; use bitcoin::ScriptBuf as Script; -use bitcoin_script::{define_pushable, script}; +use bitcoin_script::script; use common::AsU32Vec; use itertools::Itertools; use serde::{Deserialize, Serialize}; @@ -156,18 +155,16 @@ impl BitCommitment { #[cfg(test)] mod test { - use core::ops::{Add, Mul, Neg}; + use core::ops::Add; - use bitcoin_script::{define_pushable, script}; + use bitcoin_script::script; use p3_baby_bear::BabyBear; - use p3_field::{AbstractExtensionField, AbstractField, PrimeField32}; + use p3_field::{AbstractExtensionField, PrimeField32}; use primitives::field::BfField; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha20Rng; - use crate::u31_lib::{ - u31_equalverify, u31ext_add, u31ext_double, u31ext_equalverify, BabyBear4, - }; + use crate::u31_lib::{u31_equalverify, u31ext_add, u31ext_equalverify, BabyBear4}; use crate::{execute_script, execute_script_with_inputs}; // signuture is the input of this script diff --git a/scripts/src/bit_comm/mod.rs b/scripts/src/bit_comm/mod.rs index 45d75e8..9c80830 100644 --- a/scripts/src/bit_comm/mod.rs +++ b/scripts/src/bit_comm/mod.rs @@ -4,6 +4,5 @@ pub mod secret_generator; pub mod winternitz; pub use common::{AsU32Vec, BabyBear, BinomialExtensionField}; -use winternitz::*; type Witness = Vec>; diff --git a/scripts/src/bit_comm/secret_generator.rs b/scripts/src/bit_comm/secret_generator.rs index 5b89596..3e33a40 100644 --- a/scripts/src/bit_comm/secret_generator.rs +++ b/scripts/src/bit_comm/secret_generator.rs @@ -1,7 +1,7 @@ use std::fmt::Debug; use bitcoin::hex::DisplayHex; -use rand::{thread_rng, Rng}; +use rand::Rng; pub trait SecretGen: Debug + Clone + Default + PartialEq + Eq { fn gen() -> String; diff --git a/scripts/src/bit_comm/winternitz.rs b/scripts/src/bit_comm/winternitz.rs index 51b2042..b1821fc 100644 --- a/scripts/src/bit_comm/winternitz.rs +++ b/scripts/src/bit_comm/winternitz.rs @@ -307,8 +307,6 @@ pub fn equivocation(_pub_key: &[Vec]) -> Script { #[cfg(test)] mod test { - use p3_baby_bear::BabyBear; - use super::*; use crate::execute_script_with_inputs; diff --git a/scripts/src/u32/u32_std.rs b/scripts/src/u32/u32_std.rs index 723bd45..2530216 100644 --- a/scripts/src/u32/u32_std.rs +++ b/scripts/src/u32/u32_std.rs @@ -206,7 +206,7 @@ mod test { for _ in 0..30 { let mut origin_value0: u32 = rng.gen(); origin_value0 = origin_value0 % 1 << 31; - let mut origin_value1: u32 = rng.gen(); + let origin_value1: u32 = rng.gen(); origin_value0 = origin_value1 % 1 << 31; let v = origin_value0 + origin_value1; diff --git a/segment/Cargo.toml b/segment/Cargo.toml index 2fdd961..2720980 100644 --- a/segment/Cargo.toml +++ b/segment/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" [dependencies] bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } -bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } -bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } +bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bitvm" } +bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec",branch = "bitvm"} scripts ={ path = "../scripts"} \ No newline at end of file diff --git a/uni-stark/Cargo.toml b/uni-stark/Cargo.toml index 8f2865b..fa2c4e9 100644 --- a/uni-stark/Cargo.toml +++ b/uni-stark/Cargo.toml @@ -5,10 +5,10 @@ edition = "2021" license = "MIT OR Apache-2.0" [dependencies] -bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git", branch = "bf-stark"} +bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git", branch = "bitvm"} bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } -bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bf-stark" } -bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec" } +bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bitvm" } +bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec", branch = "bitvm"} p3-air = { git = "https://github.com/Plonky3/Plonky3.git" } p3-field = { git = "https://github.com/Plonky3/Plonky3.git" } p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git" } diff --git a/uni-stark/src/config.rs b/uni-stark/src/config.rs index 12d5809..dd0439f 100644 --- a/uni-stark/src/config.rs +++ b/uni-stark/src/config.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use p3_challenger::{CanObserve, CanSample, FieldChallenger}; +use p3_challenger::{CanObserve, CanSample}; use p3_commit::PolynomialSpace; use p3_field::{ExtensionField, Field}; use primitives::bf_pcs; diff --git a/uni-stark/src/expr_helper.rs b/uni-stark/src/expr_helper.rs index 9bb7cf3..a1a7d56 100644 --- a/uni-stark/src/expr_helper.rs +++ b/uni-stark/src/expr_helper.rs @@ -1,13 +1,9 @@ -use std::cell::Cell; -use std::sync::Arc; -use bitcoin_script_stack::stack::StackVariable; -use p3_field::{AbstractField, Field}; -use primitives::field::BfField; -use script_expr::{Dsl, ValueVariable, Variable}; +use p3_field::Field; +use script_expr::Variable; use crate::symbolic_variable::SymbolicVariable; -use crate::{Entry, SymbolicExpression}; +use crate::Entry; // impl From<&SymbolicExpression> for Dsl { // fn from(value: &SymbolicExpression) -> Self { @@ -96,15 +92,15 @@ impl From<&SymbolicVariable> for Variable { #[cfg(test)] mod tests { - use alloc::vec::Vec; + use common::{BabyBear, BinomialExtensionField}; - use p3_air::AirBuilder; - use p3_matrix::Matrix; - use script_expr::{Dsl, *}; + + + type EF = BinomialExtensionField; - use crate::SymbolicAirBuilder; + // #[test] // fn test_symbolic_expr_constraints() { // let air_width: usize = 2; diff --git a/uni-stark/src/script_verifier.rs b/uni-stark/src/script_verifier.rs index 5d6a325..e342b86 100644 --- a/uni-stark/src/script_verifier.rs +++ b/uni-stark/src/script_verifier.rs @@ -8,20 +8,18 @@ use p3_air::{Air, BaseAir}; use p3_challenger::{CanObserve, CanSample}; use p3_commit::PolynomialSpace; use p3_field::{AbstractExtensionField, AbstractField, Field, TwoAdicField}; -use p3_matrix::dense::{RowMajorMatrix, RowMajorMatrixView}; +use p3_matrix::dense::RowMajorMatrixView; use p3_matrix::stack::VerticalPair; use p3_util::log2_strict_usize; use primitives::bf_pcs::{Pcs, PcsExpr}; -use primitives::challenger::chan_field::U32; use primitives::field::BfField; use script_expr::{ - selectors_at_point_expr, BfChallengerExpr, Dsl, InputManager, ManagerAssign, + selectors_at_point_expr, Dsl, ScriptConstraintBuilder, ValueCounter, }; -use serde::de::value; use tracing::instrument; -use crate::symbolic_builder::{self, get_log_quotient_degree, SymbolicAirBuilder}; +use crate::symbolic_builder::{get_log_quotient_degree, SymbolicAirBuilder}; use crate::{ compute_quotient_expr, PcsError, Proof, StarkGenericConfig, Val, VerifierConstraintFolder, }; diff --git a/uni-stark/src/scripts/bf_unistark.rs b/uni-stark/src/scripts/bf_unistark.rs index 2524cbf..62785b9 100644 --- a/uni-stark/src/scripts/bf_unistark.rs +++ b/uni-stark/src/scripts/bf_unistark.rs @@ -1,13 +1,9 @@ -use std::cell::Cell; -use std::collections::BTreeMap; -use std::sync::{Arc, MutexGuard}; +use std::sync::MutexGuard; -use bitcoin_script_stack::stack::{StackTracker, StackVariable}; use itertools::Itertools; use p3_field::ExtensionField; use primitives::field::BfField; -use script_expr::{Dsl, Expression, InputManager}; -use scripts::u31_lib::u31_equalverify; +use script_expr::{Dsl, InputManager}; use crate::get_table; diff --git a/uni-stark/src/scripts/utils.rs b/uni-stark/src/scripts/utils.rs index 657048f..ea0fd3a 100644 --- a/uni-stark/src/scripts/utils.rs +++ b/uni-stark/src/scripts/utils.rs @@ -1,15 +1,12 @@ -use bitcoin::opcodes::{OP_ADD, OP_DROP, OP_SUB, OP_SWAP, OP_TOALTSTACK, OP_TRUE}; -use bitcoin::{script, ScriptBuf as Script}; +use bitcoin::ScriptBuf as Script; use bitcoin_script::{define_pushable, script}; use primitives::field::BfField; use scripts::pseudo::{ - OP_4DROP, OP_4DUP, OP_4FROMALTSTACK, OP_4MUL, OP_4PICK, OP_4ROLL, OP_4SWAP, OP_4TOALTSTACK, - OP_NDUP, + OP_4DUP, OP_4FROMALTSTACK, OP_4MUL, OP_4PICK, OP_4TOALTSTACK, }; use scripts::u31_lib::{ - u31_add, u31_double, u31_mul, u31_sub, u31_sub_u31ext, u31_to_u31ext, u31ext_add, - u31ext_double, u31ext_equalverify, u31ext_mul, u31ext_mul_u31, u31ext_mul_u31_by_constant, - u31ext_sub, u31ext_sub_u31, BabyBear4, BabyBearU31, + u31_mul, u31_sub, u31ext_mul, + u31ext_sub, BabyBear4, BabyBearU31, }; define_pushable!(); diff --git a/uni-stark/src/verifier.rs b/uni-stark/src/verifier.rs index 5bc7e9d..880f5ce 100644 --- a/uni-stark/src/verifier.rs +++ b/uni-stark/src/verifier.rs @@ -1,24 +1,18 @@ -use alloc::collections::BTreeMap; use alloc::vec; use alloc::vec::Vec; -use bitcoin_script_stack::stack::StackTracker; use itertools::Itertools; use p3_air::{Air, BaseAir}; use p3_challenger::{CanObserve, CanSample}; use p3_commit::PolynomialSpace; use p3_field::{AbstractExtensionField, AbstractField, Field}; -use p3_matrix::dense::{RowMajorMatrix, RowMajorMatrixView}; +use p3_matrix::dense::RowMajorMatrixView; use p3_matrix::stack::VerticalPair; -use p3_util::log2_strict_usize; use primitives::bf_pcs::Pcs; use primitives::field::BfField; -use script_expr::{selectors_at_point_expr, Expression, ScriptConstraintBuilder}; -use script_manager::script_info::ScriptInfo; -use scripts::execute_script_with_inputs; use tracing::instrument; -use crate::symbolic_builder::{self, get_log_quotient_degree, SymbolicAirBuilder}; +use crate::symbolic_builder::{get_log_quotient_degree, SymbolicAirBuilder}; use crate::{PcsError, Proof, StarkGenericConfig, Val, VerifierConstraintFolder}; #[instrument(skip_all)] diff --git a/uni-stark/src/zerofier_coset.rs b/uni-stark/src/zerofier_coset.rs index a396742..5425436 100644 --- a/uni-stark/src/zerofier_coset.rs +++ b/uni-stark/src/zerofier_coset.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use itertools::Itertools; use p3_field::{ - batch_multiplicative_inverse, cyclic_subgroup_coset_known_order, Field, PackedField, + batch_multiplicative_inverse, cyclic_subgroup_coset_known_order, PackedField, TwoAdicField, }; use primitives::field::BfField; diff --git a/uni-stark/tests/fib_air.rs b/uni-stark/tests/fib_air.rs index 5eb56a6..5435d41 100644 --- a/uni-stark/tests/fib_air.rs +++ b/uni-stark/tests/fib_air.rs @@ -1,33 +1,22 @@ use std::borrow::Borrow; -use std::collections::BTreeMap; -use bitcoin_script_stack::stack::StackTracker; use fri::{FriConfig, TwoAdicFriPcs}; -use itertools::Itertools; use p3_air::{Air, AirBuilder, AirBuilderWithPublicValues, BaseAir}; use p3_baby_bear::BabyBear; -use p3_commit::{ExtensionMmcs, PolynomialSpace, TwoAdicMultiplicativeCoset}; use p3_dft::Radix2DitParallel; use p3_field::extension::BinomialExtensionField; use p3_field::{ - AbstractExtensionField, AbstractField, ExtensionField, Field, PrimeField64, TwoAdicField, + AbstractField, PrimeField64, }; use p3_matrix::dense::RowMajorMatrix; use p3_matrix::Matrix; -use primitives::bf_pcs::Pcs; use primitives::challenger::chan_field::U32; // use p3_challenger::DuplexChallenger; use primitives::challenger::{BfChallenger, Blake3Permutation}; -use primitives::field::BfField; use primitives::mmcs::taptree_mmcs::TapTreeMmcs; -use rand::{thread_rng, Rng, SeedableRng}; -use rand_chacha::ChaCha20Rng; -use script_expr::{BfChallengerExpr, Dsl, Expression, ManagerAssign}; -use script_manager::bc_assignment::DefaultBCAssignment; -use scripts::execute_script_with_inputs; -use scripts::u31_lib::{u31ext_equalverify, BabyBear4}; +use script_expr::BfChallengerExpr; use uni_stark::{ - compute_quotient_expr, generate_script_verifier, get_log_quotient_degree, prove, verify, Proof, + generate_script_verifier, prove, verify, StarkConfig, }; From 81dd0f22adaf6f2fdf947dd74a56c195d694c6c6 Mon Sep 17 00:00:00 2001 From: 0xhhh <52317293+cyl19970726@users.noreply.github.com> Date: Sun, 1 Dec 2024 11:30:30 +0800 Subject: [PATCH 24/25] Apply TCS (#35) * apply new TCS * remove unuse file * cargo fix --allow-dirty * cargo fix --allow-dirty * cargo clippy --fix * cargo fix --clippy * fix warning --- Cargo.toml | 5 +- basic/Cargo.toml | 38 + {primitives => basic}/src/bf_pcs.rs | 0 .../src/challenger/chan_field.rs | 2 +- {primitives => basic}/src/challenger/mod.rs | 36 +- {primitives => basic}/src/field/mod.rs | 9 +- {primitives => basic}/src/lib.rs | 1 + {primitives => basic}/src/mmcs/bf_mmcs.rs | 15 +- {primitives => basic}/src/mmcs/error.rs | 0 {primitives => basic}/src/mmcs/mod.rs | 3 - basic/src/mmcs/taptree_mmcs.rs | 239 ++++ basic/src/tcs/builder.rs | 106 ++ basic/src/tcs/complete_taptree.rs | 372 ++++++ basic/src/tcs/error.rs | 11 + basic/src/tcs/mod.rs | 718 ++++++++++ common/Cargo.toml | 4 +- common/src/lib.rs | 2 +- fri/Cargo.toml | 43 +- fri/src/config.rs | 2 +- fri/src/error.rs | 2 +- fri/src/fold_even_odd.rs | 121 +- fri/src/fri_scripts/fiat_shamir_subtree.rs | 863 ------------ fri/src/fri_scripts/leaf.rs | 789 ----------- fri/src/fri_scripts/mod.rs | 4 - fri/src/fri_scripts/pcs.rs | 476 ------- fri/src/fri_scripts/point.rs | 250 ---- fri/src/fri_scripts/verify_folding.rs | 1159 ----------------- fri/src/lib.rs | 1 - fri/src/proof.rs | 11 +- fri/src/prover.rs | 33 +- fri/src/script_verifier.rs | 85 +- fri/src/two_adic_pcs.rs | 78 +- fri/src/verifier.rs | 85 +- fri/tests/fri.rs | 124 +- fri/tests/pcs.rs | 19 +- p3/Cargo.toml | 6 - p3/src/lib.rs | 14 - primitives/Cargo.toml | 37 - primitives/src/mmcs/point.rs | 266 ---- primitives/src/mmcs/tapleaf.rs | 42 - primitives/src/mmcs/taptree.rs | 622 --------- primitives/src/mmcs/taptree_mmcs.rs | 311 ----- script_expr/Cargo.toml | 22 +- script_expr/src/alias.rs | 4 +- script_expr/src/challenger_expr.rs | 23 +- script_expr/src/field_script_expr.rs | 115 -- script_expr/src/fraction_expr.rs | 71 - script_expr/src/input_manager.rs | 4 +- script_expr/src/lagrange.rs | 9 +- script_expr/src/lib.rs | 2 +- script_expr/src/opcode.rs | 19 +- script_expr/src/script_builder.rs | 2 +- script_expr/src/script_gen.rs | 2 +- script_expr/src/script_helper.rs | 5 +- script_expr/src/variable.rs | 2 +- script_manager/Cargo.toml | 48 - script_manager/README.md | 46 - script_manager/src/bc_assignment.rs | 120 -- script_manager/src/lib.rs | 3 - script_manager/src/planner.rs | 556 -------- script_manager/src/script_info.rs | 367 ------ scripts/Cargo.toml | 24 +- scripts/src/bit_comm/bit_comm.rs | 13 +- scripts/src/bit_comm/bit_comm_u32.rs | 6 +- scripts/src/bit_comm/winternitz.rs | 24 +- scripts/src/hashes/blake3.rs | 2 +- scripts/src/lib.rs | 4 +- scripts/src/u32/u32_rrot.rs | 11 +- scripts/src/u32/u32_std.rs | 6 +- scripts/src/u32/u32_zip.rs | 6 +- segment/Cargo.toml | 10 - segment/src/lib.rs | 16 - uni-stark/Cargo.toml | 40 +- uni-stark/src/config.rs | 8 +- uni-stark/src/expr_helper.rs | 7 +- uni-stark/src/proof.rs | 2 +- uni-stark/src/prover.rs | 2 +- uni-stark/src/script_verifier.rs | 14 +- uni-stark/src/scripts/bf_unistark.rs | 8 +- uni-stark/src/scripts/utils.rs | 11 +- uni-stark/src/verifier.rs | 4 +- uni-stark/src/zerofier_coset.rs | 5 +- uni-stark/tests/fib_air.rs | 36 +- uni-stark/tests/mul_air.rs | 2 +- 84 files changed, 1900 insertions(+), 6785 deletions(-) create mode 100644 basic/Cargo.toml rename {primitives => basic}/src/bf_pcs.rs (100%) rename {primitives => basic}/src/challenger/chan_field.rs (99%) rename {primitives => basic}/src/challenger/mod.rs (91%) rename {primitives => basic}/src/field/mod.rs (94%) rename {primitives => basic}/src/lib.rs (83%) rename {primitives => basic}/src/mmcs/bf_mmcs.rs (88%) rename {primitives => basic}/src/mmcs/error.rs (100%) rename {primitives => basic}/src/mmcs/mod.rs (62%) create mode 100644 basic/src/mmcs/taptree_mmcs.rs create mode 100644 basic/src/tcs/builder.rs create mode 100644 basic/src/tcs/complete_taptree.rs create mode 100644 basic/src/tcs/error.rs create mode 100644 basic/src/tcs/mod.rs delete mode 100644 fri/src/fri_scripts/fiat_shamir_subtree.rs delete mode 100644 fri/src/fri_scripts/leaf.rs delete mode 100644 fri/src/fri_scripts/mod.rs delete mode 100644 fri/src/fri_scripts/pcs.rs delete mode 100644 fri/src/fri_scripts/point.rs delete mode 100644 fri/src/fri_scripts/verify_folding.rs delete mode 100644 p3/Cargo.toml delete mode 100644 p3/src/lib.rs delete mode 100644 primitives/Cargo.toml delete mode 100644 primitives/src/mmcs/point.rs delete mode 100644 primitives/src/mmcs/tapleaf.rs delete mode 100644 primitives/src/mmcs/taptree.rs delete mode 100644 primitives/src/mmcs/taptree_mmcs.rs delete mode 100644 script_expr/src/field_script_expr.rs delete mode 100644 script_expr/src/fraction_expr.rs delete mode 100644 script_manager/Cargo.toml delete mode 100644 script_manager/README.md delete mode 100644 script_manager/src/bc_assignment.rs delete mode 100644 script_manager/src/lib.rs delete mode 100644 script_manager/src/planner.rs delete mode 100644 script_manager/src/script_info.rs delete mode 100644 segment/Cargo.toml delete mode 100644 segment/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 09bef38..78b0e8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,8 @@ [workspace] members = [ "fri", - "primitives", - "p3", + "basic", "scripts", - "script_manager", - "segment", "common", "uni-stark" , "script_expr"] diff --git a/basic/Cargo.toml b/basic/Cargo.toml new file mode 100644 index 0000000..b0f0df9 --- /dev/null +++ b/basic/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "basic" +version = "0.1.0" +edition = "2021" + +[dependencies] +bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } +bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bitvm", features = ["serde"] } +bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec", branch = "bitvm"} +bitcomm = { git = "https://github.com/bitlayer-org/bitcoin-verifier", branch = "bitvm"} +primitives = { git = "https://github.com/bitlayer-org/bitcoin-verifier", branch = "bitvm" } + +lazy_static = "1.4.0" +itertools = "0.12.0" +tracing = "0.1.37" +tracing-subscriber = { version = "0.3.17", features = ["std", "env-filter"] } +serde = { version = "1.0", default-features = false, features = ["derive", "alloc"] } +blake3 = "1.5" +rand = "0.8.5" +rand_chacha = "0.3.1" + + +p3-symmetric ={ git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-field = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-util = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-maybe-rayon ={ git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-matrix = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-commit = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } + +common = { path = "../common"} +scripts = {path = "../scripts"} + +[dev-dependencies] +p3-interpolation = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-dft = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-maybe-rayon ={ git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } \ No newline at end of file diff --git a/primitives/src/bf_pcs.rs b/basic/src/bf_pcs.rs similarity index 100% rename from primitives/src/bf_pcs.rs rename to basic/src/bf_pcs.rs diff --git a/primitives/src/challenger/chan_field.rs b/basic/src/challenger/chan_field.rs similarity index 99% rename from primitives/src/challenger/chan_field.rs rename to basic/src/challenger/chan_field.rs index c3a3f19..913dd43 100644 --- a/primitives/src/challenger/chan_field.rs +++ b/basic/src/challenger/chan_field.rs @@ -38,7 +38,7 @@ pub trait PermutationField: for _ in 0..U8_NUM { by.push(0); } - 1 << U8_NUM * 3 + 1 << (U8_NUM * 3) } fn from_u64(value: u64) -> Self { diff --git a/primitives/src/challenger/mod.rs b/basic/src/challenger/mod.rs similarity index 91% rename from primitives/src/challenger/mod.rs rename to basic/src/challenger/mod.rs index 11f2d2e..e327acb 100644 --- a/primitives/src/challenger/mod.rs +++ b/basic/src/challenger/mod.rs @@ -33,7 +33,7 @@ impl Permutation for Blake3Permutation { fn permute_mut(&self, input: &mut StateLength) { let mut hasher = blake3::Hasher::new(); - for chunk in input.clone() { + for chunk in *input { hasher.update(&chunk); } let hashed: [u8; 32] = hasher.finalize().into(); @@ -100,7 +100,7 @@ where .expect("failed to find witness"); assert!(self.check_witness(bits, witness)); self.grind_bits = Some(bits); - self.grind_output = self.sample_output.last().unwrap().clone(); + self.grind_output = *self.sample_output.last().unwrap(); witness } @@ -138,7 +138,7 @@ where pub fn record_sample(&mut self, input: &Vec, output: &F) { self.sample_input.push(input.clone()); - self.sample_output.push(output.clone()); + self.sample_output.push(*output); } } @@ -158,17 +158,17 @@ where // Record this permutation to build fiat shamir subtree for future self.permutation_input_records - .push(self.sponge_state.try_into().unwrap()); + .push(self.sponge_state.into()); // Apply the permutation. self.permutation.permute_mut(&mut self.sponge_state); self.permutation_output_records - .push(self.sponge_state[WIDTH / 2..WIDTH].try_into().unwrap()); + .push(self.sponge_state[WIDTH / 2..WIDTH].into()); self.output_buffer.clear(); for i in WIDTH / 2..WIDTH { - self.output_buffer.push(self.sponge_state[i].clone()); + self.output_buffer.push(self.sponge_state[i]); } tracing::debug! {"state change: {:?}", u32::from_le_bytes(self.sponge_state[8].as_u8_array())}; } @@ -208,6 +208,20 @@ where } } +impl CanObserve> + for BfChallenger +where + F: Field + BitExtractor, + PF: PermutationField<4>, + P: CryptographicPermutation<[PF; WIDTH]>, +{ + fn observe(&mut self, values: Vec<[PF; N]>) { + for value in values { + self.observe(value); + } + } +} + impl CanObserve> for BfChallenger where @@ -262,7 +276,7 @@ where // commit records let output = BabyBear::from_pf(&value); sample_input.push(value); - res = (&output as &dyn Any).downcast_ref::().unwrap().clone(); + res = *(&output as &dyn Any).downcast_ref::().unwrap(); } // else, F would be a extension field of Babybear else if TypeId::of::() == TypeId::of::>() { @@ -287,7 +301,7 @@ where // commit records let output = BinomialExtensionField::::from_base_slice(&base_slice); - res = (&output as &dyn Any).downcast_ref::().unwrap().clone(); + res = *(&output as &dyn Any).downcast_ref::().unwrap(); } else { panic!("the type of base or f is invalid") } // no other implementation yet @@ -311,10 +325,8 @@ impl BitExtractor for BabyBear { impl BitExtractor for BinomialExtensionField { fn as_usize(&self) -> usize { - let s: BabyBear = >::as_base_slice(self) - .get(0) - .unwrap() - .clone(); + let s: BabyBear = *>::as_base_slice(self).first() + .unwrap(); s.as_canonical_u32() as usize } } diff --git a/primitives/src/field/mod.rs b/basic/src/field/mod.rs similarity index 94% rename from primitives/src/field/mod.rs rename to basic/src/field/mod.rs index 08d450a..fa87431 100644 --- a/primitives/src/field/mod.rs +++ b/basic/src/field/mod.rs @@ -24,7 +24,7 @@ pub trait BfField: AbstractField + TwoAdicField + Clone + Copy + AsU32Vec { subgroups.push(Self::one()); for _ in 0..group_size - 1 { subgroups.push(acc); - acc = acc * generator; + acc *= generator; } subgroups } @@ -62,12 +62,9 @@ impl BfField for BinomialExtensionField { .collect() } } - +#[cfg(test)] mod tests { - use p3_baby_bear::BabyBear; - use p3_field::{AbstractField, PrimeField32}; - - use super::BfField; + use super::*; #[test] fn test_subgroup() { diff --git a/primitives/src/lib.rs b/basic/src/lib.rs similarity index 83% rename from primitives/src/lib.rs rename to basic/src/lib.rs index 4c2c235..afaac7c 100644 --- a/primitives/src/lib.rs +++ b/basic/src/lib.rs @@ -2,3 +2,4 @@ pub mod bf_pcs; pub mod challenger; pub mod field; pub mod mmcs; +pub mod tcs; diff --git a/primitives/src/mmcs/bf_mmcs.rs b/basic/src/mmcs/bf_mmcs.rs similarity index 88% rename from primitives/src/mmcs/bf_mmcs.rs rename to basic/src/mmcs/bf_mmcs.rs index b6f749a..0a9d29c 100644 --- a/primitives/src/mmcs/bf_mmcs.rs +++ b/basic/src/mmcs/bf_mmcs.rs @@ -33,28 +33,21 @@ pub trait BFMmcs: Clone { self.commit_matrix(RowMajorMatrix::new_col(input)) } - fn open_taptree(&self, index: usize, prover_data: &Self::ProverData) -> Self::Proof; fn open_batch( &self, - index: usize, + query_times_index: usize, + query_index: usize, // This is the index corresponding to the highest matrix prover_data: &Self::ProverData, - ) -> (Vec>, Self::Proof) { - unimplemented!() - } + ) -> (Vec>, Self::Proof); fn verify_batch( &self, + query_times_index: usize, opened_values: &Vec>, proof: &Self::Proof, root: &Self::Commitment, ) -> Result<(), Self::Error>; - fn verify_taptree( - &self, - proof: &Self::Proof, - root: &Self::Commitment, - ) -> Result<(), Self::Error>; - /// Get the matrices that were committed to. fn get_matrices<'a>(&self, prover_data: &'a Self::ProverData) -> Vec<&'a RowMajorMatrix>; diff --git a/primitives/src/mmcs/error.rs b/basic/src/mmcs/error.rs similarity index 100% rename from primitives/src/mmcs/error.rs rename to basic/src/mmcs/error.rs diff --git a/primitives/src/mmcs/mod.rs b/basic/src/mmcs/mod.rs similarity index 62% rename from primitives/src/mmcs/mod.rs rename to basic/src/mmcs/mod.rs index 3579e4f..ea2ad1e 100644 --- a/primitives/src/mmcs/mod.rs +++ b/basic/src/mmcs/mod.rs @@ -2,7 +2,4 @@ pub mod bf_mmcs; pub mod error; -pub mod point; -pub mod tapleaf; -pub mod taptree; pub mod taptree_mmcs; diff --git a/basic/src/mmcs/taptree_mmcs.rs b/basic/src/mmcs/taptree_mmcs.rs new file mode 100644 index 0000000..3d8924b --- /dev/null +++ b/basic/src/mmcs/taptree_mmcs.rs @@ -0,0 +1,239 @@ +use core::marker::PhantomData; +use core::usize; + +use bitcoin::hashes::Hash as Bitcoin_HASH; +use bitcoin::TapNodeHash; +use itertools::Itertools; +use p3_matrix::dense::RowMajorMatrix; +use p3_matrix::Matrix; +use p3_util::log2_ceil_usize; + +use super::bf_mmcs::BFMmcs; +use super::error::BfError; +use crate::challenger::chan_field::{u256_to_u32, u32_to_u256, U32}; +use crate::field::BfField; +use crate::tcs::{ + CommitedData, CommitedProof, DefaultSyncBcManager, PolyTCS, B, BM, BO, SG, TCS, +}; + +pub type TreeRoot = [U32; ROOT_WIDTH]; +// Commit two adjacent points to a leaf node +pub const DEFAULT_MATRIX_WIDTH: usize = 2; +pub const LOG_DEFAULT_MATRIX_WIDTH: usize = 1; + +pub const ROOT_WIDTH: usize = 8; +#[derive(Clone)] +pub struct TapTreeMmcs { + tcs: TCS, + num_queries: usize, + _marker: PhantomData, +} + +impl<'a, F> TapTreeMmcs { + pub fn new(manager: DefaultSyncBcManager, num_queries: usize) -> Self { + Self { + tcs: TCS::new(manager), + num_queries, + _marker: PhantomData, + } + } +} + +impl BFMmcs for TapTreeMmcs { + type ProverData = Vec>; + type Proof = CommitedProof; + type Commitment = Vec; + type Error = BfError; + + fn open_batch( + &self, + query_times_index: usize, + query_index: usize, // This is the index corresponding to the highest matrix + prover_data: &Self::ProverData, + ) -> (Vec>, Self::Proof) { + let max_height = prover_data[0].get_max_height(); + let log_max_height = log2_ceil_usize(max_height); + let openings = prover_data[0] + .leaves + .iter() + .map(|matrix| { + let log2_height = log2_ceil_usize(matrix.height()); + let bits_reduced = log_max_height - log2_height; + let reduced_index = query_index >> bits_reduced; + matrix.row(reduced_index).collect() + }) + .collect_vec(); + + let (commited_proof, openings_evals) = self.tcs.open_with_one_query( + query_times_index, + query_index, + prover_data, + self.num_queries, + ); + let openings_flatten: Vec = openings.clone().into_iter().flatten().collect(); + assert_eq!(openings_flatten, openings_evals); + + (openings, commited_proof) + } + + fn verify_batch( + &self, + query_times_index: usize, + opened_values: &Vec>, + proofs: &Self::Proof, + roots: &Self::Commitment, + ) -> Result<(), Self::Error> { + let openings_flatten: Vec = opened_values.clone().into_iter().flatten().collect(); + + let commitments: Vec = roots + .iter() + .map(|root| TapNodeHash::from_byte_array(u32_to_u256(*root))) + .collect(); + + let success = self + .tcs + .verify(commitments[query_times_index], proofs, openings_flatten); + if success { + Ok(()) + } else { + Err(BfError::InvalidOpenedValue) + } + } + + fn commit(&self, inputs: Vec>) -> (Self::Commitment, Self::ProverData) { + let commited_data = self + .tcs + .commit_poly_with_query_times(inputs, self.num_queries); + let commitments: Vec<[U32; 8]> = commited_data + .iter() + .map(|data| { + let root = *data + .commit_taptree + .root() + .hash + .as_byte_array(); + u256_to_u32(root) + }) + .collect(); + + (commitments, commited_data) + } + + fn get_matrices<'a>(&self, prover_data: &'a Self::ProverData) -> Vec<&'a RowMajorMatrix> { + prover_data[0].leaves.iter().collect() + } +} + +#[cfg(test)] +mod test { + + use p3_baby_bear::BabyBear; + use p3_field::AbstractField; + use p3_matrix::dense::RowMajorMatrix; + + + use super::TapTreeMmcs; + use crate::mmcs::bf_mmcs::BFMmcs; + use crate::tcs::DefaultSyncBcManager; + type F = BabyBear; + + #[test] + fn test_taptree_mmcs() { + // mat_1 = [ + // 0 1 + // 2 1 + // 2 2 + // 1 0 + // ] + let mat_1 = RowMajorMatrix::new( + vec![ + F::zero(), + F::one(), + F::two(), + F::one(), + F::two(), + F::two(), + F::one(), + F::zero(), + ], + 2, + ); + + // mat_2 = [ + // 0 1 2 1 + // 2 2 1 0 + // 0 1 2 1 + // 2 2 1 0 + // ] + let mat_2 = RowMajorMatrix::new( + vec![ + F::zero(), + F::one(), + F::two(), + F::one(), + F::two(), + F::two(), + F::one(), + F::zero(), + F::zero(), + F::one(), + F::two(), + F::one(), + F::two(), + F::two(), + F::one(), + F::zero(), + ], + 4, + ); + + // mat_3 = [ + // 0 + // 1 + // 2 + // 1 + // 2 + // 2 + // 1 + // 0 + // ] + let mat_3 = RowMajorMatrix::new( + vec![ + F::zero(), + F::one(), + F::two(), + F::one(), + F::two(), + F::two(), + F::one(), + F::zero(), + ], + 1, + ); + + // we get pointleafs like: + // index:0, ys:[0, 0, 1, 0, 1, 2, 1] + // index:1, ys:[1, 0, 1, 0, 1, 2, 1] + // index:2, ys:[2, 2, 1, 2, 2, 1, 0] + // index:3, ys:[1, 2, 1, 2, 2, 1, 0] + // index:4, ys:[2, 2, 2, 0, 1, 2, 1] + // index:5, ys:[2, 2, 2, 0, 1, 2, 1] + // index:6, ys:[1, 1, 0, 2, 2, 1, 0] + // index:7, ys:[0, 1, 0, 2, 2, 1, 0] + + // let inputs = vec![mat_1, mat_2, mat_3]; + let inputs = vec![mat_3, mat_2, mat_1]; + let query_times = 10; + let mmcs = TapTreeMmcs::new(DefaultSyncBcManager::new(), query_times); + let (commits, prover_datas) = mmcs.commit(inputs); + + for query_index in 0..8 { + for query_times_index in 0..query_times { + let (openings, proof) = + mmcs.open_batch(query_times_index, query_index, &prover_datas); + mmcs.verify_batch(query_times_index, &openings, &proof, &commits) + .unwrap(); + } + } + } +} diff --git a/basic/src/tcs/builder.rs b/basic/src/tcs/builder.rs new file mode 100644 index 0000000..ade17da --- /dev/null +++ b/basic/src/tcs/builder.rs @@ -0,0 +1,106 @@ +use bitcoin::taproot::LeafVersion::TapScript; +use bitcoin::taproot::NodeInfo; +use bitcoin::ScriptBuf; +use itertools::Itertools; + +use super::complete_taptree::CompleteTaptree; + +#[derive(Clone, Debug, Default)] +pub struct TreeBuilder { + pub(crate) leaf_count: usize, + pub(crate) leaf_indices: Vec, + pub(crate) to_add_leaves: Vec, +} + +impl TreeBuilder { + pub fn new() -> Self { + Self { + leaf_count: 0, + leaf_indices: Vec::new(), + to_add_leaves: Vec::new(), + } + } + + pub fn add_leaf(&mut self, leaf_script: ScriptBuf) { + self.leaf_count += 1; + let leaf = NodeInfo::new_leaf_with_ver(leaf_script, TapScript); + self.leaf_indices.push(self.leaf_count - 1); + self.to_add_leaves.push(leaf); + } + + /* + The leaves_indices are postion info of merkle tree leaves in the taptree. + When we building the taptree, it is much easier to work with a dict where the index is + the taptree position and the element is the merkle tree postion. + We flip the dict and save it to the leaf_indices. + + */ + pub fn build_tree(&mut self) -> CompleteTaptree { + let leaf_count = self.to_add_leaves.len(); + assert!(is_power_of_two(leaf_count as u32)); + // this build tree now only working on the leaf-num equal to + let mut working_nodes = self.to_add_leaves.clone(); + let mut t_idx_to_m_idx = self.leaf_indices.clone(); + + while working_nodes.len() > 1 { + // println!("working_nodes len:{:?}", working_nodes.len()); + //the tuple() method in itertool will drop the elements in Iter if the size is not enough to + //generate a tuple, so we have to save the last node if the size of working node is odd. + let mut reminder_node: Option = None; + if working_nodes.len() % 2 == 1 { + reminder_node = working_nodes.pop(); + } + + let node_tuples = working_nodes.into_iter().tuples(); + let mut todo: Vec = Vec::new(); + let mut a_start_idx = 0usize; // will be updated after finishing combining two nodes. + + for (a, b) in node_tuples { + let a_leaf_size = a.leaf_nodes().len(); + let a_end_idx = a_start_idx + a_leaf_size; + let b_start_idx = a_end_idx; + let b_leaf_size = b.leaf_nodes().len(); + let b_end_idx = b_start_idx + b_leaf_size; + let (ret_node, left_first) = NodeInfo::combine_with_order(a, b).unwrap(); + + todo.push(ret_node); + + //swap index when !left_first + if !left_first { + let mut temp_a_leaf_indices = vec![0usize; a_leaf_size]; + temp_a_leaf_indices + .as_mut_slice() + .copy_from_slice(&t_idx_to_m_idx[a_start_idx..a_end_idx]); + + let mut temp_b_leaf_indices = vec![0usize; b_leaf_size]; + temp_b_leaf_indices + .as_mut_slice() + .copy_from_slice(&t_idx_to_m_idx[b_start_idx..b_end_idx]); + temp_b_leaf_indices.append(&mut temp_a_leaf_indices); + t_idx_to_m_idx[a_start_idx..b_end_idx] + .copy_from_slice(temp_b_leaf_indices.as_slice()); + } + a_start_idx += a_leaf_size + b_leaf_size; + } + working_nodes = todo; + todo = Vec::new(); + } + CompleteTaptree::new( + working_nodes.into_iter().next().unwrap(), + leaf_count, + reverse_idx_dict(&t_idx_to_m_idx), + ) + } +} + +pub(crate) fn reverse_idx_dict(idx_dict: &Vec) -> Vec { + let mut ret_vec = vec![0usize; idx_dict.len()]; + for (idx, pos) in idx_dict.iter().enumerate() { + ret_vec[*pos] = idx; + } + ret_vec +} + +fn is_power_of_two(n: u32) -> bool { + n > 0 && (n & (n - 1)) == 0 +} diff --git a/basic/src/tcs/complete_taptree.rs b/basic/src/tcs/complete_taptree.rs new file mode 100644 index 0000000..2222bf3 --- /dev/null +++ b/basic/src/tcs/complete_taptree.rs @@ -0,0 +1,372 @@ +use bitcoin::taproot::{LeafNode, LeafNodes, NodeInfo, TaprootMerkleBranch}; +use bitcoin::TapNodeHash; + +use super::builder::TreeBuilder; +use super::{combine_two_nodes, ScriptToEmbbed, TaptreeConcater}; + +#[derive(Clone, Debug)] +pub(crate) struct CompleteTaptree { + pub root_node: NodeInfo, + leaf_count: usize, + leaf_indices: Vec, +} + +impl CompleteTaptree { + pub fn new(root: NodeInfo, leaf_count: usize, leaf_indices: Vec) -> Self { + CompleteTaptree { + root_node: root, + leaf_count, + leaf_indices, + } + } + + pub fn root(&self) -> &NodeInfo { + + (&self.root_node) as _ + } + + pub fn leaf_count(&self) -> usize { + self.leaf_count + } + + pub fn leaves(&self) -> LeafNodes { + let nodes = self.root_node.leaf_nodes(); + nodes + } + + pub fn get_leaf_merkle_path(&self, index: usize) -> Option<&TaprootMerkleBranch> { + let index = self.index_map(index); + if let Some(leaf) = self.leaves().nth(index) { + Some(leaf.merkle_branch()) + } else { + None + } + } + + fn index_map(&self, index: usize) -> usize { + self.leaf_indices[index] + } + + pub fn get_tapleaf(&self, index: usize) -> Option<&LeafNode> { + let index = self.index_map(index); + self.leaves().nth(index) + } + + pub(crate) fn verify_inclusion_by_index(&self, index: usize) -> bool { + let index = self.index_map(index); + let leaf = self.get_tapleaf(index).unwrap(); + let path = self.get_leaf_merkle_path(index).unwrap(); + let mut first_node_hash = TapNodeHash::from_node_hashes(leaf.node_hash(), path[0]); + path[1..].iter().for_each(|sibling_node| { + first_node_hash = TapNodeHash::from_node_hashes(first_node_hash, *sibling_node); + }); + + first_node_hash == self.root().node_hash() + } +} + +pub fn verify_inclusion(root: TapNodeHash, leaf: &LeafNode) -> bool { + let path = leaf.merkle_branch(); + let mut first_node_hash = TapNodeHash::from_node_hashes(leaf.node_hash(), path[0]); + path[1..].iter().for_each(|sibling_node| { + first_node_hash = TapNodeHash::from_node_hashes(first_node_hash, *sibling_node); + }); + + first_node_hash == root +} + +impl TaptreeConcater for CompleteTaptree { + fn new_with_scripts(scripts: Vec) -> Self { + let mut builder = TreeBuilder::new(); + for script in scripts { + builder.add_leaf(script.compelte_script()); + } + builder.build_tree() + } + + // todo: add test + fn combine_other_script(&mut self, scripts: Vec) -> Self { + let mut builder = TreeBuilder::new(); + for script in scripts { + builder.add_leaf(script.compelte_script()); + } + let other_tapree = builder.build_tree(); + self.combine(other_tapree) + } + + fn combine(&self, other: impl TaptreeConcater) -> Self { + let mut a_leaf_indices: Vec = self.get_indices().clone(); + let mut b_leaf_indices = other.get_indices().clone(); + + let (combined_tree, left_first) = + combine_two_nodes(self.get_root().clone(), other.get_root().clone()).unwrap(); + + // if the left_first is ture, leaves will places as [a.leaves... ,b.leaves...] + let taptree_indices = match left_first { + // for swap no happen, for the merkletree index is [a_merkle_tree_indices,b_merkle_tree_indices] + // the acctually taptree indices is [a_taptree_indices,b_taptree_indices] + true => { + for b_idx in b_leaf_indices.iter_mut() { + *b_idx += self.leaf_count(); + } + a_leaf_indices.append(&mut b_leaf_indices); + println!("left first {:?}", a_leaf_indices); + a_leaf_indices + } + false => { + // for swap happen, for the merkletree index is still [a_merkle_tree_indices,b_merkle_tree_indices] + // the acctually taptree indices is [b_taptree_indices,a_taptree_indices] + for a_idx in a_leaf_indices.iter_mut() { + *a_idx += other.leaf_count(); + } + a_leaf_indices.append(&mut b_leaf_indices); + + println!("right first {:?}", a_leaf_indices); + a_leaf_indices + } + }; + + Self { + root_node: combined_tree, + leaf_count: taptree_indices.len(), + leaf_indices: taptree_indices, + } + } + + fn get_indices(&self) -> &Vec { + &self.leaf_indices + } + + fn leaf_count(&self) -> usize { + self.leaf_count + } + + fn get_root(&self) -> &NodeInfo { + &self.root_node + } + + fn get_leaf_proof(&self, index: usize) -> (LeafNode, TaprootMerkleBranch) { + let leaf = self.get_tapleaf(index).unwrap(); + let path = self.get_leaf_merkle_path(index).unwrap(); + (leaf.clone(), path.clone()) + } +} + +#[cfg(test)] +mod tests { + + + use bitcoin::ScriptBuf; + use bitcoin_script::{define_pushable, script}; + + use super::{CompleteTaptree, TaptreeConcater}; + define_pushable!(); + + #[test] + fn test_build_tree() { + let nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15u32]; + // let nums = vec![0,1,2,3,4,5,6,7,8,10,11,12,13,14,15u32]; + // let nums = vec![1u32]; + let scripts = nums + .iter() + .map(|index| { + script! { + {*index} + OP_ADD + + } + }) + .collect::>(); + + let a_tree = CompleteTaptree::new_with_scripts(scripts); + + assert_eq!(a_tree.leaf_count(), 16); + + let ap = a_tree.get_tapleaf(0).unwrap(); + assert_eq!( + ap.leaf().as_script().unwrap().0.as_bytes(), + script! { {0} OP_ADD}.as_bytes() + ); + + let ap = a_tree.get_tapleaf(6).unwrap(); + assert_eq!( + ap.leaf().as_script().unwrap().0.as_bytes(), + script! { {6} OP_ADD}.as_bytes() + ); + + let indices = a_tree.get_indices(); + println!("{:?}", indices); + // let ap = a_tree.get_tapleaf(8).unwrap(); + // println!("ap {:?}",ap); + + for (query_index, value) in nums.iter().enumerate() { + println!("query_index {:?}, value: {:?}", query_index, value); + let ap = a_tree.get_tapleaf(query_index).unwrap(); + assert!(a_tree.verify_inclusion_by_index(query_index)); + assert_eq!( + ap.leaf().as_script().unwrap().0.as_bytes(), + script! { {*value} OP_ADD}.as_bytes() + ); + } + } + + #[test] + fn test_combine_tree() { + let nums = [0, 1, 2, 3, 4, 5, 6, 7u32]; + let scripts = nums + .iter() + .map(|index| { + script! { + {*index} + OP_ADD + + } + }) + .collect::>(); + + let a_tree = CompleteTaptree::new_with_scripts(scripts); + + for (query_index, value) in nums.iter().enumerate() { + let ap = a_tree.get_tapleaf(query_index).unwrap(); + assert_eq!( + ap.leaf().as_script().unwrap().0.as_bytes(), + script! { {*value} OP_ADD}.as_bytes() + ); + } + + let b_nums = [8, 9, 10, 11, 12, 13, 14, 15u32]; + let b_scripts = b_nums + .iter() + .map(|index| { + script! { + {*index} + OP_ADD + + } + }) + .collect::>(); + let b_tree = CompleteTaptree::new_with_scripts(b_scripts); + for (query_index, value) in b_nums.iter().enumerate() { + let ap = b_tree.get_tapleaf(query_index).unwrap(); + assert_eq!( + ap.leaf().as_script().unwrap().0.as_bytes(), + script! { {*value} OP_ADD}.as_bytes() + ); + } + + // combine tree with right-first + let c_tree = a_tree.clone().combine(b_tree.clone()); + println!("a_tree: {:?}", a_tree.leaf_indices); + println!("b_tree: {:?}", b_tree.leaf_indices); + println!("c_tree: {:?}", c_tree.leaf_indices); + let expect_nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15u32]; + for (query_index, value) in expect_nums.iter().enumerate() { + println!("query_index {:?}, value: {:?}", query_index, value); + let ap = c_tree.get_tapleaf(query_index).unwrap(); + println!("{:?}", ap.leaf().as_script().unwrap()); + assert!(c_tree.verify_inclusion_by_index(query_index)); + assert_eq!( + ap.leaf().as_script().unwrap().0.as_bytes(), + script! { {*value} OP_ADD}.as_bytes() + ); + } + + // combine tree with left-first + let c_tree = b_tree.clone().combine(a_tree.clone()); + + println!("a_tree: {:?}", a_tree.leaf_indices); + println!("b_tree: {:?}", b_tree.leaf_indices); + println!("c_tree: {:?}", c_tree.leaf_indices); + let expect_nums = [8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7u32]; + for (query_index, value) in expect_nums.iter().enumerate() { + println!("query_index {:?}, value: {:?}", query_index, value); + let ap = c_tree.get_tapleaf(query_index).unwrap(); + println!("{:?}", ap.leaf().as_script().unwrap()); + assert!(c_tree.verify_inclusion_by_index(query_index)); + assert_eq!( + ap.leaf().as_script().unwrap().0.as_bytes(), + script! { {*value} OP_ADD}.as_bytes() + ); + } + } + + #[test] + fn test_combine_with_different_depth() { + let nums = [0, 1, 2, 3, 4, 5, 6, 7u32]; + let scripts = nums + .iter() + .map(|index| { + script! { + {*index} + OP_ADD + + } + }) + .collect::>(); + + let a_tree = CompleteTaptree::new_with_scripts(scripts); + + for (query_index, value) in nums.iter().enumerate() { + let ap = a_tree.get_tapleaf(query_index).unwrap(); + assert_eq!( + ap.leaf().as_script().unwrap().0.as_bytes(), + script! { {*value} OP_ADD}.as_bytes() + ); + } + + let b_nums = [8, 9, 10, 11u32]; + let b_scripts = b_nums + .iter() + .map(|index| { + script! { + {*index} + OP_ADD + + } + }) + .collect::>(); + let b_tree = CompleteTaptree::new_with_scripts(b_scripts); + for (query_index, value) in b_nums.iter().enumerate() { + let ap = b_tree.get_tapleaf(query_index).unwrap(); + assert_eq!( + ap.leaf().as_script().unwrap().0.as_bytes(), + script! { {*value} OP_ADD}.as_bytes() + ); + } + + // combine tree with right-first + let c_tree = a_tree.clone().combine(b_tree.clone()); + println!("a_tree: {:?}", a_tree.leaf_indices); + println!("b_tree: {:?}", b_tree.leaf_indices); + println!("c_tree: {:?}", c_tree.leaf_indices); + let expect_nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11u32]; + for (query_index, value) in expect_nums.iter().enumerate() { + println!("query_index {:?}, value: {:?}", query_index, value); + let ap = c_tree.get_tapleaf(query_index).unwrap(); + println!("{:?}", ap.leaf().as_script().unwrap()); + assert!(c_tree.verify_inclusion_by_index(query_index)); + assert_eq!( + ap.leaf().as_script().unwrap().0.as_bytes(), + script! { {*value} OP_ADD}.as_bytes() + ); + } + + // combine tree with left-first + let c_tree = b_tree.clone().combine(a_tree.clone()); + + println!("a_tree: {:?}", a_tree.leaf_indices); + println!("b_tree: {:?}", b_tree.leaf_indices); + println!("c_tree: {:?}", c_tree.leaf_indices); + let expect_nums = [8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7u32]; + for (query_index, value) in expect_nums.iter().enumerate() { + println!("query_index {:?}, value: {:?}", query_index, value); + let ap = c_tree.get_tapleaf(query_index).unwrap(); + println!("{:?}", ap.leaf().as_script().unwrap()); + assert!(c_tree.verify_inclusion_by_index(query_index)); + assert_eq!( + ap.leaf().as_script().unwrap().0.as_bytes(), + script! { {*value} OP_ADD}.as_bytes() + ); + } + } +} diff --git a/basic/src/tcs/error.rs b/basic/src/tcs/error.rs new file mode 100644 index 0000000..c6eb505 --- /dev/null +++ b/basic/src/tcs/error.rs @@ -0,0 +1,11 @@ +use bitcoin::taproot::TaprootBuilderError; +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum TCSError { + TaprootBuilderError(TaprootBuilderError), +} + +impl From for TCSError { + fn from(error: TaprootBuilderError) -> Self { + TCSError::TaprootBuilderError(error) + } +} diff --git a/basic/src/tcs/mod.rs b/basic/src/tcs/mod.rs new file mode 100644 index 0000000..f682a75 --- /dev/null +++ b/basic/src/tcs/mod.rs @@ -0,0 +1,718 @@ +// use std::str::pattern::SearchStep; + +use std::cmp::Reverse; +use std::marker::PhantomData; +use std::slice::Iter; +use std::sync::{Arc, Mutex}; + +use bitcoin::taproot::{LeafNode, NodeInfo, TaprootMerkleBranch}; +use bitcoin::{ScriptBuf, TapNodeHash}; +use bitcoin_script::{define_pushable, script}; +use bitcomm::{BcManagerIns, BcOperator, SecretGenIns, Winternitz}; +use complete_taptree::{verify_inclusion, CompleteTaptree}; +use error::TCSError; +use itertools::Itertools; +use p3_matrix::dense::RowMajorMatrix; +use p3_matrix::Matrix; +use p3_util::log2_ceil_usize; +use primitives::{ + BCManager, BCommitOperator, BCommitWithSecret, CommitType, CompressType, SecretGen, +}; +use scripts::execute_script_with_inputs; +use serde::{Deserialize, Serialize}; + +use crate::field::BfField; +define_pushable!(); + +pub mod builder; +pub mod complete_taptree; +pub mod error; + +pub type SG = SecretGenIns; +pub type B = Winternitz; +pub type BO = BcOperator; +pub type BM = BcManagerIns; +pub type DefaultSyncBcManager = SyncBcManager; + +#[derive(Clone)] +pub struct SyncBcManager< + BM: BCManager, + SG: SecretGen, + BC: BCommitOperator, + B: BCommitWithSecret, +> { + bc_manager: Arc>>, + _marker: PhantomData<(SG, BC, B)>, +} + +impl, SG: SecretGen, BC: BCommitOperator, B: BCommitWithSecret> Default for SyncBcManager { + fn default() -> Self { + Self::new() + } +} + +impl, SG: SecretGen, BC: BCommitOperator, B: BCommitWithSecret> + SyncBcManager +{ + fn assign_bc(&self, ct: CommitType) -> BC { + self.bc_manager.lock().unwrap().assign_bc(ct) + } + + pub fn new() -> Self { + Self { + bc_manager: Arc::new(Mutex::new(Box::new(BM::new(SG::new())))), + _marker: PhantomData, + } + } +} + +#[derive(Clone)] +pub struct TCS< + BM: BCManager, + SG: SecretGen, + BC: BCommitOperator, + B: BCommitWithSecret, +> { + bc_manager: SyncBcManager, + _marker: PhantomData<(SG, BC, B)>, +} + +#[derive(Clone)] +pub struct CommitedData, B: BCommitWithSecret> { + pub(crate) leaves: Vec>, + pub(crate) commit_leaves: Vec>, + pub(crate) commit_taptree: CompleteTaptree, + pub(crate) use_bcs: UseBComm, +} + +impl, B: BCommitWithSecret> CommitedData { + pub(crate) fn get_max_height(&self) -> usize { + let mut max_height = 0; + for matrix in &self.leaves { + max_height = max_height.max(matrix.height()); + } + max_height + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct CommitedProof, B: BCommitWithSecret> { + leaf: LeafNode, + use_bcs: UseBComm, + query_index: usize, +} + +type CommitProofAlias = (LeafNode, UseBComm, usize); + +impl, B: BCommitWithSecret> From> + for CommitedProof +{ + fn from(alias: CommitProofAlias) -> Self { + CommitedProof { + leaf: alias.0, + use_bcs: alias.1, + query_index: alias.2, + } + } +} + +impl, B: BCommitWithSecret> CommitedProof { + fn to_commited_leaf(self, evaluations: Vec) -> CommitedLeaf { + CommitedLeaf { + index: self.query_index, + evaluations, + use_bcs: self.use_bcs, + _marker: PhantomData, + } + } +} + +impl, B: BCommitWithSecret> CommitedData { + fn query_proof(&self, query_index: usize) -> CommitedProof { + let tapleaf = self.commit_taptree.get_tapleaf(query_index).unwrap(); + (tapleaf.clone(), self.use_bcs.clone(), query_index).into() + } +} + +pub fn verify_proof(root: TapNodeHash, leaf: &LeafNode, witness: Vec>) -> bool { + let inclusion = verify_inclusion(root, leaf); + let success = execute_script_with_inputs(leaf.script().unwrap().into(), witness).success; + inclusion && success +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct CommitedLeaf, B: BCommitWithSecret> { + use_bcs: UseBComm, + index: usize, + evaluations: Vec, + _marker: PhantomData, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct UseBComm, B: BCommitWithSecret> { + index_bc: BC, + evaluations_bc: Vec, + _marker: PhantomData, +} + +impl, B: BCommitWithSecret> CommitedLeaf { + fn new_with_bcs(bcs: UseBComm, index: usize, evaluations: Vec) -> Self { + Self { + use_bcs: bcs, + index, + evaluations, + _marker: PhantomData, + } + } + + fn generate_witness(&mut self) -> Vec> { + self.set_commited_value(); + let mut witness = vec![]; + self.use_bcs.evaluations_bc.iter().rev().for_each(|bc| { + witness.append(&mut bc.witness()); + }); + + witness.append(&mut self.use_bcs.index_bc.witness()); + witness + } + + fn set_commited_value(&mut self) { + self.use_bcs + .index_bc + .set_commit_value((self.index as u32).into()); + self.use_bcs + .evaluations_bc + .iter_mut() + .enumerate() + .for_each(|(index, bc)| { + bc.set_commit_value(self.evaluations[index].as_u32_vec().into()); + }); + } + + fn generate_script(&mut self) -> ScriptBuf { + self.set_commited_value(); + let mut exec_scripts = script! { + {self.use_bcs.index_bc.locking_script_with_type(CompressType::U32).compile() } + {self.index} + OP_EQUALVERIFY + }; + + self.use_bcs + .evaluations_bc + .iter() + .enumerate() + .for_each(|(index, bc)| { + let values = self.evaluations[index].as_u32_vec(); + exec_scripts = script! { + {exec_scripts.clone()} + { bc.locking_script_with_type(CompressType::U32).compile() } + for i in (0..values.len()).rev() { + {values[i]} + OP_EQUALVERIFY + } + }; + }); + + script! { + {exec_scripts} + OP_1 + } + } +} + +impl, SG: SecretGen, BC: BCommitOperator, B: BCommitWithSecret> + PolyTCS for TCS +{ + fn new(manager: SyncBcManager) -> Self { + Self { + bc_manager: manager, + _marker: PhantomData, + } + } + + + fn commit_polys(&self, leaves: Vec>) -> CommitedData { + let commit_type = match F::U32_SIZE { + 1 => CommitType::U32, + 4 => CommitType::U128, + _ => { + panic!("only support 1 or 4"); + } + }; + + let leaf_ys = self.padding_matrix(leaves.iter()); + + let first_width = leaf_ys[0].len(); + let max_height = leaf_ys.len(); + // assign bc here + let index_bc = self.bc_manager.assign_bc(CommitType::U32); + let evaluations_bc: Vec = (0..first_width) + .map(|_index| self.bc_manager.assign_bc(commit_type.clone())) + .collect(); + let use_bcs = UseBComm { + index_bc, + evaluations_bc, + _marker: PhantomData, + }; + let mut leaves_script = vec![]; + let mut commited_leaves = vec![]; + + for index in 0..max_height { + if !leaf_ys[index].is_empty() { + //println!("index:{:?}, ys:{:?}", index, leaf_ys[index]); + let mut to_commit_leaf = + CommitedLeaf::new_with_bcs(use_bcs.clone(), index, leaf_ys[index].clone()); + leaves_script.push(to_commit_leaf.generate_script()); + commited_leaves.push(to_commit_leaf); + } + } + + // generate commit taptree + let commit_tree = CompleteTaptree::new_with_scripts(leaves_script); + CommitedData { + leaves, + commit_leaves: commited_leaves, + commit_taptree: commit_tree, + use_bcs, + } + } + + fn commit_poly_with_query_times( + &self, + polys: Vec>, + total_query_times: usize, + ) -> Vec> { + (0..total_query_times) + .map(|_| self.commit_polys(polys.clone())) + .collect() + } + + fn open( + &self, + index: usize, + prover_data: &CommitedData, + ) -> (CommitedProof, Vec) { + let leaves_evals = self.padding_matrix(prover_data.leaves.iter()); + (prover_data.query_proof(index), leaves_evals[index].clone()) + } + + fn open_with_query_times( + &self, + indices: Vec, + prover_datas: &Vec>, + query_times: usize, + ) -> (Vec>, Vec>) { + assert_eq!(indices.len(), query_times); + assert_eq!(prover_datas.len(), query_times); + + let proofs = (0..query_times) + .zip(indices.clone()) + .map(|(query_times_index, query_index)| { + prover_datas[query_times_index].query_proof(query_index) + }) + .collect(); + + let leaves_evals = self.padding_matrix(prover_datas[0].leaves.iter()); + let opening_values: Vec> = indices + .iter() + .map(|query_index| leaves_evals[*query_index].clone()) + .collect(); + + (proofs, opening_values) + } +} + +// polynomial Taptree Commitment Scheme +pub trait PolyTCS< + BM: BCManager, + SG: SecretGen, + BC: BCommitOperator, + B: BCommitWithSecret, +> +{ + fn new(manager: SyncBcManager) -> Self; + + fn padding_matrix( + &self, + leaves: Iter<'_, p3_matrix::dense::DenseMatrix>, + ) -> Vec> { + //evaluations sorted by height + let mut leaves_largest_first = leaves.sorted_by_key(|l| Reverse(l.height())).peekable(); + let max_height = leaves_largest_first.peek().unwrap().height(); + let log_max_height = log2_ceil_usize(max_height); + //println!("max height:{:?}", max_height); + let mut leaf_ys = vec![vec![]; max_height]; + + for log_height in (0..log_max_height + 1).rev() { + let matrices = leaves_largest_first + .peeking_take_while(|m| log2_ceil_usize(m.height()) == log_height) + .collect_vec(); + if !matrices.is_empty() { + let curr_height = matrices[0].height(); + for matrix in matrices.iter() { + let width = matrix.width(); + for index in 0..curr_height { + //find which leaf to store + let curr_index = index << (log_max_height - log_height); + let next_index = (index + 1) << (log_max_height - log_height); + for i in 0..width { + for leaf_index in curr_index..next_index { + leaf_ys[leaf_index].push(matrix.values[index * matrix.width() + i]); + } + } + } + } + } + } + + // check the leaf_ys has the same width + let frist_width = leaf_ys[0].len(); + leaf_ys.iter().for_each(|ys| { + assert_eq!(frist_width, ys.len()); + }); + leaf_ys + } + // only use for prover + // different leaf use the same bit-comm set within the Polynomial-Commitment-Scheme-Taptree + // index use a unique bit-comm to simulate the open-index + // each evalutaion corresponding to each unique bitcomm within one leaf + // the sequences of bcs: vec, vec + // return the pair (polynomial index, query_times index) which uses to as the key of the polynomial taptree + fn commit_polys(&self, poly: Vec>) -> CommitedData; + + // only use for prover + // different leaf use the same bit-comm set within the Polynomial-Commitment-Scheme-Taptree + // index use a unique bit-comm to simulate the open-index + // each evalutaion corresponding to each unique bitcomm within one leaf + // the sequences of bcs: index-bitcomm, eval1-bitcomm, eval2-bitcomm ... + // return the polynomial index which uses to as the key of the polynomial taptree + fn commit_poly_with_query_times( + &self, + polys: Vec>, + total_query_times: usize, + ) -> Vec>; + + fn open( + &self, + query_index: usize, + prover_data: &CommitedData, + ) -> (CommitedProof, Vec); + + fn open_with_one_query( + &self, + query_times_index: usize, + query_index: usize, + prover_data: &Vec>, + query_times: usize, + ) -> (CommitedProof, Vec) { + assert_eq!(prover_data.len(), query_times); + self.open(query_index, &prover_data[query_times_index]) + } + + fn open_with_query_times( + &self, + indices: Vec, + prover_data: &Vec>, + query_times: usize, + ) -> (Vec>, Vec>); + + fn verify( + &self, + root: TapNodeHash, + proof: &CommitedProof, + opening_values: Vec, + ) -> bool { + // genreate the witness by constrcting the CommitedLeaf + let mut commited_leaf = proof.clone().to_commited_leaf(opening_values); + + verify_proof(root, &proof.leaf, commited_leaf.generate_witness()) + } + + fn verify_with_query_times( + &self, + root: Vec, + proofs: &Vec>, + opening_values: Vec>, + query_times: usize, + ) -> bool { + let mut success = true; + for query_times_index in 0..query_times { + if !success { + return false; + } + success = self.verify( + root[query_times_index], + &proofs[query_times_index], + opening_values[query_times_index].clone(), + ); + } + success + } + // each poly only support one query + // return the taptree_root,the tapleaf which should be opened, the merklepath for the opening tapleaf, and the bcs set +} + +trait TaptreeConcater { + fn new_with_scripts(scripts: Vec) -> Self; + + fn combine_other_script(&mut self, slash_scripts: Vec) -> Self; + + fn combine(&self, other: impl TaptreeConcater) -> Self; + + fn get_indices(&self) -> &Vec; + + fn leaf_count(&self) -> usize; + + fn get_root(&self) -> &NodeInfo; + + // + fn get_leaf_proof(&self, index: usize) -> (LeafNode, TaprootMerkleBranch); +} + +trait FinalTaptree { + fn to_taproot(&self) -> TapNodeHash; +} + +pub fn combine_two_nodes(a: NodeInfo, b: NodeInfo) -> Result<(NodeInfo, bool), TCSError> { + let parent = NodeInfo::combine_with_order(a, b)?; + Ok(parent) +} + +trait ScriptToEmbbed { + fn prefix_concat(&self) -> ScriptBuf { + ScriptBuf::new() + } + + fn suffix_concat(&self) -> ScriptBuf { + ScriptBuf::new() + } + + fn origin_script(&self) -> ScriptBuf; + + fn compelte_script(&self) -> ScriptBuf { + script! { + {self.prefix_concat()} + {self.origin_script()} + {self.suffix_concat()} + } + } +} + +impl ScriptToEmbbed for ScriptBuf { + fn origin_script(&self) -> ScriptBuf { + self.clone() + } +} + +#[cfg(test)] +mod tests { + use p3_baby_bear::BabyBear; + use p3_field::AbstractField; + use p3_matrix::dense::RowMajorMatrix; + + use super::*; + type F = BabyBear; + + #[test] + fn test_taptree_mmcs() { + // mat_1 = [ + // 0 1 + // 2 1 + // 2 2 + // 1 0 + // ] + let mat_1 = RowMajorMatrix::new( + vec![ + F::zero(), + F::one(), + F::two(), + F::one(), + F::two(), + F::two(), + F::one(), + F::zero(), + ], + 2, + ); + + // mat_2 = [ + // 0 1 2 1 + // 2 2 1 0 + // 0 1 2 1 + // 2 2 1 0 + // ] + let mat_2 = RowMajorMatrix::new( + vec![ + F::zero(), + F::one(), + F::two(), + F::one(), + F::two(), + F::two(), + F::one(), + F::zero(), + F::zero(), + F::one(), + F::two(), + F::one(), + F::two(), + F::two(), + F::one(), + F::zero(), + ], + 4, + ); + + // mat_3 = [ + // 0 + // 1 + // 2 + // 1 + // 2 + // 2 + // 1 + // 0 + // ] + let mat_3 = RowMajorMatrix::new( + vec![ + F::zero(), + F::one(), + F::two(), + F::one(), + F::two(), + F::two(), + F::one(), + F::zero(), + ], + 1, + ); + + // we get pointleafs like: + // index:0, ys:[0, 0, 1, 0, 1, 2, 1] + // index:1, ys:[1, 0, 1, 0, 1, 2, 1] + // index:2, ys:[2, 2, 1, 2, 2, 1, 0] + // index:3, ys:[1, 2, 1, 2, 2, 1, 0] + // index:4, ys:[2, 2, 2, 0, 1, 2, 1] + // index:5, ys:[2, 2, 2, 0, 1, 2, 1] + // index:6, ys:[1, 1, 0, 2, 2, 1, 0] + // index:7, ys:[0, 1, 0, 2, 2, 1, 0] + + let manager = DefaultSyncBcManager::new(); + let inputs = vec![mat_1, mat_2, mat_3]; + let tcs = TCS::new(manager); + let commit_data = tcs.commit_polys(inputs); + + (0..7).for_each(|index| { + let (proof, opening) = tcs.open(index, &commit_data); + assert!(tcs.verify(commit_data.commit_taptree.root().hash, &proof, opening)); + }) + } + + #[test] + fn test_taptree_mmcs_with_multi_query() { + // mat_1 = [ + // 0 1 + // 2 1 + // 2 2 + // 1 0 + // ] + let mat_1 = RowMajorMatrix::new( + vec![ + F::zero(), + F::one(), + F::two(), + F::one(), + F::two(), + F::two(), + F::one(), + F::zero(), + ], + 2, + ); + + // mat_2 = [ + // 0 1 2 1 + // 2 2 1 0 + // 0 1 2 1 + // 2 2 1 0 + // ] + let mat_2 = RowMajorMatrix::new( + vec![ + F::zero(), + F::one(), + F::two(), + F::one(), + F::two(), + F::two(), + F::one(), + F::zero(), + F::zero(), + F::one(), + F::two(), + F::one(), + F::two(), + F::two(), + F::one(), + F::zero(), + ], + 4, + ); + + // mat_3 = [ + // 0 + // 1 + // 2 + // 1 + // 2 + // 2 + // 1 + // 0 + // ] + let mat_3 = RowMajorMatrix::new( + vec![ + F::zero(), + F::one(), + F::two(), + F::one(), + F::two(), + F::two(), + F::one(), + F::zero(), + ], + 1, + ); + + // we get pointleafs like: + // index:0, ys:[0, 0, 1, 0, 1, 2, 1] + // index:1, ys:[1, 0, 1, 0, 1, 2, 1] + // index:2, ys:[2, 2, 1, 2, 2, 1, 0] + // index:3, ys:[1, 2, 1, 2, 2, 1, 0] + // index:4, ys:[2, 2, 2, 0, 1, 2, 1] + // index:5, ys:[2, 2, 2, 0, 1, 2, 1] + // index:6, ys:[1, 1, 0, 2, 2, 1, 0] + // index:7, ys:[0, 1, 0, 2, 2, 1, 0] + + let manager = DefaultSyncBcManager::new(); + let inputs = vec![mat_1, mat_2, mat_3]; + let tcs = TCS::new(manager); + let query_times = 8; + let commit_data = tcs.commit_poly_with_query_times::(inputs, query_times); + + let roots: Vec = commit_data + .iter() + .map(|data| data.commit_taptree.root().hash) + .collect(); + + (0..7).for_each(|index| { + let (proof, opening) = tcs.open_with_query_times::( + vec![index; query_times], + &commit_data, + query_times, + ); + assert!(tcs.verify_with_query_times(roots.clone(), &proof, opening, query_times)); + }) + } +} diff --git a/common/Cargo.toml b/common/Cargo.toml index 1603dd6..a188bcb 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -4,5 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] -p3-field = { git = "https://github.com/Plonky3/Plonky3.git" } -p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } \ No newline at end of file +p3-field = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } \ No newline at end of file diff --git a/common/src/lib.rs b/common/src/lib.rs index 1710836..baeb757 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -9,7 +9,7 @@ pub trait AsU32Vec { impl AsU32Vec for u32 { fn bc_as_u32_vec(&self) -> Vec { - vec![self.clone()] + vec![*self] } } diff --git a/fri/Cargo.toml b/fri/Cargo.toml index 8e0cc55..2de772d 100644 --- a/fri/Cargo.toml +++ b/fri/Cargo.toml @@ -8,17 +8,16 @@ license = "MIT OR Apache-2.0" bitcoin-script = { git = "https://github.com/bitlayer-org/rust-bitcoin-script" } bitcoin = { git = "https://github.com/bitlayer-org/rust-bitcoin", branch = "bitvm" } bitcoin-scriptexec = { git = "https://github.com/bitlayer-org/rust-bitcoin-scriptexec", branch = "bitvm"} -#bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git"} bitcoin-script-stack = {git = "https://github.com/bitlayer-org/rust-bitcoin-script-stack.git", branch = "bitvm"} -p3-commit ={ git = "https://github.com/Plonky3/Plonky3.git" } -p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git" } -p3-dft = { git = "https://github.com/Plonky3/Plonky3.git" } -p3-field = { git = "https://github.com/Plonky3/Plonky3.git" } -p3-interpolation = { git = "https://github.com/Plonky3/Plonky3.git" } -p3-matrix = { git = "https://github.com/Plonky3/Plonky3.git" } -p3-maybe-rayon = { git = "https://github.com/Plonky3/Plonky3.git" } -p3-util = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-commit ={ git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a"} +p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-dft = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-field = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-interpolation = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-matrix = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-maybe-rayon = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-util = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } itertools = "0.12.0" tracing = "0.1.37" tracing-subscriber = { version = "0.3.17", features = ["std", "env-filter"] } @@ -26,24 +25,20 @@ serde = { version = "1.0", default-features = false, features = ["derive", "allo script_expr ={ path = "../script_expr" } rand = "0.8.5" - - scripts = { path = "../scripts"} -primitives = {path = "../primitives"} -segment ={ path = "../segment"} -script_manager = {path = "../script_manager"} +basic = {path = "../basic"} -p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } -p3-symmetric = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-symmetric = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } [dev-dependencies] -p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git" } -p3-goldilocks = { git = "https://github.com/Plonky3/Plonky3.git" } -p3-mersenne-31 = { git = "https://github.com/Plonky3/Plonky3.git" } -p3-mds = { git = "https://github.com/Plonky3/Plonky3.git" } -p3-merkle-tree = { git = "https://github.com/Plonky3/Plonky3.git" } -p3-blake3 = { git = "https://github.com/Plonky3/Plonky3.git" } -p3-keccak = { git = "https://github.com/Plonky3/Plonky3.git" } -p3-interpolation = { git = "https://github.com/Plonky3/Plonky3.git" } +p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-goldilocks = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-mersenne-31 = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-mds = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-merkle-tree = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-blake3 = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-keccak = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } +p3-interpolation = { git = "https://github.com/Plonky3/Plonky3.git", rev = "72b2fc162738df459619488a98bb06eaf64e5b4a" } criterion = "0.5.1" rand = "0.8.5" rand_chacha = "0.3.1" diff --git a/fri/src/config.rs b/fri/src/config.rs index e3d9a7a..3ea0b33 100644 --- a/fri/src/config.rs +++ b/fri/src/config.rs @@ -2,9 +2,9 @@ use alloc::vec::Vec; use core::fmt::Debug; use std::sync::MutexGuard; +use basic::field::BfField; use p3_field::Field; use p3_matrix::Matrix; -use primitives::field::BfField; use script_expr::{Dsl, InputManager}; #[derive(Debug)] diff --git a/fri/src/error.rs b/fri/src/error.rs index 8f201c0..e5598f2 100644 --- a/fri/src/error.rs +++ b/fri/src/error.rs @@ -1,4 +1,4 @@ -use primitives::mmcs::error::BfError; +use basic::mmcs::error::BfError; #[derive(Debug, PartialEq, Eq, Clone)] pub enum SVError { VerifyCalNegXScriptError, diff --git a/fri/src/fold_even_odd.rs b/fri/src/fold_even_odd.rs index 99d8d5b..0e0151c 100644 --- a/fri/src/fold_even_odd.rs +++ b/fri/src/fold_even_odd.rs @@ -54,18 +54,16 @@ pub fn fold_even_odd(poly: Vec, beta: F) -> Vec { #[cfg(test)] mod tests { + use itertools::izip; use p3_baby_bear::BabyBear; use p3_dft::{Radix2Dit, TwoAdicSubgroupDft}; - use p3_field::extension::BinomialExtensionField; - use p3_field::AbstractExtensionField; - use primitives::field::BfField; + + use rand::{thread_rng, Rng}; - use scripts::execute_script; use super::*; - use crate::fri_scripts::verify_folding::fold_degree; #[test] fn test_fold_even_odd() { @@ -99,117 +97,4 @@ mod tests { assert_eq!(expected, folded); } - - #[test] - fn test_fold_even_odd_1() { - type F = BabyBear; - - let log_n = 4; - let n = 1 << log_n; - let coeffs = (0..n).map(|i: u32| F::from_u32(i)).collect::>(); - - let dft = Radix2Dit::default(); - let evals = dft.dft(coeffs.clone()); - - let even_coeffs = coeffs.iter().cloned().step_by(2).collect_vec(); - let even_evals = dft.dft(even_coeffs); - - let odd_coeffs = coeffs.iter().cloned().skip(1).step_by(2).collect_vec(); - let odd_evals = dft.dft(odd_coeffs); - - let beta = F::from_u32(2); - let expected = izip!(even_evals, odd_evals) - .map(|(even, odd)| even + beta * odd) - .collect::>(); - - print!("{:?}", expected); - print!("{:?}", evals); - // fold_even_odd takes and returns in bitrev order. - let mut folded = evals; - reverse_slice_index_bits(&mut folded); - folded = fold_even_odd(folded, beta); - reverse_slice_index_bits(&mut folded); - - assert_eq!(expected, folded); - } - - #[test] - fn test_fold_bitcoin_script() { - use p3_field::AbstractField; - type AF = BabyBear; - type F = BinomialExtensionField; - - let mut rng = thread_rng(); - let log_n = 4; - let n = 1 << log_n; - let coeffs = (0..n) - .map(|i: u32| F::from_base_fn(|_i| rng.gen::())) - .collect::>(); - - let dft = Radix2Dit::default(); - let evals = dft.dft(coeffs.clone()); - - let even_coeffs = coeffs.iter().cloned().step_by(2).collect_vec(); - let even_evals = dft.dft(even_coeffs); - - let odd_coeffs = coeffs.iter().cloned().skip(1).step_by(2).collect_vec(); - let odd_evals = dft.dft(odd_coeffs); - - let beta = F::from_base_slice(vec![AF::from_canonical_u32(2); 4].as_slice()); - let expected = izip!(even_evals, odd_evals) - .map(|(even, odd)| even + beta * odd) - .collect::>(); - - println!("{:?}", evals); - println!("------- folding -------"); - println!("{:?}", expected); - - // fold_even_odd takes and returns in bitrev order. - let mut folded = evals.clone(); - reverse_slice_index_bits(&mut folded); - folded = fold_even_odd(folded, beta); - reverse_slice_index_bits(&mut folded); - - assert_eq!(expected, folded); - - for (_index, log_n) in vec![4].iter().enumerate() { - let n = 1 << log_n; - let y0 = evals.clone(); - let y1 = expected.clone(); - - let subgroup_generator = F::two_adic_generator(*log_n); - - for j in 0..n as usize { - let x_index = j; - let x_nge_index = (n / 2 + x_index) % n; - let x = subgroup_generator.exp_u64(x_index as u64); - let y0_x = y0[x_index]; - let y0_neg_x = y0[x_nge_index]; - let y_1_x_quare = y1[x_index % (n / 2)]; - - let with_input_script = fold_degree::( - x.as_u32_vec(), - y0_x.as_u32_vec(), - y0_neg_x.as_u32_vec(), - beta.as_u32_vec(), - y_1_x_quare.as_u32_vec(), - true, - ); - let result = execute_script(with_input_script); - println!("{:?}", result); - assert!(result.success); - - // let script = fold_degree::( - // x.as_u32_vec(), - // y0_x.as_u32_vec(), - // y0_neg_x.as_u32_vec(), - // beta.as_u32_vec(), - // y_1_x_quare.as_u32_vec(), - // false, - // ); - // let result = execute_script(script); - // assert!(result.success); - } - } - } } diff --git a/fri/src/fri_scripts/fiat_shamir_subtree.rs b/fri/src/fri_scripts/fiat_shamir_subtree.rs deleted file mode 100644 index 9255859..0000000 --- a/fri/src/fri_scripts/fiat_shamir_subtree.rs +++ /dev/null @@ -1,863 +0,0 @@ -use std::usize; - -use bitcoin::ScriptBuf as Script; -use bitcoin_script::script; -use itertools::Itertools; -use primitives::challenger::chan_field::{PermutationField, U32}; -use primitives::challenger::{BfChallenger, BitExtractor, Blake3Permutation}; -use primitives::field::BfField; -use script_manager::bc_assignment::DefaultBCAssignment; -use scripts::bit_comm::bit_comm::BitCommitment; -use scripts::bit_comm_u32::*; -use scripts::blake3; -use scripts::pseudo::{OP_4FROMALTSTACK, OP_4TOALTSTACK}; -use scripts::u32_std::{u32_compress, u32_equalverify}; - -/// fiat shamir subtree contains a series script leafs and coressponding -trait SubTree { - fn locking_leafs(&self) -> Vec