From b4eb83734628b256a9a7338be0dfcc7c49acaf9e Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Thu, 23 Mar 2023 17:26:52 -0700 Subject: [PATCH 01/20] A few fixes for terminal instructions --- evm/src/cpu/kernel/asm/core/terminate.asm | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/evm/src/cpu/kernel/asm/core/terminate.asm b/evm/src/cpu/kernel/asm/core/terminate.asm index c124db34..7feef337 100644 --- a/evm/src/cpu/kernel/asm/core/terminate.asm +++ b/evm/src/cpu/kernel/asm/core/terminate.asm @@ -10,7 +10,10 @@ global sys_stop: %jump(terminate_common) global sys_return: - // stack: kexit_info + // stack: kexit_info, offset, size + // TODO: For now we're ignoring the returned data. Need to return it to the parent context. + %stack (kexit_info, offset, size) -> (kexit_info) + %leftover_gas // stack: leftover_gas // TODO: Set parent context's CTX_METADATA_RETURNDATA_SIZE. @@ -23,10 +26,10 @@ global sys_selfdestruct: SWAP1 %u256_to_addr DUP1 %insert_accessed_addresses_no_return // TODO: Use return value in gas calculation. // stack: address, kexit_info - SWAP1 - // TODO: Charge gas. + POP // TODO: Transfer balance to address. + // stack: kexit_info // TODO: Add address to the access list. - %consume_gas_const(@GAS_SELFDESTRUCT) + %charge_gas_const(@GAS_SELFDESTRUCT) %leftover_gas // stack: leftover_gas // TODO: Destroy account. @@ -34,7 +37,10 @@ global sys_selfdestruct: %jump(terminate_common) global sys_revert: - // stack: kexit_info + // stack: kexit_info, offset, size + // TODO: For now we're ignoring the returned data. Need to return it to the parent context. + %stack (kexit_info, offset, size) -> (kexit_info) + %leftover_gas // stack: leftover_gas // TODO: Revert state changes. From 911dfedd07c7e4e9e211d2307148651651de8c7e Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Thu, 23 Mar 2023 16:26:42 -0700 Subject: [PATCH 02/20] Rework CREATE, CREATE2 syscalls The old code was outdated in various ways, e.g. it was trying to share code with contract-creation txns, so I would ignore the diff and just look at the new code. Still a bunch of TODOs left here, like actually saving code that's returned. --- evm/src/cpu/kernel/aggregator.rs | 1 + evm/src/cpu/kernel/asm/core/create.asm | 172 +++++++++--------- .../cpu/kernel/asm/core/create_addresses.asm | 6 +- .../asm/core/create_contract_account.asm | 51 ++++++ evm/src/cpu/kernel/asm/core/gas.asm | 42 +++++ evm/src/cpu/kernel/asm/core/process_txn.asm | 25 +-- evm/src/cpu/kernel/asm/core/terminate.asm | 18 -- .../asm/mpt/insert/insert_trie_specific.asm | 1 + 8 files changed, 199 insertions(+), 117 deletions(-) create mode 100644 evm/src/cpu/kernel/asm/core/create_contract_account.asm diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index 6f45013d..251271ff 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -24,6 +24,7 @@ pub(crate) fn combined_kernel() -> Kernel { include_str!("asm/core/call.asm"), include_str!("asm/core/create.asm"), include_str!("asm/core/create_addresses.asm"), + include_str!("asm/core/create_contract_account.asm"), include_str!("asm/core/gas.asm"), include_str!("asm/core/intrinsic_gas.asm"), include_str!("asm/core/invalid.asm"), diff --git a/evm/src/cpu/kernel/asm/core/create.asm b/evm/src/cpu/kernel/asm/core/create.asm index 3157a262..11e89aa4 100644 --- a/evm/src/cpu/kernel/asm/core/create.asm +++ b/evm/src/cpu/kernel/asm/core/create.asm @@ -1,42 +1,27 @@ -// TODO: This file needs to be cleaned up. -// `create` is no longer being used for contract-creation txns, -// so it can be inlined. Also need to set metadata on new ctx. - -// The CREATE syscall. +// The CREATE syscall. Address will be +// address = KEC(RLP(sender, nonce))[12:] // // Pre stack: kexit_info, value, code_offset, code_len // Post stack: address global sys_create: + // stack: kexit_info, value, code_offset, code_len // TODO: Charge gas. %stack (kexit_info, value, code_offset, code_len) - -> (value, 0, @SEGMENT_MAIN_MEMORY, code_offset, code_len) + -> (value, code_offset, code_len, kexit_info) + PUSH sys_create_got_address + // stack: sys_create_got_address, value, code_offset, code_len, kexit_info %address - // stack: sender, value, CODE_ADDR: 3, code_len, sys_create_finish, kexit_info - %jump(create) -sys_create_finish: - // stack: address, kexit_info - SWAP1 - EXIT_KERNEL - -// Create a new contract account with the traditional address scheme, i.e. -// address = KEC(RLP(sender, nonce))[12:] -// This can be used both for the CREATE instruction and for contract-creation -// transactions. -// -// Pre stack: sender, endowment, CODE_ADDR: 3, code_len, retdest -// Post stack: address -// Note: CODE_ADDR refers to a (context, segment, offset) tuple. -global create: - // stack: sender, endowment, CODE_ADDR, code_len, retdest + // stack: sender, sys_create_got_address, value, code_offset, code_len, kexit_info DUP1 %nonce - - // stack: nonce, sender, endowment, CODE_ADDR, code_len, retdest - // Call get_create_address and have it return to create_inner. - %stack (nonce, sender) - -> (sender, nonce, create_inner, sender) + // stack: nonce, sender, sys_create_got_address, value, code_offset, code_len, kexit_info + SWAP1 + // stack: sender, nonce, sys_create_got_address, value, code_offset, code_len, kexit_info %jump(get_create_address) +sys_create_got_address: + // stack: address, value, code_offset, code_len, kexit_info + %jump(create_common) -// CREATE2; see EIP-1014. Address will be +// The CREATE2 syscall; see EIP-1014. Address will be // address = KEC(0xff || sender || salt || code_hash)[12:] // // Pre stack: kexit_info, value, code_offset, code_len, salt @@ -45,75 +30,100 @@ global sys_create2: // stack: kexit_info, value, code_offset, code_len, salt // TODO: Charge gas. SWAP4 - %stack (salt) -> (salt, sys_create2_got_address) - // stack: salt, sys_create2_got_address, value, code_offset, code_len, kexit_info + %stack (salt) -> (salt, create_common) + // stack: salt, create_common, value, code_offset, code_len, kexit_info + + // Hash the code. DUP5 // code_len DUP5 // code_offset PUSH @SEGMENT_MAIN_MEMORY GET_CONTEXT KECCAK_GENERAL - // stack: hash, salt, sys_create2_got_address, value, code_offset, code_len, kexit_info + // stack: hash, salt, create_common, value, code_offset, code_len, kexit_info + %address - // stack: sender, hash, salt, sys_create2_got_address, value, code_offset, code_len, kexit_info + // stack: sender, hash, salt, create_common, value, code_offset, code_len, kexit_info %jump(get_create2_address) -sys_create2_got_address: - // stack: address, value, code_offset, code_len, kexit_info - %address - %stack (sender, address, value, code_offset, code_len, kexit_info) - -> (address, sender, value, 0, @SEGMENT_MAIN_MEMORY, code_offset, code_len, - sys_create2_finish, kexit_info) - %jump(create_inner) -sys_create2_finish: - // stack: address, kexit_info - SWAP1 - EXIT_KERNEL -// Pre stack: address, sender, endowment, CODE_ADDR, code_len, retdest +// Pre stack: address, value, code_offset, code_len, kexit_info // Post stack: address -// Note: CODE_ADDR refers to a (context, segment, offset) tuple. -global create_inner: - // stack: address, sender, endowment, CODE_ADDR, code_len, retdest +global create_common: + // stack: address, value, code_offset, code_len, kexit_info DUP1 %insert_accessed_addresses_no_return - %stack (address, sender, endowment) - -> (sender, address, endowment, sender, address) - - %transfer_eth - // stack: transfer_eth_status, sender, address, CODE_ADDR, code_len, retdest - %jumpi(fault_exception) - // stack: sender, address, CODE_ADDR, code_len, retdest + // Increment the sender's nonce. + %address %increment_nonce - // stack: address, CODE_ADDR, code_len, retdest + // stack: address, value, code_offset, code_len, kexit_info + + // Deduct value from the caller. + DUP2 + %address + // stack: sender, value, address, value, code_offset, code_len, kexit_info + %deduct_eth + // stack: deduct_eth_status, address, value, code_offset, code_len, kexit_info + %jumpi(fault_exception) + // stack: address, value, code_offset, code_len, kexit_info + + // Create the new contract account in the state trie. + DUP1 DUP3 + // stack: value, address, address, value, code_offset, code_len, kexit_info + %create_contract_account + // stack: status, address, value, code_offset, code_len, kexit_info + %jumpi(fault_exception) + // stack: address, value, code_offset, code_len, kexit_info %create_context - // stack: new_ctx, address, CODE_ADDR, code_len, retdest - %stack (new_ctx, address, src_ctx, src_segment, src_offset, code_len) - -> (new_ctx, @SEGMENT_CODE, 0, - src_ctx, src_segment, src_offset, - code_len, run_constructor, - new_ctx, address) + // stack: new_ctx, address, value, code_offset, code_len, kexit_info + GET_CONTEXT + // stack: src_ctx, new_ctx, address, value, code_offset, code_len, kexit_info + + // Copy the code from txdata to the new context's code segment. + %stack (src_ctx, new_ctx, address, value, code_offset, code_len) + -> (new_ctx, @SEGMENT_CODE, 0, // DST + src_ctx, @SEGMENT_MAIN_MEMORY, code_offset, // SRC + code_len, + run_constructor, + new_ctx, value, address) %jump(memcpy) run_constructor: - // stack: new_ctx, address, retdest - // At this point, the initialization code has been loaded. - // Save our return address in memory, so we'll be in `after_constructor` - // after the new context returns. - // Note: We can't use %mstore_context_metadata because we're writing to - // memory owned by the new context, not the current one. - %stack (new_ctx) -> (new_ctx, @SEGMENT_CONTEXT_METADATA, - @CTX_METADATA_PARENT_PC, after_constructor, new_ctx) - MSTORE_GENERAL - // stack: new_ctx, address, retdest + // stack: new_ctx, value, address, kexit_info + %set_new_ctx_value + // stack: new_ctx, address, kexit_info - // Now, switch to the new context and go to usermode with PC=0. - SET_CONTEXT - // stack: (empty, since we're in the new context) - PUSH 0 - EXIT_KERNEL + // Each line in the block below does not change the stack. + DUP2 %set_new_ctx_addr + %address %set_new_ctx_caller + %set_new_ctx_parent_ctx + %set_new_ctx_parent_pc(after_constructor) + // stack: new_ctx, address, kexit_info + + // All but 1/64 of the sender's remaining gas goes to the constructor. + SWAP2 + // stack: kexit_info, address, new_ctx + %drain_all_but_one_64th_gas + %stack (kexit_info, drained_gas, address, new_ctx) -> (drained_gas, new_ctx, address, kexit_info) + %set_new_ctx_gas_limit + // stack: new_ctx, address, kexit_info + + %enter_new_ctx + // (Old context) stack: new_ctx, address, kexit_info after_constructor: - // stack: address, retdest - // TODO: If code was returned, store it in the account. - SWAP1 - JUMP + // stack: success, leftover_gas, new_ctx, address, kexit_info + SWAP2 + // stack: new_ctx, leftover_gas, success, address, kexit_info + POP // TODO: Ignoring new_ctx for now, but we will need it to store code that was returned, if any. + // stack: leftover_gas, success, address, kexit_info + %shl_const(192) + // stack: leftover_gas << 192, success, address, kexit_info + SWAP2 + // stack: address, success, leftover_gas << 192, kexit_info + MUL + // stack: address_if_success, leftover_gas << 192, kexit_info + SWAP2 + // stack: kexit_info, leftover_gas << 192, address_if_success + ADD + // stack: kexit_info, address_if_success + EXIT_KERNEL diff --git a/evm/src/cpu/kernel/asm/core/create_addresses.asm b/evm/src/cpu/kernel/asm/core/create_addresses.asm index d72d7e67..70f57b6f 100644 --- a/evm/src/cpu/kernel/asm/core/create_addresses.asm +++ b/evm/src/cpu/kernel/asm/core/create_addresses.asm @@ -19,7 +19,8 @@ global get_create_address: PUSH 0 // context // stack: RLP_ADDR: 3, rlp_len, retdest KECCAK_GENERAL - %mod_const(0x10000000000000000000000000000000000000000) // 2^160 + // stack: hash, retdest + %u256_to_addr // stack: address, retdest %observe_new_address SWAP1 @@ -54,8 +55,9 @@ get_create2_address_finish: POP %stack (retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 0, 85, retdest) // context, segment, offset, len KECCAK_GENERAL + // stack: hash, retdest + %u256_to_addr // stack: address, retdest - %mod_const(0x10000000000000000000000000000000000000000) // 2^160 %observe_new_address SWAP1 JUMP diff --git a/evm/src/cpu/kernel/asm/core/create_contract_account.asm b/evm/src/cpu/kernel/asm/core/create_contract_account.asm new file mode 100644 index 00000000..5ce12779 --- /dev/null +++ b/evm/src/cpu/kernel/asm/core/create_contract_account.asm @@ -0,0 +1,51 @@ +// Create a smart contract account with the given address and the given endowment value. +// Pre stack: value, address +// Post stack: status +%macro create_contract_account + // stack: value, address + DUP2 %mpt_read_state_trie + // stack: existing_account_ptr, value, address + // If the account doesn't exist, there's need to check its balance or nonce, + // so we can skip ahead, setting existing_balance = existing_account_ptr = 0. + DUP1 ISZERO %jumpi(%%do_insert) + + // stack: existing_account_ptr, value, address + DUP1 %mload_trie_data // nonce = account[0] + // stack: nonce, existing_account_ptr, value, address + %jumpi(%%error_nonzero_nonce) + // stack: existing_account_ptr, value, address + %increment %mload_trie_data // balance = account[1] + +%%do_insert: + // stack: existing_balance, value, address + ADD + // stack: new_acct_value, address + // Write the new account's data to MPT data, and get a pointer to it. + %get_trie_data_size + // stack: account_ptr, new_acct_value, address + PUSH 1 %append_to_trie_data // nonce = 1 + // stack: account_ptr, new_acct_value, address + SWAP1 %append_to_trie_data // balance = new_acct_value + // stack: account_ptr, address + PUSH 0 %append_to_trie_data // storage_root = nil + // stack: account_ptr, address + PUSH @EMPTY_STRING_HASH %append_to_trie_data // code_hash = keccak('') + // stack: account_ptr, address + SWAP1 + // stack: address, account_ptr + %addr_to_state_key + // stack: state_key, account_ptr + %mpt_insert_state_trie + // stack: (empty) + PUSH 0 // success + %jump(%%end) + +// If the nonce is nonzero, that means a contract has already been deployed to this address. +// (This should be impossible with contract creation transactions or CREATE, but possible with CREATE2.) +// So we return 1 to indicate an error. +%%error_nonzero_nonce: + %stack (existing_account_ptr, address, value) -> (1) + +%%end: + // stack: status +%endmacro diff --git a/evm/src/cpu/kernel/asm/core/gas.asm b/evm/src/cpu/kernel/asm/core/gas.asm index 78cc065c..ad2966a5 100644 --- a/evm/src/cpu/kernel/asm/core/gas.asm +++ b/evm/src/cpu/kernel/asm/core/gas.asm @@ -56,3 +56,45 @@ global sys_gasprice: // stack: gas_price, kexit_info SWAP1 EXIT_KERNEL + +// Checks how much gas is remaining in this context, given the current kexit_info. +%macro leftover_gas + // stack: kexit_info + %shr_const(192) + // stack: gas_used + %mload_context_metadata(@CTX_METADATA_GAS_LIMIT) + // stack: gas_limit, gas_used + SWAP1 + // stack: gas_used, gas_limit + DUP2 DUP2 LT + // stack: gas_used < gas_limit, gas_used, gas_limit + SWAP2 + // stack: gas_limit, gas_used, gas_used < gas_limit + SUB + // stack: gas_limit - gas_used, gas_used < gas_limit + MUL + // stack: leftover_gas = (gas_limit - gas_used) * (gas_used < gas_limit) +%endmacro + +// Given the current kexit_info, drains all but one 64th of its remaining gas. +// Returns how much gas was drained. +%macro drain_all_but_one_64th_gas + // stack: kexit_info + DUP1 %leftover_gas + // stack: leftover_gas, kexit_info + %all_but_one_64th + // stack: all_but_one_64th, kexit_info + %stack (all_but_one_64th, kexit_info) -> (all_but_one_64th, kexit_info, all_but_one_64th) + %charge_gas + // stack: kexit_info, drained_gas +%endmacro + +// This is L(n), the "all but one 64th" function in the yellowpaper, i.e. +// L(n) = n - floor(n / 64) +%macro all_but_one_64th + // stack: n + DUP1 %div_const(64) + // stack: floor(n / 64), n + SWAP1 SUB + // stack: n - floor(n / 64) +%endmacro diff --git a/evm/src/cpu/kernel/asm/core/process_txn.asm b/evm/src/cpu/kernel/asm/core/process_txn.asm index 1c30d88a..b044e9ed 100644 --- a/evm/src/cpu/kernel/asm/core/process_txn.asm +++ b/evm/src/cpu/kernel/asm/core/process_txn.asm @@ -68,22 +68,15 @@ global process_contract_creation_txn: %jumpi(panic) // stack: address, retdest - // Write the new account's data to MPT data, and get a pointer to it. - %get_trie_data_size - // stack: account_ptr, address, retdest - PUSH 1 %append_to_trie_data // nonce = 1 - // stack: account_ptr, address, retdest - DUP2 %balance %mload_txn_field(@TXN_FIELD_VALUE) ADD %append_to_trie_data // balance = old_balance + txn_value - // stack: account_ptr, address, retdest - PUSH 0 %append_to_trie_data // storage_root = nil - // stack: account_ptr, address, retdest - PUSH @EMPTY_STRING_HASH %append_to_trie_data // code_hash = keccak('') - // stack: account_ptr, address, retdest - DUP2 - // stack: address, account_ptr, address, retdest - %addr_to_state_key - // stack: state_key, account_ptr, address, retdest - %mpt_insert_state_trie + // Create the new contract account in the state trie. + DUP1 + %mload_txn_field(@TXN_FIELD_VALUE) + // stack: value, address, address, retdest + %create_contract_account + // stack: status, address, retdest + // It should be impossible to create address collisions with a contract creation txn, + // since the address was derived from nonce, unlike with CREATE2. + %jumpi(panic) // stack: address, retdest %create_context diff --git a/evm/src/cpu/kernel/asm/core/terminate.asm b/evm/src/cpu/kernel/asm/core/terminate.asm index c124db34..bd86470e 100644 --- a/evm/src/cpu/kernel/asm/core/terminate.asm +++ b/evm/src/cpu/kernel/asm/core/terminate.asm @@ -96,21 +96,3 @@ global terminate_common: // stack: parent_pc, success, leftover_gas JUMP - -%macro leftover_gas - // stack: kexit_info - %shr_const(192) - // stack: gas_used - %mload_context_metadata(@CTX_METADATA_GAS_LIMIT) - // stack: gas_limit, gas_used - SWAP1 - // stack: gas_used, gas_limit - DUP2 DUP2 LT - // stack: gas_used < gas_limit, gas_used, gas_limit - SWAP2 - // stack: gas_limit, gas_used, gas_used < gas_limit - SUB - // stack: gas_limit - gas_used, gas_used < gas_limit - MUL - // stack: leftover_gas = (gas_limit - gas_used) * (gas_used < gas_limit) -%endmacro diff --git a/evm/src/cpu/kernel/asm/mpt/insert/insert_trie_specific.asm b/evm/src/cpu/kernel/asm/mpt/insert/insert_trie_specific.asm index 60df845e..37d7fda1 100644 --- a/evm/src/cpu/kernel/asm/mpt/insert/insert_trie_specific.asm +++ b/evm/src/cpu/kernel/asm/mpt/insert/insert_trie_specific.asm @@ -3,6 +3,7 @@ // Mutate the state trie, inserting the given key-value pair. // Pre stack: key, value_ptr, retdest // Post stack: (empty) +// TODO: Have this take an address and do %mpt_insert_state_trie? To match mpt_read_state_trie. global mpt_insert_state_trie: // stack: key, value_ptr, retdest %stack (key, value_ptr) From 60ad9e03ba4817f99716b475c8dcdb1e00fe01f9 Mon Sep 17 00:00:00 2001 From: BGluth Date: Mon, 27 Mar 2023 17:30:11 -0600 Subject: [PATCH 03/20] Bumped `eth_trie_utils` to `0.5.0` --- evm/Cargo.toml | 2 +- evm/src/cpu/kernel/constants/trie_type.rs | 16 ++--- evm/src/cpu/kernel/tests/account_code.rs | 7 ++- evm/src/cpu/kernel/tests/balance.rs | 7 ++- evm/src/cpu/kernel/tests/mpt/hash.rs | 29 +++++---- evm/src/cpu/kernel/tests/mpt/insert.rs | 71 +++++++++++++---------- evm/src/cpu/kernel/tests/mpt/load.rs | 16 ++--- evm/src/cpu/kernel/tests/mpt/mod.rs | 8 ++- evm/src/generation/mod.rs | 2 +- evm/src/generation/mpt.rs | 36 +++++++----- evm/src/generation/trie_extractor.rs | 2 +- evm/src/lib.rs | 4 ++ evm/tests/add11_yml.rs | 22 +++---- evm/tests/basic_smart_contract.rs | 36 +++++++----- evm/tests/empty_txn_list.rs | 15 ++--- evm/tests/simple_transfer.rs | 30 +++++----- 16 files changed, 173 insertions(+), 130 deletions(-) diff --git a/evm/Cargo.toml b/evm/Cargo.toml index 90e9b136..9245138a 100644 --- a/evm/Cargo.toml +++ b/evm/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" anyhow = "1.0.40" blake2 = "0.10.5" env_logger = "0.10.0" -eth_trie_utils = "0.4.1" +eth_trie_utils = "0.5.0" ethereum-types = "0.14.0" hex = { version = "0.4.3", optional = true } hex-literal = "0.3.4" diff --git a/evm/src/cpu/kernel/constants/trie_type.rs b/evm/src/cpu/kernel/constants/trie_type.rs index fc71c1f4..34700a5f 100644 --- a/evm/src/cpu/kernel/constants/trie_type.rs +++ b/evm/src/cpu/kernel/constants/trie_type.rs @@ -1,4 +1,6 @@ -use eth_trie_utils::partial_trie::PartialTrie; +use std::ops::Deref; + +use crate::{Node, PartialTrie}; #[derive(Copy, Clone, Debug)] pub(crate) enum PartialTrieType { @@ -13,12 +15,12 @@ impl PartialTrieType { pub(crate) const COUNT: usize = 5; pub(crate) fn of(trie: &PartialTrie) -> Self { - match trie { - PartialTrie::Empty => Self::Empty, - PartialTrie::Hash(_) => Self::Hash, - PartialTrie::Branch { .. } => Self::Branch, - PartialTrie::Extension { .. } => Self::Extension, - PartialTrie::Leaf { .. } => Self::Leaf, + match trie.deref() { + Node::Empty => Self::Empty, + Node::Hash(_) => Self::Hash, + Node::Branch { .. } => Self::Branch, + Node::Extension { .. } => Self::Extension, + Node::Leaf { .. } => Self::Leaf, } } diff --git a/evm/src/cpu/kernel/tests/account_code.rs b/evm/src/cpu/kernel/tests/account_code.rs index c6d7f156..38d2ce4b 100644 --- a/evm/src/cpu/kernel/tests/account_code.rs +++ b/evm/src/cpu/kernel/tests/account_code.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use anyhow::Result; -use eth_trie_utils::partial_trie::PartialTrie; +use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; use ethereum_types::{Address, BigEndianHash, H256, U256}; use keccak_hash::keccak; use rand::{thread_rng, Rng}; @@ -12,13 +12,14 @@ use crate::cpu::kernel::interpreter::Interpreter; use crate::cpu::kernel::tests::mpt::nibbles_64; use crate::generation::mpt::{all_mpt_prover_inputs_reversed, AccountRlp}; use crate::memory::segments::Segment; +use crate::{Node, PartialTrie}; // Test account with a given code hash. fn test_account(code: &[u8]) -> AccountRlp { AccountRlp { nonce: U256::from(1111), balance: U256::from(2222), - storage_root: PartialTrie::Empty.calc_hash(), + storage_root: PartialTrie::from(Node::Empty).hash(), code_hash: keccak(code), } } @@ -96,7 +97,7 @@ fn prepare_interpreter( let hash = H256::from_uint(&interpreter.stack()[0]); state_trie.insert(k, rlp::encode(account).to_vec()); - let expected_state_trie_hash = state_trie.calc_hash(); + let expected_state_trie_hash = state_trie.hash(); assert_eq!(hash, expected_state_trie_hash); Ok(()) diff --git a/evm/src/cpu/kernel/tests/balance.rs b/evm/src/cpu/kernel/tests/balance.rs index b0e087a9..b5f75ac4 100644 --- a/evm/src/cpu/kernel/tests/balance.rs +++ b/evm/src/cpu/kernel/tests/balance.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use eth_trie_utils::partial_trie::PartialTrie; +use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; use ethereum_types::{Address, BigEndianHash, H256, U256}; use keccak_hash::keccak; use rand::{thread_rng, Rng}; @@ -9,13 +9,14 @@ use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; use crate::cpu::kernel::interpreter::Interpreter; use crate::cpu::kernel::tests::mpt::nibbles_64; use crate::generation::mpt::{all_mpt_prover_inputs_reversed, AccountRlp}; +use crate::{Node, PartialTrie}; // Test account with a given code hash. fn test_account(balance: U256) -> AccountRlp { AccountRlp { nonce: U256::from(1111), balance, - storage_root: PartialTrie::Empty.calc_hash(), + storage_root: PartialTrie::from(Node::Empty).hash(), code_hash: H256::from_uint(&U256::from(8888)), } } @@ -87,7 +88,7 @@ fn prepare_interpreter( let hash = H256::from_uint(&interpreter.stack()[0]); state_trie.insert(k, rlp::encode(account).to_vec()); - let expected_state_trie_hash = state_trie.calc_hash(); + let expected_state_trie_hash = state_trie.hash(); assert_eq!(hash, expected_state_trie_hash); Ok(()) diff --git a/evm/src/cpu/kernel/tests/mpt/hash.rs b/evm/src/cpu/kernel/tests/mpt/hash.rs index 1b49dafa..9ab021f9 100644 --- a/evm/src/cpu/kernel/tests/mpt/hash.rs +++ b/evm/src/cpu/kernel/tests/mpt/hash.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use eth_trie_utils::partial_trie::PartialTrie; +use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; use ethereum_types::{BigEndianHash, H256}; use crate::cpu::kernel::aggregator::KERNEL; @@ -7,6 +7,7 @@ use crate::cpu::kernel::interpreter::Interpreter; use crate::cpu::kernel::tests::mpt::{extension_to_leaf, test_account_1_rlp, test_account_2_rlp}; use crate::generation::mpt::all_mpt_prover_inputs_reversed; use crate::generation::TrieInputs; +use crate::Node; // TODO: Test with short leaf. Might need to be a storage trie. @@ -24,11 +25,12 @@ fn mpt_hash_empty() -> Result<()> { #[test] fn mpt_hash_empty_branch() -> Result<()> { - let children = core::array::from_fn(|_| PartialTrie::Empty.into()); - let state_trie = PartialTrie::Branch { + let children = core::array::from_fn(|_| Node::Empty.into()); + let state_trie = Node::Branch { children, value: vec![], - }; + } + .into(); let trie_inputs = TrieInputs { state_trie, transactions_trie: Default::default(), @@ -42,7 +44,7 @@ fn mpt_hash_empty_branch() -> Result<()> { fn mpt_hash_hash() -> Result<()> { let hash = H256::random(); let trie_inputs = TrieInputs { - state_trie: PartialTrie::Hash(hash), + state_trie: Node::Hash(hash).into(), transactions_trie: Default::default(), receipts_trie: Default::default(), storage_tries: vec![], @@ -53,10 +55,11 @@ fn mpt_hash_hash() -> Result<()> { #[test] fn mpt_hash_leaf() -> Result<()> { - let state_trie = PartialTrie::Leaf { + let state_trie = Node::Leaf { nibbles: 0xABC_u64.into(), value: test_account_1_rlp(), - }; + } + .into(); let trie_inputs = TrieInputs { state_trie, transactions_trie: Default::default(), @@ -80,17 +83,19 @@ fn mpt_hash_extension_to_leaf() -> Result<()> { #[test] fn mpt_hash_branch_to_leaf() -> Result<()> { - let leaf = PartialTrie::Leaf { + let leaf = Node::Leaf { nibbles: 0xABC_u64.into(), value: test_account_2_rlp(), } .into(); - let mut children = core::array::from_fn(|_| PartialTrie::Empty.into()); + + let mut children = core::array::from_fn(|_| Node::Empty.into()); children[3] = leaf; - let state_trie = PartialTrie::Branch { + let state_trie = Node::Branch { children, value: vec![], - }; + } + .into(); let trie_inputs = TrieInputs { state_trie, @@ -124,7 +129,7 @@ fn test_state_trie(trie_inputs: TrieInputs) -> Result<()> { interpreter.stack() ); let hash = H256::from_uint(&interpreter.stack()[0]); - let expected_state_trie_hash = trie_inputs.state_trie.calc_hash(); + let expected_state_trie_hash = trie_inputs.state_trie.hash(); assert_eq!(hash, expected_state_trie_hash); Ok(()) diff --git a/evm/src/cpu/kernel/tests/mpt/insert.rs b/evm/src/cpu/kernel/tests/mpt/insert.rs index 6d6d6951..7858e2d7 100644 --- a/evm/src/cpu/kernel/tests/mpt/insert.rs +++ b/evm/src/cpu/kernel/tests/mpt/insert.rs @@ -1,5 +1,6 @@ use anyhow::Result; -use eth_trie_utils::partial_trie::{Nibbles, PartialTrie}; +use eth_trie_utils::nibbles::Nibbles; +use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; use ethereum_types::{BigEndianHash, H256}; use crate::cpu::kernel::aggregator::KERNEL; @@ -10,6 +11,7 @@ use crate::cpu::kernel::tests::mpt::{ }; use crate::generation::mpt::{all_mpt_prover_inputs_reversed, AccountRlp}; use crate::generation::TrieInputs; +use crate::{Node, PartialTrie}; #[test] fn mpt_insert_empty() -> Result<()> { @@ -19,58 +21,64 @@ fn mpt_insert_empty() -> Result<()> { #[test] fn mpt_insert_leaf_identical_keys() -> Result<()> { let key = nibbles_64(0xABC); - let state_trie = PartialTrie::Leaf { + let state_trie = Node::Leaf { nibbles: key, value: test_account_1_rlp(), - }; + } + .into(); test_state_trie(state_trie, key, test_account_2()) } #[test] fn mpt_insert_leaf_nonoverlapping_keys() -> Result<()> { - let state_trie = PartialTrie::Leaf { + let state_trie = Node::Leaf { nibbles: nibbles_64(0xABC), value: test_account_1_rlp(), - }; + } + .into(); test_state_trie(state_trie, nibbles_64(0x123), test_account_2()) } #[test] fn mpt_insert_leaf_overlapping_keys() -> Result<()> { - let state_trie = PartialTrie::Leaf { + let state_trie = Node::Leaf { nibbles: nibbles_64(0xABC), value: test_account_1_rlp(), - }; + } + .into(); test_state_trie(state_trie, nibbles_64(0xADE), test_account_2()) } #[test] #[ignore] // TODO: Not valid for state trie, all keys have same len. fn mpt_insert_leaf_insert_key_extends_leaf_key() -> Result<()> { - let state_trie = PartialTrie::Leaf { + let state_trie = Node::Leaf { nibbles: 0xABC_u64.into(), value: test_account_1_rlp(), - }; + } + .into(); test_state_trie(state_trie, nibbles_64(0xABCDE), test_account_2()) } #[test] #[ignore] // TODO: Not valid for state trie, all keys have same len. fn mpt_insert_leaf_leaf_key_extends_insert_key() -> Result<()> { - let state_trie = PartialTrie::Leaf { + let state_trie = Node::Leaf { nibbles: 0xABCDE_u64.into(), value: test_account_1_rlp(), - }; + } + .into(); test_state_trie(state_trie, nibbles_64(0xABC), test_account_2()) } #[test] fn mpt_insert_branch_replacing_empty_child() -> Result<()> { - let children = core::array::from_fn(|_| PartialTrie::Empty.into()); - let state_trie = PartialTrie::Branch { + let children = core::array::from_fn(|_| Node::Empty.into()); + let state_trie = Node::Branch { children, value: vec![], - }; + } + .into(); test_state_trie(state_trie, nibbles_64(0xABC), test_account_2()) } @@ -81,20 +89,21 @@ fn mpt_insert_branch_replacing_empty_child() -> Result<()> { #[ignore] fn mpt_insert_extension_nonoverlapping_keys() -> Result<()> { // Existing keys are 0xABC, 0xABCDEF; inserted key is 0x12345. - let mut children = core::array::from_fn(|_| PartialTrie::Empty.into()); - children[0xD] = PartialTrie::Leaf { + let mut children = core::array::from_fn(|_| Node::Empty.into()); + children[0xD] = Node::Leaf { nibbles: 0xEF_u64.into(), value: test_account_1_rlp(), } .into(); - let state_trie = PartialTrie::Extension { + let state_trie = Node::Extension { nibbles: 0xABC_u64.into(), - child: PartialTrie::Branch { + child: Node::Branch { children, value: test_account_1_rlp(), } .into(), - }; + } + .into(); test_state_trie(state_trie, nibbles_64(0x12345), test_account_2()) } @@ -104,37 +113,39 @@ fn mpt_insert_extension_nonoverlapping_keys() -> Result<()> { #[ignore] fn mpt_insert_extension_insert_key_extends_node_key() -> Result<()> { // Existing keys are 0xA, 0xABCD; inserted key is 0xABCDEF. - let mut children = core::array::from_fn(|_| PartialTrie::Empty.into()); - children[0xB] = PartialTrie::Leaf { + let mut children = core::array::from_fn(|_| Node::Empty.into()); + children[0xB] = Node::Leaf { nibbles: 0xCD_u64.into(), value: test_account_1_rlp(), } .into(); - let state_trie = PartialTrie::Extension { + let state_trie = Node::Extension { nibbles: 0xA_u64.into(), - child: PartialTrie::Branch { + child: Node::Branch { children, value: test_account_1_rlp(), } .into(), - }; + } + .into(); test_state_trie(state_trie, nibbles_64(0xABCDEF), test_account_2()) } #[test] fn mpt_insert_branch_to_leaf_same_key() -> Result<()> { - let leaf = PartialTrie::Leaf { + let leaf = Node::Leaf { nibbles: nibbles_count(0xBCD, 63), value: test_account_1_rlp(), } .into(); - let mut children = core::array::from_fn(|_| PartialTrie::Empty.into()); + let mut children = core::array::from_fn(|_| Node::Empty.into()); children[0] = leaf; - let state_trie = PartialTrie::Branch { + let state_trie = Node::Branch { children, value: vec![], - }; + } + .into(); test_state_trie(state_trie, nibbles_64(0xABCD), test_account_2()) } @@ -145,7 +156,7 @@ fn test_state_trie(mut state_trie: PartialTrie, k: Nibbles, mut account: Account assert_eq!(k.count, 64); // Ignore any storage_root; see documentation note. - account.storage_root = PartialTrie::Empty.calc_hash(); + account.storage_root = PartialTrie::from(Node::Empty).hash(); let trie_inputs = TrieInputs { state_trie: state_trie.clone(), @@ -207,7 +218,7 @@ fn test_state_trie(mut state_trie: PartialTrie, k: Nibbles, mut account: Account let hash = H256::from_uint(&interpreter.stack()[0]); state_trie.insert(k, rlp::encode(&account).to_vec()); - let expected_state_trie_hash = state_trie.calc_hash(); + let expected_state_trie_hash = state_trie.hash(); assert_eq!(hash, expected_state_trie_hash); Ok(()) diff --git a/evm/src/cpu/kernel/tests/mpt/load.rs b/evm/src/cpu/kernel/tests/mpt/load.rs index 292de36b..aed311d2 100644 --- a/evm/src/cpu/kernel/tests/mpt/load.rs +++ b/evm/src/cpu/kernel/tests/mpt/load.rs @@ -1,5 +1,4 @@ use anyhow::Result; -use eth_trie_utils::partial_trie::PartialTrie; use ethereum_types::{BigEndianHash, H256, U256}; use crate::cpu::kernel::aggregator::KERNEL; @@ -9,6 +8,7 @@ use crate::cpu::kernel::interpreter::Interpreter; use crate::cpu::kernel::tests::mpt::{extension_to_leaf, test_account_1, test_account_1_rlp}; use crate::generation::mpt::all_mpt_prover_inputs_reversed; use crate::generation::TrieInputs; +use crate::Node; #[test] fn load_all_mpts_empty() -> Result<()> { @@ -48,10 +48,11 @@ fn load_all_mpts_empty() -> Result<()> { #[test] fn load_all_mpts_leaf() -> Result<()> { let trie_inputs = TrieInputs { - state_trie: PartialTrie::Leaf { + state_trie: Node::Leaf { nibbles: 0xABC_u64.into(), value: test_account_1_rlp(), - }, + } + .into(), transactions_trie: Default::default(), receipts_trie: Default::default(), storage_tries: vec![], @@ -100,7 +101,7 @@ fn load_all_mpts_leaf() -> Result<()> { fn load_all_mpts_hash() -> Result<()> { let hash = H256::random(); let trie_inputs = TrieInputs { - state_trie: PartialTrie::Hash(hash), + state_trie: Node::Hash(hash).into(), transactions_trie: Default::default(), receipts_trie: Default::default(), storage_tries: vec![], @@ -134,11 +135,12 @@ fn load_all_mpts_hash() -> Result<()> { #[test] fn load_all_mpts_empty_branch() -> Result<()> { - let children = core::array::from_fn(|_| PartialTrie::Empty.into()); - let state_trie = PartialTrie::Branch { + let children = core::array::from_fn(|_| Node::Empty.into()); + let state_trie = Node::Branch { children, value: vec![], - }; + } + .into(); let trie_inputs = TrieInputs { state_trie, transactions_trie: Default::default(), diff --git a/evm/src/cpu/kernel/tests/mpt/mod.rs b/evm/src/cpu/kernel/tests/mpt/mod.rs index d5da1d6c..93d12f5e 100644 --- a/evm/src/cpu/kernel/tests/mpt/mod.rs +++ b/evm/src/cpu/kernel/tests/mpt/mod.rs @@ -1,7 +1,8 @@ -use eth_trie_utils::partial_trie::{Nibbles, PartialTrie}; +use eth_trie_utils::nibbles::Nibbles; use ethereum_types::{BigEndianHash, H256, U256}; use crate::generation::mpt::AccountRlp; +use crate::{Node, PartialTrie}; mod hash; mod hex_prefix; @@ -47,9 +48,9 @@ pub(crate) fn test_account_2_rlp() -> Vec { /// A `PartialTrie` where an extension node leads to a leaf node containing an account. pub(crate) fn extension_to_leaf(value: Vec) -> PartialTrie { - PartialTrie::Extension { + Node::Extension { nibbles: 0xABC_u64.into(), - child: PartialTrie::Leaf { + child: Node::Leaf { nibbles: Nibbles { count: 3, packed: 0xDEF.into(), @@ -58,4 +59,5 @@ pub(crate) fn extension_to_leaf(value: Vec) -> PartialTrie { } .into(), } + .into() } diff --git a/evm/src/generation/mod.rs b/evm/src/generation/mod.rs index 2c786d8f..d8be82c0 100644 --- a/evm/src/generation/mod.rs +++ b/evm/src/generation/mod.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; -use eth_trie_utils::partial_trie::PartialTrie; use ethereum_types::{Address, BigEndianHash, H256, U256}; use plonky2::field::extension::Extendable; use plonky2::field::polynomial::PolynomialValues; @@ -24,6 +23,7 @@ use crate::memory::segments::Segment; use crate::proof::{BlockMetadata, PublicValues, TrieRoots}; use crate::witness::memory::{MemoryAddress, MemoryChannel}; use crate::witness::transition::transition; +use crate::PartialTrie; pub mod mpt; pub mod outputs; diff --git a/evm/src/generation/mpt.rs b/evm/src/generation/mpt.rs index 6c4afd4a..737393ad 100644 --- a/evm/src/generation/mpt.rs +++ b/evm/src/generation/mpt.rs @@ -1,12 +1,15 @@ use std::collections::HashMap; +use std::ops::Deref; -use eth_trie_utils::partial_trie::{Nibbles, PartialTrie}; +use eth_trie_utils::nibbles::Nibbles; +use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; use ethereum_types::{BigEndianHash, H256, U256}; use keccak_hash::keccak; use rlp_derive::{RlpDecodable, RlpEncodable}; use crate::cpu::kernel::constants::trie_type::PartialTrieType; use crate::generation::TrieInputs; +use crate::{Node, PartialTrie}; #[derive(RlpEncodable, RlpDecodable, Debug)] pub struct AccountRlp { @@ -21,7 +24,7 @@ impl Default for AccountRlp { Self { nonce: U256::zero(), balance: U256::zero(), - storage_root: PartialTrie::Empty.calc_hash(), + storage_root: PartialTrie::from(Node::Empty).hash(), code_hash: keccak([]), } } @@ -77,10 +80,11 @@ pub(crate) fn mpt_prover_inputs( F: Fn(&[u8]) -> Vec, { prover_inputs.push((PartialTrieType::of(trie) as u32).into()); - match trie { - PartialTrie::Empty => {} - PartialTrie::Hash(h) => prover_inputs.push(U256::from_big_endian(h.as_bytes())), - PartialTrie::Branch { children, value } => { + + match trie.deref() { + Node::Empty => {} + Node::Hash(h) => prover_inputs.push(U256::from_big_endian(h.as_bytes())), + Node::Branch { children, value } => { if value.is_empty() { prover_inputs.push(U256::zero()); // value_present = 0 } else { @@ -92,12 +96,12 @@ pub(crate) fn mpt_prover_inputs( mpt_prover_inputs(child, prover_inputs, parse_value); } } - PartialTrie::Extension { nibbles, child } => { + Node::Extension { nibbles, child } => { prover_inputs.push(nibbles.count.into()); prover_inputs.push(nibbles.packed); mpt_prover_inputs(child, prover_inputs, parse_value); } - PartialTrie::Leaf { nibbles, value } => { + Node::Leaf { nibbles, value } => { prover_inputs.push(nibbles.count.into()); prover_inputs.push(nibbles.packed); let leaf = parse_value(value); @@ -115,10 +119,10 @@ pub(crate) fn mpt_prover_inputs_state_trie( storage_tries_by_state_key: &HashMap, ) { prover_inputs.push((PartialTrieType::of(trie) as u32).into()); - match trie { - PartialTrie::Empty => {} - PartialTrie::Hash(h) => prover_inputs.push(U256::from_big_endian(h.as_bytes())), - PartialTrie::Branch { children, value } => { + match trie.deref() { + Node::Empty => {} + Node::Hash(h) => prover_inputs.push(U256::from_big_endian(h.as_bytes())), + Node::Branch { children, value } => { assert!(value.is_empty(), "State trie should not have branch values"); prover_inputs.push(U256::zero()); // value_present = 0 @@ -135,7 +139,7 @@ pub(crate) fn mpt_prover_inputs_state_trie( ); } } - PartialTrie::Extension { nibbles, child } => { + Node::Extension { nibbles, child } => { prover_inputs.push(nibbles.count.into()); prover_inputs.push(nibbles.packed); let extended_key = key.merge_nibbles(nibbles); @@ -146,7 +150,7 @@ pub(crate) fn mpt_prover_inputs_state_trie( storage_tries_by_state_key, ); } - PartialTrie::Leaf { nibbles, value } => { + Node::Leaf { nibbles, value } => { let account: AccountRlp = rlp::decode(value).expect("Decoding failed"); let AccountRlp { nonce, @@ -155,14 +159,14 @@ pub(crate) fn mpt_prover_inputs_state_trie( code_hash, } = account; - let storage_hash_only = PartialTrie::Hash(storage_root); + let storage_hash_only = PartialTrie::new(Node::Hash(storage_root)); let merged_key = key.merge_nibbles(nibbles); let storage_trie: &PartialTrie = storage_tries_by_state_key .get(&merged_key) .copied() .unwrap_or(&storage_hash_only); - assert_eq!(storage_trie.calc_hash(), storage_root, + assert_eq!(storage_trie.hash(), storage_root, "In TrieInputs, an account's storage_root didn't match the associated storage trie hash"); prover_inputs.push(nibbles.count.into()); diff --git a/evm/src/generation/trie_extractor.rs b/evm/src/generation/trie_extractor.rs index 66174419..7c9aceb8 100644 --- a/evm/src/generation/trie_extractor.rs +++ b/evm/src/generation/trie_extractor.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; -use eth_trie_utils::partial_trie::Nibbles; +use eth_trie_utils::nibbles::Nibbles; use ethereum_types::{BigEndianHash, H256, U256}; use crate::cpu::kernel::constants::trie_type::PartialTrieType; diff --git a/evm/src/lib.rs b/evm/src/lib.rs index dc2204df..6c7b0cd8 100644 --- a/evm/src/lib.rs +++ b/evm/src/lib.rs @@ -34,6 +34,7 @@ pub mod vars; pub mod verifier; pub mod witness; +use eth_trie_utils::partial_trie::HashedPartialTrie; // Set up Jemalloc #[cfg(not(target_env = "msvc"))] use jemallocator::Jemalloc; @@ -41,3 +42,6 @@ use jemallocator::Jemalloc; #[cfg(not(target_env = "msvc"))] #[global_allocator] static GLOBAL: Jemalloc = Jemalloc; + +pub type PartialTrie = HashedPartialTrie; +pub type Node = eth_trie_utils::partial_trie::Node; diff --git a/evm/tests/add11_yml.rs b/evm/tests/add11_yml.rs index 4b1eba54..f7d7746f 100644 --- a/evm/tests/add11_yml.rs +++ b/evm/tests/add11_yml.rs @@ -2,7 +2,8 @@ use std::collections::HashMap; use std::time::Duration; use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; -use eth_trie_utils::partial_trie::{Nibbles, PartialTrie}; +use eth_trie_utils::nibbles::Nibbles; +use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; use ethereum_types::Address; use hex_literal::hex; use keccak_hash::keccak; @@ -16,6 +17,7 @@ use plonky2_evm::generation::{GenerationInputs, TrieInputs}; use plonky2_evm::proof::BlockMetadata; use plonky2_evm::prover::prove; use plonky2_evm::verifier::verify_proof; +use plonky2_evm::{Node, PartialTrie}; type F = GoldilocksField; const D: usize = 2; @@ -58,7 +60,7 @@ fn add11_yml() -> anyhow::Result<()> { ..AccountRlp::default() }; - let mut state_trie_before = PartialTrie::Empty; + let mut state_trie_before = PartialTrie::from(Node::Empty); state_trie_before.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_before).to_vec(), @@ -68,9 +70,9 @@ fn add11_yml() -> anyhow::Result<()> { let tries_before = TrieInputs { state_trie: state_trie_before, - transactions_trie: PartialTrie::Empty, - receipts_trie: PartialTrie::Empty, - storage_tries: vec![(Address::from_slice(&to), PartialTrie::Empty)], + transactions_trie: Node::Empty.into(), + receipts_trie: Node::Empty.into(), + storage_tries: vec![(Address::from_slice(&to), Node::Empty.into())], }; let txn = hex!("f863800a83061a8094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a0801ba0ffb600e63115a7362e7811894a91d8ba4330e526f22121c994c4692035dfdfd5a06198379fcac8de3dbfac48b165df4bf88e2088f294b61efb9a65fe2281c76e16"); @@ -110,15 +112,15 @@ fn add11_yml() -> anyhow::Result<()> { balance: 0xde0b6b3a76586a0u64.into(), code_hash, // Storage map: { 0 => 2 } - storage_root: PartialTrie::Leaf { + storage_root: PartialTrie::from(Node::Leaf { nibbles: Nibbles::from_h256_be(keccak([0u8; 32])), value: vec![2], - } - .calc_hash(), + }) + .hash(), ..AccountRlp::default() }; - let mut expected_state_trie_after = PartialTrie::Empty; + let mut expected_state_trie_after = PartialTrie::from(Node::Empty); expected_state_trie_after.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_after).to_vec(), @@ -128,7 +130,7 @@ fn add11_yml() -> anyhow::Result<()> { assert_eq!( proof.public_values.trie_roots_after.state_root, - expected_state_trie_after.calc_hash() + expected_state_trie_after.hash() ); verify_proof(&all_stark, proof, &config) diff --git a/evm/tests/basic_smart_contract.rs b/evm/tests/basic_smart_contract.rs index 4809ea93..b6e45c01 100644 --- a/evm/tests/basic_smart_contract.rs +++ b/evm/tests/basic_smart_contract.rs @@ -2,7 +2,8 @@ use std::collections::HashMap; use std::time::Duration; use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; -use eth_trie_utils::partial_trie::{Nibbles, PartialTrie}; +use eth_trie_utils::nibbles::Nibbles; +use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; use ethereum_types::{Address, U256}; use hex_literal::hex; use keccak_hash::keccak; @@ -17,6 +18,7 @@ use plonky2_evm::generation::{GenerationInputs, TrieInputs}; use plonky2_evm::proof::BlockMetadata; use plonky2_evm::prover::prove; use plonky2_evm::verifier::verify_proof; +use plonky2_evm::{Node, PartialTrie}; type F = GoldilocksField; const D: usize = 2; @@ -61,27 +63,28 @@ fn test_basic_smart_contract() -> anyhow::Result<()> { }; let state_trie_before = { - let mut children = core::array::from_fn(|_| PartialTrie::Empty.into()); - children[sender_nibbles.get_nibble(0) as usize] = PartialTrie::Leaf { + let mut children = core::array::from_fn(|_| Node::Empty.into()); + children[sender_nibbles.get_nibble(0) as usize] = Node::Leaf { nibbles: sender_nibbles.truncate_n_nibbles_front(1), value: rlp::encode(&sender_account_before).to_vec(), } .into(); - children[to_nibbles.get_nibble(0) as usize] = PartialTrie::Leaf { + children[to_nibbles.get_nibble(0) as usize] = Node::Leaf { nibbles: to_nibbles.truncate_n_nibbles_front(1), value: rlp::encode(&to_account_before).to_vec(), } .into(); - PartialTrie::Branch { + Node::Branch { children, value: vec![], } - }; + } + .into(); let tries_before = TrieInputs { state_trie: state_trie_before, - transactions_trie: PartialTrie::Empty, - receipts_trie: PartialTrie::Empty, + transactions_trie: Node::Empty.into(), + receipts_trie: Node::Empty.into(), storage_tries: vec![], }; @@ -110,7 +113,7 @@ fn test_basic_smart_contract() -> anyhow::Result<()> { let proof = prove::(&all_stark, &config, inputs, &mut timing)?; timing.filter(Duration::from_millis(100)).print(); - let expected_state_trie_after = { + let expected_state_trie_after: PartialTrie = { let txdata_gas = 2 * 16; let gas_used = 21_000 + code_gas + txdata_gas; @@ -128,31 +131,32 @@ fn test_basic_smart_contract() -> anyhow::Result<()> { ..to_account_before }; - let mut children = core::array::from_fn(|_| PartialTrie::Empty.into()); - children[beneficiary_nibbles.get_nibble(0) as usize] = PartialTrie::Leaf { + let mut children = core::array::from_fn(|_| Node::Empty.into()); + children[beneficiary_nibbles.get_nibble(0) as usize] = Node::Leaf { nibbles: beneficiary_nibbles.truncate_n_nibbles_front(1), value: rlp::encode(&beneficiary_account_after).to_vec(), } .into(); - children[sender_nibbles.get_nibble(0) as usize] = PartialTrie::Leaf { + children[sender_nibbles.get_nibble(0) as usize] = Node::Leaf { nibbles: sender_nibbles.truncate_n_nibbles_front(1), value: rlp::encode(&sender_account_after).to_vec(), } .into(); - children[to_nibbles.get_nibble(0) as usize] = PartialTrie::Leaf { + children[to_nibbles.get_nibble(0) as usize] = Node::Leaf { nibbles: to_nibbles.truncate_n_nibbles_front(1), value: rlp::encode(&to_account_after).to_vec(), } .into(); - PartialTrie::Branch { + Node::Branch { children, value: vec![], } - }; + } + .into(); assert_eq!( proof.public_values.trie_roots_after.state_root, - expected_state_trie_after.calc_hash() + expected_state_trie_after.hash() ); verify_proof(&all_stark, proof, &config) diff --git a/evm/tests/empty_txn_list.rs b/evm/tests/empty_txn_list.rs index a0148e74..e70aeef2 100644 --- a/evm/tests/empty_txn_list.rs +++ b/evm/tests/empty_txn_list.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::time::Duration; use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; -use eth_trie_utils::partial_trie::PartialTrie; +use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; use plonky2::plonk::config::PoseidonGoldilocksConfig; @@ -14,6 +14,7 @@ use plonky2_evm::generation::{GenerationInputs, TrieInputs}; use plonky2_evm::proof::BlockMetadata; use plonky2_evm::prover::prove; use plonky2_evm::verifier::verify_proof; +use plonky2_evm::{Node, PartialTrie}; type F = GoldilocksField; const D: usize = 2; @@ -30,14 +31,14 @@ fn test_empty_txn_list() -> anyhow::Result<()> { let block_metadata = BlockMetadata::default(); - let state_trie = PartialTrie::Empty; - let transactions_trie = PartialTrie::Empty; - let receipts_trie = PartialTrie::Empty; + let state_trie = PartialTrie::from(Node::Empty); + let transactions_trie = PartialTrie::from(Node::Empty); + let receipts_trie = PartialTrie::from(Node::Empty); let storage_tries = vec![]; - let state_trie_root = state_trie.calc_hash(); - let txns_trie_root = transactions_trie.calc_hash(); - let receipts_trie_root = receipts_trie.calc_hash(); + let state_trie_root = state_trie.hash(); + let txns_trie_root = transactions_trie.hash(); + let receipts_trie_root = receipts_trie.hash(); let mut contract_code = HashMap::new(); contract_code.insert(keccak(vec![]), vec![]); diff --git a/evm/tests/simple_transfer.rs b/evm/tests/simple_transfer.rs index ff2bed31..11562ee0 100644 --- a/evm/tests/simple_transfer.rs +++ b/evm/tests/simple_transfer.rs @@ -2,7 +2,8 @@ use std::collections::HashMap; use std::time::Duration; use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; -use eth_trie_utils::partial_trie::{Nibbles, PartialTrie}; +use eth_trie_utils::nibbles::Nibbles; +use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; use ethereum_types::{Address, U256}; use hex_literal::hex; use keccak_hash::keccak; @@ -16,6 +17,7 @@ use plonky2_evm::generation::{GenerationInputs, TrieInputs}; use plonky2_evm::proof::BlockMetadata; use plonky2_evm::prover::prove; use plonky2_evm::verifier::verify_proof; +use plonky2_evm::{Node, PartialTrie}; type F = GoldilocksField; const D: usize = 2; @@ -45,19 +47,20 @@ fn test_simple_transfer() -> anyhow::Result<()> { let sender_account_before = AccountRlp { nonce: 5.into(), balance: eth_to_wei(100_000.into()), - storage_root: PartialTrie::Empty.calc_hash(), + storage_root: PartialTrie::from(Node::Empty).hash(), code_hash: keccak([]), }; let to_account_before = AccountRlp::default(); - let state_trie_before = PartialTrie::Leaf { + let state_trie_before = Node::Leaf { nibbles: sender_nibbles, value: rlp::encode(&sender_account_before).to_vec(), - }; + } + .into(); let tries_before = TrieInputs { state_trie: state_trie_before, - transactions_trie: PartialTrie::Empty, - receipts_trie: PartialTrie::Empty, + transactions_trie: PartialTrie::from(Node::Empty), + receipts_trie: PartialTrie::from(Node::Empty), storage_tries: vec![], }; @@ -85,7 +88,7 @@ fn test_simple_transfer() -> anyhow::Result<()> { let proof = prove::(&all_stark, &config, inputs, &mut timing)?; timing.filter(Duration::from_millis(100)).print(); - let expected_state_trie_after = { + let expected_state_trie_after: PartialTrie = { let txdata_gas = 2 * 16; let gas_used = 21_000 + txdata_gas; @@ -103,31 +106,32 @@ fn test_simple_transfer() -> anyhow::Result<()> { ..to_account_before }; - let mut children = core::array::from_fn(|_| PartialTrie::Empty.into()); - children[beneficiary_nibbles.get_nibble(0) as usize] = PartialTrie::Leaf { + let mut children = core::array::from_fn(|_| Node::Empty.into()); + children[beneficiary_nibbles.get_nibble(0) as usize] = Node::Leaf { nibbles: beneficiary_nibbles.truncate_n_nibbles_front(1), value: rlp::encode(&beneficiary_account_after).to_vec(), } .into(); - children[sender_nibbles.get_nibble(0) as usize] = PartialTrie::Leaf { + children[sender_nibbles.get_nibble(0) as usize] = Node::Leaf { nibbles: sender_nibbles.truncate_n_nibbles_front(1), value: rlp::encode(&sender_account_after).to_vec(), } .into(); - children[to_nibbles.get_nibble(0) as usize] = PartialTrie::Leaf { + children[to_nibbles.get_nibble(0) as usize] = Node::Leaf { nibbles: to_nibbles.truncate_n_nibbles_front(1), value: rlp::encode(&to_account_after).to_vec(), } .into(); - PartialTrie::Branch { + Node::Branch { children, value: vec![], } + .into() }; assert_eq!( proof.public_values.trie_roots_after.state_root, - expected_state_trie_after.calc_hash() + expected_state_trie_after.hash() ); verify_proof(&all_stark, proof, &config) From 3c7bc8835cd5e2d77e585dfbc8b92992b920a2b3 Mon Sep 17 00:00:00 2001 From: BGluth Date: Tue, 28 Mar 2023 14:38:58 -0600 Subject: [PATCH 04/20] Removed a type alias - Was conflicting with the trait `PartialTrie` and also making the types harder to follow. --- evm/src/cpu/kernel/constants/trie_type.rs | 6 ++++-- evm/src/cpu/kernel/tests/account_code.rs | 8 ++++---- evm/src/cpu/kernel/tests/balance.rs | 8 ++++---- evm/src/cpu/kernel/tests/mpt/hash.rs | 2 +- evm/src/cpu/kernel/tests/mpt/insert.rs | 12 ++++++++---- evm/src/cpu/kernel/tests/mpt/mod.rs | 5 +++-- evm/src/generation/mod.rs | 10 +++++----- evm/src/generation/mpt.rs | 16 ++++++++-------- evm/src/lib.rs | 3 +-- evm/tests/add11_yml.rs | 10 +++++----- evm/tests/basic_smart_contract.rs | 6 +++--- evm/tests/empty_txn_list.rs | 10 +++++----- evm/tests/simple_transfer.rs | 12 ++++++------ 13 files changed, 57 insertions(+), 51 deletions(-) diff --git a/evm/src/cpu/kernel/constants/trie_type.rs b/evm/src/cpu/kernel/constants/trie_type.rs index 34700a5f..7f936529 100644 --- a/evm/src/cpu/kernel/constants/trie_type.rs +++ b/evm/src/cpu/kernel/constants/trie_type.rs @@ -1,6 +1,8 @@ use std::ops::Deref; -use crate::{Node, PartialTrie}; +use eth_trie_utils::partial_trie::HashedPartialTrie; + +use crate::Node; #[derive(Copy, Clone, Debug)] pub(crate) enum PartialTrieType { @@ -14,7 +16,7 @@ pub(crate) enum PartialTrieType { impl PartialTrieType { pub(crate) const COUNT: usize = 5; - pub(crate) fn of(trie: &PartialTrie) -> Self { + pub(crate) fn of(trie: &HashedPartialTrie) -> Self { match trie.deref() { Node::Empty => Self::Empty, Node::Hash(_) => Self::Hash, diff --git a/evm/src/cpu/kernel/tests/account_code.rs b/evm/src/cpu/kernel/tests/account_code.rs index 38d2ce4b..da27c703 100644 --- a/evm/src/cpu/kernel/tests/account_code.rs +++ b/evm/src/cpu/kernel/tests/account_code.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use anyhow::Result; -use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; +use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; use ethereum_types::{Address, BigEndianHash, H256, U256}; use keccak_hash::keccak; use rand::{thread_rng, Rng}; @@ -12,14 +12,14 @@ use crate::cpu::kernel::interpreter::Interpreter; use crate::cpu::kernel::tests::mpt::nibbles_64; use crate::generation::mpt::{all_mpt_prover_inputs_reversed, AccountRlp}; use crate::memory::segments::Segment; -use crate::{Node, PartialTrie}; +use crate::Node; // Test account with a given code hash. fn test_account(code: &[u8]) -> AccountRlp { AccountRlp { nonce: U256::from(1111), balance: U256::from(2222), - storage_root: PartialTrie::from(Node::Empty).hash(), + storage_root: HashedPartialTrie::from(Node::Empty).hash(), code_hash: keccak(code), } } @@ -40,7 +40,7 @@ fn prepare_interpreter( let load_all_mpts = KERNEL.global_labels["load_all_mpts"]; let mpt_insert_state_trie = KERNEL.global_labels["mpt_insert_state_trie"]; let mpt_hash_state_trie = KERNEL.global_labels["mpt_hash_state_trie"]; - let mut state_trie: PartialTrie = Default::default(); + let mut state_trie: HashedPartialTrie = Default::default(); let trie_inputs = Default::default(); interpreter.generation_state.registers.program_counter = load_all_mpts; diff --git a/evm/src/cpu/kernel/tests/balance.rs b/evm/src/cpu/kernel/tests/balance.rs index b5f75ac4..cf9ea74c 100644 --- a/evm/src/cpu/kernel/tests/balance.rs +++ b/evm/src/cpu/kernel/tests/balance.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; +use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; use ethereum_types::{Address, BigEndianHash, H256, U256}; use keccak_hash::keccak; use rand::{thread_rng, Rng}; @@ -9,14 +9,14 @@ use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; use crate::cpu::kernel::interpreter::Interpreter; use crate::cpu::kernel::tests::mpt::nibbles_64; use crate::generation::mpt::{all_mpt_prover_inputs_reversed, AccountRlp}; -use crate::{Node, PartialTrie}; +use crate::Node; // Test account with a given code hash. fn test_account(balance: U256) -> AccountRlp { AccountRlp { nonce: U256::from(1111), balance, - storage_root: PartialTrie::from(Node::Empty).hash(), + storage_root: HashedPartialTrie::from(Node::Empty).hash(), code_hash: H256::from_uint(&U256::from(8888)), } } @@ -31,7 +31,7 @@ fn prepare_interpreter( let load_all_mpts = KERNEL.global_labels["load_all_mpts"]; let mpt_insert_state_trie = KERNEL.global_labels["mpt_insert_state_trie"]; let mpt_hash_state_trie = KERNEL.global_labels["mpt_hash_state_trie"]; - let mut state_trie: PartialTrie = Default::default(); + let mut state_trie: HashedPartialTrie = Default::default(); let trie_inputs = Default::default(); interpreter.generation_state.registers.program_counter = load_all_mpts; diff --git a/evm/src/cpu/kernel/tests/mpt/hash.rs b/evm/src/cpu/kernel/tests/mpt/hash.rs index 9ab021f9..3d6c2a23 100644 --- a/evm/src/cpu/kernel/tests/mpt/hash.rs +++ b/evm/src/cpu/kernel/tests/mpt/hash.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; +use eth_trie_utils::partial_trie::PartialTrie; use ethereum_types::{BigEndianHash, H256}; use crate::cpu::kernel::aggregator::KERNEL; diff --git a/evm/src/cpu/kernel/tests/mpt/insert.rs b/evm/src/cpu/kernel/tests/mpt/insert.rs index 7858e2d7..e6c203e3 100644 --- a/evm/src/cpu/kernel/tests/mpt/insert.rs +++ b/evm/src/cpu/kernel/tests/mpt/insert.rs @@ -1,6 +1,6 @@ use anyhow::Result; use eth_trie_utils::nibbles::Nibbles; -use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; +use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; use ethereum_types::{BigEndianHash, H256}; use crate::cpu::kernel::aggregator::KERNEL; @@ -11,7 +11,7 @@ use crate::cpu::kernel::tests::mpt::{ }; use crate::generation::mpt::{all_mpt_prover_inputs_reversed, AccountRlp}; use crate::generation::TrieInputs; -use crate::{Node, PartialTrie}; +use crate::Node; #[test] fn mpt_insert_empty() -> Result<()> { @@ -152,11 +152,15 @@ fn mpt_insert_branch_to_leaf_same_key() -> Result<()> { /// Note: The account's storage_root is ignored, as we can't insert a new storage_root without the /// accompanying trie data. An empty trie's storage_root is used instead. -fn test_state_trie(mut state_trie: PartialTrie, k: Nibbles, mut account: AccountRlp) -> Result<()> { +fn test_state_trie( + mut state_trie: HashedPartialTrie, + k: Nibbles, + mut account: AccountRlp, +) -> Result<()> { assert_eq!(k.count, 64); // Ignore any storage_root; see documentation note. - account.storage_root = PartialTrie::from(Node::Empty).hash(); + account.storage_root = HashedPartialTrie::from(Node::Empty).hash(); let trie_inputs = TrieInputs { state_trie: state_trie.clone(), diff --git a/evm/src/cpu/kernel/tests/mpt/mod.rs b/evm/src/cpu/kernel/tests/mpt/mod.rs index 93d12f5e..638f1a4d 100644 --- a/evm/src/cpu/kernel/tests/mpt/mod.rs +++ b/evm/src/cpu/kernel/tests/mpt/mod.rs @@ -1,8 +1,9 @@ use eth_trie_utils::nibbles::Nibbles; +use eth_trie_utils::partial_trie::HashedPartialTrie; use ethereum_types::{BigEndianHash, H256, U256}; use crate::generation::mpt::AccountRlp; -use crate::{Node, PartialTrie}; +use crate::Node; mod hash; mod hex_prefix; @@ -47,7 +48,7 @@ pub(crate) fn test_account_2_rlp() -> Vec { } /// A `PartialTrie` where an extension node leads to a leaf node containing an account. -pub(crate) fn extension_to_leaf(value: Vec) -> PartialTrie { +pub(crate) fn extension_to_leaf(value: Vec) -> HashedPartialTrie { Node::Extension { nibbles: 0xABC_u64.into(), child: Node::Leaf { diff --git a/evm/src/generation/mod.rs b/evm/src/generation/mod.rs index d8be82c0..ae73c705 100644 --- a/evm/src/generation/mod.rs +++ b/evm/src/generation/mod.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use eth_trie_utils::partial_trie::HashedPartialTrie; use ethereum_types::{Address, BigEndianHash, H256, U256}; use plonky2::field::extension::Extendable; use plonky2::field::polynomial::PolynomialValues; @@ -23,7 +24,6 @@ use crate::memory::segments::Segment; use crate::proof::{BlockMetadata, PublicValues, TrieRoots}; use crate::witness::memory::{MemoryAddress, MemoryChannel}; use crate::witness::transition::transition; -use crate::PartialTrie; pub mod mpt; pub mod outputs; @@ -59,19 +59,19 @@ pub struct GenerationInputs { pub struct TrieInputs { /// A partial version of the state trie prior to these transactions. It should include all nodes /// that will be accessed by these transactions. - pub state_trie: PartialTrie, + pub state_trie: HashedPartialTrie, /// A partial version of the transaction trie prior to these transactions. It should include all /// nodes that will be accessed by these transactions. - pub transactions_trie: PartialTrie, + pub transactions_trie: HashedPartialTrie, /// A partial version of the receipt trie prior to these transactions. It should include all nodes /// that will be accessed by these transactions. - pub receipts_trie: PartialTrie, + pub receipts_trie: HashedPartialTrie, /// A partial version of each storage trie prior to these transactions. It should include all /// storage tries, and nodes therein, that will be accessed by these transactions. - pub storage_tries: Vec<(Address, PartialTrie)>, + pub storage_tries: Vec<(Address, HashedPartialTrie)>, } fn apply_metadata_memops, const D: usize>( diff --git a/evm/src/generation/mpt.rs b/evm/src/generation/mpt.rs index 737393ad..8a8e3d06 100644 --- a/evm/src/generation/mpt.rs +++ b/evm/src/generation/mpt.rs @@ -2,14 +2,14 @@ use std::collections::HashMap; use std::ops::Deref; use eth_trie_utils::nibbles::Nibbles; -use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; +use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; use ethereum_types::{BigEndianHash, H256, U256}; use keccak_hash::keccak; use rlp_derive::{RlpDecodable, RlpEncodable}; use crate::cpu::kernel::constants::trie_type::PartialTrieType; use crate::generation::TrieInputs; -use crate::{Node, PartialTrie}; +use crate::Node; #[derive(RlpEncodable, RlpDecodable, Debug)] pub struct AccountRlp { @@ -24,7 +24,7 @@ impl Default for AccountRlp { Self { nonce: U256::zero(), balance: U256::zero(), - storage_root: PartialTrie::from(Node::Empty).hash(), + storage_root: HashedPartialTrie::from(Node::Empty).hash(), code_hash: keccak([]), } } @@ -73,7 +73,7 @@ pub(crate) fn all_mpt_prover_inputs(trie_inputs: &TrieInputs) -> Vec { /// is serialized as `(TYPE_LEAF, key, value)`, where key is a `(nibbles, depth)` pair and `value` /// is a variable-length structure which depends on which trie we're dealing with. pub(crate) fn mpt_prover_inputs( - trie: &PartialTrie, + trie: &HashedPartialTrie, prover_inputs: &mut Vec, parse_value: &F, ) where @@ -113,10 +113,10 @@ pub(crate) fn mpt_prover_inputs( /// Like `mpt_prover_inputs`, but for the state trie, which is a bit unique since each value /// leads to a storage trie which we recursively traverse. pub(crate) fn mpt_prover_inputs_state_trie( - trie: &PartialTrie, + trie: &HashedPartialTrie, key: Nibbles, prover_inputs: &mut Vec, - storage_tries_by_state_key: &HashMap, + storage_tries_by_state_key: &HashMap, ) { prover_inputs.push((PartialTrieType::of(trie) as u32).into()); match trie.deref() { @@ -159,9 +159,9 @@ pub(crate) fn mpt_prover_inputs_state_trie( code_hash, } = account; - let storage_hash_only = PartialTrie::new(Node::Hash(storage_root)); + let storage_hash_only = HashedPartialTrie::new(Node::Hash(storage_root)); let merged_key = key.merge_nibbles(nibbles); - let storage_trie: &PartialTrie = storage_tries_by_state_key + let storage_trie: &HashedPartialTrie = storage_tries_by_state_key .get(&merged_key) .copied() .unwrap_or(&storage_hash_only); diff --git a/evm/src/lib.rs b/evm/src/lib.rs index 6c7b0cd8..3a3df21d 100644 --- a/evm/src/lib.rs +++ b/evm/src/lib.rs @@ -43,5 +43,4 @@ use jemallocator::Jemalloc; #[global_allocator] static GLOBAL: Jemalloc = Jemalloc; -pub type PartialTrie = HashedPartialTrie; -pub type Node = eth_trie_utils::partial_trie::Node; +pub type Node = eth_trie_utils::partial_trie::Node; diff --git a/evm/tests/add11_yml.rs b/evm/tests/add11_yml.rs index f7d7746f..b4c9b179 100644 --- a/evm/tests/add11_yml.rs +++ b/evm/tests/add11_yml.rs @@ -3,7 +3,7 @@ use std::time::Duration; use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use eth_trie_utils::nibbles::Nibbles; -use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; +use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; use ethereum_types::Address; use hex_literal::hex; use keccak_hash::keccak; @@ -17,7 +17,7 @@ use plonky2_evm::generation::{GenerationInputs, TrieInputs}; use plonky2_evm::proof::BlockMetadata; use plonky2_evm::prover::prove; use plonky2_evm::verifier::verify_proof; -use plonky2_evm::{Node, PartialTrie}; +use plonky2_evm::Node; type F = GoldilocksField; const D: usize = 2; @@ -60,7 +60,7 @@ fn add11_yml() -> anyhow::Result<()> { ..AccountRlp::default() }; - let mut state_trie_before = PartialTrie::from(Node::Empty); + let mut state_trie_before = HashedPartialTrie::from(Node::Empty); state_trie_before.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_before).to_vec(), @@ -112,7 +112,7 @@ fn add11_yml() -> anyhow::Result<()> { balance: 0xde0b6b3a76586a0u64.into(), code_hash, // Storage map: { 0 => 2 } - storage_root: PartialTrie::from(Node::Leaf { + storage_root: HashedPartialTrie::from(Node::Leaf { nibbles: Nibbles::from_h256_be(keccak([0u8; 32])), value: vec![2], }) @@ -120,7 +120,7 @@ fn add11_yml() -> anyhow::Result<()> { ..AccountRlp::default() }; - let mut expected_state_trie_after = PartialTrie::from(Node::Empty); + let mut expected_state_trie_after = HashedPartialTrie::from(Node::Empty); expected_state_trie_after.insert( beneficiary_nibbles, rlp::encode(&beneficiary_account_after).to_vec(), diff --git a/evm/tests/basic_smart_contract.rs b/evm/tests/basic_smart_contract.rs index b6e45c01..8db237ec 100644 --- a/evm/tests/basic_smart_contract.rs +++ b/evm/tests/basic_smart_contract.rs @@ -3,7 +3,7 @@ use std::time::Duration; use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use eth_trie_utils::nibbles::Nibbles; -use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; +use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; use ethereum_types::{Address, U256}; use hex_literal::hex; use keccak_hash::keccak; @@ -18,7 +18,7 @@ use plonky2_evm::generation::{GenerationInputs, TrieInputs}; use plonky2_evm::proof::BlockMetadata; use plonky2_evm::prover::prove; use plonky2_evm::verifier::verify_proof; -use plonky2_evm::{Node, PartialTrie}; +use plonky2_evm::Node; type F = GoldilocksField; const D: usize = 2; @@ -113,7 +113,7 @@ fn test_basic_smart_contract() -> anyhow::Result<()> { let proof = prove::(&all_stark, &config, inputs, &mut timing)?; timing.filter(Duration::from_millis(100)).print(); - let expected_state_trie_after: PartialTrie = { + let expected_state_trie_after: HashedPartialTrie = { let txdata_gas = 2 * 16; let gas_used = 21_000 + code_gas + txdata_gas; diff --git a/evm/tests/empty_txn_list.rs b/evm/tests/empty_txn_list.rs index e70aeef2..84f143bd 100644 --- a/evm/tests/empty_txn_list.rs +++ b/evm/tests/empty_txn_list.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::time::Duration; use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; -use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; +use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; use plonky2::plonk::config::PoseidonGoldilocksConfig; @@ -14,7 +14,7 @@ use plonky2_evm::generation::{GenerationInputs, TrieInputs}; use plonky2_evm::proof::BlockMetadata; use plonky2_evm::prover::prove; use plonky2_evm::verifier::verify_proof; -use plonky2_evm::{Node, PartialTrie}; +use plonky2_evm::Node; type F = GoldilocksField; const D: usize = 2; @@ -31,9 +31,9 @@ fn test_empty_txn_list() -> anyhow::Result<()> { let block_metadata = BlockMetadata::default(); - let state_trie = PartialTrie::from(Node::Empty); - let transactions_trie = PartialTrie::from(Node::Empty); - let receipts_trie = PartialTrie::from(Node::Empty); + let state_trie = HashedPartialTrie::from(Node::Empty); + let transactions_trie = HashedPartialTrie::from(Node::Empty); + let receipts_trie = HashedPartialTrie::from(Node::Empty); let storage_tries = vec![]; let state_trie_root = state_trie.hash(); diff --git a/evm/tests/simple_transfer.rs b/evm/tests/simple_transfer.rs index 11562ee0..a4ef5361 100644 --- a/evm/tests/simple_transfer.rs +++ b/evm/tests/simple_transfer.rs @@ -3,7 +3,7 @@ use std::time::Duration; use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use eth_trie_utils::nibbles::Nibbles; -use eth_trie_utils::partial_trie::PartialTrie as PartialTrieTrait; +use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; use ethereum_types::{Address, U256}; use hex_literal::hex; use keccak_hash::keccak; @@ -17,7 +17,7 @@ use plonky2_evm::generation::{GenerationInputs, TrieInputs}; use plonky2_evm::proof::BlockMetadata; use plonky2_evm::prover::prove; use plonky2_evm::verifier::verify_proof; -use plonky2_evm::{Node, PartialTrie}; +use plonky2_evm::Node; type F = GoldilocksField; const D: usize = 2; @@ -47,7 +47,7 @@ fn test_simple_transfer() -> anyhow::Result<()> { let sender_account_before = AccountRlp { nonce: 5.into(), balance: eth_to_wei(100_000.into()), - storage_root: PartialTrie::from(Node::Empty).hash(), + storage_root: HashedPartialTrie::from(Node::Empty).hash(), code_hash: keccak([]), }; let to_account_before = AccountRlp::default(); @@ -59,8 +59,8 @@ fn test_simple_transfer() -> anyhow::Result<()> { .into(); let tries_before = TrieInputs { state_trie: state_trie_before, - transactions_trie: PartialTrie::from(Node::Empty), - receipts_trie: PartialTrie::from(Node::Empty), + transactions_trie: HashedPartialTrie::from(Node::Empty), + receipts_trie: HashedPartialTrie::from(Node::Empty), storage_tries: vec![], }; @@ -88,7 +88,7 @@ fn test_simple_transfer() -> anyhow::Result<()> { let proof = prove::(&all_stark, &config, inputs, &mut timing)?; timing.filter(Duration::from_millis(100)).print(); - let expected_state_trie_after: PartialTrie = { + let expected_state_trie_after: HashedPartialTrie = { let txdata_gas = 2 * 16; let gas_used = 21_000 + txdata_gas; From 9f1a5f975c4601cc5b39e52c3e0286153811d6ef Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 29 Mar 2023 19:58:29 +0200 Subject: [PATCH 05/20] Charge gas for keccak (#943) --- evm/src/cpu/kernel/asm/util/keccak.asm | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/asm/util/keccak.asm b/evm/src/cpu/kernel/asm/util/keccak.asm index 280a4047..1d3f985b 100644 --- a/evm/src/cpu/kernel/asm/util/keccak.asm +++ b/evm/src/cpu/kernel/asm/util/keccak.asm @@ -1,6 +1,20 @@ global sys_keccak256: // stack: kexit_info, offset, len - // TODO: Charge gas. + PUSH @GAS_KECCAK256 + DUP4 + // stack: len, static_gas, kexit_info, offset, len + ISZERO %jumpi(sys_keccak256_empty) + // stack: static_gas, kexit_info, offset, len + DUP4 %num_bytes_to_num_words %mul_const(@GAS_KECCAK256WORD) + ADD + %charge_gas + // stack: kexit_info, offset, len + + %stack (kexit_info, offset, len) -> (offset, len, kexit_info, offset, len) + ADD // TODO: need to check for overflow? + DUP1 %ensure_reasonable_offset + %update_mem_bytes + %stack (kexit_info, offset, len) -> (offset, len, kexit_info) PUSH @SEGMENT_MAIN_MEMORY GET_CONTEXT @@ -10,6 +24,12 @@ global sys_keccak256: SWAP1 EXIT_KERNEL +sys_keccak256_empty: + // stack: static_gas, kexit_info, offset, len + %charge_gas + %stack (kexit_info, offset, len) -> (kexit_info, @EMPTY_STRING_HASH) + EXIT_KERNEL + // Computes Keccak256(input_word). Clobbers @SEGMENT_KERNEL_GENERAL. // // Pre stack: input_word From a0d04ca3d80efc04ed6e87495809bbd31c3680f9 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 29 Mar 2023 19:58:44 +0200 Subject: [PATCH 06/20] Fix Wcopy when size=0 (#944) --- evm/src/cpu/kernel/asm/memory/syscalls.asm | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/asm/memory/syscalls.asm b/evm/src/cpu/kernel/asm/memory/syscalls.asm index 86435408..082b44fa 100644 --- a/evm/src/cpu/kernel/asm/memory/syscalls.asm +++ b/evm/src/cpu/kernel/asm/memory/syscalls.asm @@ -122,7 +122,12 @@ sys_calldataload_after_mload_packing: // Macro for {CALLDATA,CODE,RETURNDATA}COPY (W_copy in Yellow Paper). %macro wcopy(segment) // stack: kexit_info, dest_offset, offset, size - DUP4 %num_bytes_to_num_words %mul_const(@GAS_COPY) %add_const(@GAS_VERYLOW) %charge_gas + PUSH @GAS_VERYLOW + DUP5 + // stack: size, Gverylow, kexit_info, dest_offset, offset, size + ISZERO %jumpi(%%wcopy_empty) + // stack: Gverylow, kexit_info, dest_offset, offset, size + DUP5 %num_bytes_to_num_words %mul_const(@GAS_COPY) ADD %charge_gas %stack (kexit_info, dest_offset, offset, size) -> (dest_offset, size, kexit_info, dest_offset, offset, size) ADD // TODO: check for overflow, see discussion here https://github.com/mir-protocol/plonky2/pull/930/files/a4ea0965d79561c345e2f77836c07949c7e0bc69#r1143630253 @@ -137,6 +142,11 @@ sys_calldataload_after_mload_packing: %%after: // stack: kexit_info EXIT_KERNEL +%%wcopy_empty: + // stack: Gverylow, kexit_info, dest_offset, offset, size + %charge_gas + %stack (kexit_info, dest_offset, offset, size) -> (kexit_info) + EXIT_KERNEL %endmacro global sys_calldatacopy: From 39fdad8c86e406d534a67ddf7fac3908eecf3584 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Wed, 29 Mar 2023 11:00:41 -0700 Subject: [PATCH 07/20] Feedback --- evm/src/cpu/kernel/asm/core/create.asm | 4 +--- evm/src/cpu/kernel/asm/core/create_contract_account.asm | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/evm/src/cpu/kernel/asm/core/create.asm b/evm/src/cpu/kernel/asm/core/create.asm index 11e89aa4..00f6c5d0 100644 --- a/evm/src/cpu/kernel/asm/core/create.asm +++ b/evm/src/cpu/kernel/asm/core/create.asm @@ -7,9 +7,7 @@ global sys_create: // stack: kexit_info, value, code_offset, code_len // TODO: Charge gas. %stack (kexit_info, value, code_offset, code_len) - -> (value, code_offset, code_len, kexit_info) - PUSH sys_create_got_address - // stack: sys_create_got_address, value, code_offset, code_len, kexit_info + -> (sys_create_got_address, value, code_offset, code_len, kexit_info) %address // stack: sender, sys_create_got_address, value, code_offset, code_len, kexit_info DUP1 %nonce diff --git a/evm/src/cpu/kernel/asm/core/create_contract_account.asm b/evm/src/cpu/kernel/asm/core/create_contract_account.asm index 5ce12779..00a19272 100644 --- a/evm/src/cpu/kernel/asm/core/create_contract_account.asm +++ b/evm/src/cpu/kernel/asm/core/create_contract_account.asm @@ -5,7 +5,7 @@ // stack: value, address DUP2 %mpt_read_state_trie // stack: existing_account_ptr, value, address - // If the account doesn't exist, there's need to check its balance or nonce, + // If the account doesn't exist, there's no need to check its balance or nonce, // so we can skip ahead, setting existing_balance = existing_account_ptr = 0. DUP1 ISZERO %jumpi(%%do_insert) From 2d87c5d62772d7e019aad727fc90e2a9ba445ba4 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Wed, 29 Mar 2023 11:27:55 -0700 Subject: [PATCH 08/20] Remove `CONSUME_GAS` Now that gas info is in `kexit_info`. --- evm/src/cpu/kernel/asm/util/basic_macros.asm | 5 ----- evm/src/cpu/kernel/interpreter.rs | 2 -- evm/src/cpu/kernel/opcodes.rs | 1 - 3 files changed, 8 deletions(-) diff --git a/evm/src/cpu/kernel/asm/util/basic_macros.asm b/evm/src/cpu/kernel/asm/util/basic_macros.asm index 2ba6ad0b..f85b7792 100644 --- a/evm/src/cpu/kernel/asm/util/basic_macros.asm +++ b/evm/src/cpu/kernel/asm/util/basic_macros.asm @@ -160,11 +160,6 @@ // stack: input >= c, ... %endmacro -%macro consume_gas_const(c) - PUSH $c - CONSUME_GAS -%endmacro - // If pred is zero, yields z; otherwise, yields nz %macro select // stack: pred, nz, z diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 8347d896..fbd43247 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -385,7 +385,6 @@ impl<'a> Interpreter<'a> { 0xf5 => todo!(), // "CREATE2", 0xf6 => self.run_get_context(), // "GET_CONTEXT", 0xf7 => self.run_set_context(), // "SET_CONTEXT", - 0xf8 => todo!(), // "CONSUME_GAS", 0xf9 => todo!(), // "EXIT_KERNEL", 0xfa => todo!(), // "STATICCALL", 0xfb => self.run_mload_general(), // "MLOAD_GENERAL", @@ -966,7 +965,6 @@ fn get_mnemonic(opcode: u8) -> &'static str { 0xf5 => "CREATE2", 0xf6 => "GET_CONTEXT", 0xf7 => "SET_CONTEXT", - 0xf8 => "CONSUME_GAS", 0xf9 => "EXIT_KERNEL", 0xfa => "STATICCALL", 0xfb => "MLOAD_GENERAL", diff --git a/evm/src/cpu/kernel/opcodes.rs b/evm/src/cpu/kernel/opcodes.rs index 112de792..be17f6f4 100644 --- a/evm/src/cpu/kernel/opcodes.rs +++ b/evm/src/cpu/kernel/opcodes.rs @@ -122,7 +122,6 @@ pub fn get_opcode(mnemonic: &str) -> u8 { "CREATE2" => 0xf5, "GET_CONTEXT" => 0xf6, "SET_CONTEXT" => 0xf7, - "CONSUME_GAS" => 0xf8, "EXIT_KERNEL" => 0xf9, "STATICCALL" => 0xfa, "MLOAD_GENERAL" => 0xfb, From 9480cbed99a13117faec580fdd29cab7c0379ba9 Mon Sep 17 00:00:00 2001 From: Hamish Ivey-Law <426294+unzvfu@users.noreply.github.com> Date: Thu, 30 Mar 2023 05:56:01 +1100 Subject: [PATCH 09/20] Signed operations as syscalls (#933) * Implement syscalls for BYTE, SIGNEXTEND, SAR, SLT and SGT. * Implement SDIV and SMOD; minor documentation and tidying. * Implement EXP. * Add sys_byte to the syscall jumptable. * Test suite for signed syscalls. * Handle `EXIT_KERNEL` "properly". * Add gas charges; rename label. * Uppercase all opcodes. * Add test for BYTE; fix bug in BYTE. * Calculate and charge gas for calling `EXP`. * Fix gas calculation for `exponent = 0`. * Address Jacqui's comments. * Remove BYTE syscall as it will be implemented natively. * Oops, forgot to remove this bit. --- evm/src/cpu/kernel/aggregator.rs | 1 + evm/src/cpu/kernel/asm/core/syscall_stubs.asm | 12 - evm/src/cpu/kernel/asm/exp.asm | 28 ++- evm/src/cpu/kernel/asm/signed.asm | 216 ++++++++++++++++++ evm/src/cpu/kernel/interpreter.rs | 6 +- evm/src/cpu/kernel/tests/mod.rs | 1 + evm/src/cpu/kernel/tests/signed_syscalls.rs | 166 ++++++++++++++ 7 files changed, 416 insertions(+), 14 deletions(-) create mode 100644 evm/src/cpu/kernel/asm/signed.asm create mode 100644 evm/src/cpu/kernel/tests/signed_syscalls.rs diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index 40189b80..0b7233e0 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -112,6 +112,7 @@ pub(crate) fn combined_kernel() -> Kernel { include_str!("asm/rlp/num_bytes.asm"), include_str!("asm/rlp/read_to_memory.asm"), include_str!("asm/shift.asm"), + include_str!("asm/signed.asm"), include_str!("asm/transactions/common_decoding.asm"), include_str!("asm/transactions/router.asm"), include_str!("asm/transactions/type_0.asm"), diff --git a/evm/src/cpu/kernel/asm/core/syscall_stubs.asm b/evm/src/cpu/kernel/asm/core/syscall_stubs.asm index f94bcad4..95b50b0b 100644 --- a/evm/src/cpu/kernel/asm/core/syscall_stubs.asm +++ b/evm/src/cpu/kernel/asm/core/syscall_stubs.asm @@ -1,18 +1,6 @@ // Labels for unimplemented syscalls to make the kernel assemble. // Each label should be removed from this file once it is implemented. -global sys_sdiv: - PANIC -global sys_smod: - PANIC -global sys_signextend: - PANIC -global sys_slt: - PANIC -global sys_sgt: - PANIC -global sys_sar: - PANIC global sys_blockhash: PANIC global sys_prevrandao: diff --git a/evm/src/cpu/kernel/asm/exp.asm b/evm/src/cpu/kernel/asm/exp.asm index 0aa40048..a2f34b13 100644 --- a/evm/src/cpu/kernel/asm/exp.asm +++ b/evm/src/cpu/kernel/asm/exp.asm @@ -73,4 +73,30 @@ recursion_return: jump global sys_exp: - PANIC // TODO: Implement. + // stack: x, e, return_info + push 0 + // stack: shift, x, e, return_info + %jump(sys_exp_gas_loop_enter) +sys_exp_gas_loop: + %add_const(8) +sys_exp_gas_loop_enter: + dup3 + dup2 + shr + // stack: e >> shift, shift, x, e, return_info + %jumpi(sys_exp_gas_loop) + // stack: shift_bits, x, e, return_info + %div_const(8) + // stack: byte_size_of_e := shift_bits / 8, x, e, return_info + %mul_const(@GAS_EXPBYTE) + %add_const(@GAS_EXP) + // stack: gas_cost := 10 + 50 * byte_size_of_e, x, e, return_info + %stack(gas_cost, x, e, return_info) -> (gas_cost, return_info, x, e) + %charge_gas + + %stack(return_info, x, e) -> (x, e, sys_exp_return, return_info) + jump exp +sys_exp_return: + // stack: pow(x, e), return_info + swap1 + exit_kernel diff --git a/evm/src/cpu/kernel/asm/signed.asm b/evm/src/cpu/kernel/asm/signed.asm new file mode 100644 index 00000000..7dd9c482 --- /dev/null +++ b/evm/src/cpu/kernel/asm/signed.asm @@ -0,0 +1,216 @@ +// SDIV(a, b): signed division operation. +// +// If b = 0, then SDIV(a, b) = 0, +// else if a = -2^255 and b = -1, then SDIV(a, b) = -2^255 +// else SDIV(a, b) = sgn(a/b) * floor(|a/b|). +global _sys_sdiv: + // stack: num, denom, return_info + DUP1 + PUSH 0x8000000000000000000000000000000000000000000000000000000000000000 + GT + // stack: num_is_nonneg := sign_bit > num, num, denom, return_info + DUP1 + %jumpi(sys_sdiv_nonneg_num) + // stack: num_is_nonneg, num, denom, return_info + SWAP1 + PUSH 0 + SUB + SWAP1 + // stack: num_is_nonneg, num := -num, denom, return_info +sys_sdiv_nonneg_num: + SWAP2 + DUP1 + PUSH 0x8000000000000000000000000000000000000000000000000000000000000000 + GT + // stack: denom_is_nonneg := sign_bit > denom, denom, num, num_is_nonneg, return_info + DUP1 + %jumpi(sys_sdiv_nonneg_denom) + // stack: denom_is_nonneg, denom, num, num_is_nonneg, return_info + SWAP1 + PUSH 0 + SUB + // stack: denom := -denom, denom_is_nonneg, num, num_is_nonneg, return_info + SWAP1 +sys_sdiv_nonneg_denom: + // stack: denom_is_nonneg, denom, num, num_is_nonneg, return_info + SWAP2 + DIV + // stack: num / denom, denom_is_nonneg, num_is_nonneg, return_info + SWAP2 + EQ + // stack: denom_is_nonneg == num_is_nonneg, num / denom, return_info + %jumpi(sys_sdiv_same_sign) + PUSH 0 + SUB +sys_sdiv_same_sign: + SWAP1 + JUMP + + +// SMOD(a, b): signed "modulo remainder" operation. +// +// If b != 0, then SMOD(a, b) = sgn(a) * MOD(|a|, |b|), +// else SMOD(a, 0) = 0. +global _sys_smod: + // stack: x, mod, return_info + PUSH 0x8000000000000000000000000000000000000000000000000000000000000000 + // stack: sign_bit, x, mod, return_info + DUP1 + DUP4 + LT + // stack: mod < sign_bit, sign_bit, x, mod, return_info + %jumpi(sys_smod_pos_mod) + // mod is negative, so we negate it + // sign_bit, x, mod, return_info + SWAP2 + PUSH 0 + SUB + SWAP2 + // sign_bit, x, mod := 0 - mod, return_info +sys_smod_pos_mod: + // At this point, we know that mod is non-negative. + DUP2 + LT + // stack: x < sign_bit, x, mod, return_info + %jumpi(sys_smod_pos_x) + // x is negative, so let's negate it + // stack: x, mod, return_info + PUSH 0 + SUB + // stack: x := 0 - x, mod, return_info + MOD + // negate the result + PUSH 0 + SUB + SWAP1 + JUMP +sys_smod_pos_x: + // Both x and mod are non-negative + // stack: x, mod, return_info + MOD + SWAP1 + JUMP + + +// SIGNEXTEND from the Nth byte of value, where the bytes of value are +// considered in LITTLE-endian order. Just a SHL followed by a SAR. +global _sys_signextend: + // Stack: N, value, return_info + // Handle N >= 31, which is a no-op. + PUSH 31 + %min + // Stack: min(31, N), value, return_info + %increment + %mul_const(8) + // Stack: 8*(N + 1), value, return_info + PUSH 256 + SUB + // Stack: 256 - 8*(N + 1), value, return_info + %stack(bits, value, return_info) -> (bits, value, bits, return_info) + SHL + SWAP1 + // Stack: bits, value << bits, return_info + // fall through to sys_sar + + +// SAR, i.e. shift arithmetic right, shifts `value` `shift` bits to +// the right, preserving sign by filling with the most significant bit. +// +// Trick: x >>s i = (x + sign_bit >>u i) - (sign_bit >>u i), +// where >>s is arithmetic shift and >>u is logical shift. +// Reference: Hacker's Delight, 2013, 2nd edition, §2-7. +global _sys_sar: + // SAR(shift, value) is the same for all shift >= 255, so we + // replace shift with min(shift, 255) + + // Stack: shift, value, return_info + PUSH 255 + %min + // Stack: min(shift, 255), value, return_info + + // Now assume shift < 256. + // Stack: shift, value, return_info + PUSH 0x8000000000000000000000000000000000000000000000000000000000000000 + DUP2 + SHR + // Stack: 2^255 >> shift, shift, value, return_info + SWAP2 + %add_const(0x8000000000000000000000000000000000000000000000000000000000000000) + // Stack: 2^255 + value, shift, 2^255 >> shift, return_info + SWAP1 + SHR + SUB + // Stack: ((2^255 + value) >> shift) - (2^255 >> shift), return_info + SWAP1 + JUMP + + +// SGT, i.e. signed greater than, returns 1 if lhs > rhs as signed +// integers, 0 otherwise. +// +// Just swap argument order and fall through to signed less than. +global _sys_sgt: + SWAP1 + + +// SLT, i.e. signed less than, returns 1 if lhs < rhs as signed +// integers, 0 otherwise. +// +// Trick: x (_sys_sdiv, x, y, _syscall_return, kernel_return) + JUMP + +global sys_smod: + %charge_gas_const(@GAS_LOW) + %stack(x, y, kernel_return) -> (_sys_smod, x, y, _syscall_return, kernel_return) + JUMP + +global sys_signextend: + %charge_gas_const(@GAS_LOW) + %stack(x, y, kernel_return) -> (_sys_signextend, x, y, _syscall_return, kernel_return) + JUMP + +global sys_sar: + %charge_gas_const(@GAS_VERYLOW) + %stack(x, y, kernel_return) -> (_sys_sar, x, y, _syscall_return, kernel_return) + JUMP + +global sys_slt: + %charge_gas_const(@GAS_VERYLOW) + %stack(x, y, kernel_return) -> (_sys_slt, x, y, _syscall_return, kernel_return) + JUMP + +global sys_sgt: + %charge_gas_const(@GAS_VERYLOW) + %stack(x, y, kernel_return) -> (_sys_sgt, x, y, _syscall_return, kernel_return) + JUMP + +_syscall_return: + SWAP1 + EXIT_KERNEL diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 8347d896..f48e6a8c 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -558,7 +558,11 @@ impl<'a> Interpreter<'a> { fn run_shl(&mut self) { let shift = self.pop(); let value = self.pop(); - self.push(value << shift); + self.push(if shift < U256::from(256usize) { + value << shift + } else { + U256::zero() + }); } fn run_shr(&mut self) { diff --git a/evm/src/cpu/kernel/tests/mod.rs b/evm/src/cpu/kernel/tests/mod.rs index 68695e2f..83ded791 100644 --- a/evm/src/cpu/kernel/tests/mod.rs +++ b/evm/src/cpu/kernel/tests/mod.rs @@ -10,6 +10,7 @@ mod hash; mod mpt; mod packing; mod rlp; +mod signed_syscalls; mod transaction_parsing; use std::str::FromStr; diff --git a/evm/src/cpu/kernel/tests/signed_syscalls.rs b/evm/src/cpu/kernel/tests/signed_syscalls.rs new file mode 100644 index 00000000..728d5565 --- /dev/null +++ b/evm/src/cpu/kernel/tests/signed_syscalls.rs @@ -0,0 +1,166 @@ +use ethereum_types::U256; + +use crate::cpu::kernel::aggregator::KERNEL; +use crate::cpu::kernel::interpreter::Interpreter; + +/// Generate a list of inputs suitable for testing the signed operations +/// +/// The result includes 0, ±1, ±2^(16i ± 1) for i = 0..15, and ±2^255 +/// and then each of those ±1. Little attempt has been made to avoid +/// duplicates. Total length is 279. +fn test_inputs() -> Vec { + let mut res = vec![U256::zero()]; + for i in 1..16 { + res.push(U256::one() << (16 * i)); + res.push(U256::one() << (16 * i + 1)); + res.push(U256::one() << (16 * i - 1)); + } + res.push(U256::one() << 255); + + let n = res.len(); + for i in 1..n { + // push -res[i] + res.push(res[i].overflowing_neg().0); + } + + let n = res.len(); + for i in 0..n { + res.push(res[i].overflowing_add(U256::one()).0); + res.push(res[i].overflowing_sub(U256::one()).0); + } + + res +} + +// U256_TOP_BIT == 2^255. +const U256_TOP_BIT: U256 = U256([0x0, 0x0, 0x0, 0x8000000000000000]); + +/// Given a U256 `value`, interpret as a signed 256-bit number and +/// return the arithmetic right shift of `value` by `shift` bit +/// positions, i.e. the right shift of `value` with sign extension. +fn u256_sar(shift: U256, value: U256) -> U256 { + // Reference: Hacker's Delight, 2013, 2nd edition, §2-7. + let shift = shift.min(U256::from(255)); + ((value ^ U256_TOP_BIT) >> shift) + .overflowing_sub(U256_TOP_BIT >> shift) + .0 +} + +/// Given a U256 x, interpret it as a signed 256-bit number and return +/// the pair abs(x) and sign(x), where sign(x) = 1 if x < 0, and 0 +/// otherwise. NB: abs(x) is interpreted as an unsigned value, so +/// u256_abs_sgn(-2^255) = (2^255, -1). +fn u256_abs_sgn(x: U256) -> (U256, bool) { + let is_neg = x.bit(255); + + // negate x if it's negative + let x = if is_neg { x.overflowing_neg().0 } else { x }; + (x, is_neg) +} + +fn u256_sdiv(x: U256, y: U256) -> U256 { + let (abs_x, x_is_neg) = u256_abs_sgn(x); + let (abs_y, y_is_neg) = u256_abs_sgn(y); + if y.is_zero() { + U256::zero() + } else { + let quot = abs_x / abs_y; + // negate the quotient if arguments had opposite signs + if x_is_neg != y_is_neg { + quot.overflowing_neg().0 + } else { + quot + } + } +} + +fn u256_smod(x: U256, y: U256) -> U256 { + let (abs_x, x_is_neg) = u256_abs_sgn(x); + let (abs_y, _) = u256_abs_sgn(y); + + if y.is_zero() { + U256::zero() + } else { + let rem = abs_x % abs_y; + // negate the remainder if dividend was negative + if x_is_neg { + rem.overflowing_neg().0 + } else { + rem + } + } +} + +// signextend is just a SHL followed by SAR. +fn u256_signextend(byte: U256, value: U256) -> U256 { + // byte = min(31, byte) + let byte: u32 = byte.min(U256::from(31)).try_into().unwrap(); + let bit_offset = 256 - 8 * (byte + 1); + u256_sar(U256::from(bit_offset), value << bit_offset) +} + +// Reference: Hacker's Delight, 2013, 2nd edition, §2-12. +fn u256_slt(x: U256, y: U256) -> U256 { + let top_bit: U256 = U256::one() << 255; + U256::from(((x ^ top_bit) < (y ^ top_bit)) as u32) +} + +fn u256_sgt(x: U256, y: U256) -> U256 { + u256_slt(y, x) +} + +fn run_test(fn_label: &str, expected_fn: fn(U256, U256) -> U256, opname: &str) { + let inputs = test_inputs(); + let fn_label = KERNEL.global_labels[fn_label]; + let retdest = U256::from(0xDEADBEEFu32); + + for &x in &inputs { + for &y in &inputs { + let stack = vec![retdest, y, x]; + let mut interpreter = Interpreter::new_with_kernel(fn_label, stack); + interpreter.run().unwrap(); + assert_eq!(interpreter.stack().len(), 1usize, "unexpected stack size"); + let output = interpreter.stack()[0]; + let expected_output = expected_fn(x, y); + assert_eq!( + output, expected_output, + "{opname}({x}, {y}): expected {expected_output} but got {output}" + ); + } + } +} + +#[test] +fn test_sdiv() { + // Double-check that the expected output calculation is correct in the special case. + let x = U256::one() << 255; // -2^255 + let y = U256::one().overflowing_neg().0; // -1 + assert_eq!(u256_sdiv(x, y), x); // SDIV(-2^255, -1) = -2^255. + + run_test("_sys_sdiv", u256_sdiv, "SDIV"); +} + +#[test] +fn test_smod() { + run_test("_sys_smod", u256_smod, "SMOD"); +} + +#[test] +fn test_signextend() { + run_test("_sys_signextend", u256_signextend, "SIGNEXTEND"); +} + +#[test] +fn test_sar() { + run_test("_sys_sar", u256_sar, "SAR"); +} + +#[test] +fn test_slt() { + run_test("_sys_slt", u256_slt, "SLT"); +} + +#[test] +fn test_sgt() { + run_test("_sys_sgt", u256_sgt, "SGT"); +} From 56bf08921bb94883d12af90e5bc570752e397d78 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 30 Mar 2023 06:46:26 +0200 Subject: [PATCH 10/20] Charge gas for extcodecopy (#942) * Charge gas for extcodecopy * Check for size=0 --- evm/src/cpu/kernel/asm/account_code.asm | 33 ++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/evm/src/cpu/kernel/asm/account_code.asm b/evm/src/cpu/kernel/asm/account_code.asm index 8cbc3221..d69adc25 100644 --- a/evm/src/cpu/kernel/asm/account_code.asm +++ b/evm/src/cpu/kernel/asm/account_code.asm @@ -86,15 +86,42 @@ global extcodesize: // Pre stack: kexit_info, address, dest_offset, offset, size // Post stack: (empty) global sys_extcodecopy: - // TODO: Call %update_mem_bytes to expand memory. - // TODO: Charge other gas. %stack (kexit_info, address, dest_offset, offset, size) -> (address, dest_offset, offset, size, kexit_info) - %u256_to_addr DUP1 %insert_accessed_addresses POP // TODO: Use return value in gas calculation. + %u256_to_addr DUP1 %insert_accessed_addresses + // stack: cold_access, address, dest_offset, offset, size, kexit_info + PUSH @GAS_COLDACCOUNTACCESS_MINUS_WARMACCESS + MUL + PUSH @GAS_WARMACCESS + ADD + // stack: Gaccess, address, dest_offset, offset, size, kexit_info + + DUP5 + // stack: size, Gaccess, address, dest_offset, offset, size, kexit_info + ISZERO %jumpi(sys_extcodecopy_empty) + + // stack: Gaccess, address, dest_offset, offset, size, kexit_info + DUP5 %num_bytes_to_num_words %mul_const(@GAS_COPY) ADD + %stack (gas, address, dest_offset, offset, size, kexit_info) -> (gas, kexit_info, address, dest_offset, offset, size) + %charge_gas + + %stack (kexit_info, address, dest_offset, offset, size) -> (dest_offset, size, kexit_info, address, dest_offset, offset, size) + ADD // TODO: check for overflow, see discussion here https://github.com/mir-protocol/plonky2/pull/930/files/a4ea0965d79561c345e2f77836c07949c7e0bc69#r1143630253 + // stack: expanded_num_bytes, kexit_info, address, dest_offset, offset, size + DUP1 %ensure_reasonable_offset + %update_mem_bytes + + %stack (kexit_info, address, dest_offset, offset, size) -> (address, dest_offset, offset, size, kexit_info) %extcodecopy // stack: kexit_info EXIT_KERNEL +sys_extcodecopy_empty: + %stack (Gaccess, address, dest_offset, offset, size, kexit_info) -> (Gaccess, kexit_info) + %charge_gas + EXIT_KERNEL + + // Pre stack: address, dest_offset, offset, size, retdest // Post stack: (empty) global extcodecopy: From 9ae69a7c21660cfec7e073f65a8a59ee5d4e05a0 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Thu, 30 Mar 2023 16:09:34 -0700 Subject: [PATCH 11/20] Add an integration test for the `selfBalanceGasCost` case --- evm/tests/add11_yml.rs | 2 +- evm/tests/self_balance_gas_cost.rs | 141 +++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 evm/tests/self_balance_gas_cost.rs diff --git a/evm/tests/add11_yml.rs b/evm/tests/add11_yml.rs index b4c9b179..e9ba979f 100644 --- a/evm/tests/add11_yml.rs +++ b/evm/tests/add11_yml.rs @@ -23,7 +23,7 @@ type F = GoldilocksField; const D: usize = 2; type C = PoseidonGoldilocksConfig; -/// Test a simple token transfer to a new address. +/// The `add11_yml` test case from https://github.com/ethereum/tests #[test] fn add11_yml() -> anyhow::Result<()> { init_logger(); diff --git a/evm/tests/self_balance_gas_cost.rs b/evm/tests/self_balance_gas_cost.rs new file mode 100644 index 00000000..8546cc41 --- /dev/null +++ b/evm/tests/self_balance_gas_cost.rs @@ -0,0 +1,141 @@ +use std::collections::HashMap; +use std::str::FromStr; +use std::time::Duration; + +use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; +use eth_trie_utils::nibbles::Nibbles; +use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; +use ethereum_types::Address; +use hex_literal::hex; +use keccak_hash::keccak; +use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::plonk::config::PoseidonGoldilocksConfig; +use plonky2::util::timing::TimingTree; +use plonky2_evm::all_stark::AllStark; +use plonky2_evm::config::StarkConfig; +use plonky2_evm::generation::mpt::AccountRlp; +use plonky2_evm::generation::{GenerationInputs, TrieInputs}; +use plonky2_evm::proof::BlockMetadata; +use plonky2_evm::prover::prove; +use plonky2_evm::verifier::verify_proof; +use plonky2_evm::Node; + +type F = GoldilocksField; +const D: usize = 2; +type C = PoseidonGoldilocksConfig; + +/// The `selfBalanceGasCost` test case from https://github.com/ethereum/tests +#[test] +fn self_balance_gas_cost() -> anyhow::Result<()> { + init_logger(); + + let all_stark = AllStark::::default(); + let config = StarkConfig::standard_fast_config(); + + let beneficiary = hex!("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"); + let sender = hex!("a94f5374fce5edbc8e2a8697c15331677e6ebf0b"); + let to = hex!("1000000000000000000000000000000000000000"); + + let beneficiary_state_key = keccak(beneficiary); + let sender_state_key = keccak(sender); + let to_state_key = keccak(to); + + let beneficiary_nibbles = Nibbles::from_bytes_be(beneficiary_state_key.as_bytes()).unwrap(); + let sender_nibbles = Nibbles::from_bytes_be(sender_state_key.as_bytes()).unwrap(); + let to_nibbles = Nibbles::from_bytes_be(to_state_key.as_bytes()).unwrap(); + + let code = [ + 0x5a, 0x47, 0x5a, 0x90, 0x50, 0x90, 0x03, 0x60, 0x02, 0x90, 0x03, 0x60, 0x01, 0x55, 0x00, + ]; + let code_hash = keccak(code); + + let beneficiary_account_before = AccountRlp::default(); + let sender_account_before = AccountRlp { + balance: 0x3635c9adc5dea00000u128.into(), + ..AccountRlp::default() + }; + let to_account_before = AccountRlp { + code_hash, + ..AccountRlp::default() + }; + + let mut state_trie_before = HashedPartialTrie::from(Node::Empty); + state_trie_before.insert( + beneficiary_nibbles, + rlp::encode(&beneficiary_account_before).to_vec(), + ); + state_trie_before.insert(sender_nibbles, rlp::encode(&sender_account_before).to_vec()); + state_trie_before.insert(to_nibbles, rlp::encode(&to_account_before).to_vec()); + + let tries_before = TrieInputs { + state_trie: state_trie_before, + transactions_trie: Node::Empty.into(), + receipts_trie: Node::Empty.into(), + storage_tries: vec![(Address::from_slice(&to), Node::Empty.into())], + }; + + let txn = hex!("f861800a8405f5e10094100000000000000000000000000000000000000080801ba07e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37a05f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509b"); + + let block_metadata = BlockMetadata { + block_beneficiary: Address::from(beneficiary), + block_base_fee: 0xa.into(), + ..BlockMetadata::default() + }; + + let mut contract_code = HashMap::new(); + contract_code.insert(keccak(vec![]), vec![]); + contract_code.insert(code_hash, code.to_vec()); + + let inputs = GenerationInputs { + signed_txns: vec![txn.to_vec()], + tries: tries_before, + contract_code, + block_metadata, + addresses: vec![], + }; + + let mut timing = TimingTree::new("prove", log::Level::Debug); + let proof = prove::(&all_stark, &config, inputs, &mut timing)?; + timing.filter(Duration::from_millis(100)).print(); + + let beneficiary_account_after = AccountRlp::default(); + let sender_account_after = AccountRlp { + balance: 999999999999999568680u128.into(), + nonce: 1.into(), + ..AccountRlp::default() + }; + let to_account_after = AccountRlp { + code_hash, + // Storage map: { 1 => 5 } + storage_root: HashedPartialTrie::from(Node::Leaf { + // TODO: Could do keccak(pad32(1)) + nibbles: Nibbles::from_str( + "0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6", + ) + .unwrap(), + value: vec![5], + }) + .hash(), + ..AccountRlp::default() + }; + + let mut expected_state_trie_after = HashedPartialTrie::from(Node::Empty); + expected_state_trie_after.insert( + beneficiary_nibbles, + rlp::encode(&beneficiary_account_after).to_vec(), + ); + expected_state_trie_after.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec()); + expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec()); + + dbg!(&proof.public_values.trie_roots_after.state_root); + assert_eq!( + proof.public_values.trie_roots_after.state_root, + expected_state_trie_after.hash() + ); + + verify_proof(&all_stark, proof, &config) +} + +fn init_logger() { + let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "info")); +} From 31cd0f6445e8c5704d4e4907ed41267eb91a21dc Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Thu, 30 Mar 2023 17:24:12 -0700 Subject: [PATCH 12/20] Remove dbg --- evm/tests/self_balance_gas_cost.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/evm/tests/self_balance_gas_cost.rs b/evm/tests/self_balance_gas_cost.rs index 8546cc41..d38c066b 100644 --- a/evm/tests/self_balance_gas_cost.rs +++ b/evm/tests/self_balance_gas_cost.rs @@ -127,7 +127,6 @@ fn self_balance_gas_cost() -> anyhow::Result<()> { expected_state_trie_after.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec()); expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec()); - dbg!(&proof.public_values.trie_roots_after.state_root); assert_eq!( proof.public_values.trie_roots_after.state_root, expected_state_trie_after.hash() From 2ca00a9ad4ea6ec1656da5183dad58b53e8f8380 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 31 Mar 2023 11:13:36 +0200 Subject: [PATCH 13/20] Selfdestruct gas and set (#947) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add new segment and global metadata * Insert into self-destruct set * Implement sys_selfdestruct * PR feedback * Fix stack underflow * Forgot that NOT 1 ≠ 0. Added %not_bit macro for that. --- evm/src/cpu/kernel/aggregator.rs | 1 + .../cpu/kernel/asm/core/selfdestruct_set.asm | 43 ++++++++++++++ evm/src/cpu/kernel/asm/core/terminate.asm | 57 ++++++++++++++++--- evm/src/cpu/kernel/asm/core/transfer.asm | 7 ++- evm/src/cpu/kernel/asm/core/util.asm | 40 +++++++++++++ evm/src/cpu/kernel/asm/util/basic_macros.asm | 8 +++ .../cpu/kernel/constants/global_metadata.rs | 6 +- evm/src/memory/segments.rs | 7 ++- 8 files changed, 159 insertions(+), 10 deletions(-) create mode 100644 evm/src/cpu/kernel/asm/core/selfdestruct_set.asm diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index 0b7233e0..79d22f87 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -37,6 +37,7 @@ pub(crate) fn combined_kernel() -> Kernel { include_str!("asm/core/transfer.asm"), include_str!("asm/core/util.asm"), include_str!("asm/core/access_lists.asm"), + include_str!("asm/core/selfdestruct_set.asm"), include_str!("asm/curve/bls381/util.asm"), include_str!("asm/curve/bn254/curve_arithmetic/constants.asm"), include_str!("asm/curve/bn254/curve_arithmetic/curve_add.asm"), diff --git a/evm/src/cpu/kernel/asm/core/selfdestruct_set.asm b/evm/src/cpu/kernel/asm/core/selfdestruct_set.asm new file mode 100644 index 00000000..ad62c6f1 --- /dev/null +++ b/evm/src/cpu/kernel/asm/core/selfdestruct_set.asm @@ -0,0 +1,43 @@ +/// Self-destruct set. +/// Essentially the same code as in `access_lists.asm`, with the exception that the insert function doesn't return anything. +/// TODO: Would it make sense to merge this with `access_lists.asm`? +/// TODO: Look into using a more efficient data structure. + +%macro insert_selfdestruct_set + %stack (addr) -> (addr, %%after) + %jump(insert_selfdestruct_set) +%%after: + // stack: (empty) +%endmacro + +/// Inserts the address into the self-destruct set if it is not already present. +global insert_selfdestruct_set: + // stack: addr, retdest + %mload_global_metadata(@GLOBAL_METADATA_SELFDESTRUCT_SET_LEN) + // stack: len, addr, retdest + PUSH 0 +insert_selfdestruct_set_loop: + %stack (i, len, addr, retdest) -> (i, len, i, len, addr, retdest) + EQ %jumpi(insert_address) + // stack: i, len, addr, retdest + DUP1 %mload_kernel(@SEGMENT_SELFDESTRUCT_SET) + // stack: loaded_addr, i, len, addr, retdest + DUP4 + // stack: addr, loaded_addr, i, len, addr, retdest + EQ %jumpi(insert_address_found) + // stack: i, len, addr, retdest + %increment + %jump(insert_selfdestruct_set_loop) + +insert_address: + %stack (i, len, addr, retdest) -> (i, addr, len, retdest) + %mstore_kernel(@SEGMENT_SELFDESTRUCT_SET) // Store new address at the end of the array. + // stack: len, retdest + %increment + %mstore_global_metadata(@GLOBAL_METADATA_SELFDESTRUCT_SET_LEN) // Store new length. + JUMP + +insert_address_found: + // stack: i, len, addr, retdest + %pop3 + JUMP diff --git a/evm/src/cpu/kernel/asm/core/terminate.asm b/evm/src/cpu/kernel/asm/core/terminate.asm index e9508bd7..27758e6a 100644 --- a/evm/src/cpu/kernel/asm/core/terminate.asm +++ b/evm/src/cpu/kernel/asm/core/terminate.asm @@ -22,17 +22,60 @@ global sys_return: %jump(terminate_common) global sys_selfdestruct: - // stack: kexit_info, address + // stack: kexit_info, recipient SWAP1 %u256_to_addr - DUP1 %insert_accessed_addresses_no_return // TODO: Use return value in gas calculation. - // stack: address, kexit_info - POP // TODO: Transfer balance to address. + %address DUP1 %balance + + // Insert recipient into the accessed addresses list. + // stack: balance, address, recipient, kexit_info + DUP3 %insert_accessed_addresses + + // Compute gas. + // stack: cold_access, balance, address, recipient, kexit_info + %mul_const(@GAS_COLDACCOUNTACCESS) + DUP2 + // stack: balance, gas_coldaccess, balance, address, recipient, kexit_info + ISZERO %not_bit + // stack: balance!=0, gas_coldaccess, balance, address, recipient, kexit_info + DUP5 %is_dead MUL %mul_const(@GAS_NEWACCOUNT) + // stack: gas_newaccount, gas_coldaccess, balance, address, recipient, kexit_info + ADD %add_const(@GAS_SELFDESTRUCT) + %stack (gas, balance, address, recipient, kexit_info) -> (gas, kexit_info, balance, address, recipient) + %charge_gas + %stack (kexit_info, balance, address, recipient) -> (balance, address, recipient, kexit_info) + + // Insert address into the selfdestruct set. + // stack: balance, address, recipient, kexit_info + DUP2 %insert_selfdestruct_set + + // Set the balance of the address to 0. + // stack: balance, address, recipient, kexit_info + PUSH 0 + // stack: 0, balance, address, recipient, kexit_info + DUP3 %mpt_read_state_trie + // stack: account_ptr, 0, balance, address, recipient, kexit_info + %add_const(1) + // stack: balance_ptr, 0, balance, address, recipient, kexit_info + %mstore_trie_data // TODO: This should be a copy-on-write operation. + + // If the recipient is the same as the address, then we're done. + // Otherwise, send the balance to the recipient. + %stack (balance, address, recipient, kexit_info) -> (address, recipient, recipient, balance, kexit_info) + EQ %jumpi(sys_selfdestruct_same_addr) + // stack: recipient, balance, kexit_info + %add_eth + // stack: kexit_info - // TODO: Add address to the access list. - %charge_gas_const(@GAS_SELFDESTRUCT) %leftover_gas // stack: leftover_gas - // TODO: Destroy account. + PUSH 1 // success + %jump(terminate_common) + +sys_selfdestruct_same_addr: + // stack: recipient, balance, kexit_info + %pop2 + %leftover_gas + // stack: leftover_gas PUSH 1 // success %jump(terminate_common) diff --git a/evm/src/cpu/kernel/asm/core/transfer.asm b/evm/src/cpu/kernel/asm/core/transfer.asm index c001e726..9ab71627 100644 --- a/evm/src/cpu/kernel/asm/core/transfer.asm +++ b/evm/src/cpu/kernel/asm/core/transfer.asm @@ -81,9 +81,10 @@ global add_eth: // stack: retdest JUMP global add_eth_new_account: - // TODO: Skip creation if amount == 0? // stack: null_account_ptr, addr, amount, retdest POP + // stack: addr, amount, retdest + DUP2 ISZERO %jumpi(add_eth_new_account_zero) %get_trie_data_size // pointer to new account we're about to create // stack: new_account_ptr, addr, amount, retdest SWAP2 @@ -98,6 +99,10 @@ global add_eth_new_account: // stack: key, new_account_ptr, retdest %jump(mpt_insert_state_trie) +add_eth_new_account_zero: + // stack: addr, amount, retdest + %pop2 JUMP + // Convenience macro to call add_eth and return where we left off. %macro add_eth %stack (addr, amount) -> (addr, amount, %%after) diff --git a/evm/src/cpu/kernel/asm/core/util.asm b/evm/src/cpu/kernel/asm/core/util.asm index dfacf1a2..a183b120 100644 --- a/evm/src/cpu/kernel/asm/core/util.asm +++ b/evm/src/cpu/kernel/asm/core/util.asm @@ -30,3 +30,43 @@ // If there is no "to" field, then this is a contract creation. // stack: to == 0 %endmacro + +// Returns 1 if the account is non-existent, 0 otherwise. +%macro is_non_existent + // stack: addr + %mpt_read_state_trie + ISZERO +%endmacro + +// Returns 1 if the account is empty, 0 otherwise. +%macro is_empty + // stack: addr + %mpt_read_state_trie + // stack: account_ptr + DUP1 ISZERO %jumpi(%%false) + // stack: account_ptr + DUP1 %mload_trie_data + // stack: nonce, account_ptr + ISZERO %not_bit %jumpi(%%false) + %increment DUP1 %mload_trie_data + // stack: balance, balance_ptr + ISZERO %not_bit %jumpi(%%false) + %add_const(2) %mload_trie_data + // stack: code_hash + PUSH @EMPTY_STRING_HASH + EQ + %jump(%%after) +%%false: + // stack: account_ptr + POP + PUSH 0 +%%after: +%endmacro + +// Returns 1 if the account is dead (i.e., empty or non-existent), 0 otherwise. +%macro is_dead + // stack: addr + DUP1 %is_non_existent + SWAP1 %is_empty + ADD // OR +%endmacro \ No newline at end of file diff --git a/evm/src/cpu/kernel/asm/util/basic_macros.asm b/evm/src/cpu/kernel/asm/util/basic_macros.asm index f85b7792..0edd0367 100644 --- a/evm/src/cpu/kernel/asm/util/basic_macros.asm +++ b/evm/src/cpu/kernel/asm/util/basic_macros.asm @@ -345,3 +345,11 @@ // stack: x %mod_const(0x10000000000000000000000000000000000000000) // 2^160 %endmacro + +%macro not_bit + // stack: b + PUSH 1 + // stack: 1, b + SUB + // stack: 1 - b +%endmacro diff --git a/evm/src/cpu/kernel/constants/global_metadata.rs b/evm/src/cpu/kernel/constants/global_metadata.rs index f04c06e1..a9e1a9fd 100644 --- a/evm/src/cpu/kernel/constants/global_metadata.rs +++ b/evm/src/cpu/kernel/constants/global_metadata.rs @@ -49,10 +49,12 @@ pub(crate) enum GlobalMetadata { AccessedAddressesLen = 23, /// Length of the storage keys access list. AccessedStorageKeysLen = 24, + /// Length of the self-destruct set. + SelfDestructSetLen = 25, } impl GlobalMetadata { - pub(crate) const COUNT: usize = 24; + pub(crate) const COUNT: usize = 25; pub(crate) fn all() -> [Self; Self::COUNT] { [ @@ -80,6 +82,7 @@ impl GlobalMetadata { Self::RefundCounter, Self::AccessedAddressesLen, Self::AccessedStorageKeysLen, + Self::SelfDestructSetLen, ] } @@ -110,6 +113,7 @@ impl GlobalMetadata { Self::RefundCounter => "GLOBAL_METADATA_REFUND_COUNTER", Self::AccessedAddressesLen => "GLOBAL_METADATA_ACCESSED_ADDRESSES_LEN", Self::AccessedStorageKeysLen => "GLOBAL_METADATA_ACCESSED_STORAGE_KEYS_LEN", + Self::SelfDestructSetLen => "GLOBAL_METADATA_SELFDESTRUCT_SET_LEN", } } } diff --git a/evm/src/memory/segments.rs b/evm/src/memory/segments.rs index 61c5a911..0b74550d 100644 --- a/evm/src/memory/segments.rs +++ b/evm/src/memory/segments.rs @@ -48,10 +48,12 @@ pub enum Segment { AccessedAddresses = 23, /// List of storage keys that have been accessed in the current transaction. AccessedStorageKeys = 24, + /// List of addresses that have called SELFDESTRUCT in the current transaction. + SelfDestructSet = 25, } impl Segment { - pub(crate) const COUNT: usize = 25; + pub(crate) const COUNT: usize = 26; pub(crate) fn all() -> [Self; Self::COUNT] { [ @@ -80,6 +82,7 @@ impl Segment { Self::BnPairing, Self::AccessedAddresses, Self::AccessedStorageKeys, + Self::SelfDestructSet, ] } @@ -111,6 +114,7 @@ impl Segment { Segment::BnPairing => "SEGMENT_KERNEL_BN_PAIRING", Segment::AccessedAddresses => "SEGMENT_ACCESSED_ADDRESSES", Segment::AccessedStorageKeys => "SEGMENT_ACCESSED_STORAGE_KEYS", + Segment::SelfDestructSet => "SEGMENT_SELFDESTRUCT_SET", } } @@ -142,6 +146,7 @@ impl Segment { Segment::BnPairing => 256, Segment::AccessedAddresses => 256, Segment::AccessedStorageKeys => 256, + Segment::SelfDestructSet => 256, } } } From e857c020bfe09c8489d805b09b3eae9c5151de1a Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Tue, 22 Nov 2022 08:48:48 -0500 Subject: [PATCH 14/20] Make hash functions generic --- evm/src/arithmetic/arithmetic_stark.rs | 20 +- evm/src/cpu/cpu_stark.rs | 12 +- evm/src/cross_table_lookup.rs | 14 +- evm/src/fixed_recursive_verifier.rs | 171 +++++++----- evm/src/get_challenges.rs | 57 +++- evm/src/keccak/keccak_stark.rs | 22 +- evm/src/keccak_sponge/keccak_sponge_stark.rs | 12 +- evm/src/lib.rs | 1 + evm/src/logic.rs | 12 +- evm/src/memory/memory_stark.rs | 12 +- evm/src/permutation.rs | 58 ++-- evm/src/proof.rs | 80 ++++-- evm/src/prover.rs | 92 ++++--- evm/src/recursive_verifier.rs | 132 ++++++---- evm/src/stark_testing.rs | 12 +- evm/src/verifier.rs | 35 ++- evm/tests/add11_yml.rs | 8 +- evm/tests/basic_smart_contract.rs | 8 +- evm/tests/empty_txn_list.rs | 10 +- evm/tests/simple_transfer.rs | 8 +- plonky2/benches/hashing.rs | 9 +- plonky2/benches/merkle.rs | 16 +- plonky2/examples/bench_recursion.rs | 84 ++++-- plonky2/examples/factorial.rs | 10 +- plonky2/examples/fibonacci.rs | 10 +- plonky2/examples/square_root.rs | 10 +- plonky2/src/fri/challenges.rs | 26 +- plonky2/src/fri/oracle.rs | 41 ++- plonky2/src/fri/proof.rs | 75 ++++-- plonky2/src/fri/prover.rs | 114 +++++--- plonky2/src/fri/recursive_verifier.rs | 33 ++- plonky2/src/fri/validate_shape.rs | 9 +- plonky2/src/fri/verifier.rs | 58 ++-- plonky2/src/fri/witness_util.rs | 8 +- plonky2/src/gadgets/arithmetic_extension.rs | 29 +- plonky2/src/gadgets/hash.rs | 16 +- plonky2/src/gadgets/interpolation.rs | 10 +- plonky2/src/gadgets/random_access.rs | 10 +- plonky2/src/gadgets/select.rs | 10 +- plonky2/src/gadgets/split_base.rs | 14 +- plonky2/src/gates/arithmetic_base.rs | 8 +- plonky2/src/gates/arithmetic_extension.rs | 8 +- plonky2/src/gates/base_sum.rs | 8 +- plonky2/src/gates/constant.rs | 8 +- plonky2/src/gates/coset_interpolation.rs | 16 +- plonky2/src/gates/exponentiation.rs | 14 +- plonky2/src/gates/gate_testing.rs | 15 +- plonky2/src/gates/multiplication_extension.rs | 8 +- plonky2/src/gates/noop.rs | 8 +- plonky2/src/gates/poseidon.rs | 20 +- plonky2/src/gates/poseidon_mds.rs | 15 +- plonky2/src/gates/public_input.rs | 8 +- plonky2/src/gates/random_access.rs | 14 +- plonky2/src/gates/reducing.rs | 8 +- plonky2/src/gates/reducing_extension.rs | 8 +- plonky2/src/hash/hashing.rs | 82 ++++-- plonky2/src/hash/keccak.rs | 18 +- plonky2/src/hash/merkle_proofs.rs | 71 +++-- plonky2/src/hash/merkle_tree.rs | 70 +++-- plonky2/src/hash/path_compression.rs | 27 +- plonky2/src/hash/poseidon.rs | 188 ++++++------- plonky2/src/iop/challenger.rs | 209 ++++++++++----- plonky2/src/iop/generator.rs | 7 +- plonky2/src/iop/witness.rs | 46 +++- plonky2/src/lib.rs | 2 + plonky2/src/plonk/circuit_builder.rs | 49 +++- plonky2/src/plonk/circuit_data.rs | 145 +++++++--- plonky2/src/plonk/config.rs | 58 ++-- plonky2/src/plonk/get_challenges.rs | 114 +++++--- plonky2/src/plonk/proof.rs | 149 ++++++++--- plonky2/src/plonk/prover.rs | 71 +++-- plonky2/src/plonk/validate_shape.rs | 17 +- plonky2/src/plonk/verifier.rs | 38 ++- .../conditional_recursive_verifier.rs | 47 +++- plonky2/src/recursion/cyclic_recursion.rs | 94 ++++--- plonky2/src/recursion/dummy_circuit.rs | 82 ++++-- plonky2/src/recursion/recursive_verifier.rs | 180 +++++++++---- plonky2/src/util/reducing.rs | 18 +- plonky2/src/util/serialization.rs | 247 +++++++++++------- starky/src/fibonacci_stark.rs | 53 ++-- starky/src/get_challenges.rs | 61 +++-- starky/src/lib.rs | 1 + starky/src/permutation.rs | 58 ++-- starky/src/proof.rs | 56 ++-- starky/src/prover.rs | 28 +- starky/src/recursive_verifier.rs | 52 +++- starky/src/stark_testing.rs | 12 +- starky/src/verifier.rs | 37 ++- 88 files changed, 2635 insertions(+), 1286 deletions(-) diff --git a/evm/src/arithmetic/arithmetic_stark.rs b/evm/src/arithmetic/arithmetic_stark.rs index 0a89f3c6..397bceb4 100644 --- a/evm/src/arithmetic/arithmetic_stark.rs +++ b/evm/src/arithmetic/arithmetic_stark.rs @@ -171,7 +171,7 @@ mod tests { use anyhow::Result; use ethereum_types::U256; use plonky2::field::types::{Field, PrimeField64}; - use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; @@ -183,7 +183,9 @@ mod tests { fn degree() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = ArithmeticStark; let stark = S { @@ -196,20 +198,24 @@ mod tests { fn circuit() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = ArithmeticStark; let stark = S { f: Default::default(), }; - test_stark_circuit_constraints::(stark) + test_stark_circuit_constraints::(stark) } #[test] fn basic_trace() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = ArithmeticStark; let stark = S { @@ -295,7 +301,9 @@ mod tests { fn big_traces() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = ArithmeticStark; let stark = S { diff --git a/evm/src/cpu/cpu_stark.rs b/evm/src/cpu/cpu_stark.rs index d922c473..e6891bba 100644 --- a/evm/src/cpu/cpu_stark.rs +++ b/evm/src/cpu/cpu_stark.rs @@ -199,7 +199,7 @@ impl, const D: usize> Stark for CpuStark Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = CpuStark; let stark = S { @@ -221,12 +223,14 @@ mod tests { fn test_stark_circuit() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = CpuStark; let stark = S { f: Default::default(), }; - test_stark_circuit_constraints::(stark) + test_stark_circuit_constraints::(stark) } } diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index 15e186aa..75dd1025 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -8,6 +8,7 @@ use plonky2::field::packed::PackedField; use plonky2::field::polynomial::PolynomialValues; use plonky2::field::types::Field; use plonky2::hash::hash_types::RichField; +use plonky2::hash::hashing::HashConfig; use plonky2::iop::ext_target::ExtensionTarget; use plonky2::iop::target::Target; use plonky2::plonk::circuit_builder::CircuitBuilder; @@ -322,12 +323,19 @@ where impl<'a, F: RichField + Extendable, const D: usize> CtlCheckVars<'a, F, F::Extension, F::Extension, D> { - pub(crate) fn from_proofs>( - proofs: &[StarkProofWithMetadata; NUM_TABLES], + pub(crate) fn from_proofs< + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + >( + proofs: &[StarkProofWithMetadata; NUM_TABLES], cross_table_lookups: &'a [CrossTableLookup], ctl_challenges: &'a GrandProductChallengeSet, num_permutation_zs: &[usize; NUM_TABLES], - ) -> [Vec; NUM_TABLES] { + ) -> [Vec; NUM_TABLES] + where + [(); HCO::WIDTH]:, + { let mut ctl_zs = proofs .iter() .zip(num_permutation_zs) diff --git a/evm/src/fixed_recursive_verifier.rs b/evm/src/fixed_recursive_verifier.rs index 0f04cc33..c64edbb4 100644 --- a/evm/src/fixed_recursive_verifier.rs +++ b/evm/src/fixed_recursive_verifier.rs @@ -6,7 +6,7 @@ use plonky2::field::extension::Extendable; use plonky2::fri::FriParams; use plonky2::gates::noop::NoopGate; use plonky2::hash::hash_types::RichField; -use plonky2::hash::hashing::SPONGE_WIDTH; +use plonky2::hash::hashing::HashConfig; use plonky2::iop::challenger::RecursiveChallenger; use plonky2::iop::target::{BoolTarget, Target}; use plonky2::iop::witness::{PartialWitness, WitnessWrite}; @@ -45,28 +45,33 @@ const THRESHOLD_DEGREE_BITS: usize = 13; /// `degree_bits`, this contains a chain of recursive circuits for shrinking that STARK from /// `degree_bits` to a constant `THRESHOLD_DEGREE_BITS`. It also contains a special root circuit /// for combining each STARK's shrunk wrapper proof into a single proof. -pub struct AllRecursiveCircuits +pub struct AllRecursiveCircuits where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + [(); HCO::WIDTH]:, { /// The EVM root circuit, which aggregates the (shrunk) per-table recursive proofs. - pub root: RootCircuitData, - pub aggregation: AggregationCircuitData, + pub root: RootCircuitData, + pub aggregation: AggregationCircuitData, /// The block circuit, which verifies an aggregation root proof and a previous block proof. - pub block: BlockCircuitData, + pub block: BlockCircuitData, /// Holds chains of circuits for each table and for each initial `degree_bits`. - by_table: [RecursiveCircuitsForTable; NUM_TABLES], + by_table: [RecursiveCircuitsForTable; NUM_TABLES], } /// Data for the EVM root circuit, which is used to combine each STARK's shrunk wrapper proof /// into a single proof. -pub struct RootCircuitData +pub struct RootCircuitData where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { - circuit: CircuitData, + circuit: CircuitData, proof_with_pis: [ProofWithPublicInputsTarget; NUM_TABLES], /// For each table, various inner circuits may be used depending on the initial table size. /// This target holds the index of the circuit (within `final_circuits()`) that was used. @@ -78,12 +83,14 @@ where /// Data for the aggregation circuit, which is used to compress two proofs into one. Each inner /// proof can be either an EVM root proof or another aggregation proof. -pub struct AggregationCircuitData +pub struct AggregationCircuitData where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { - circuit: CircuitData, + circuit: CircuitData, lhs: AggregationChildTarget, rhs: AggregationChildTarget, cyclic_vk: VerifierCircuitTarget, @@ -95,29 +102,35 @@ pub struct AggregationChildTarget { evm_proof: ProofWithPublicInputsTarget, } -pub struct BlockCircuitData +pub struct BlockCircuitData where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { - circuit: CircuitData, + circuit: CircuitData, has_parent_block: BoolTarget, parent_block_proof: ProofWithPublicInputsTarget, agg_root_proof: ProofWithPublicInputsTarget, cyclic_vk: VerifierCircuitTarget, } -impl AllRecursiveCircuits +impl AllRecursiveCircuits where F: RichField + Extendable, - C: GenericConfig + 'static, - C::Hasher: AlgebraicHasher, + HCO: HashConfig + 'static, + HCI: HashConfig + 'static, + C: GenericConfig + 'static, + C::Hasher: AlgebraicHasher, [(); C::Hasher::HASH_SIZE]:, [(); CpuStark::::COLUMNS]:, [(); KeccakStark::::COLUMNS]:, [(); KeccakSpongeStark::::COLUMNS]:, [(); LogicStark::::COLUMNS]:, [(); MemoryStark::::COLUMNS]:, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { /// Preprocess all recursive circuits used by the system. pub fn new( @@ -174,9 +187,9 @@ where } fn create_root_circuit( - by_table: &[RecursiveCircuitsForTable; NUM_TABLES], + by_table: &[RecursiveCircuitsForTable; NUM_TABLES], stark_config: &StarkConfig, - ) -> RootCircuitData { + ) -> RootCircuitData { let inner_common_data: [_; NUM_TABLES] = core::array::from_fn(|i| &by_table[i].final_circuits()[0].common); @@ -184,11 +197,11 @@ where let recursive_proofs = core::array::from_fn(|i| builder.add_virtual_proof_with_pis(inner_common_data[i])); let pis: [_; NUM_TABLES] = core::array::from_fn(|i| { - PublicInputs::from_vec(&recursive_proofs[i].public_inputs, stark_config) + PublicInputs::::from_vec(&recursive_proofs[i].public_inputs, stark_config) }); let index_verifier_data = core::array::from_fn(|_i| builder.add_virtual_target()); - let mut challenger = RecursiveChallenger::::new(&mut builder); + let mut challenger = RecursiveChallenger::::new(&mut builder); for pi in &pis { for h in &pi.trace_cap { challenger.observe_elements(h); @@ -214,12 +227,12 @@ where } let state = challenger.compact(&mut builder); - for k in 0..SPONGE_WIDTH { + for k in 0..HCO::WIDTH { builder.connect(state[k], pis[0].challenger_state_before[k]); } // Check that the challenger state is consistent between proofs. for i in 1..NUM_TABLES { - for k in 0..SPONGE_WIDTH { + for k in 0..HCO::WIDTH { builder.connect( pis[i].challenger_state_before[k], pis[i - 1].challenger_state_after[k], @@ -255,7 +268,7 @@ where let inner_verifier_data = builder.random_access_verifier_data(index_verifier_data[i], possible_vks); - builder.verify_proof::( + builder.verify_proof::( &recursive_proofs[i], &inner_verifier_data, inner_common_data[i], @@ -267,7 +280,7 @@ where let cyclic_vk = builder.add_verifier_data_public_inputs(); RootCircuitData { - circuit: builder.build(), + circuit: builder.build::(), proof_with_pis: recursive_proofs, index_verifier_data, cyclic_vk, @@ -275,8 +288,8 @@ where } fn create_aggregation_circuit( - root: &RootCircuitData, - ) -> AggregationCircuitData { + root: &RootCircuitData, + ) -> AggregationCircuitData { let mut builder = CircuitBuilder::::new(root.circuit.common.config.clone()); let cyclic_vk = builder.add_verifier_data_public_inputs(); let lhs = Self::add_agg_child(&mut builder, root); @@ -287,7 +300,7 @@ where builder.add_gate(NoopGate, vec![]); } - let circuit = builder.build::(); + let circuit = builder.build::(); AggregationCircuitData { circuit, lhs, @@ -298,7 +311,7 @@ where fn add_agg_child( builder: &mut CircuitBuilder, - root: &RootCircuitData, + root: &RootCircuitData, ) -> AggregationChildTarget { let common = &root.circuit.common; let root_vk = builder.constant_verifier_data(&root.circuit.verifier_only); @@ -306,7 +319,7 @@ where let agg_proof = builder.add_virtual_proof_with_pis(common); let evm_proof = builder.add_virtual_proof_with_pis(common); builder - .conditionally_verify_cyclic_proof::( + .conditionally_verify_cyclic_proof::( is_agg, &agg_proof, &evm_proof, &root_vk, common, ) .expect("Failed to build cyclic recursion circuit"); @@ -317,7 +330,9 @@ where } } - fn create_block_circuit(agg: &AggregationCircuitData) -> BlockCircuitData { + fn create_block_circuit( + agg: &AggregationCircuitData, + ) -> BlockCircuitData { // The block circuit is similar to the agg circuit; both verify two inner proofs. // We need to adjust a few things, but it's easier than making a new CommonCircuitData. let expected_common_data = CommonCircuitData { @@ -335,7 +350,7 @@ where let cyclic_vk = builder.add_verifier_data_public_inputs(); builder - .conditionally_verify_cyclic_proof_or_dummy::( + .conditionally_verify_cyclic_proof_or_dummy::( has_parent_block, &parent_block_proof, &expected_common_data, @@ -343,9 +358,13 @@ where .expect("Failed to build cyclic recursion circuit"); let agg_verifier_data = builder.constant_verifier_data(&agg.circuit.verifier_only); - builder.verify_proof::(&agg_root_proof, &agg_verifier_data, &agg.circuit.common); + builder.verify_proof::( + &agg_root_proof, + &agg_verifier_data, + &agg.circuit.common, + ); - let circuit = builder.build::(); + let circuit = builder.build::(); BlockCircuitData { circuit, has_parent_block, @@ -362,8 +381,8 @@ where config: &StarkConfig, generation_inputs: GenerationInputs, timing: &mut TimingTree, - ) -> anyhow::Result> { - let all_proof = prove::(all_stark, config, generation_inputs, timing)?; + ) -> anyhow::Result> { + let all_proof = prove::(all_stark, config, generation_inputs, timing)?; let mut root_inputs = PartialWitness::new(); for table in 0..NUM_TABLES { @@ -392,17 +411,20 @@ where self.root.circuit.prove(root_inputs) } - pub fn verify_root(&self, agg_proof: ProofWithPublicInputs) -> anyhow::Result<()> { + pub fn verify_root( + &self, + agg_proof: ProofWithPublicInputs, + ) -> anyhow::Result<()> { self.root.circuit.verify(agg_proof) } pub fn prove_aggregation( &self, lhs_is_agg: bool, - lhs_proof: &ProofWithPublicInputs, + lhs_proof: &ProofWithPublicInputs, rhs_is_agg: bool, - rhs_proof: &ProofWithPublicInputs, - ) -> anyhow::Result> { + rhs_proof: &ProofWithPublicInputs, + ) -> anyhow::Result> { let mut agg_inputs = PartialWitness::new(); agg_inputs.set_bool_target(self.aggregation.lhs.is_agg, lhs_is_agg); @@ -423,7 +445,7 @@ where pub fn verify_aggregation( &self, - agg_proof: &ProofWithPublicInputs, + agg_proof: &ProofWithPublicInputs, ) -> anyhow::Result<()> { self.aggregation.circuit.verify(agg_proof.clone())?; check_cyclic_proof_verifier_data( @@ -435,9 +457,9 @@ where pub fn prove_block( &self, - opt_parent_block_proof: Option<&ProofWithPublicInputs>, - agg_root_proof: &ProofWithPublicInputs, - ) -> anyhow::Result> { + opt_parent_block_proof: Option<&ProofWithPublicInputs>, + agg_root_proof: &ProofWithPublicInputs, + ) -> anyhow::Result> { let mut block_inputs = PartialWitness::new(); block_inputs.set_bool_target( @@ -457,7 +479,10 @@ where self.block.circuit.prove(block_inputs) } - pub fn verify_block(&self, block_proof: &ProofWithPublicInputs) -> anyhow::Result<()> { + pub fn verify_block( + &self, + block_proof: &ProofWithPublicInputs, + ) -> anyhow::Result<()> { self.block.circuit.verify(block_proof.clone())?; check_cyclic_proof_verifier_data( block_proof, @@ -467,22 +492,29 @@ where } } -struct RecursiveCircuitsForTable +struct RecursiveCircuitsForTable where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + [(); HCO::WIDTH]:, { /// A map from `log_2(height)` to a chain of shrinking recursion circuits starting at that /// height. - by_stark_size: BTreeMap>, + by_stark_size: BTreeMap>, } -impl RecursiveCircuitsForTable +impl RecursiveCircuitsForTable where F: RichField + Extendable, - C: GenericConfig, - C::Hasher: AlgebraicHasher, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + C::Hasher: AlgebraicHasher, [(); C::Hasher::HASH_SIZE]:, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { fn new>( table: Table, @@ -513,7 +545,7 @@ where /// For each initial `degree_bits`, get the final circuit at the end of that shrinking chain. /// Each of these final circuits should have degree `THRESHOLD_DEGREE_BITS`. - fn final_circuits(&self) -> Vec<&CircuitData> { + fn final_circuits(&self) -> Vec<&CircuitData> { self.by_stark_size .values() .map(|chain| { @@ -529,21 +561,28 @@ where /// A chain of shrinking wrapper circuits, ending with a final circuit with `degree_bits` /// `THRESHOLD_DEGREE_BITS`. -struct RecursiveCircuitsForTableSize +struct RecursiveCircuitsForTableSize where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + [(); HCO::WIDTH]:, { - initial_wrapper: StarkWrapperCircuit, - shrinking_wrappers: Vec>, + initial_wrapper: StarkWrapperCircuit, + shrinking_wrappers: Vec>, } -impl RecursiveCircuitsForTableSize +impl RecursiveCircuitsForTableSize where F: RichField + Extendable, - C: GenericConfig, - C::Hasher: AlgebraicHasher, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + C::Hasher: AlgebraicHasher, [(); C::Hasher::HASH_SIZE]:, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { fn new>( table: Table, @@ -570,7 +609,7 @@ where loop { let last = shrinking_wrappers .last() - .map(|wrapper: &PlonkWrapperCircuit| &wrapper.circuit) + .map(|wrapper: &PlonkWrapperCircuit| &wrapper.circuit) .unwrap_or(&initial_wrapper.circuit); let last_degree_bits = last.common.degree_bits(); assert!(last_degree_bits >= THRESHOLD_DEGREE_BITS); @@ -581,10 +620,10 @@ where let mut builder = CircuitBuilder::new(shrinking_config()); let proof_with_pis_target = builder.add_virtual_proof_with_pis(&last.common); let last_vk = builder.constant_verifier_data(&last.verifier_only); - builder.verify_proof::(&proof_with_pis_target, &last_vk, &last.common); + builder.verify_proof::(&proof_with_pis_target, &last_vk, &last.common); builder.register_public_inputs(&proof_with_pis_target.public_inputs); // carry PIs forward add_common_recursion_gates(&mut builder); - let circuit = builder.build(); + let circuit = builder.build::(); assert!( circuit.common.degree_bits() < last_degree_bits, @@ -606,9 +645,9 @@ where fn shrink( &self, - stark_proof_with_metadata: &StarkProofWithMetadata, + stark_proof_with_metadata: &StarkProofWithMetadata, ctl_challenges: &GrandProductChallengeSet, - ) -> anyhow::Result> { + ) -> anyhow::Result> { let mut proof = self .initial_wrapper .prove(stark_proof_with_metadata, ctl_challenges)?; diff --git a/evm/src/get_challenges.rs b/evm/src/get_challenges.rs index fdc0e315..6d441634 100644 --- a/evm/src/get_challenges.rs +++ b/evm/src/get_challenges.rs @@ -1,6 +1,7 @@ use plonky2::field::extension::Extendable; use plonky2::fri::proof::{FriProof, FriProofTarget}; use plonky2::hash::hash_types::RichField; +use plonky2::hash::hashing::HashConfig; use plonky2::iop::challenger::{Challenger, RecursiveChallenger}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; @@ -13,14 +14,27 @@ use crate::permutation::{ }; use crate::proof::*; -impl, C: GenericConfig, const D: usize> AllProof { +impl< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + > AllProof +where + [(); HCO::WIDTH]:, +{ /// Computes all Fiat-Shamir challenges used in the STARK proof. pub(crate) fn get_challenges( &self, all_stark: &AllStark, config: &StarkConfig, - ) -> AllProofChallenges { - let mut challenger = Challenger::::new(); + ) -> AllProofChallenges + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { + let mut challenger = Challenger::::new(); for proof in &self.stark_proofs { challenger.observe_cap(&proof.proof.trace_cap); @@ -53,8 +67,12 @@ impl, C: GenericConfig, const D: usize> A &self, all_stark: &AllStark, config: &StarkConfig, - ) -> AllChallengerState { - let mut challenger = Challenger::::new(); + ) -> AllChallengerState + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { + let mut challenger = Challenger::::new(); for proof in &self.stark_proofs { challenger.observe_cap(&proof.proof.trace_cap); @@ -86,19 +104,25 @@ impl, C: GenericConfig, const D: usize> A } } -impl StarkProof +impl StarkProof where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { /// Computes all Fiat-Shamir challenges used in the STARK proof. pub(crate) fn get_challenges( &self, - challenger: &mut Challenger, + challenger: &mut Challenger, stark_use_permutation: bool, stark_permutation_batch_size: usize, config: &StarkConfig, - ) -> StarkProofChallenges { + ) -> StarkProofChallenges + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { let degree_bits = self.recover_degree_bits(config); let StarkProof { @@ -138,7 +162,7 @@ where permutation_challenge_sets, stark_alphas, stark_zeta, - fri_challenges: challenger.fri_challenges::( + fri_challenges: challenger.fri_challenges::( commit_phase_merkle_caps, final_poly, *pow_witness, @@ -150,16 +174,23 @@ where } impl StarkProofTarget { - pub(crate) fn get_challenges, C: GenericConfig>( + pub(crate) fn get_challenges< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + >( &self, builder: &mut CircuitBuilder, - challenger: &mut RecursiveChallenger, + challenger: &mut RecursiveChallenger, stark_use_permutation: bool, stark_permutation_batch_size: usize, config: &StarkConfig, ) -> StarkProofChallengesTarget where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let StarkProofTarget { permutation_ctl_zs_cap, diff --git a/evm/src/keccak/keccak_stark.rs b/evm/src/keccak/keccak_stark.rs index c8fe8086..34d68d11 100644 --- a/evm/src/keccak/keccak_stark.rs +++ b/evm/src/keccak/keccak_stark.rs @@ -607,7 +607,7 @@ mod tests { use plonky2::field::types::{Field, PrimeField64}; use plonky2::fri::oracle::PolynomialBatch; use plonky2::iop::challenger::Challenger; - use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; use plonky2::timed; use plonky2::util::timing::TimingTree; use tiny_keccak::keccakf; @@ -624,7 +624,9 @@ mod tests { fn test_stark_degree() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = KeccakStark; let stark = S { @@ -637,13 +639,15 @@ mod tests { fn test_stark_circuit() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = KeccakStark; let stark = S { f: Default::default(), }; - test_stark_circuit_constraints::(stark) + test_stark_circuit_constraints::(stark) } #[test] @@ -652,7 +656,9 @@ mod tests { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = KeccakStark; let stark = S { @@ -685,7 +691,9 @@ mod tests { const NUM_PERMS: usize = 85; const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = KeccakStark; let stark = S::default(); let config = StarkConfig::standard_fast_config(); @@ -708,7 +716,7 @@ mod tests { let trace_commitments = timed!( timing, "compute trace commitment", - PolynomialBatch::::from_values( + PolynomialBatch::::from_values( cloned_trace_poly_values, config.fri_config.rate_bits, false, diff --git a/evm/src/keccak_sponge/keccak_sponge_stark.rs b/evm/src/keccak_sponge/keccak_sponge_stark.rs index 3fe59f74..57033b52 100644 --- a/evm/src/keccak_sponge/keccak_sponge_stark.rs +++ b/evm/src/keccak_sponge/keccak_sponge_stark.rs @@ -411,7 +411,7 @@ mod tests { use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; use plonky2::field::types::PrimeField64; - use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; use crate::keccak_sponge::columns::KeccakSpongeColumnsView; use crate::keccak_sponge::keccak_sponge_stark::{KeccakSpongeOp, KeccakSpongeStark}; @@ -423,7 +423,9 @@ mod tests { fn test_stark_degree() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = KeccakSpongeStark; let stark = S::default(); @@ -434,11 +436,13 @@ mod tests { fn test_stark_circuit() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = KeccakSpongeStark; let stark = S::default(); - test_stark_circuit_constraints::(stark) + test_stark_circuit_constraints::(stark) } #[test] diff --git a/evm/src/lib.rs b/evm/src/lib.rs index 3a3df21d..dc07d233 100644 --- a/evm/src/lib.rs +++ b/evm/src/lib.rs @@ -3,6 +3,7 @@ #![allow(clippy::too_many_arguments)] #![allow(clippy::type_complexity)] #![allow(clippy::field_reassign_with_default)] +#![allow(clippy::upper_case_acronyms)] #![feature(let_chains)] #![feature(generic_const_exprs)] diff --git a/evm/src/logic.rs b/evm/src/logic.rs index b7429610..f007eb2c 100644 --- a/evm/src/logic.rs +++ b/evm/src/logic.rs @@ -303,7 +303,7 @@ impl, const D: usize> Stark for LogicStark Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = LogicStark; let stark = S { @@ -325,12 +327,14 @@ mod tests { fn test_stark_circuit() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = LogicStark; let stark = S { f: Default::default(), }; - test_stark_circuit_constraints::(stark) + test_stark_circuit_constraints::(stark) } } diff --git a/evm/src/memory/memory_stark.rs b/evm/src/memory/memory_stark.rs index a0481029..4fed6ac4 100644 --- a/evm/src/memory/memory_stark.rs +++ b/evm/src/memory/memory_stark.rs @@ -462,7 +462,7 @@ impl, const D: usize> Stark for MemoryStark Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = MemoryStark; let stark = S { @@ -484,12 +486,14 @@ pub(crate) mod tests { fn test_stark_circuit() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = MemoryStark; let stark = S { f: Default::default(), }; - test_stark_circuit_constraints::(stark) + test_stark_circuit_constraints::(stark) } } diff --git a/evm/src/permutation.rs b/evm/src/permutation.rs index a92774cb..7dc21871 100644 --- a/evm/src/permutation.rs +++ b/evm/src/permutation.rs @@ -9,6 +9,7 @@ use plonky2::field::packed::PackedField; use plonky2::field::polynomial::PolynomialValues; use plonky2::field::types::Field; use plonky2::hash::hash_types::RichField; +use plonky2::hash::hashing::HashConfig; use plonky2::iop::challenger::{Challenger, RecursiveChallenger}; use plonky2::iop::ext_target::ExtensionTarget; use plonky2::iop::target::Target; @@ -175,29 +176,38 @@ fn poly_product_elementwise( product } -fn get_grand_product_challenge>( - challenger: &mut Challenger, -) -> GrandProductChallenge { +fn get_grand_product_challenge>( + challenger: &mut Challenger, +) -> GrandProductChallenge +where + [(); HC::WIDTH]:, +{ let beta = challenger.get_challenge(); let gamma = challenger.get_challenge(); GrandProductChallenge { beta, gamma } } -pub(crate) fn get_grand_product_challenge_set>( - challenger: &mut Challenger, +pub(crate) fn get_grand_product_challenge_set>( + challenger: &mut Challenger, num_challenges: usize, -) -> GrandProductChallengeSet { +) -> GrandProductChallengeSet +where + [(); HC::WIDTH]:, +{ let challenges = (0..num_challenges) .map(|_| get_grand_product_challenge(challenger)) .collect(); GrandProductChallengeSet { challenges } } -pub(crate) fn get_n_grand_product_challenge_sets>( - challenger: &mut Challenger, +pub(crate) fn get_n_grand_product_challenge_sets>( + challenger: &mut Challenger, num_challenges: usize, num_sets: usize, -) -> Vec> { +) -> Vec> +where + [(); HC::WIDTH]:, +{ (0..num_sets) .map(|_| get_grand_product_challenge_set(challenger, num_challenges)) .collect() @@ -205,12 +215,16 @@ pub(crate) fn get_n_grand_product_challenge_sets>( fn get_grand_product_challenge_target< F: RichField + Extendable, - H: AlgebraicHasher, + HC: HashConfig, + H: AlgebraicHasher, const D: usize, >( builder: &mut CircuitBuilder, - challenger: &mut RecursiveChallenger, -) -> GrandProductChallenge { + challenger: &mut RecursiveChallenger, +) -> GrandProductChallenge +where + [(); HC::WIDTH]:, +{ let beta = challenger.get_challenge(builder); let gamma = challenger.get_challenge(builder); GrandProductChallenge { beta, gamma } @@ -218,13 +232,17 @@ fn get_grand_product_challenge_target< pub(crate) fn get_grand_product_challenge_set_target< F: RichField + Extendable, - H: AlgebraicHasher, + HC: HashConfig, + H: AlgebraicHasher, const D: usize, >( builder: &mut CircuitBuilder, - challenger: &mut RecursiveChallenger, + challenger: &mut RecursiveChallenger, num_challenges: usize, -) -> GrandProductChallengeSet { +) -> GrandProductChallengeSet +where + [(); HC::WIDTH]:, +{ let challenges = (0..num_challenges) .map(|_| get_grand_product_challenge_target(builder, challenger)) .collect(); @@ -233,14 +251,18 @@ pub(crate) fn get_grand_product_challenge_set_target< pub(crate) fn get_n_grand_product_challenge_sets_target< F: RichField + Extendable, - H: AlgebraicHasher, + HC: HashConfig, + H: AlgebraicHasher, const D: usize, >( builder: &mut CircuitBuilder, - challenger: &mut RecursiveChallenger, + challenger: &mut RecursiveChallenger, num_challenges: usize, num_sets: usize, -) -> Vec> { +) -> Vec> +where + [(); HC::WIDTH]:, +{ (0..num_sets) .map(|_| get_grand_product_challenge_set_target(builder, challenger, num_challenges)) .collect() diff --git a/evm/src/proof.rs b/evm/src/proof.rs index d0f56873..f1464cb2 100644 --- a/evm/src/proof.rs +++ b/evm/src/proof.rs @@ -7,7 +7,7 @@ use plonky2::fri::structure::{ FriOpeningBatch, FriOpeningBatchTarget, FriOpenings, FriOpeningsTarget, }; use plonky2::hash::hash_types::{MerkleCapTarget, RichField}; -use plonky2::hash::hashing::SPONGE_WIDTH; +use plonky2::hash::hashing::HashConfig; use plonky2::hash::merkle_tree::MerkleCap; use plonky2::iop::ext_target::ExtensionTarget; use plonky2::iop::target::Target; @@ -21,13 +21,30 @@ use crate::permutation::GrandProductChallengeSet; /// A STARK proof for each table, plus some metadata used to create recursive wrapper proofs. #[derive(Debug, Clone)] -pub struct AllProof, C: GenericConfig, const D: usize> { - pub stark_proofs: [StarkProofWithMetadata; NUM_TABLES], +pub struct AllProof< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +> where + [(); HCO::WIDTH]:, +{ + pub stark_proofs: [StarkProofWithMetadata; NUM_TABLES], pub(crate) ctl_challenges: GrandProductChallengeSet, pub public_values: PublicValues, } -impl, C: GenericConfig, const D: usize> AllProof { +impl< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + > AllProof +where + [(); HCO::WIDTH]:, +{ pub fn degree_bits(&self, config: &StarkConfig) -> [usize; NUM_TABLES] { core::array::from_fn(|i| self.stark_proofs[i].proof.recover_degree_bits(config)) } @@ -39,10 +56,13 @@ pub(crate) struct AllProofChallenges, const D: usiz } #[allow(unused)] // TODO: should be used soon -pub(crate) struct AllChallengerState, const D: usize> { +pub(crate) struct AllChallengerState, HC: HashConfig, const D: usize> +where + [(); HC::WIDTH]:, +{ /// Sponge state of the challenger before starting each proof, /// along with the final state after all proofs are done. This final state isn't strictly needed. - pub states: [[F; SPONGE_WIDTH]; NUM_TABLES + 1], + pub states: [[F; HC::WIDTH]; NUM_TABLES + 1], pub ctl_challenges: GrandProductChallengeSet, } @@ -97,32 +117,48 @@ pub struct BlockMetadataTarget { } #[derive(Debug, Clone)] -pub struct StarkProof, C: GenericConfig, const D: usize> { +pub struct StarkProof< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +> { /// Merkle cap of LDEs of trace values. - pub trace_cap: MerkleCap, + pub trace_cap: MerkleCap, /// Merkle cap of LDEs of permutation Z values. - pub permutation_ctl_zs_cap: MerkleCap, + pub permutation_ctl_zs_cap: MerkleCap, /// Merkle cap of LDEs of trace values. - pub quotient_polys_cap: MerkleCap, + pub quotient_polys_cap: MerkleCap, /// Purported values of each polynomial at the challenge point. pub openings: StarkOpeningSet, /// A batch FRI argument for all openings. - pub opening_proof: FriProof, + pub opening_proof: FriProof, } /// A `StarkProof` along with some metadata about the initial Fiat-Shamir state, which is used when /// creating a recursive wrapper proof around a STARK proof. #[derive(Debug, Clone)] -pub struct StarkProofWithMetadata +pub struct StarkProofWithMetadata where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + [(); HCO::WIDTH]:, { - pub(crate) init_challenger_state: [F; SPONGE_WIDTH], - pub(crate) proof: StarkProof, + pub(crate) init_challenger_state: [F; HCO::WIDTH], + pub(crate) proof: StarkProof, } -impl, C: GenericConfig, const D: usize> StarkProof { +impl< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + > StarkProof +{ /// Recover the length of the trace from a STARK proof and a STARK config. pub fn recover_degree_bits(&self, config: &StarkConfig) -> usize { let initial_merkle_proof = &self.opening_proof.query_round_proofs[0] @@ -196,22 +232,22 @@ pub struct StarkOpeningSet, const D: usize> { } impl, const D: usize> StarkOpeningSet { - pub fn new>( + pub fn new>( zeta: F::Extension, g: F, - trace_commitment: &PolynomialBatch, - permutation_ctl_zs_commitment: &PolynomialBatch, - quotient_commitment: &PolynomialBatch, + trace_commitment: &PolynomialBatch, + permutation_ctl_zs_commitment: &PolynomialBatch, + quotient_commitment: &PolynomialBatch, degree_bits: usize, num_permutation_zs: usize, ) -> Self { - let eval_commitment = |z: F::Extension, c: &PolynomialBatch| { + let eval_commitment = |z: F::Extension, c: &PolynomialBatch| { c.polynomials .par_iter() .map(|p| p.to_extension().eval(z)) .collect::>() }; - let eval_commitment_base = |z: F, c: &PolynomialBatch| { + let eval_commitment_base = |z: F, c: &PolynomialBatch| { c.polynomials .par_iter() .map(|p| p.eval(z)) diff --git a/evm/src/prover.rs b/evm/src/prover.rs index 97b28a4b..bed796fd 100644 --- a/evm/src/prover.rs +++ b/evm/src/prover.rs @@ -11,6 +11,7 @@ use plonky2::field::types::Field; use plonky2::field::zero_poly_coset::ZeroPolyOnCoset; use plonky2::fri::oracle::PolynomialBatch; use plonky2::hash::hash_types::RichField; +use plonky2::hash::hashing::HashConfig; use plonky2::iop::challenger::Challenger; use plonky2::plonk::config::{GenericConfig, Hasher}; use plonky2::timed; @@ -41,21 +42,25 @@ use crate::vanishing_poly::eval_vanishing_poly; use crate::vars::StarkEvaluationVars; /// Generate traces, then create all STARK proofs. -pub fn prove( +pub fn prove( all_stark: &AllStark, config: &StarkConfig, inputs: GenerationInputs, timing: &mut TimingTree, -) -> Result> +) -> Result> where F: RichField + Extendable, - C: GenericConfig, - [(); C::Hasher::HASH_SIZE]:, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, [(); CpuStark::::COLUMNS]:, [(); KeccakStark::::COLUMNS]:, [(); KeccakSpongeStark::::COLUMNS]:, [(); LogicStark::::COLUMNS]:, [(); MemoryStark::::COLUMNS]:, + [(); C::Hasher::HASH_SIZE]:, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let (proof, _outputs) = prove_with_outputs(all_stark, config, inputs, timing)?; Ok(proof) @@ -63,21 +68,25 @@ where /// Generate traces, then create all STARK proofs. Returns information about the post-state, /// intended for debugging, in addition to the proof. -pub fn prove_with_outputs( +pub fn prove_with_outputs( all_stark: &AllStark, config: &StarkConfig, inputs: GenerationInputs, timing: &mut TimingTree, -) -> Result<(AllProof, GenerationOutputs)> +) -> Result<(AllProof, GenerationOutputs)> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, [(); C::Hasher::HASH_SIZE]:, [(); CpuStark::::COLUMNS]:, [(); KeccakStark::::COLUMNS]:, [(); KeccakSpongeStark::::COLUMNS]:, [(); LogicStark::::COLUMNS]:, [(); MemoryStark::::COLUMNS]:, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { timed!(timing, "build kernel", Lazy::force(&KERNEL)); let (traces, public_values, outputs) = timed!( @@ -90,22 +99,26 @@ where } /// Compute all STARK proofs. -pub(crate) fn prove_with_traces( +pub(crate) fn prove_with_traces( all_stark: &AllStark, config: &StarkConfig, trace_poly_values: [Vec>; NUM_TABLES], public_values: PublicValues, timing: &mut TimingTree, -) -> Result> +) -> Result> where F: RichField + Extendable, - C: GenericConfig, - [(); C::Hasher::HASH_SIZE]:, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, [(); CpuStark::::COLUMNS]:, [(); KeccakStark::::COLUMNS]:, [(); KeccakSpongeStark::::COLUMNS]:, [(); LogicStark::::COLUMNS]:, [(); MemoryStark::::COLUMNS]:, + [(); C::Hasher::HASH_SIZE]:, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let rate_bits = config.fri_config.rate_bits; let cap_height = config.fri_config.cap_height; @@ -120,7 +133,7 @@ where timed!( timing, &format!("compute trace commitment for {:?}", table), - PolynomialBatch::::from_values( + PolynomialBatch::::from_values( // TODO: Cloning this isn't great; consider having `from_values` accept a reference, // or having `compute_permutation_z_polys` read trace values from the `PolynomialBatch`. trace.clone(), @@ -139,7 +152,7 @@ where .iter() .map(|c| c.merkle_tree.cap.clone()) .collect::>(); - let mut challenger = Challenger::::new(); + let mut challenger = Challenger::::new(); for cap in &trace_caps { challenger.observe_cap(cap); } @@ -176,24 +189,28 @@ where }) } -fn prove_with_commitments( +fn prove_with_commitments( all_stark: &AllStark, config: &StarkConfig, trace_poly_values: [Vec>; NUM_TABLES], - trace_commitments: Vec>, + trace_commitments: Vec>, ctl_data_per_table: [CtlData; NUM_TABLES], - challenger: &mut Challenger, + challenger: &mut Challenger, timing: &mut TimingTree, -) -> Result<[StarkProofWithMetadata; NUM_TABLES]> +) -> Result<[StarkProofWithMetadata; NUM_TABLES]> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, [(); C::Hasher::HASH_SIZE]:, [(); CpuStark::::COLUMNS]:, [(); KeccakStark::::COLUMNS]:, [(); KeccakSpongeStark::::COLUMNS]:, [(); LogicStark::::COLUMNS]:, [(); MemoryStark::::COLUMNS]:, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let cpu_proof = timed!( timing, @@ -270,21 +287,24 @@ where } /// Compute proof for a single STARK table. -pub(crate) fn prove_single_table( +pub(crate) fn prove_single_table( stark: &S, config: &StarkConfig, trace_poly_values: &[PolynomialValues], - trace_commitment: &PolynomialBatch, + trace_commitment: &PolynomialBatch, ctl_data: &CtlData, - challenger: &mut Challenger, + challenger: &mut Challenger, timing: &mut TimingTree, -) -> Result> +) -> Result> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, - [(); C::Hasher::HASH_SIZE]:, [(); S::COLUMNS]:, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let degree = trace_poly_values[0].len(); let degree_bits = log2_strict(degree); @@ -357,7 +377,7 @@ where let quotient_polys = timed!( timing, "compute quotient polys", - compute_quotient_polys::::Packing, C, S, D>( + compute_quotient_polys::::Packing, HCO, HCI, C, S, D>( stark, trace_commitment, &permutation_ctl_zs_commitment, @@ -454,10 +474,10 @@ where /// Computes the quotient polynomials `(sum alpha^i C_i(x)) / Z_H(x)` for `alpha` in `alphas`, /// where the `C_i`s are the Stark constraints. -fn compute_quotient_polys<'a, F, P, C, S, const D: usize>( +fn compute_quotient_polys<'a, F, P, HCO, HCI, C, S, const D: usize>( stark: &S, - trace_commitment: &'a PolynomialBatch, - permutation_ctl_zs_commitment: &'a PolynomialBatch, + trace_commitment: &'a PolynomialBatch, + permutation_ctl_zs_commitment: &'a PolynomialBatch, permutation_challenges: Option<&'a Vec>>, ctl_data: &CtlData, alphas: Vec, @@ -468,7 +488,9 @@ fn compute_quotient_polys<'a, F, P, C, S, const D: usize>( where F: RichField + Extendable, P: PackedField, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, [(); S::COLUMNS]:, { @@ -591,10 +613,10 @@ where /// Check that all constraints evaluate to zero on `H`. /// Can also be used to check the degree of the constraints by evaluating on a larger subgroup. -fn check_constraints<'a, F, C, S, const D: usize>( +fn check_constraints<'a, F, HCO, HCI, C, S, const D: usize>( stark: &S, - trace_commitment: &'a PolynomialBatch, - permutation_ctl_zs_commitment: &'a PolynomialBatch, + trace_commitment: &'a PolynomialBatch, + permutation_ctl_zs_commitment: &'a PolynomialBatch, permutation_challenges: Option<&'a Vec>>, ctl_data: &CtlData, alphas: Vec, @@ -603,7 +625,9 @@ fn check_constraints<'a, F, C, S, const D: usize>( config: &StarkConfig, ) where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, [(); S::COLUMNS]:, { @@ -621,7 +645,7 @@ fn check_constraints<'a, F, C, S, const D: usize>( let subgroup = F::two_adic_subgroup(degree_bits + rate_bits); // Get the evaluations of a batch of polynomials over our subgroup. - let get_subgroup_evals = |comm: &PolynomialBatch| -> Vec> { + let get_subgroup_evals = |comm: &PolynomialBatch| -> Vec> { let values = comm .polynomials .par_iter() diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index d3018ba4..ea6f9b47 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -9,14 +9,14 @@ use plonky2::gates::exponentiation::ExponentiationGate; use plonky2::gates::gate::GateRef; use plonky2::gates::noop::NoopGate; use plonky2::hash::hash_types::RichField; -use plonky2::hash::hashing::SPONGE_WIDTH; +use plonky2::hash::hashing::HashConfig; use plonky2::iop::challenger::{Challenger, RecursiveChallenger}; use plonky2::iop::ext_target::ExtensionTarget; use plonky2::iop::target::Target; use plonky2::iop::witness::{PartialWitness, Witness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, VerifierCircuitData}; -use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, Hasher}; +use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; use plonky2::util::reducing::ReducingFactorTarget; use plonky2::with_context; @@ -43,18 +43,23 @@ use crate::vars::StarkEvaluationTargets; /// Table-wise recursive proofs of an `AllProof`. pub struct RecursiveAllProof< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, > { - pub recursive_proofs: [ProofWithPublicInputs; NUM_TABLES], + pub recursive_proofs: [ProofWithPublicInputs; NUM_TABLES], } -pub(crate) struct PublicInputs { +pub(crate) struct PublicInputs +where + [(); HC::WIDTH]:, +{ pub(crate) trace_cap: Vec>, pub(crate) ctl_zs_last: Vec, pub(crate) ctl_challenges: GrandProductChallengeSet, - pub(crate) challenger_state_before: [T; SPONGE_WIDTH], - pub(crate) challenger_state_after: [T; SPONGE_WIDTH], + pub(crate) challenger_state_before: [T; HC::WIDTH], + pub(crate) challenger_state_after: [T; HC::WIDTH], } /// Similar to the unstable `Iterator::next_chunk`. Could be replaced with that when it's stable. @@ -66,7 +71,10 @@ fn next_chunk(iter: &mut impl Iterator) -> [ .expect("Not enough elements") } -impl PublicInputs { +impl PublicInputs +where + [(); HC::WIDTH]:, +{ pub(crate) fn from_vec(v: &[T], config: &StarkConfig) -> Self { let mut iter = v.iter().copied(); let trace_cap = (0..config.fri_config.num_cap_elements()) @@ -94,24 +102,30 @@ impl PublicInputs { } } -impl, C: GenericConfig, const D: usize> - RecursiveAllProof +impl< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + > RecursiveAllProof { /// Verify every recursive proof. pub fn verify( self, - verifier_data: &[VerifierCircuitData; NUM_TABLES], + verifier_data: &[VerifierCircuitData; NUM_TABLES], cross_table_lookups: Vec>, inner_config: &StarkConfig, ) -> Result<()> where - [(); C::Hasher::HASH_SIZE]:, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let pis: [_; NUM_TABLES] = core::array::from_fn(|i| { - PublicInputs::from_vec(&self.recursive_proofs[i].public_inputs, inner_config) + PublicInputs::::from_vec(&self.recursive_proofs[i].public_inputs, inner_config) }); - let mut challenger = Challenger::::new(); + let mut challenger = Challenger::::new(); for pi in &pis { for h in &pi.trace_cap { challenger.observe_elements(h); @@ -147,29 +161,36 @@ impl, C: GenericConfig, const D: usize> } /// Represents a circuit which recursively verifies a STARK proof. -pub(crate) struct StarkWrapperCircuit +pub(crate) struct StarkWrapperCircuit where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + [(); HCO::WIDTH]:, { - pub(crate) circuit: CircuitData, + pub(crate) circuit: CircuitData, pub(crate) stark_proof_target: StarkProofTarget, pub(crate) ctl_challenges_target: GrandProductChallengeSet, - pub(crate) init_challenger_state_target: [Target; SPONGE_WIDTH], + pub(crate) init_challenger_state_target: [Target; HCO::WIDTH], pub(crate) zero_target: Target, } -impl StarkWrapperCircuit +impl StarkWrapperCircuit where F: RichField + Extendable, - C: GenericConfig, - C::Hasher: AlgebraicHasher, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { pub(crate) fn prove( &self, - proof_with_metadata: &StarkProofWithMetadata, + proof_with_metadata: &StarkProofWithMetadata, ctl_challenges: &GrandProductChallengeSet, - ) -> Result> { + ) -> Result> { let mut inputs = PartialWitness::new(); set_stark_proof_target( @@ -199,25 +220,31 @@ where } /// Represents a circuit which recursively verifies a PLONK proof. -pub(crate) struct PlonkWrapperCircuit +pub(crate) struct PlonkWrapperCircuit where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { - pub(crate) circuit: CircuitData, + pub(crate) circuit: CircuitData, pub(crate) proof_with_pis_target: ProofWithPublicInputsTarget, } -impl PlonkWrapperCircuit +impl PlonkWrapperCircuit where F: RichField + Extendable, - C: GenericConfig, - C::Hasher: AlgebraicHasher, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { pub(crate) fn prove( &self, - proof: &ProofWithPublicInputs, - ) -> Result> { + proof: &ProofWithPublicInputs, + ) -> Result> { let mut inputs = PartialWitness::new(); inputs.set_proof_with_pis_target(&self.proof_with_pis_target, proof); self.circuit.prove(inputs) @@ -227,7 +254,9 @@ where /// Returns the recursive Stark circuit. pub(crate) fn recursive_stark_circuit< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, const D: usize, >( @@ -238,11 +267,12 @@ pub(crate) fn recursive_stark_circuit< inner_config: &StarkConfig, circuit_config: &CircuitConfig, min_degree_bits: usize, -) -> StarkWrapperCircuit +) -> StarkWrapperCircuit where [(); S::COLUMNS]:, - [(); C::Hasher::HASH_SIZE]:, - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let mut builder = CircuitBuilder::::new(circuit_config.clone()); let zero_target = builder.zero(); @@ -281,8 +311,8 @@ where let init_challenger_state_target = core::array::from_fn(|_| builder.add_virtual_public_input()); let mut challenger = - RecursiveChallenger::::from_state(init_challenger_state_target); - let challenges = proof_target.get_challenges::( + RecursiveChallenger::::from_state(init_challenger_state_target); + let challenges = proof_target.get_challenges::( &mut builder, &mut challenger, num_permutation_zs > 0, @@ -294,7 +324,7 @@ where builder.register_public_inputs(&proof_target.openings.ctl_zs_last); - verify_stark_proof_with_challenges_circuit::( + verify_stark_proof_with_challenges_circuit::( &mut builder, stark, &proof_target, @@ -310,7 +340,7 @@ where builder.add_gate(NoopGate, vec![]); } - let circuit = builder.build::(); + let circuit = builder.build::(); StarkWrapperCircuit { circuit, stark_proof_target: proof_target, @@ -334,7 +364,9 @@ pub(crate) fn add_common_recursion_gates, const D: /// Recursively verifies an inner proof. fn verify_stark_proof_with_challenges_circuit< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, const D: usize, >( @@ -345,8 +377,9 @@ fn verify_stark_proof_with_challenges_circuit< ctl_vars: &[CtlCheckVarsTarget], inner_config: &StarkConfig, ) where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, [(); S::COLUMNS]:, + [(); HCO::WIDTH]:, { let zero = builder.zero(); let one = builder.one_extension(); @@ -430,7 +463,7 @@ fn verify_stark_proof_with_challenges_circuit< ctl_zs_last.len(), inner_config, ); - builder.verify_fri_proof::( + builder.verify_fri_proof::( &fri_instance, &proof.openings.to_fri_openings(zero), &challenges.fri_challenges, @@ -558,14 +591,23 @@ fn add_virtual_stark_opening_set, S: Stark, c } } -pub(crate) fn set_stark_proof_target, W, const D: usize>( +pub(crate) fn set_stark_proof_target< + F, + HCO, + HCI, + C: GenericConfig, + W, + const D: usize, +>( witness: &mut W, proof_target: &StarkProofTarget, - proof: &StarkProof, + proof: &StarkProof, zero: Target, ) where F: RichField + Extendable, - C::Hasher: AlgebraicHasher, + HCO: HashConfig, + HCI: HashConfig, + C::Hasher: AlgebraicHasher, W: Witness, { witness.set_cap_target(&proof_target.trace_cap, &proof.trace_cap); diff --git a/evm/src/stark_testing.rs b/evm/src/stark_testing.rs index df1352a6..e1c36f9d 100644 --- a/evm/src/stark_testing.rs +++ b/evm/src/stark_testing.rs @@ -3,10 +3,11 @@ use plonky2::field::extension::{Extendable, FieldExtension}; use plonky2::field::polynomial::{PolynomialCoeffs, PolynomialValues}; use plonky2::field::types::{Field, Sample}; use plonky2::hash::hash_types::RichField; +use plonky2::hash::hashing::HashConfig; use plonky2::iop::witness::{PartialWitness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; -use plonky2::plonk::config::{GenericConfig, Hasher}; +use plonky2::plonk::config::GenericConfig; use plonky2::util::transpose; use plonky2_util::{log2_ceil, log2_strict}; @@ -78,7 +79,9 @@ where /// Tests that the circuit constraints imposed by the given STARK are coherent with the native constraints. pub fn test_stark_circuit_constraints< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, const D: usize, >( @@ -86,7 +89,8 @@ pub fn test_stark_circuit_constraints< ) -> Result<()> where [(); S::COLUMNS]:, - [(); C::Hasher::HASH_SIZE]:, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { // Compute native constraint evaluation on random values. let vars = StarkEvaluationVars { @@ -144,7 +148,7 @@ where let native_eval_t = builder.constant_extension(native_eval); builder.connect_extension(circuit_eval, native_eval_t); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; data.verify(proof) } diff --git a/evm/src/verifier.rs b/evm/src/verifier.rs index b4b2f6bd..850fb51b 100644 --- a/evm/src/verifier.rs +++ b/evm/src/verifier.rs @@ -5,7 +5,8 @@ use plonky2::field::extension::{Extendable, FieldExtension}; use plonky2::field::types::Field; use plonky2::fri::verifier::verify_fri_proof; use plonky2::hash::hash_types::RichField; -use plonky2::plonk::config::{GenericConfig, Hasher}; +use plonky2::hash::hashing::HashConfig; +use plonky2::plonk::config::GenericConfig; use plonky2::plonk::plonk_common::reduce_with_powers; use crate::all_stark::{AllStark, Table}; @@ -25,9 +26,15 @@ use crate::stark::Stark; use crate::vanishing_poly::eval_vanishing_poly; use crate::vars::StarkEvaluationVars; -pub fn verify_proof, C: GenericConfig, const D: usize>( +pub fn verify_proof< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +>( all_stark: &AllStark, - all_proof: AllProof, + all_proof: AllProof, config: &StarkConfig, ) -> Result<()> where @@ -36,7 +43,8 @@ where [(); KeccakSpongeStark::::COLUMNS]:, [(); LogicStark::::COLUMNS]:, [(); MemoryStark::::COLUMNS]:, - [(); C::Hasher::HASH_SIZE]:, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let AllProofChallenges { stark_challenges, @@ -106,19 +114,21 @@ where pub(crate) fn verify_stark_proof_with_challenges< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, const D: usize, >( stark: &S, - proof: &StarkProof, + proof: &StarkProof, challenges: &StarkProofChallenges, ctl_vars: &[CtlCheckVars], config: &StarkConfig, ) -> Result<()> where [(); S::COLUMNS]:, - [(); C::Hasher::HASH_SIZE]:, + [(); HCO::WIDTH]:, { log::debug!("Checking proof: {}", type_name::()); validate_proof_shape(stark, proof, config, ctl_vars.len())?; @@ -189,7 +199,7 @@ where proof.quotient_polys_cap.clone(), ]; - verify_fri_proof::( + verify_fri_proof::( &stark.fri_instance( challenges.stark_zeta, F::primitive_root_of_unity(degree_bits), @@ -207,18 +217,19 @@ where Ok(()) } -fn validate_proof_shape( +fn validate_proof_shape( stark: &S, - proof: &StarkProof, + proof: &StarkProof, config: &StarkConfig, num_ctl_zs: usize, ) -> anyhow::Result<()> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, [(); S::COLUMNS]:, - [(); C::Hasher::HASH_SIZE]:, { let StarkProof { trace_cap, diff --git a/evm/tests/add11_yml.rs b/evm/tests/add11_yml.rs index e9ba979f..7b9fbc99 100644 --- a/evm/tests/add11_yml.rs +++ b/evm/tests/add11_yml.rs @@ -1,3 +1,5 @@ +#![allow(clippy::upper_case_acronyms)] + use std::collections::HashMap; use std::time::Duration; @@ -8,7 +10,7 @@ use ethereum_types::Address; use hex_literal::hex; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; -use plonky2::plonk::config::PoseidonGoldilocksConfig; +use plonky2::plonk::config::{PoseidonGoldilocksConfig, PoseidonHashConfig}; use plonky2::util::timing::TimingTree; use plonky2_evm::all_stark::AllStark; use plonky2_evm::config::StarkConfig; @@ -22,6 +24,8 @@ use plonky2_evm::Node; type F = GoldilocksField; const D: usize = 2; type C = PoseidonGoldilocksConfig; +type HCO = PoseidonHashConfig; +type HCI = HCO; /// The `add11_yml` test case from https://github.com/ethereum/tests #[test] @@ -96,7 +100,7 @@ fn add11_yml() -> anyhow::Result<()> { }; let mut timing = TimingTree::new("prove", log::Level::Debug); - let proof = prove::(&all_stark, &config, inputs, &mut timing)?; + let proof = prove::(&all_stark, &config, inputs, &mut timing)?; timing.filter(Duration::from_millis(100)).print(); let beneficiary_account_after = AccountRlp { diff --git a/evm/tests/basic_smart_contract.rs b/evm/tests/basic_smart_contract.rs index 8db237ec..0ced7334 100644 --- a/evm/tests/basic_smart_contract.rs +++ b/evm/tests/basic_smart_contract.rs @@ -1,3 +1,5 @@ +#![allow(clippy::upper_case_acronyms)] + use std::collections::HashMap; use std::time::Duration; @@ -8,7 +10,7 @@ use ethereum_types::{Address, U256}; use hex_literal::hex; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; -use plonky2::plonk::config::PoseidonGoldilocksConfig; +use plonky2::plonk::config::{PoseidonGoldilocksConfig, PoseidonHashConfig}; use plonky2::util::timing::TimingTree; use plonky2_evm::all_stark::AllStark; use plonky2_evm::config::StarkConfig; @@ -23,6 +25,8 @@ use plonky2_evm::Node; type F = GoldilocksField; const D: usize = 2; type C = PoseidonGoldilocksConfig; +type HCO = PoseidonHashConfig; +type HCI = HCO; /// Test a simple token transfer to a new address. #[test] @@ -110,7 +114,7 @@ fn test_basic_smart_contract() -> anyhow::Result<()> { }; let mut timing = TimingTree::new("prove", log::Level::Debug); - let proof = prove::(&all_stark, &config, inputs, &mut timing)?; + let proof = prove::(&all_stark, &config, inputs, &mut timing)?; timing.filter(Duration::from_millis(100)).print(); let expected_state_trie_after: HashedPartialTrie = { diff --git a/evm/tests/empty_txn_list.rs b/evm/tests/empty_txn_list.rs index 84f143bd..2adadc8a 100644 --- a/evm/tests/empty_txn_list.rs +++ b/evm/tests/empty_txn_list.rs @@ -1,3 +1,5 @@ +#![allow(clippy::upper_case_acronyms)] + use std::collections::HashMap; use std::time::Duration; @@ -5,7 +7,7 @@ use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; -use plonky2::plonk::config::PoseidonGoldilocksConfig; +use plonky2::plonk::config::{PoseidonGoldilocksConfig, PoseidonHashConfig}; use plonky2::util::timing::TimingTree; use plonky2_evm::all_stark::AllStark; use plonky2_evm::config::StarkConfig; @@ -19,6 +21,8 @@ use plonky2_evm::Node; type F = GoldilocksField; const D: usize = 2; type C = PoseidonGoldilocksConfig; +type HCO = PoseidonHashConfig; +type HCI = HCO; /// Execute the empty list of transactions, i.e. a no-op. #[test] @@ -60,7 +64,7 @@ fn test_empty_txn_list() -> anyhow::Result<()> { // TODO: This is redundant; prove_root below calls this prove method internally. // Just keeping it for now because the root proof returned by prove_root doesn't contain public // values yet, and we want those for the assertions below. - let proof = prove::(&all_stark, &config, inputs.clone(), &mut timing)?; + let proof = prove::(&all_stark, &config, inputs.clone(), &mut timing)?; timing.filter(Duration::from_millis(100)).print(); assert_eq!( @@ -90,7 +94,7 @@ fn test_empty_txn_list() -> anyhow::Result<()> { verify_proof(&all_stark, proof, &config)?; - let all_circuits = AllRecursiveCircuits::::new(&all_stark, 9..19, &config); + let all_circuits = AllRecursiveCircuits::::new(&all_stark, 9..19, &config); let root_proof = all_circuits.prove_root(&all_stark, &config, inputs, &mut timing)?; all_circuits.verify_root(root_proof.clone())?; diff --git a/evm/tests/simple_transfer.rs b/evm/tests/simple_transfer.rs index a4ef5361..fb1635d8 100644 --- a/evm/tests/simple_transfer.rs +++ b/evm/tests/simple_transfer.rs @@ -1,3 +1,5 @@ +#![allow(clippy::upper_case_acronyms)] + use std::collections::HashMap; use std::time::Duration; @@ -8,7 +10,7 @@ use ethereum_types::{Address, U256}; use hex_literal::hex; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; -use plonky2::plonk::config::PoseidonGoldilocksConfig; +use plonky2::plonk::config::{PoseidonGoldilocksConfig, PoseidonHashConfig}; use plonky2::util::timing::TimingTree; use plonky2_evm::all_stark::AllStark; use plonky2_evm::config::StarkConfig; @@ -22,6 +24,8 @@ use plonky2_evm::Node; type F = GoldilocksField; const D: usize = 2; type C = PoseidonGoldilocksConfig; +type HCO = PoseidonHashConfig; +type HCI = HCO; /// Test a simple token transfer to a new address. #[test] @@ -85,7 +89,7 @@ fn test_simple_transfer() -> anyhow::Result<()> { }; let mut timing = TimingTree::new("prove", log::Level::Debug); - let proof = prove::(&all_stark, &config, inputs, &mut timing)?; + let proof = prove::(&all_stark, &config, inputs, &mut timing)?; timing.filter(Duration::from_millis(100)).print(); let expected_state_trie_after: HashedPartialTrie = { diff --git a/plonky2/benches/hashing.rs b/plonky2/benches/hashing.rs index 485a6361..ef433112 100644 --- a/plonky2/benches/hashing.rs +++ b/plonky2/benches/hashing.rs @@ -4,17 +4,18 @@ use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; use plonky2::field::goldilocks_field::GoldilocksField; use plonky2::field::types::Sample; use plonky2::hash::hash_types::{BytesHash, RichField}; -use plonky2::hash::hashing::SPONGE_WIDTH; use plonky2::hash::keccak::KeccakHash; -use plonky2::hash::poseidon::Poseidon; -use plonky2::plonk::config::Hasher; +use plonky2::hash::poseidon::{Poseidon, SPONGE_WIDTH}; +use plonky2::plonk::config::{Hasher, KeccakHashConfig}; use tynm::type_name; pub(crate) fn bench_keccak(c: &mut Criterion) { c.bench_function("keccak256", |b| { b.iter_batched( || (BytesHash::<32>::rand(), BytesHash::<32>::rand()), - |(left, right)| as Hasher>::two_to_one(left, right), + |(left, right)| { + as Hasher>::two_to_one(left, right) + }, BatchSize::SmallInput, ) }); diff --git a/plonky2/benches/merkle.rs b/plonky2/benches/merkle.rs index f9bae127..11d73b8c 100644 --- a/plonky2/benches/merkle.rs +++ b/plonky2/benches/merkle.rs @@ -1,17 +1,23 @@ +#![feature(generic_const_exprs)] + mod allocator; use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; use plonky2::field::goldilocks_field::GoldilocksField; use plonky2::hash::hash_types::RichField; +use plonky2::hash::hashing::HashConfig; use plonky2::hash::keccak::KeccakHash; use plonky2::hash::merkle_tree::MerkleTree; use plonky2::hash::poseidon::PoseidonHash; -use plonky2::plonk::config::Hasher; +use plonky2::plonk::config::{Hasher, KeccakHashConfig, PoseidonHashConfig}; use tynm::type_name; const ELEMS_PER_LEAF: usize = 135; -pub(crate) fn bench_merkle_tree>(c: &mut Criterion) { +pub(crate) fn bench_merkle_tree>(c: &mut Criterion) +where + [(); HC::WIDTH]:, +{ let mut group = c.benchmark_group(&format!( "merkle-tree<{}, {}>", type_name::(), @@ -23,14 +29,14 @@ pub(crate) fn bench_merkle_tree>(c: &mut Criterion) { let size = 1 << size_log; group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, _| { let leaves = vec![F::rand_vec(ELEMS_PER_LEAF); size]; - b.iter(|| MerkleTree::::new(leaves.clone(), 0)); + b.iter(|| MerkleTree::::new(leaves.clone(), 0)); }); } } fn criterion_benchmark(c: &mut Criterion) { - bench_merkle_tree::(c); - bench_merkle_tree::>(c); + bench_merkle_tree::(c); + bench_merkle_tree::>(c); } criterion_group!(benches, criterion_benchmark); diff --git a/plonky2/examples/bench_recursion.rs b/plonky2/examples/bench_recursion.rs index 9b06b435..1afaf930 100644 --- a/plonky2/examples/bench_recursion.rs +++ b/plonky2/examples/bench_recursion.rs @@ -3,6 +3,9 @@ // put it in `src/bin/`, but then we wouldn't have access to // `[dev-dependencies]`. +#![feature(generic_const_exprs)] +#![allow(clippy::upper_case_acronyms)] + use core::num::ParseIntError; use core::ops::RangeInclusive; use core::str::FromStr; @@ -11,10 +14,13 @@ use anyhow::{anyhow, Context as _, Result}; use log::{info, Level, LevelFilter}; use plonky2::gates::noop::NoopGate; use plonky2::hash::hash_types::RichField; +use plonky2::hash::hashing::HashConfig; use plonky2::iop::witness::{PartialWitness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::{CircuitConfig, CommonCircuitData, VerifierOnlyCircuitData}; -use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, PoseidonGoldilocksConfig}; +use plonky2::plonk::config::{ + AlgebraicHasher, GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig, +}; use plonky2::plonk::proof::{CompressedProofWithPublicInputs, ProofWithPublicInputs}; use plonky2::plonk::prover::prove; use plonky2::util::timing::TimingTree; @@ -25,9 +31,9 @@ use rand::{RngCore, SeedableRng}; use rand_chacha::ChaCha8Rng; use structopt::StructOpt; -type ProofTuple = ( - ProofWithPublicInputs, - VerifierOnlyCircuitData, +type ProofTuple = ( + ProofWithPublicInputs, + VerifierOnlyCircuitData, CommonCircuitData, ); @@ -59,10 +65,20 @@ struct Options { } /// Creates a dummy proof which should have `2 ** log2_size` rows. -fn dummy_proof, C: GenericConfig, const D: usize>( +fn dummy_proof< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +>( config: &CircuitConfig, log2_size: usize, -) -> Result> { +) -> Result> +where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, +{ // 'size' is in degree, but we want number of noop gates. A non-zero amount of padding will be added and size will be rounded to the next power of two. To hit our target size, we go just under the previous power of two and hope padding is less than half the proof. let num_dummy_gates = match log2_size { 0 => return Err(anyhow!("size must be at least 1")), @@ -77,11 +93,11 @@ fn dummy_proof, C: GenericConfig, const D } builder.print_gate_counts(0); - let data = builder.build::(); + let data = builder.build::(); let inputs = PartialWitness::new(); let mut timing = TimingTree::new("prove", Level::Debug); - let proof = prove(&data.prover_only, &data.common, inputs, &mut timing)?; + let proof = prove::(&data.prover_only, &data.common, inputs, &mut timing)?; timing.print(); data.verify(proof.clone())?; @@ -90,16 +106,24 @@ fn dummy_proof, C: GenericConfig, const D fn recursive_proof< F: RichField + Extendable, - C: GenericConfig, - InnerC: GenericConfig, + HCOO: HashConfig, + HCOI: HashConfig, + HCIO: HashConfig, + HCII: HashConfig, + C: GenericConfig, + InnerC: GenericConfig, const D: usize, >( - inner: &ProofTuple, + inner: &ProofTuple, config: &CircuitConfig, min_degree_bits: Option, -) -> Result> +) -> Result> where - InnerC::Hasher: AlgebraicHasher, + InnerC::Hasher: AlgebraicHasher, + [(); HCOO::WIDTH]:, + [(); HCOI::WIDTH]:, + [(); HCIO::WIDTH]:, + [(); HCII::WIDTH]:, { let (inner_proof, inner_vd, inner_cd) = inner; let mut builder = CircuitBuilder::::new(config.clone()); @@ -107,7 +131,7 @@ where let inner_data = builder.add_virtual_verifier_data(inner_cd.config.fri_config.cap_height); - builder.verify_proof::(&pt, &inner_data, inner_cd); + builder.verify_proof::(&pt, &inner_data, inner_cd); builder.print_gate_counts(0); if let Some(min_degree_bits) = min_degree_bits { @@ -121,14 +145,14 @@ where } } - let data = builder.build::(); + let data = builder.build::(); let mut pw = PartialWitness::new(); pw.set_proof_with_pis_target(&pt, inner_proof); pw.set_verifier_data_target(&inner_data, inner_vd); let mut timing = TimingTree::new("prove", Level::Debug); - let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?; + let proof = prove::(&data.prover_only, &data.common, pw, &mut timing)?; timing.print(); data.verify(proof.clone())?; @@ -137,11 +161,21 @@ where } /// Test serialization and print some size info. -fn test_serialization, C: GenericConfig, const D: usize>( - proof: &ProofWithPublicInputs, - vd: &VerifierOnlyCircuitData, +fn test_serialization< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +>( + proof: &ProofWithPublicInputs, + vd: &VerifierOnlyCircuitData, cd: &CommonCircuitData, -) -> Result<()> { +) -> Result<()> +where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, +{ let proof_bytes = proof.to_bytes(); info!("Proof length: {} bytes", proof_bytes.len()); let proof_from_bytes = ProofWithPublicInputs::from_bytes(proof_bytes, cd)?; @@ -170,10 +204,12 @@ fn test_serialization, C: GenericConfig, fn benchmark(config: &CircuitConfig, log2_inner_size: usize) -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; // Start with a dummy proof of specified size - let inner = dummy_proof::(config, log2_inner_size)?; + let inner = dummy_proof::(config, log2_inner_size)?; let (_, _, cd) = &inner; info!( "Initial proof degree {} = 2^{}", @@ -182,7 +218,7 @@ fn benchmark(config: &CircuitConfig, log2_inner_size: usize) -> Result<()> { ); // Recursively verify the proof - let middle = recursive_proof::(&inner, config, None)?; + let middle = recursive_proof::(&inner, config, None)?; let (_, _, cd) = &middle; info!( "Single recursion proof degree {} = 2^{}", @@ -191,7 +227,7 @@ fn benchmark(config: &CircuitConfig, log2_inner_size: usize) -> Result<()> { ); // Add a second layer of recursion to shrink the proof size further - let outer = recursive_proof::(&middle, config, None)?; + let outer = recursive_proof::(&middle, config, None)?; let (proof, vd, cd) = &outer; info!( "Double recursion proof degree {} = 2^{}", diff --git a/plonky2/examples/factorial.rs b/plonky2/examples/factorial.rs index 019a7aa5..cde1d0d7 100644 --- a/plonky2/examples/factorial.rs +++ b/plonky2/examples/factorial.rs @@ -1,9 +1,11 @@ +#![allow(clippy::upper_case_acronyms)] + use anyhow::Result; use plonky2::field::types::Field; use plonky2::iop::witness::{PartialWitness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; -use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; +use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; /// An example of using Plonky2 to prove a statement of the form /// "I know n * (n + 1) * ... * (n + 99)". @@ -11,7 +13,9 @@ use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; fn main() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); @@ -31,7 +35,7 @@ fn main() -> Result<()> { let mut pw = PartialWitness::new(); pw.set_target(initial, F::ONE); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; println!( diff --git a/plonky2/examples/fibonacci.rs b/plonky2/examples/fibonacci.rs index 28403862..cc7ffd05 100644 --- a/plonky2/examples/fibonacci.rs +++ b/plonky2/examples/fibonacci.rs @@ -1,9 +1,11 @@ +#![allow(clippy::upper_case_acronyms)] + use anyhow::Result; use plonky2::field::types::Field; use plonky2::iop::witness::{PartialWitness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; -use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; +use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; /// An example of using Plonky2 to prove a statement of the form /// "I know the 100th element of the Fibonacci sequence, starting with constants a and b." @@ -11,7 +13,9 @@ use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; fn main() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); @@ -37,7 +41,7 @@ fn main() -> Result<()> { pw.set_target(initial_a, F::ZERO); pw.set_target(initial_b, F::ONE); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; println!( diff --git a/plonky2/examples/square_root.rs b/plonky2/examples/square_root.rs index b20eecc5..d26ef8b4 100644 --- a/plonky2/examples/square_root.rs +++ b/plonky2/examples/square_root.rs @@ -1,3 +1,5 @@ +#![allow(clippy::upper_case_acronyms)] + use core::marker::PhantomData; use anyhow::Result; @@ -8,7 +10,7 @@ use plonky2::iop::target::Target; use plonky2::iop::witness::{PartialWitness, PartitionWitness, Witness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; -use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; +use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; use plonky2_field::extension::Extendable; /// A generator used by the prover to calculate the square root (`x`) of a given value @@ -42,7 +44,9 @@ impl, const D: usize> SimpleGenerator fn main() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); @@ -71,7 +75,7 @@ fn main() -> Result<()> { let mut pw = PartialWitness::new(); pw.set_target(x_squared, x_squared_value); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw.clone())?; let x_squared_actual = proof.public_inputs[0]; diff --git a/plonky2/src/fri/challenges.rs b/plonky2/src/fri/challenges.rs index 41b00a7e..23c0d1c4 100644 --- a/plonky2/src/fri/challenges.rs +++ b/plonky2/src/fri/challenges.rs @@ -5,25 +5,30 @@ use crate::fri::structure::{FriOpenings, FriOpeningsTarget}; use crate::fri::FriConfig; use crate::gadgets::polynomial::PolynomialCoeffsExtTarget; use crate::hash::hash_types::{MerkleCapTarget, RichField}; +use crate::hash::hashing::HashConfig; use crate::hash::merkle_tree::MerkleCap; use crate::iop::challenger::{Challenger, RecursiveChallenger}; use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::config::{AlgebraicHasher, GenericConfig, Hasher}; -impl> Challenger { +impl> Challenger +where + [(); HCO::WIDTH]:, +{ pub fn observe_openings(&mut self, openings: &FriOpenings) where F: RichField + Extendable, + [(); HCO::WIDTH]:, { for v in &openings.batches { self.observe_extension_elements(&v.values); } } - pub fn fri_challenges, const D: usize>( + pub fn fri_challenges, const D: usize>( &mut self, - commit_phase_merkle_caps: &[MerkleCap], + commit_phase_merkle_caps: &[MerkleCap], final_poly: &PolynomialCoeffs, pow_witness: F, degree_bits: usize, @@ -31,6 +36,8 @@ impl> Challenger { ) -> FriChallenges where F: RichField + Extendable, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let num_fri_queries = config.num_query_rounds; let lde_size = 1 << (degree_bits + config.rate_bits); @@ -41,7 +48,7 @@ impl> Challenger { let fri_betas = commit_phase_merkle_caps .iter() .map(|cap| { - self.observe_cap(cap); + self.observe_cap::(cap); self.get_extension_challenge::() }) .collect(); @@ -64,10 +71,15 @@ impl> Challenger { } } -impl, H: AlgebraicHasher, const D: usize> - RecursiveChallenger +impl, HCO: HashConfig, H: AlgebraicHasher, const D: usize> + RecursiveChallenger +where + [(); HCO::WIDTH]:, { - pub fn observe_openings(&mut self, openings: &FriOpeningsTarget) { + pub fn observe_openings(&mut self, openings: &FriOpeningsTarget) + where + [(); HCO::WIDTH]:, + { for v in &openings.batches { self.observe_extension_elements(&v.values); } diff --git a/plonky2/src/fri/oracle.rs b/plonky2/src/fri/oracle.rs index cddcf048..eed0a449 100644 --- a/plonky2/src/fri/oracle.rs +++ b/plonky2/src/fri/oracle.rs @@ -14,6 +14,7 @@ use crate::fri::prover::fri_proof; use crate::fri::structure::{FriBatchInfo, FriInstanceInfo}; use crate::fri::FriParams; use crate::hash::hash_types::RichField; +use crate::hash::hashing::HashConfig; use crate::hash::merkle_tree::MerkleTree; use crate::iop::challenger::Challenger; use crate::plonk::config::GenericConfig; @@ -26,17 +27,27 @@ use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place, transp pub const SALT_SIZE: usize = 4; /// Represents a FRI oracle, i.e. a batch of polynomials which have been Merklized. -pub struct PolynomialBatch, C: GenericConfig, const D: usize> -{ +pub struct PolynomialBatch< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +> { pub polynomials: Vec>, - pub merkle_tree: MerkleTree, + pub merkle_tree: MerkleTree, pub degree_log: usize, pub rate_bits: usize, pub blinding: bool, } -impl, C: GenericConfig, const D: usize> - PolynomialBatch +impl< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + > PolynomialBatch { /// Creates a list polynomial commitment for the polynomials interpolating the values in `values`. pub fn from_values( @@ -46,7 +57,10 @@ impl, C: GenericConfig, const D: usize> cap_height: usize, timing: &mut TimingTree, fft_root_table: Option<&FftRootTable>, - ) -> Self { + ) -> Self + where + [(); HCO::WIDTH]:, + { let coeffs = timed!( timing, "IFFT", @@ -71,7 +85,10 @@ impl, C: GenericConfig, const D: usize> cap_height: usize, timing: &mut TimingTree, fft_root_table: Option<&FftRootTable>, - ) -> Self { + ) -> Self + where + [(); HCO::WIDTH]:, + { let degree = polynomials[0].len(); let lde_values = timed!( timing, @@ -161,10 +178,14 @@ impl, C: GenericConfig, const D: usize> pub fn prove_openings( instance: &FriInstanceInfo, oracles: &[&Self], - challenger: &mut Challenger, + challenger: &mut Challenger, fri_params: &FriParams, timing: &mut TimingTree, - ) -> FriProof { + ) -> FriProof + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { assert!(D > 1, "Not implemented for D=1."); let alpha = challenger.get_extension_challenge::(); let mut alpha = ReducingFactor::new(alpha); @@ -202,7 +223,7 @@ impl, C: GenericConfig, const D: usize> lde_final_poly.coset_fft(F::coset_shift().into()) ); - let fri_proof = fri_proof::( + let fri_proof = fri_proof::( &oracles .par_iter() .map(|c| &c.merkle_tree) diff --git a/plonky2/src/fri/proof.rs b/plonky2/src/fri/proof.rs index 0e0d7df3..cf1a60d1 100644 --- a/plonky2/src/fri/proof.rs +++ b/plonky2/src/fri/proof.rs @@ -10,6 +10,7 @@ use crate::field::polynomial::PolynomialCoeffs; use crate::fri::FriParams; use crate::gadgets::polynomial::PolynomialCoeffsExtTarget; use crate::hash::hash_types::{MerkleCapTarget, RichField}; +use crate::hash::hashing::HashConfig; use crate::hash::merkle_proofs::{MerkleProof, MerkleProofTarget}; use crate::hash::merkle_tree::MerkleCap; use crate::hash::path_compression::{compress_merkle_proofs, decompress_merkle_proofs}; @@ -22,9 +23,14 @@ use crate::plonk::proof::{FriInferredElements, ProofChallenges}; /// Evaluations and Merkle proof produced by the prover in a FRI query step. #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct FriQueryStep, H: Hasher, const D: usize> { +pub struct FriQueryStep< + F: RichField + Extendable, + HC: HashConfig, + H: Hasher, + const D: usize, +> { pub evals: Vec, - pub merkle_proof: MerkleProof, + pub merkle_proof: MerkleProof, } #[derive(Clone, Debug)] @@ -37,11 +43,11 @@ pub struct FriQueryStepTarget { /// before they are combined into a composition polynomial. #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct FriInitialTreeProof> { - pub evals_proofs: Vec<(Vec, MerkleProof)>, +pub struct FriInitialTreeProof> { + pub evals_proofs: Vec<(Vec, MerkleProof)>, } -impl> FriInitialTreeProof { +impl> FriInitialTreeProof { pub(crate) fn unsalted_eval(&self, oracle_index: usize, poly_index: usize, salted: bool) -> F { self.unsalted_evals(oracle_index, salted)[poly_index] } @@ -76,9 +82,14 @@ impl FriInitialTreeProofTarget { /// Proof for a FRI query round. #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct FriQueryRound, H: Hasher, const D: usize> { - pub initial_trees_proof: FriInitialTreeProof, - pub steps: Vec>, +pub struct FriQueryRound< + F: RichField + Extendable, + HC: HashConfig, + H: Hasher, + const D: usize, +> { + pub initial_trees_proof: FriInitialTreeProof, + pub steps: Vec>, } #[derive(Clone, Debug)] @@ -90,22 +101,28 @@ pub struct FriQueryRoundTarget { /// Compressed proof of the FRI query rounds. #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct CompressedFriQueryRounds, H: Hasher, const D: usize> { +pub struct CompressedFriQueryRounds< + F: RichField + Extendable, + HC: HashConfig, + H: Hasher, + const D: usize, +> { /// Query indices. pub indices: Vec, /// Map from initial indices `i` to the `FriInitialProof` for the `i`th leaf. - pub initial_trees_proofs: HashMap>, + pub initial_trees_proofs: HashMap>, /// For each FRI query step, a map from indices `i` to the `FriQueryStep` for the `i`th leaf. - pub steps: Vec>>, + pub steps: Vec>>, } #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct FriProof, H: Hasher, const D: usize> { +pub struct FriProof, HC: HashConfig, H: Hasher, const D: usize> +{ /// A Merkle cap for each reduced polynomial in the commit phase. - pub commit_phase_merkle_caps: Vec>, + pub commit_phase_merkle_caps: Vec>, /// Query rounds proofs - pub query_round_proofs: Vec>, + pub query_round_proofs: Vec>, /// The final polynomial in coefficient form. pub final_poly: PolynomialCoeffs, /// Witness showing that the prover did PoW. @@ -122,20 +139,31 @@ pub struct FriProofTarget { #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct CompressedFriProof, H: Hasher, const D: usize> { +pub struct CompressedFriProof< + F: RichField + Extendable, + HC: HashConfig, + H: Hasher, + const D: usize, +> { /// A Merkle cap for each reduced polynomial in the commit phase. - pub commit_phase_merkle_caps: Vec>, + pub commit_phase_merkle_caps: Vec>, /// Compressed query rounds proof. - pub query_round_proofs: CompressedFriQueryRounds, + pub query_round_proofs: CompressedFriQueryRounds, /// The final polynomial in coefficient form. pub final_poly: PolynomialCoeffs, /// Witness showing that the prover did PoW. pub pow_witness: F, } -impl, H: Hasher, const D: usize> FriProof { +impl, HCO: HashConfig, H: Hasher, const D: usize> + FriProof +{ /// Compress all the Merkle paths in the FRI proof and remove duplicate indices. - pub fn compress(self, indices: &[usize], params: &FriParams) -> CompressedFriProof { + pub fn compress( + self, + indices: &[usize], + params: &FriParams, + ) -> CompressedFriProof { let FriProof { commit_phase_merkle_caps, query_round_proofs, @@ -235,14 +263,19 @@ impl, H: Hasher, const D: usize> FriProof, H: Hasher, const D: usize> CompressedFriProof { +impl, HCO: HashConfig, H: Hasher, const D: usize> + CompressedFriProof +{ /// Decompress all the Merkle paths in the FRI proof and reinsert duplicate indices. pub(crate) fn decompress( self, challenges: &ProofChallenges, fri_inferred_elements: FriInferredElements, params: &FriParams, - ) -> FriProof { + ) -> FriProof + where + [(); HCO::WIDTH]:, + { let CompressedFriProof { commit_phase_merkle_caps, query_round_proofs, diff --git a/plonky2/src/fri/prover.rs b/plonky2/src/fri/prover.rs index 9e933528..a2a27c18 100644 --- a/plonky2/src/fri/prover.rs +++ b/plonky2/src/fri/prover.rs @@ -7,7 +7,7 @@ use crate::field::polynomial::{PolynomialCoeffs, PolynomialValues}; use crate::fri::proof::{FriInitialTreeProof, FriProof, FriQueryRound, FriQueryStep}; use crate::fri::{FriConfig, FriParams}; use crate::hash::hash_types::RichField; -use crate::hash::hashing::{PlonkyPermutation, SPONGE_RATE}; +use crate::hash::hashing::{HashConfig, PlonkyPermutation}; use crate::hash::merkle_tree::MerkleTree; use crate::iop::challenger::Challenger; use crate::plonk::config::{GenericConfig, Hasher}; @@ -17,16 +17,26 @@ use crate::util::reverse_index_bits_in_place; use crate::util::timing::TimingTree; /// Builds a FRI proof. -pub fn fri_proof, C: GenericConfig, const D: usize>( - initial_merkle_trees: &[&MerkleTree], +pub fn fri_proof< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +>( + initial_merkle_trees: &[&MerkleTree], // Coefficients of the polynomial on which the LDT is performed. Only the first `1/rate` coefficients are non-zero. lde_polynomial_coeffs: PolynomialCoeffs, // Evaluation of the polynomial on the large domain. lde_polynomial_values: PolynomialValues, - challenger: &mut Challenger, + challenger: &mut Challenger, fri_params: &FriParams, timing: &mut TimingTree, -) -> FriProof { +) -> FriProof +where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, +{ let n = lde_polynomial_values.len(); assert_eq!(lde_polynomial_coeffs.len(), n); @@ -34,7 +44,7 @@ pub fn fri_proof, C: GenericConfig, const let (trees, final_coeffs) = timed!( timing, "fold codewords in the commitment phase", - fri_committed_trees::( + fri_committed_trees::( lde_polynomial_coeffs, lde_polynomial_values, challenger, @@ -46,12 +56,17 @@ pub fn fri_proof, C: GenericConfig, const let pow_witness = timed!( timing, "find proof-of-work witness", - fri_proof_of_work::(challenger, &fri_params.config) + fri_proof_of_work::(challenger, &fri_params.config) ); // Query phase - let query_round_proofs = - fri_prover_query_rounds::(initial_merkle_trees, &trees, challenger, n, fri_params); + let query_round_proofs = fri_prover_query_rounds::( + initial_merkle_trees, + &trees, + challenger, + n, + fri_params, + ); FriProof { commit_phase_merkle_caps: trees.iter().map(|t| t.cap.clone()).collect(), @@ -61,17 +76,26 @@ pub fn fri_proof, C: GenericConfig, const } } -type FriCommitedTrees = ( - Vec>::Hasher>>, +type FriCommitedTrees = ( + Vec>::Hasher>>, PolynomialCoeffs<>::Extension>, ); -fn fri_committed_trees, C: GenericConfig, const D: usize>( +fn fri_committed_trees< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +>( mut coeffs: PolynomialCoeffs, mut values: PolynomialValues, - challenger: &mut Challenger, + challenger: &mut Challenger, fri_params: &FriParams, -) -> FriCommitedTrees { +) -> FriCommitedTrees +where + [(); HCO::WIDTH]:, +{ let mut trees = Vec::new(); let mut shift = F::MULTIPLICATIVE_GROUP_GENERATOR; @@ -84,7 +108,8 @@ fn fri_committed_trees, C: GenericConfig, .par_chunks(arity) .map(|chunk: &[F::Extension]| flatten(chunk)) .collect(); - let tree = MerkleTree::::new(chunked_values, fri_params.config.cap_height); + let tree = + MerkleTree::::new(chunked_values, fri_params.config.cap_height); challenger.observe_cap(&tree.cap); trees.push(tree); @@ -112,10 +137,20 @@ fn fri_committed_trees, C: GenericConfig, } /// Performs the proof-of-work (a.k.a. grinding) step of the FRI protocol. Returns the PoW witness. -fn fri_proof_of_work, C: GenericConfig, const D: usize>( - challenger: &mut Challenger, +fn fri_proof_of_work< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +>( + challenger: &mut Challenger, config: &FriConfig, -) -> F { +) -> F +where + [(); HCI::WIDTH]:, + [(); HCO::WIDTH]:, +{ let min_leading_zeros = config.proof_of_work_bits + (64 - F::order().bits()) as u32; // The easiest implementation would be repeatedly clone our Challenger. With each clone, we'd @@ -126,7 +161,7 @@ fn fri_proof_of_work, C: GenericConfig, c // since it stores vectors, which means allocations. We'd like a more compact state to clone. // // We know that a duplex will be performed right after we send the PoW witness, so we can ignore - // any output_buffer, which will be invalidated. We also know input_buffer.len() < SPONGE_WIDTH, + // any output_buffer, which will be invalidated. We also know input_buffer.len() < HCO::WIDTH, // an invariant of Challenger. // // We separate the duplex operation into two steps, one which can be performed now, and the @@ -146,8 +181,10 @@ fn fri_proof_of_work, C: GenericConfig, c let mut duplex_state = duplex_intermediate_state; duplex_state[witness_input_pos] = F::from_canonical_u64(candidate); duplex_state = - <>::Hasher as Hasher>::Permutation::permute(duplex_state); - let pow_response = duplex_state[SPONGE_RATE - 1]; + <>::Hasher as Hasher>::Permutation::permute( + duplex_state, + ); + let pow_response = duplex_state[HCO::RATE - 1]; let leading_zeros = pow_response.to_canonical_u64().leading_zeros(); leading_zeros >= min_leading_zeros }) @@ -164,35 +201,50 @@ fn fri_proof_of_work, C: GenericConfig, c fn fri_prover_query_rounds< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, >( - initial_merkle_trees: &[&MerkleTree], - trees: &[MerkleTree], - challenger: &mut Challenger, + initial_merkle_trees: &[&MerkleTree], + trees: &[MerkleTree], + challenger: &mut Challenger, n: usize, fri_params: &FriParams, -) -> Vec> { +) -> Vec> +where + [(); HCO::WIDTH]:, +{ challenger .get_n_challenges(fri_params.config.num_query_rounds) .into_par_iter() .map(|rand| { let x_index = rand.to_canonical_u64() as usize % n; - fri_prover_query_round::(initial_merkle_trees, trees, x_index, fri_params) + fri_prover_query_round::( + initial_merkle_trees, + trees, + x_index, + fri_params, + ) }) .collect() } fn fri_prover_query_round< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, >( - initial_merkle_trees: &[&MerkleTree], - trees: &[MerkleTree], + initial_merkle_trees: &[&MerkleTree], + trees: &[MerkleTree], mut x_index: usize, fri_params: &FriParams, -) -> FriQueryRound { +) -> FriQueryRound +where + [(); HCO::WIDTH]:, +{ let mut query_steps = Vec::new(); let initial_proof = initial_merkle_trees .iter() diff --git a/plonky2/src/fri/recursive_verifier.rs b/plonky2/src/fri/recursive_verifier.rs index 8e9329d5..033eeb30 100644 --- a/plonky2/src/fri/recursive_verifier.rs +++ b/plonky2/src/fri/recursive_verifier.rs @@ -14,6 +14,7 @@ use crate::gates::coset_interpolation::CosetInterpolationGate; use crate::gates::gate::Gate; use crate::gates::random_access::RandomAccessGate; use crate::hash::hash_types::{MerkleCapTarget, RichField}; +use crate::hash::hashing::HashConfig; use crate::iop::ext_target::{flatten_target, ExtensionTarget}; use crate::iop::target::{BoolTarget, Target}; use crate::plonk::circuit_builder::CircuitBuilder; @@ -98,7 +99,11 @@ impl, const D: usize> CircuitBuilder { ); } - pub fn verify_fri_proof>( + pub fn verify_fri_proof< + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + >( &mut self, instance: &FriInstanceInfoTarget, openings: &FriOpeningsTarget, @@ -107,7 +112,8 @@ impl, const D: usize> CircuitBuilder { proof: &FriProofTarget, params: &FriParams, ) where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, { if let Some(max_arity_bits) = params.max_arity_bits() { self.check_recursion_config(max_arity_bits); @@ -160,7 +166,7 @@ impl, const D: usize> CircuitBuilder { self, level, &format!("verify one (of {num_queries}) query rounds"), - self.fri_verifier_query_round::( + self.fri_verifier_query_round::( instance, challenges, &precomputed_reduced_evals, @@ -175,13 +181,15 @@ impl, const D: usize> CircuitBuilder { } } - fn fri_verify_initial_proof>( + fn fri_verify_initial_proof>( &mut self, x_index_bits: &[BoolTarget], proof: &FriInitialTreeProofTarget, initial_merkle_caps: &[MerkleCapTarget], cap_index: Target, - ) { + ) where + [(); HC::WIDTH]:, + { for (i, ((evals, merkle_proof), cap)) in proof .evals_proofs .iter() @@ -191,7 +199,7 @@ impl, const D: usize> CircuitBuilder { with_context!( self, &format!("verify {i}'th initial Merkle proof"), - self.verify_merkle_proof_to_cap_with_cap_index::( + self.verify_merkle_proof_to_cap_with_cap_index::( evals.clone(), x_index_bits, cap_index, @@ -246,7 +254,11 @@ impl, const D: usize> CircuitBuilder { sum } - fn fri_verifier_query_round>( + fn fri_verifier_query_round< + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + >( &mut self, instance: &FriInstanceInfoTarget, challenges: &FriChallengesTarget, @@ -258,7 +270,8 @@ impl, const D: usize> CircuitBuilder { round_proof: &FriQueryRoundTarget, params: &FriParams, ) where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, { let n_log = log2_strict(n); @@ -272,7 +285,7 @@ impl, const D: usize> CircuitBuilder { with_context!( self, "check FRI initial proof", - self.fri_verify_initial_proof::( + self.fri_verify_initial_proof::( &x_index_bits, &round_proof.initial_trees_proof, initial_merkle_caps, @@ -332,7 +345,7 @@ impl, const D: usize> CircuitBuilder { with_context!( self, "verify FRI round Merkle proof.", - self.verify_merkle_proof_to_cap_with_cap_index::( + self.verify_merkle_proof_to_cap_with_cap_index::( flatten_target(evals), &coset_index_bits, cap_index, diff --git a/plonky2/src/fri/validate_shape.rs b/plonky2/src/fri/validate_shape.rs index 526da8f7..e15a2c75 100644 --- a/plonky2/src/fri/validate_shape.rs +++ b/plonky2/src/fri/validate_shape.rs @@ -5,17 +5,20 @@ use crate::fri::proof::{FriProof, FriQueryRound, FriQueryStep}; use crate::fri::structure::FriInstanceInfo; use crate::fri::FriParams; use crate::hash::hash_types::RichField; +use crate::hash::hashing::HashConfig; use crate::plonk::config::GenericConfig; use crate::plonk::plonk_common::salt_size; -pub(crate) fn validate_fri_proof_shape( - proof: &FriProof, +pub(crate) fn validate_fri_proof_shape( + proof: &FriProof, instance: &FriInstanceInfo, params: &FriParams, ) -> anyhow::Result<()> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { let FriProof { commit_phase_merkle_caps, diff --git a/plonky2/src/fri/verifier.rs b/plonky2/src/fri/verifier.rs index f860ba30..e37866e8 100644 --- a/plonky2/src/fri/verifier.rs +++ b/plonky2/src/fri/verifier.rs @@ -10,6 +10,7 @@ use crate::fri::structure::{FriBatchInfo, FriInstanceInfo, FriOpenings}; use crate::fri::validate_shape::validate_fri_proof_shape; use crate::fri::{FriConfig, FriParams}; use crate::hash::hash_types::RichField; +use crate::hash::hashing::HashConfig; use crate::hash::merkle_proofs::verify_merkle_proof_to_cap; use crate::hash::merkle_tree::MerkleCap; use crate::plonk::config::{GenericConfig, Hasher}; @@ -60,17 +61,22 @@ pub(crate) fn fri_verify_proof_of_work, const D: us pub fn verify_fri_proof< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, >( instance: &FriInstanceInfo, openings: &FriOpenings, challenges: &FriChallenges, - initial_merkle_caps: &[MerkleCap], - proof: &FriProof, + initial_merkle_caps: &[MerkleCap], + proof: &FriProof, params: &FriParams, -) -> Result<()> { - validate_fri_proof_shape::(proof, instance, params)?; +) -> Result<()> +where + [(); HCO::WIDTH]:, +{ + validate_fri_proof_shape::(proof, instance, params)?; // Size of the LDE domain. let n = params.lde_size(); @@ -91,7 +97,7 @@ pub fn verify_fri_proof< .iter() .zip(&proof.query_round_proofs) { - fri_verifier_query_round::( + fri_verifier_query_round::( instance, challenges, &precomputed_reduced_evals, @@ -107,13 +113,16 @@ pub fn verify_fri_proof< Ok(()) } -fn fri_verify_initial_proof>( +fn fri_verify_initial_proof>( x_index: usize, - proof: &FriInitialTreeProof, - initial_merkle_caps: &[MerkleCap], -) -> Result<()> { + proof: &FriInitialTreeProof, + initial_merkle_caps: &[MerkleCap], +) -> Result<()> +where + [(); HC::WIDTH]:, +{ for ((evals, merkle_proof), cap) in proof.evals_proofs.iter().zip(initial_merkle_caps) { - verify_merkle_proof_to_cap::(evals.clone(), x_index, cap, merkle_proof)?; + verify_merkle_proof_to_cap::(evals.clone(), x_index, cap, merkle_proof)?; } Ok(()) @@ -121,11 +130,13 @@ fn fri_verify_initial_proof>( pub(crate) fn fri_combine_initial< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, >( instance: &FriInstanceInfo, - proof: &FriInitialTreeProof, + proof: &FriInitialTreeProof, alpha: F::Extension, subgroup_x: F, precomputed_reduced_evals: &PrecomputedReducedOpenings, @@ -162,20 +173,25 @@ pub(crate) fn fri_combine_initial< fn fri_verifier_query_round< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, >( instance: &FriInstanceInfo, challenges: &FriChallenges, precomputed_reduced_evals: &PrecomputedReducedOpenings, - initial_merkle_caps: &[MerkleCap], - proof: &FriProof, + initial_merkle_caps: &[MerkleCap], + proof: &FriProof, mut x_index: usize, n: usize, - round_proof: &FriQueryRound, + round_proof: &FriQueryRound, params: &FriParams, -) -> Result<()> { - fri_verify_initial_proof::( +) -> Result<()> +where + [(); HCO::WIDTH]:, +{ + fri_verify_initial_proof::( x_index, &round_proof.initial_trees_proof, initial_merkle_caps, @@ -187,7 +203,7 @@ fn fri_verifier_query_round< // old_eval is the last derived evaluation; it will be checked for consistency with its // committed "parent" value in the next iteration. - let mut old_eval = fri_combine_initial::( + let mut old_eval = fri_combine_initial::( instance, &round_proof.initial_trees_proof, challenges.fri_alpha, @@ -216,7 +232,7 @@ fn fri_verifier_query_round< challenges.fri_betas[i], ); - verify_merkle_proof_to_cap::( + verify_merkle_proof_to_cap::( flatten(evals), coset_index, &proof.commit_phase_merkle_caps[i], diff --git a/plonky2/src/fri/witness_util.rs b/plonky2/src/fri/witness_util.rs index ce47e7cb..67ab8f24 100644 --- a/plonky2/src/fri/witness_util.rs +++ b/plonky2/src/fri/witness_util.rs @@ -3,18 +3,20 @@ use itertools::Itertools; use crate::field::extension::Extendable; use crate::fri::proof::{FriProof, FriProofTarget}; use crate::hash::hash_types::RichField; +use crate::hash::hashing::HashConfig; use crate::iop::witness::WitnessWrite; use crate::plonk::config::AlgebraicHasher; /// Set the targets in a `FriProofTarget` to their corresponding values in a `FriProof`. -pub fn set_fri_proof_target( +pub fn set_fri_proof_target( witness: &mut W, fri_proof_target: &FriProofTarget, - fri_proof: &FriProof, + fri_proof: &FriProof, ) where F: RichField + Extendable, W: WitnessWrite + ?Sized, - H: AlgebraicHasher, + HC: HashConfig, + H: AlgebraicHasher, { witness.set_target(fri_proof_target.pow_witness, fri_proof.pow_witness); diff --git a/plonky2/src/gadgets/arithmetic_extension.rs b/plonky2/src/gadgets/arithmetic_extension.rs index 6fcab718..c3ded869 100644 --- a/plonky2/src/gadgets/arithmetic_extension.rs +++ b/plonky2/src/gadgets/arithmetic_extension.rs @@ -576,15 +576,20 @@ mod tests { use crate::iop::witness::{PartialWitness, WitnessWrite}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, KeccakGoldilocksConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{ + GenericConfig, KeccakGoldilocksConfig, KeccakHashConfig, PoseidonGoldilocksConfig, + PoseidonHashConfig, + }; use crate::plonk::verifier::verify; #[test] fn test_mul_many() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - type FF = >::FE; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); @@ -609,7 +614,7 @@ mod tests { builder.connect_extension(mul0, mul1); builder.connect_extension(mul1, mul2); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) @@ -619,8 +624,10 @@ mod tests { fn test_div_extension() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - type FF = >::FE; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_zk_config(); @@ -636,7 +643,7 @@ mod tests { let comp_zt = builder.div_extension(xt, yt); builder.connect_extension(zt, comp_zt); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) @@ -646,8 +653,10 @@ mod tests { fn test_mul_algebra() -> Result<()> { const D: usize = 2; type C = KeccakGoldilocksConfig; - type F = >::F; - type FF = >::FE; + type HCO = KeccakHashConfig; + type HCI = PoseidonHashConfig; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); @@ -674,7 +683,7 @@ mod tests { pw.set_extension_target(zt.0[i], z.0[i]); } - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/plonky2/src/gadgets/hash.rs b/plonky2/src/gadgets/hash.rs index 2b8bfac5..5386f3f5 100644 --- a/plonky2/src/gadgets/hash.rs +++ b/plonky2/src/gadgets/hash.rs @@ -1,27 +1,27 @@ use crate::field::extension::Extendable; use crate::hash::hash_types::RichField; -use crate::hash::hashing::SPONGE_WIDTH; +use crate::hash::hashing::HashConfig; use crate::iop::target::{BoolTarget, Target}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::config::AlgebraicHasher; impl, const D: usize> CircuitBuilder { - pub fn permute>( + pub fn permute>( &mut self, - inputs: [Target; SPONGE_WIDTH], - ) -> [Target; SPONGE_WIDTH] { + inputs: [Target; HC::WIDTH], + ) -> [Target; HC::WIDTH] { // We don't want to swap any inputs, so set that wire to 0. let _false = self._false(); - self.permute_swapped::(inputs, _false) + self.permute_swapped::(inputs, _false) } /// Conditionally swap two chunks of the inputs (useful in verifying Merkle proofs), then apply /// a cryptographic permutation. - pub(crate) fn permute_swapped>( + pub(crate) fn permute_swapped>( &mut self, - inputs: [Target; SPONGE_WIDTH], + inputs: [Target; HC::WIDTH], swap: BoolTarget, - ) -> [Target; SPONGE_WIDTH] { + ) -> [Target; HC::WIDTH] { H::permute_swapped(inputs, swap, self) } } diff --git a/plonky2/src/gadgets/interpolation.rs b/plonky2/src/gadgets/interpolation.rs index daf51d21..d31e7393 100644 --- a/plonky2/src/gadgets/interpolation.rs +++ b/plonky2/src/gadgets/interpolation.rs @@ -47,15 +47,17 @@ mod tests { use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; use crate::plonk::verifier::verify; #[test] fn test_interpolate() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - type FF = >::FE; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); let mut builder = CircuitBuilder::::new(config); @@ -102,7 +104,7 @@ mod tests { builder.connect_extension(eval_coset_gate, true_eval_target); } - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/plonky2/src/gadgets/random_access.rs b/plonky2/src/gadgets/random_access.rs index 85d2c714..39e8af87 100644 --- a/plonky2/src/gadgets/random_access.rs +++ b/plonky2/src/gadgets/random_access.rs @@ -107,14 +107,16 @@ mod tests { use crate::field::types::{Field, Sample}; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; use crate::plonk::verifier::verify; fn test_random_access_given_len(len_log: usize) -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - type FF = >::FE; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + type FF = >::FE; let len = 1 << len_log; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); @@ -129,7 +131,7 @@ mod tests { builder.connect_extension(elem, res); } - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/plonky2/src/gadgets/select.rs b/plonky2/src/gadgets/select.rs index b34092ed..7526fe9a 100644 --- a/plonky2/src/gadgets/select.rs +++ b/plonky2/src/gadgets/select.rs @@ -44,15 +44,17 @@ mod tests { use crate::iop::witness::{PartialWitness, WitnessWrite}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; use crate::plonk::verifier::verify; #[test] fn test_select() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - type FF = >::FE; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); let mut pw = PartialWitness::::new(); let mut builder = CircuitBuilder::::new(config); @@ -72,7 +74,7 @@ mod tests { builder.connect_extension(should_be_x, xt); builder.connect_extension(should_be_y, yt); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/plonky2/src/gadgets/split_base.rs b/plonky2/src/gadgets/split_base.rs index dd0edf5d..fa073fae 100644 --- a/plonky2/src/gadgets/split_base.rs +++ b/plonky2/src/gadgets/split_base.rs @@ -113,14 +113,16 @@ mod tests { use super::*; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; use crate::plonk::verifier::verify; #[test] fn test_split_base() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); let mut builder = CircuitBuilder::::new(config); @@ -137,7 +139,7 @@ mod tests { builder.connect(limbs[3], one); builder.assert_leading_zeros(xt, 64 - 9); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; @@ -148,7 +150,9 @@ mod tests { fn test_base_sum() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); let mut builder = CircuitBuilder::::new(config); @@ -172,7 +176,7 @@ mod tests { builder.connect(x, y); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; diff --git a/plonky2/src/gates/arithmetic_base.rs b/plonky2/src/gates/arithmetic_base.rs index 13b4a2c5..efd932e2 100644 --- a/plonky2/src/gates/arithmetic_base.rs +++ b/plonky2/src/gates/arithmetic_base.rs @@ -218,7 +218,7 @@ mod tests { use crate::gates::arithmetic_base::ArithmeticGate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; #[test] fn low_degree() { @@ -230,8 +230,10 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let gate = ArithmeticGate::new_from_config(&CircuitConfig::standard_recursion_config()); - test_eval_fns::(gate) + test_eval_fns::(gate) } } diff --git a/plonky2/src/gates/arithmetic_extension.rs b/plonky2/src/gates/arithmetic_extension.rs index 4632dbd4..442e41e7 100644 --- a/plonky2/src/gates/arithmetic_extension.rs +++ b/plonky2/src/gates/arithmetic_extension.rs @@ -211,7 +211,7 @@ mod tests { use crate::gates::arithmetic_extension::ArithmeticExtensionGate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; #[test] fn low_degree() { @@ -224,9 +224,11 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let gate = ArithmeticExtensionGate::new_from_config(&CircuitConfig::standard_recursion_config()); - test_eval_fns::(gate) + test_eval_fns::(gate) } } diff --git a/plonky2/src/gates/base_sum.rs b/plonky2/src/gates/base_sum.rs index 5883d71c..ba0b13dd 100644 --- a/plonky2/src/gates/base_sum.rs +++ b/plonky2/src/gates/base_sum.rs @@ -204,7 +204,7 @@ mod tests { use crate::field::goldilocks_field::GoldilocksField; use crate::gates::base_sum::BaseSumGate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; #[test] fn low_degree() { @@ -215,7 +215,9 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - test_eval_fns::(BaseSumGate::<6>::new(11)) + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + test_eval_fns::(BaseSumGate::<6>::new(11)) } } diff --git a/plonky2/src/gates/constant.rs b/plonky2/src/gates/constant.rs index bf365b04..fe54596e 100644 --- a/plonky2/src/gates/constant.rs +++ b/plonky2/src/gates/constant.rs @@ -122,7 +122,7 @@ mod tests { use crate::gates::constant::ConstantGate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; #[test] fn low_degree() { @@ -135,9 +135,11 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let num_consts = CircuitConfig::standard_recursion_config().num_constants; let gate = ConstantGate { num_consts }; - test_eval_fns::(gate) + test_eval_fns::(gate) } } diff --git a/plonky2/src/gates/coset_interpolation.rs b/plonky2/src/gates/coset_interpolation.rs index da94d1c0..e7d8b14a 100644 --- a/plonky2/src/gates/coset_interpolation.rs +++ b/plonky2/src/gates/coset_interpolation.rs @@ -606,7 +606,7 @@ mod tests { use crate::field::types::{Field, Sample}; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::hash::hash_types::HashOut; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; #[test] fn test_degree_and_wires_minimized() { @@ -747,9 +747,13 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; for degree in 2..=4 { - test_eval_fns::(CosetInterpolationGate::with_max_degree(2, degree))?; + test_eval_fns::(CosetInterpolationGate::with_max_degree( + 2, degree, + ))?; } Ok(()) } @@ -758,8 +762,10 @@ mod tests { fn test_gate_constraint() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - type FF = >::FE; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + type FF = >::FE; /// Returns the local wires for an interpolation gate for given coeffs, points and eval point. fn get_wires(shift: F, values: PolynomialValues, eval_point: FF) -> Vec { diff --git a/plonky2/src/gates/exponentiation.rs b/plonky2/src/gates/exponentiation.rs index 218f77e8..5a09fe78 100644 --- a/plonky2/src/gates/exponentiation.rs +++ b/plonky2/src/gates/exponentiation.rs @@ -294,7 +294,7 @@ mod tests { use crate::field::types::Sample; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::hash::hash_types::HashOut; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; use crate::util::log2_ceil; const MAX_POWER_BITS: usize = 17; @@ -329,8 +329,10 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - test_eval_fns::(ExponentiationGate::new_from_config( + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + test_eval_fns::(ExponentiationGate::new_from_config( &CircuitConfig::standard_recursion_config(), )) } @@ -339,8 +341,10 @@ mod tests { fn test_gate_constraint() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - type FF = >::FE; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + type FF = >::FE; /// Returns the local wires for an exponentiation gate given the base, power, and power bit /// values. diff --git a/plonky2/src/gates/gate_testing.rs b/plonky2/src/gates/gate_testing.rs index f16d2950..181cba5d 100644 --- a/plonky2/src/gates/gate_testing.rs +++ b/plonky2/src/gates/gate_testing.rs @@ -8,6 +8,7 @@ use crate::field::polynomial::{PolynomialCoeffs, PolynomialValues}; use crate::field::types::{Field, Sample}; use crate::gates::gate::Gate; use crate::hash::hash_types::{HashOut, RichField}; +use crate::hash::hashing::HashConfig; use crate::iop::witness::{PartialWitness, WitnessWrite}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; @@ -88,12 +89,18 @@ fn random_low_degree_values(rate_bits: usize) -> Vec { pub fn test_eval_fns< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, G: Gate, const D: usize, >( gate: G, -) -> Result<()> { +) -> Result<()> +where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, +{ // Test that `eval_unfiltered` and `eval_unfiltered_base` are coherent. let wires_base = F::rand_vec(gate.num_wires()); let constants_base = F::rand_vec(gate.num_constants()); @@ -157,7 +164,7 @@ pub fn test_eval_fns< let evals_t = gate.eval_unfiltered_circuit(&mut builder, vars_t); pw.set_extension_targets(&evals_t, &evals); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; - verify(proof, &data.verifier_only, &data.common) + verify::(proof, &data.verifier_only, &data.common) } diff --git a/plonky2/src/gates/multiplication_extension.rs b/plonky2/src/gates/multiplication_extension.rs index 1f900441..8db53870 100644 --- a/plonky2/src/gates/multiplication_extension.rs +++ b/plonky2/src/gates/multiplication_extension.rs @@ -187,7 +187,7 @@ mod tests { use super::*; use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; #[test] fn low_degree() { @@ -199,8 +199,10 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let gate = MulExtensionGate::new_from_config(&CircuitConfig::standard_recursion_config()); - test_eval_fns::(gate) + test_eval_fns::(gate) } } diff --git a/plonky2/src/gates/noop.rs b/plonky2/src/gates/noop.rs index f6f9853a..e2111564 100644 --- a/plonky2/src/gates/noop.rs +++ b/plonky2/src/gates/noop.rs @@ -60,7 +60,7 @@ mod tests { use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::noop::NoopGate; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; #[test] fn low_degree() { @@ -71,7 +71,9 @@ mod tests { fn eval_fns() -> anyhow::Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - test_eval_fns::(NoopGate) + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + test_eval_fns::(NoopGate) } } diff --git a/plonky2/src/gates/poseidon.rs b/plonky2/src/gates/poseidon.rs index 6754f04b..d5db9390 100644 --- a/plonky2/src/gates/poseidon.rs +++ b/plonky2/src/gates/poseidon.rs @@ -10,9 +10,8 @@ use crate::gates::gate::Gate; use crate::gates::poseidon_mds::PoseidonMdsGate; use crate::gates::util::StridedConstraintConsumer; use crate::hash::hash_types::RichField; -use crate::hash::hashing::SPONGE_WIDTH; use crate::hash::poseidon; -use crate::hash::poseidon::Poseidon; +use crate::hash::poseidon::{Poseidon, SPONGE_WIDTH}; use crate::iop::ext_target::ExtensionTarget; use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; use crate::iop::target::Target; @@ -510,14 +509,13 @@ mod tests { use crate::field::types::Field; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::poseidon::PoseidonGate; - use crate::hash::hashing::SPONGE_WIDTH; - use crate::hash::poseidon::Poseidon; + use crate::hash::poseidon::{Poseidon, SPONGE_WIDTH}; use crate::iop::generator::generate_partial_witness; use crate::iop::wire::Wire; use crate::iop::witness::{PartialWitness, Witness, WitnessWrite}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; #[test] fn wire_indices() { @@ -545,7 +543,9 @@ mod tests { fn generated_output() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let config = CircuitConfig { num_wires: 143, @@ -555,7 +555,7 @@ mod tests { type Gate = PoseidonGate; let gate = Gate::new(); let row = builder.add_gate(gate, vec![]); - let circuit = builder.build_prover::(); + let circuit = builder.build_prover::(); let permutation_inputs = (0..SPONGE_WIDTH) .map(F::from_canonical_usize) @@ -603,8 +603,10 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let gate = PoseidonGate::::new(); - test_eval_fns::(gate) + test_eval_fns::(gate) } } diff --git a/plonky2/src/gates/poseidon_mds.rs b/plonky2/src/gates/poseidon_mds.rs index db517ef1..7958d1b4 100644 --- a/plonky2/src/gates/poseidon_mds.rs +++ b/plonky2/src/gates/poseidon_mds.rs @@ -11,8 +11,7 @@ use crate::field::types::Field; use crate::gates::gate::Gate; use crate::gates::util::StridedConstraintConsumer; use crate::hash::hash_types::RichField; -use crate::hash::hashing::SPONGE_WIDTH; -use crate::hash::poseidon::Poseidon; +use crate::hash::poseidon::{Poseidon, SPONGE_WIDTH}; use crate::iop::ext_target::{ExtensionAlgebraTarget, ExtensionTarget}; use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; use crate::iop::target::Target; @@ -244,13 +243,15 @@ impl + Poseidon, const D: usize> SimpleGenerator mod tests { use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::poseidon_mds::PoseidonMdsGate; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; #[test] fn low_degree() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let gate = PoseidonMdsGate::::new(); test_low_degree(gate) } @@ -259,8 +260,10 @@ mod tests { fn eval_fns() -> anyhow::Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let gate = PoseidonMdsGate::::new(); - test_eval_fns::(gate) + test_eval_fns::(gate) } } diff --git a/plonky2/src/gates/public_input.rs b/plonky2/src/gates/public_input.rs index 10c42f00..c8d2cfbe 100644 --- a/plonky2/src/gates/public_input.rs +++ b/plonky2/src/gates/public_input.rs @@ -104,7 +104,7 @@ mod tests { use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::public_input::PublicInputGate; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; #[test] fn low_degree() { @@ -115,7 +115,9 @@ mod tests { fn eval_fns() -> anyhow::Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - test_eval_fns::(PublicInputGate) + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + test_eval_fns::(PublicInputGate) } } diff --git a/plonky2/src/gates/random_access.rs b/plonky2/src/gates/random_access.rs index 80874505..e8c29713 100644 --- a/plonky2/src/gates/random_access.rs +++ b/plonky2/src/gates/random_access.rs @@ -389,7 +389,7 @@ mod tests { use crate::field::types::Sample; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::hash::hash_types::HashOut; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; #[test] fn low_degree() { @@ -400,16 +400,20 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - test_eval_fns::(RandomAccessGate::new(4, 4, 1)) + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + test_eval_fns::(RandomAccessGate::new(4, 4, 1)) } #[test] fn test_gate_constraint() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - type FF = >::FE; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + type FF = >::FE; /// Returns the local wires for a random access gate given the vectors, elements to compare, /// and indices. diff --git a/plonky2/src/gates/reducing.rs b/plonky2/src/gates/reducing.rs index 9bdadce8..ad14a7fc 100644 --- a/plonky2/src/gates/reducing.rs +++ b/plonky2/src/gates/reducing.rs @@ -216,7 +216,7 @@ mod tests { use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::reducing::ReducingGate; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; #[test] fn low_degree() { @@ -227,7 +227,9 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - test_eval_fns::(ReducingGate::new(22)) + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + test_eval_fns::(ReducingGate::new(22)) } } diff --git a/plonky2/src/gates/reducing_extension.rs b/plonky2/src/gates/reducing_extension.rs index 0ad48bb0..2b37e5b5 100644 --- a/plonky2/src/gates/reducing_extension.rs +++ b/plonky2/src/gates/reducing_extension.rs @@ -210,7 +210,7 @@ mod tests { use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::reducing_extension::ReducingExtensionGate; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; #[test] fn low_degree() { @@ -221,7 +221,9 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - test_eval_fns::(ReducingExtensionGate::new(22)) + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + test_eval_fns::(ReducingExtensionGate::new(22)) } } diff --git a/plonky2/src/hash/hashing.rs b/plonky2/src/hash/hashing.rs index 3e93447a..d8576d3c 100644 --- a/plonky2/src/hash/hashing.rs +++ b/plonky2/src/hash/hashing.rs @@ -1,6 +1,7 @@ //! Concrete instantiation of a hash function. use alloc::vec::Vec; +use core::fmt::Debug; use crate::field::extension::Extendable; use crate::hash::hash_types::{HashOut, HashOutTarget, RichField}; @@ -8,62 +9,81 @@ use crate::iop::target::Target; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::config::AlgebraicHasher; -pub(crate) const SPONGE_RATE: usize = 8; -pub(crate) const SPONGE_CAPACITY: usize = 4; -pub const SPONGE_WIDTH: usize = SPONGE_RATE + SPONGE_CAPACITY; +pub trait HashConfig: Clone + Debug + Eq + PartialEq { + const RATE: usize; + const WIDTH: usize; +} impl, const D: usize> CircuitBuilder { - pub fn hash_or_noop>(&mut self, inputs: Vec) -> HashOutTarget { + pub fn hash_or_noop>( + &mut self, + inputs: Vec, + ) -> HashOutTarget + where + [(); HC::WIDTH]:, + { let zero = self.zero(); if inputs.len() <= 4 { HashOutTarget::from_partial(&inputs, zero) } else { - self.hash_n_to_hash_no_pad::(inputs) + self.hash_n_to_hash_no_pad::(inputs) } } - pub fn hash_n_to_hash_no_pad>( + pub fn hash_n_to_hash_no_pad>( &mut self, inputs: Vec, - ) -> HashOutTarget { - HashOutTarget::from_vec(self.hash_n_to_m_no_pad::(inputs, 4)) + ) -> HashOutTarget + where + [(); HC::WIDTH]:, + { + HashOutTarget::from_vec(self.hash_n_to_m_no_pad::(inputs, 4)) } - pub fn hash_n_to_m_no_pad>( + pub fn hash_n_to_m_no_pad>( &mut self, inputs: Vec, num_outputs: usize, - ) -> Vec { + ) -> Vec + where + [(); HC::WIDTH]:, + { let zero = self.zero(); - let mut state = [zero; SPONGE_WIDTH]; + let mut state = [zero; HC::WIDTH]; // Absorb all input chunks. - for input_chunk in inputs.chunks(SPONGE_RATE) { + for input_chunk in inputs.chunks(HC::RATE) { // Overwrite the first r elements with the inputs. This differs from a standard sponge, // where we would xor or add in the inputs. This is a well-known variant, though, // sometimes called "overwrite mode". state[..input_chunk.len()].copy_from_slice(input_chunk); - state = self.permute::(state); + state = self.permute::(state); } // Squeeze until we have the desired number of outputs. let mut outputs = Vec::with_capacity(num_outputs); loop { - for i in 0..SPONGE_RATE { + for i in 0..HC::RATE { outputs.push(state[i]); if outputs.len() == num_outputs { return outputs; } } - state = self.permute::(state); + state = self.permute::(state); } } } /// A one-way compression function which takes two ~256 bit inputs and returns a ~256 bit output. -pub fn compress>(x: HashOut, y: HashOut) -> HashOut { - let mut perm_inputs = [F::ZERO; SPONGE_WIDTH]; +pub fn compress>( + x: HashOut, + y: HashOut, +) -> HashOut +where + [(); HC::WIDTH]:, +{ + let mut perm_inputs = [F::ZERO; HC::WIDTH]; perm_inputs[..4].copy_from_slice(&x.elements); perm_inputs[4..8].copy_from_slice(&y.elements); HashOut { @@ -72,20 +92,25 @@ pub fn compress>(x: HashOut, y: HashOut } /// Permutation that can be used in the sponge construction for an algebraic hash. -pub trait PlonkyPermutation { - fn permute(input: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH]; +pub trait PlonkyPermutation { + fn permute(input: [F; HC::WIDTH]) -> [F; HC::WIDTH] + where + [(); HC::WIDTH]:; } /// Hash a message without any padding step. Note that this can enable length-extension attacks. /// However, it is still collision-resistant in cases where the input has a fixed length. -pub fn hash_n_to_m_no_pad>( +pub fn hash_n_to_m_no_pad>( inputs: &[F], num_outputs: usize, -) -> Vec { - let mut state = [F::ZERO; SPONGE_WIDTH]; +) -> Vec +where + [(); HC::WIDTH]:, +{ + let mut state = [F::ZERO; HC::WIDTH]; // Absorb all input chunks. - for input_chunk in inputs.chunks(SPONGE_RATE) { + for input_chunk in inputs.chunks(HC::RATE) { state[..input_chunk.len()].copy_from_slice(input_chunk); state = P::permute(state); } @@ -93,7 +118,7 @@ pub fn hash_n_to_m_no_pad>( // Squeeze until we have the desired number of outputs. let mut outputs = Vec::new(); loop { - for &item in state.iter().take(SPONGE_RATE) { + for &item in state.iter().take(HC::RATE) { outputs.push(item); if outputs.len() == num_outputs { return outputs; @@ -103,6 +128,11 @@ pub fn hash_n_to_m_no_pad>( } } -pub fn hash_n_to_hash_no_pad>(inputs: &[F]) -> HashOut { - HashOut::from_vec(hash_n_to_m_no_pad::(inputs, 4)) +pub fn hash_n_to_hash_no_pad>( + inputs: &[F], +) -> HashOut +where + [(); HC::WIDTH]:, +{ + HashOut::from_vec(hash_n_to_m_no_pad::(inputs, 4)) } diff --git a/plonky2/src/hash/keccak.rs b/plonky2/src/hash/keccak.rs index 0efa154c..7fc83188 100644 --- a/plonky2/src/hash/keccak.rs +++ b/plonky2/src/hash/keccak.rs @@ -7,16 +7,23 @@ use itertools::Itertools; use keccak_hash::keccak; use crate::hash::hash_types::{BytesHash, RichField}; -use crate::hash::hashing::{PlonkyPermutation, SPONGE_WIDTH}; -use crate::plonk::config::Hasher; +use crate::hash::hashing::PlonkyPermutation; +use crate::plonk::config::{Hasher, KeccakHashConfig}; use crate::util::serialization::Write; +pub const SPONGE_RATE: usize = 8; +pub const SPONGE_CAPACITY: usize = 4; +pub const SPONGE_WIDTH: usize = SPONGE_RATE + SPONGE_CAPACITY; + /// Keccak-256 pseudo-permutation (not necessarily one-to-one) used in the challenger. /// A state `input: [F; 12]` is sent to the field representation of `H(input) || H(H(input)) || H(H(H(input)))` /// where `H` is the Keccak-256 hash. pub struct KeccakPermutation; -impl PlonkyPermutation for KeccakPermutation { - fn permute(input: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH] { +impl PlonkyPermutation for KeccakPermutation { + fn permute(input: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH] + where + [(); SPONGE_WIDTH]:, + { let mut state = vec![0u8; SPONGE_WIDTH * size_of::()]; for i in 0..SPONGE_WIDTH { state[i * size_of::()..(i + 1) * size_of::()] @@ -53,8 +60,7 @@ impl PlonkyPermutation for KeccakPermutation { /// Keccak-256 hash function. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct KeccakHash; - -impl Hasher for KeccakHash { +impl Hasher for KeccakHash { const HASH_SIZE: usize = N; type Hash = BytesHash; type Permutation = KeccakPermutation; diff --git a/plonky2/src/hash/merkle_proofs.rs b/plonky2/src/hash/merkle_proofs.rs index 3726d847..7798bd16 100644 --- a/plonky2/src/hash/merkle_proofs.rs +++ b/plonky2/src/hash/merkle_proofs.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use crate::field::extension::Extendable; use crate::hash::hash_types::{HashOutTarget, MerkleCapTarget, RichField}; -use crate::hash::hashing::SPONGE_WIDTH; +use crate::hash::hashing::HashConfig; use crate::hash::merkle_tree::MerkleCap; use crate::iop::target::{BoolTarget, Target}; use crate::plonk::circuit_builder::CircuitBuilder; @@ -16,12 +16,12 @@ use crate::plonk::config::{AlgebraicHasher, Hasher}; #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] #[serde(bound = "")] -pub struct MerkleProof> { +pub struct MerkleProof> { /// The Merkle digest of each sibling subtree, staying from the bottommost layer. pub siblings: Vec, } -impl> MerkleProof { +impl> MerkleProof { pub fn len(&self) -> usize { self.siblings.len() } @@ -39,24 +39,30 @@ pub struct MerkleProofTarget { /// Verifies that the given leaf data is present at the given index in the Merkle tree with the /// given root. -pub fn verify_merkle_proof>( +pub fn verify_merkle_proof>( leaf_data: Vec, leaf_index: usize, merkle_root: H::Hash, - proof: &MerkleProof, -) -> Result<()> { + proof: &MerkleProof, +) -> Result<()> +where + [(); HC::WIDTH]:, +{ let merkle_cap = MerkleCap(vec![merkle_root]); verify_merkle_proof_to_cap(leaf_data, leaf_index, &merkle_cap, proof) } /// Verifies that the given leaf data is present at the given index in the Merkle tree with the /// given cap. -pub fn verify_merkle_proof_to_cap>( +pub fn verify_merkle_proof_to_cap>( leaf_data: Vec, leaf_index: usize, - merkle_cap: &MerkleCap, - proof: &MerkleProof, -) -> Result<()> { + merkle_cap: &MerkleCap, + proof: &MerkleProof, +) -> Result<()> +where + [(); HC::WIDTH]:, +{ let mut index = leaf_index; let mut current_digest = H::hash_or_noop(&leaf_data); for &sibling_digest in proof.siblings.iter() { @@ -79,28 +85,32 @@ pub fn verify_merkle_proof_to_cap>( impl, const D: usize> CircuitBuilder { /// Verifies that the given leaf data is present at the given index in the Merkle tree with the /// given root. The index is given by its little-endian bits. - pub fn verify_merkle_proof>( + pub fn verify_merkle_proof>( &mut self, leaf_data: Vec, leaf_index_bits: &[BoolTarget], merkle_root: HashOutTarget, proof: &MerkleProofTarget, - ) { + ) where + [(); HC::WIDTH]:, + { let merkle_cap = MerkleCapTarget(vec![merkle_root]); - self.verify_merkle_proof_to_cap::(leaf_data, leaf_index_bits, &merkle_cap, proof); + self.verify_merkle_proof_to_cap::(leaf_data, leaf_index_bits, &merkle_cap, proof); } /// Verifies that the given leaf data is present at the given index in the Merkle tree with the /// given cap. The index is given by its little-endian bits. - pub fn verify_merkle_proof_to_cap>( + pub fn verify_merkle_proof_to_cap>( &mut self, leaf_data: Vec, leaf_index_bits: &[BoolTarget], merkle_cap: &MerkleCapTarget, proof: &MerkleProofTarget, - ) { + ) where + [(); HC::WIDTH]:, + { let cap_index = self.le_sum(leaf_index_bits[proof.siblings.len()..].iter().copied()); - self.verify_merkle_proof_to_cap_with_cap_index::( + self.verify_merkle_proof_to_cap_with_cap_index::( leaf_data, leaf_index_bits, cap_index, @@ -111,22 +121,27 @@ impl, const D: usize> CircuitBuilder { /// Same as `verify_merkle_proof_to_cap`, except with the final "cap index" as separate parameter, /// rather than being contained in `leaf_index_bits`. - pub(crate) fn verify_merkle_proof_to_cap_with_cap_index>( + pub(crate) fn verify_merkle_proof_to_cap_with_cap_index< + HC: HashConfig, + H: AlgebraicHasher, + >( &mut self, leaf_data: Vec, leaf_index_bits: &[BoolTarget], cap_index: Target, merkle_cap: &MerkleCapTarget, proof: &MerkleProofTarget, - ) { + ) where + [(); HC::WIDTH]:, + { let zero = self.zero(); - let mut state: HashOutTarget = self.hash_or_noop::(leaf_data); + let mut state: HashOutTarget = self.hash_or_noop::(leaf_data); for (&bit, &sibling) in leaf_index_bits.iter().zip(&proof.siblings) { - let mut perm_inputs = [zero; SPONGE_WIDTH]; + let mut perm_inputs = [zero; HC::WIDTH]; perm_inputs[..4].copy_from_slice(&state.elements); perm_inputs[4..8].copy_from_slice(&sibling.elements); - let perm_outs = self.permute_swapped::(perm_inputs, bit); + let perm_outs = self.permute_swapped::(perm_inputs, bit); let hash_outs = perm_outs[0..4].try_into().unwrap(); state = HashOutTarget { elements: hash_outs, @@ -172,7 +187,7 @@ mod tests { use crate::iop::witness::{PartialWitness, WitnessWrite}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; use crate::plonk::verifier::verify; fn random_data(n: usize, k: usize) -> Vec> { @@ -183,7 +198,9 @@ mod tests { fn test_recursive_merkle_proof() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); let mut pw = PartialWitness::new(); let mut builder = CircuitBuilder::::new(config); @@ -192,7 +209,9 @@ mod tests { let n = 1 << log_n; let cap_height = 1; let leaves = random_data::(n, 7); - let tree = MerkleTree::>::Hasher>::new(leaves, cap_height); + let tree = MerkleTree::>::Hasher>::new( + leaves, cap_height, + ); let i: usize = OsRng.gen_range(0..n); let proof = tree.prove(i); @@ -214,11 +233,11 @@ mod tests { pw.set_target(data[j], tree.leaves[i][j]); } - builder.verify_merkle_proof_to_cap::<>::InnerHasher>( + builder.verify_merkle_proof_to_cap::>::InnerHasher>( data, &i_bits, &cap_t, &proof_t, ); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/plonky2/src/hash/merkle_tree.rs b/plonky2/src/hash/merkle_tree.rs index e884554f..25055fdb 100644 --- a/plonky2/src/hash/merkle_tree.rs +++ b/plonky2/src/hash/merkle_tree.rs @@ -6,6 +6,7 @@ use plonky2_maybe_rayon::*; use serde::{Deserialize, Serialize}; use crate::hash::hash_types::RichField; +use crate::hash::hashing::HashConfig; use crate::hash::merkle_proofs::MerkleProof; use crate::plonk::config::{GenericHashOut, Hasher}; use crate::util::log2_strict; @@ -15,9 +16,9 @@ use crate::util::log2_strict; #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] #[serde(bound = "")] // TODO: Change H to GenericHashOut, since this only cares about the hash, not the hasher. -pub struct MerkleCap>(pub Vec); +pub struct MerkleCap>(pub Vec); -impl> MerkleCap { +impl> MerkleCap { pub fn len(&self) -> usize { self.0.len() } @@ -36,7 +37,7 @@ impl> MerkleCap { } #[derive(Clone, Debug)] -pub struct MerkleTree> { +pub struct MerkleTree> { /// The data in the leaves of the Merkle tree. pub leaves: Vec>, @@ -51,7 +52,7 @@ pub struct MerkleTree> { pub digests: Vec, /// The Merkle cap. - pub cap: MerkleCap, + pub cap: MerkleCap, } fn capacity_up_to_mut(v: &mut Vec, len: usize) -> &mut [MaybeUninit] { @@ -66,10 +67,13 @@ fn capacity_up_to_mut(v: &mut Vec, len: usize) -> &mut [MaybeUninit] { } } -fn fill_subtree>( +fn fill_subtree>( digests_buf: &mut [MaybeUninit], leaves: &[Vec], -) -> H::Hash { +) -> H::Hash +where + [(); HC::WIDTH]:, +{ assert_eq!(leaves.len(), digests_buf.len() / 2 + 1); if digests_buf.is_empty() { H::hash_or_noop(&leaves[0]) @@ -85,8 +89,8 @@ fn fill_subtree>( let (left_leaves, right_leaves) = leaves.split_at(leaves.len() / 2); let (left_digest, right_digest) = plonky2_maybe_rayon::join( - || fill_subtree::(left_digests_buf, left_leaves), - || fill_subtree::(right_digests_buf, right_leaves), + || fill_subtree::(left_digests_buf, left_leaves), + || fill_subtree::(right_digests_buf, right_leaves), ); left_digest_mem.write(left_digest); @@ -95,12 +99,14 @@ fn fill_subtree>( } } -fn fill_digests_buf>( +fn fill_digests_buf>( digests_buf: &mut [MaybeUninit], cap_buf: &mut [MaybeUninit], leaves: &[Vec], cap_height: usize, -) { +) where + [(); HC::WIDTH]:, +{ // Special case of a tree that's all cap. The usual case will panic because we'll try to split // an empty slice into chunks of `0`. (We would not need this if there was a way to split into // `blah` chunks as opposed to chunks _of_ `blah`.) @@ -126,12 +132,15 @@ fn fill_digests_buf>( // We have `1 << cap_height` sub-trees, one for each entry in `cap`. They are totally // independent, so we schedule one task for each. `digests_buf` and `leaves` are split // into `1 << cap_height` slices, one for each sub-tree. - subtree_cap.write(fill_subtree::(subtree_digests, subtree_leaves)); + subtree_cap.write(fill_subtree::(subtree_digests, subtree_leaves)); }, ); } -impl> MerkleTree { +impl> MerkleTree +where + [(); HC::WIDTH]:, +{ pub fn new(leaves: Vec>, cap_height: usize) -> Self { let log2_leaves_len = log2_strict(leaves.len()); assert!( @@ -149,7 +158,7 @@ impl> MerkleTree { let digests_buf = capacity_up_to_mut(&mut digests, num_digests); let cap_buf = capacity_up_to_mut(&mut cap, len_cap); - fill_digests_buf::(digests_buf, cap_buf, &leaves[..], cap_height); + fill_digests_buf::(digests_buf, cap_buf, &leaves[..], cap_height); unsafe { // SAFETY: `fill_digests_buf` and `cap` initialized the spare capacity up to @@ -170,7 +179,7 @@ impl> MerkleTree { } /// Create a Merkle proof from a leaf index. - pub fn prove(&self, leaf_index: usize) -> MerkleProof { + pub fn prove(&self, leaf_index: usize) -> MerkleProof { let cap_height = log2_strict(self.cap.len()); let num_layers = log2_strict(self.leaves.len()) - cap_height; debug_assert_eq!(leaf_index >> (cap_height + num_layers), 0); @@ -214,7 +223,7 @@ mod tests { use super::*; use crate::field::extension::Extendable; use crate::hash::merkle_proofs::verify_merkle_proof_to_cap; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; fn random_data(n: usize, k: usize) -> Vec> { (0..n).map(|_| F::rand_vec(k)).collect() @@ -222,13 +231,18 @@ mod tests { fn verify_all_leaves< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, >( leaves: Vec>, cap_height: usize, - ) -> Result<()> { - let tree = MerkleTree::::new(leaves.clone(), cap_height); + ) -> Result<()> + where + [(); HCO::WIDTH]:, + { + let tree = MerkleTree::::new(leaves.clone(), cap_height); for (i, leaf) in leaves.into_iter().enumerate() { let proof = tree.prove(i); verify_merkle_proof_to_cap(leaf, i, &tree.cap, &proof)?; @@ -241,26 +255,32 @@ mod tests { fn test_cap_height_too_big() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let log_n = 8; let cap_height = log_n + 1; // Should panic if `cap_height > len_n`. let leaves = random_data::(1 << log_n, 7); - let _ = MerkleTree::>::Hasher>::new(leaves, cap_height); + let _ = MerkleTree::>::Hasher>::new( + leaves, cap_height, + ); } #[test] fn test_cap_height_eq_log2_len() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let log_n = 8; let n = 1 << log_n; let leaves = random_data::(n, 7); - verify_all_leaves::(leaves, log_n)?; + verify_all_leaves::(leaves, log_n)?; Ok(()) } @@ -269,13 +289,15 @@ mod tests { fn test_merkle_trees() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let log_n = 8; let n = 1 << log_n; let leaves = random_data::(n, 7); - verify_all_leaves::(leaves, 1)?; + verify_all_leaves::(leaves, 1)?; Ok(()) } diff --git a/plonky2/src/hash/path_compression.rs b/plonky2/src/hash/path_compression.rs index d4f7d5eb..de507641 100644 --- a/plonky2/src/hash/path_compression.rs +++ b/plonky2/src/hash/path_compression.rs @@ -5,15 +5,16 @@ use hashbrown::HashMap; use num::Integer; use crate::hash::hash_types::RichField; +use crate::hash::hashing::HashConfig; use crate::hash::merkle_proofs::MerkleProof; use crate::plonk::config::Hasher; /// Compress multiple Merkle proofs on the same tree by removing redundancy in the Merkle paths. -pub(crate) fn compress_merkle_proofs>( +pub(crate) fn compress_merkle_proofs>( cap_height: usize, indices: &[usize], - proofs: &[MerkleProof], -) -> Vec> { + proofs: &[MerkleProof], +) -> Vec> { assert!(!proofs.is_empty()); let height = cap_height + proofs[0].siblings.len(); let num_leaves = 1 << height; @@ -53,13 +54,16 @@ pub(crate) fn compress_merkle_proofs>( /// Decompress compressed Merkle proofs. /// Note: The data and indices must be in the same order as in `compress_merkle_proofs`. -pub(crate) fn decompress_merkle_proofs>( +pub(crate) fn decompress_merkle_proofs>( leaves_data: &[Vec], leaves_indices: &[usize], - compressed_proofs: &[MerkleProof], + compressed_proofs: &[MerkleProof], height: usize, cap_height: usize, -) -> Vec> { +) -> Vec> +where + [(); HC::WIDTH]:, +{ let num_leaves = 1 << height; let compressed_proofs = compressed_proofs.to_vec(); let mut decompressed_proofs = Vec::with_capacity(compressed_proofs.len()); @@ -120,17 +124,22 @@ mod tests { use super::*; use crate::field::types::Sample; use crate::hash::merkle_tree::MerkleTree; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; #[test] fn test_path_compression() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let h = 10; let cap_height = 3; let vs = (0..1 << h).map(|_| vec![F::rand()]).collect::>(); - let mt = MerkleTree::>::Hasher>::new(vs.clone(), cap_height); + let mt = MerkleTree::>::Hasher>::new( + vs.clone(), + cap_height, + ); let mut rng = OsRng; let k = rng.gen_range(1..=1 << h); diff --git a/plonky2/src/hash/poseidon.rs b/plonky2/src/hash/poseidon.rs index e7436018..468b3d4d 100644 --- a/plonky2/src/hash/poseidon.rs +++ b/plonky2/src/hash/poseidon.rs @@ -12,11 +12,15 @@ use crate::gates::gate::Gate; use crate::gates::poseidon::PoseidonGate; use crate::gates::poseidon_mds::PoseidonMdsGate; use crate::hash::hash_types::{HashOut, RichField}; -use crate::hash::hashing::{compress, hash_n_to_hash_no_pad, PlonkyPermutation, SPONGE_WIDTH}; +use crate::hash::hashing::{compress, hash_n_to_hash_no_pad, PlonkyPermutation}; use crate::iop::ext_target::ExtensionTarget; use crate::iop::target::{BoolTarget, Target}; use crate::plonk::circuit_builder::CircuitBuilder; -use crate::plonk::config::{AlgebraicHasher, Hasher}; +use crate::plonk::config::{AlgebraicHasher, Hasher, PoseidonHashConfig}; + +pub const SPONGE_RATE: usize = 8; +pub const SPONGE_CAPACITY: usize = 4; +pub const SPONGE_WIDTH: usize = SPONGE_RATE + SPONGE_CAPACITY; // The number of full rounds and partial rounds is given by the // calc_round_numbers.py script. They happen to be the same for both @@ -47,7 +51,7 @@ fn reduce_u160((n_lo, n_hi): (u128, u32)) -> F { } /// Note that these work for the Goldilocks field, but not necessarily others. See -/// `generate_constants` about how these were generated. We include enough for a WIDTH of 12; +/// `generate_constants` about how these were generated. We include enough for a width of 12; /// smaller widths just use a subset. #[rustfmt::skip] pub const ALL_ROUND_CONSTANTS: [u64; MAX_WIDTH * N_ROUNDS] = [ @@ -150,29 +154,28 @@ pub const ALL_ROUND_CONSTANTS: [u64; MAX_WIDTH * N_ROUNDS] = [ 0x4543d9df5476d3cb, 0xf172d73e004fc90d, 0xdfd1c4febcc81238, 0xbc8dfb627fe558fc, ]; -const WIDTH: usize = SPONGE_WIDTH; pub trait Poseidon: PrimeField64 { // Total number of round constants required: width of the input // times number of rounds. - const N_ROUND_CONSTANTS: usize = WIDTH * N_ROUNDS; + const N_ROUND_CONSTANTS: usize = SPONGE_WIDTH * N_ROUNDS; // The MDS matrix we use is C + D, where C is the circulant matrix whose first row is given by // `MDS_MATRIX_CIRC`, and D is the diagonal matrix whose diagonal is given by `MDS_MATRIX_DIAG`. - const MDS_MATRIX_CIRC: [u64; WIDTH]; - const MDS_MATRIX_DIAG: [u64; WIDTH]; + const MDS_MATRIX_CIRC: [u64; SPONGE_WIDTH]; + const MDS_MATRIX_DIAG: [u64; SPONGE_WIDTH]; // Precomputed constants for the fast Poseidon calculation. See // the paper. - const FAST_PARTIAL_FIRST_ROUND_CONSTANT: [u64; WIDTH]; + const FAST_PARTIAL_FIRST_ROUND_CONSTANT: [u64; SPONGE_WIDTH]; const FAST_PARTIAL_ROUND_CONSTANTS: [u64; N_PARTIAL_ROUNDS]; - const FAST_PARTIAL_ROUND_VS: [[u64; WIDTH - 1]; N_PARTIAL_ROUNDS]; - const FAST_PARTIAL_ROUND_W_HATS: [[u64; WIDTH - 1]; N_PARTIAL_ROUNDS]; - const FAST_PARTIAL_ROUND_INITIAL_MATRIX: [[u64; WIDTH - 1]; WIDTH - 1]; + const FAST_PARTIAL_ROUND_VS: [[u64; SPONGE_WIDTH - 1]; N_PARTIAL_ROUNDS]; + const FAST_PARTIAL_ROUND_W_HATS: [[u64; SPONGE_WIDTH - 1]; N_PARTIAL_ROUNDS]; + const FAST_PARTIAL_ROUND_INITIAL_MATRIX: [[u64; SPONGE_WIDTH - 1]; SPONGE_WIDTH - 1]; #[inline(always)] #[unroll_for_loops] - fn mds_row_shf(r: usize, v: &[u64; WIDTH]) -> u128 { - debug_assert!(r < WIDTH); + fn mds_row_shf(r: usize, v: &[u64; SPONGE_WIDTH]) -> u128 { + debug_assert!(r < SPONGE_WIDTH); // The values of `MDS_MATRIX_CIRC` and `MDS_MATRIX_DIAG` are // known to be small, so we can accumulate all the products for // each row and reduce just once at the end (done by the @@ -184,8 +187,8 @@ pub trait Poseidon: PrimeField64 { // This is a hacky way of fully unrolling the loop. for i in 0..12 { - if i < WIDTH { - res += (v[(i + r) % WIDTH] as u128) * (Self::MDS_MATRIX_CIRC[i] as u128); + if i < SPONGE_WIDTH { + res += (v[(i + r) % SPONGE_WIDTH] as u128) * (Self::MDS_MATRIX_CIRC[i] as u128); } } res += (v[r] as u128) * (Self::MDS_MATRIX_DIAG[r] as u128); @@ -196,13 +199,13 @@ pub trait Poseidon: PrimeField64 { /// Same as `mds_row_shf` for field extensions of `Self`. fn mds_row_shf_field, const D: usize>( r: usize, - v: &[F; WIDTH], + v: &[F; SPONGE_WIDTH], ) -> F { - debug_assert!(r < WIDTH); + debug_assert!(r < SPONGE_WIDTH); let mut res = F::ZERO; - for i in 0..WIDTH { - res += v[(i + r) % WIDTH] * F::from_canonical_u64(Self::MDS_MATRIX_CIRC[i]); + for i in 0..SPONGE_WIDTH { + res += v[(i + r) % SPONGE_WIDTH] * F::from_canonical_u64(Self::MDS_MATRIX_CIRC[i]); } res += v[r] * F::from_canonical_u64(Self::MDS_MATRIX_DIAG[r]); @@ -213,17 +216,17 @@ pub trait Poseidon: PrimeField64 { fn mds_row_shf_circuit( builder: &mut CircuitBuilder, r: usize, - v: &[ExtensionTarget; WIDTH], + v: &[ExtensionTarget; SPONGE_WIDTH], ) -> ExtensionTarget where Self: RichField + Extendable, { - debug_assert!(r < WIDTH); + debug_assert!(r < SPONGE_WIDTH); let mut res = builder.zero_extension(); - for i in 0..WIDTH { + for i in 0..SPONGE_WIDTH { let c = Self::from_canonical_u64(::MDS_MATRIX_CIRC[i]); - res = builder.mul_const_add_extension(c, v[(i + r) % WIDTH], res); + res = builder.mul_const_add_extension(c, v[(i + r) % SPONGE_WIDTH], res); } { let c = Self::from_canonical_u64(::MDS_MATRIX_DIAG[r]); @@ -235,17 +238,17 @@ pub trait Poseidon: PrimeField64 { #[inline(always)] #[unroll_for_loops] - fn mds_layer(state_: &[Self; WIDTH]) -> [Self; WIDTH] { - let mut result = [Self::ZERO; WIDTH]; + fn mds_layer(state_: &[Self; SPONGE_WIDTH]) -> [Self; SPONGE_WIDTH] { + let mut result = [Self::ZERO; SPONGE_WIDTH]; - let mut state = [0u64; WIDTH]; - for r in 0..WIDTH { + let mut state = [0u64; SPONGE_WIDTH]; + for r in 0..SPONGE_WIDTH { state[r] = state_[r].to_noncanonical_u64(); } // This is a hacky way of fully unrolling the loop. for r in 0..12 { - if r < WIDTH { + if r < SPONGE_WIDTH { let sum = Self::mds_row_shf(r, &state); let sum_lo = sum as u64; let sum_hi = (sum >> 64) as u32; @@ -258,11 +261,11 @@ pub trait Poseidon: PrimeField64 { /// Same as `mds_layer` for field extensions of `Self`. fn mds_layer_field, const D: usize>( - state: &[F; WIDTH], - ) -> [F; WIDTH] { - let mut result = [F::ZERO; WIDTH]; + state: &[F; SPONGE_WIDTH], + ) -> [F; SPONGE_WIDTH] { + let mut result = [F::ZERO; SPONGE_WIDTH]; - for r in 0..WIDTH { + for r in 0..SPONGE_WIDTH { result[r] = Self::mds_row_shf_field(r, state); } @@ -272,8 +275,8 @@ pub trait Poseidon: PrimeField64 { /// Recursive version of `mds_layer`. fn mds_layer_circuit( builder: &mut CircuitBuilder, - state: &[ExtensionTarget; WIDTH], - ) -> [ExtensionTarget; WIDTH] + state: &[ExtensionTarget; SPONGE_WIDTH], + ) -> [ExtensionTarget; SPONGE_WIDTH] where Self: RichField + Extendable, { @@ -281,11 +284,11 @@ pub trait Poseidon: PrimeField64 { let mds_gate = PoseidonMdsGate::::new(); if builder.config.num_routed_wires >= mds_gate.num_wires() { let index = builder.add_gate(mds_gate, vec![]); - for i in 0..WIDTH { + for i in 0..SPONGE_WIDTH { let input_wire = PoseidonMdsGate::::wires_input(i); builder.connect_extension(state[i], ExtensionTarget::from_range(index, input_wire)); } - (0..WIDTH) + (0..SPONGE_WIDTH) .map(|i| { let output_wire = PoseidonMdsGate::::wires_output(i); ExtensionTarget::from_range(index, output_wire) @@ -294,9 +297,9 @@ pub trait Poseidon: PrimeField64 { .try_into() .unwrap() } else { - let mut result = [builder.zero_extension(); WIDTH]; + let mut result = [builder.zero_extension(); SPONGE_WIDTH]; - for r in 0..WIDTH { + for r in 0..SPONGE_WIDTH { result[r] = Self::mds_row_shf_circuit(builder, r, state); } @@ -307,10 +310,10 @@ pub trait Poseidon: PrimeField64 { #[inline(always)] #[unroll_for_loops] fn partial_first_constant_layer, const D: usize>( - state: &mut [F; WIDTH], + state: &mut [F; SPONGE_WIDTH], ) { for i in 0..12 { - if i < WIDTH { + if i < SPONGE_WIDTH { state[i] += F::from_canonical_u64(Self::FAST_PARTIAL_FIRST_ROUND_CONSTANT[i]); } } @@ -319,11 +322,11 @@ pub trait Poseidon: PrimeField64 { /// Recursive version of `partial_first_constant_layer`. fn partial_first_constant_layer_circuit( builder: &mut CircuitBuilder, - state: &mut [ExtensionTarget; WIDTH], + state: &mut [ExtensionTarget; SPONGE_WIDTH], ) where Self: RichField + Extendable, { - for i in 0..WIDTH { + for i in 0..SPONGE_WIDTH { let c = ::FAST_PARTIAL_FIRST_ROUND_CONSTANT[i]; let c = Self::Extension::from_canonical_u64(c); let c = builder.constant_extension(c); @@ -334,9 +337,9 @@ pub trait Poseidon: PrimeField64 { #[inline(always)] #[unroll_for_loops] fn mds_partial_layer_init, const D: usize>( - state: &[F; WIDTH], - ) -> [F; WIDTH] { - let mut result = [F::ZERO; WIDTH]; + state: &[F; SPONGE_WIDTH], + ) -> [F; SPONGE_WIDTH] { + let mut result = [F::ZERO; SPONGE_WIDTH]; // Initial matrix has first row/column = [1, 0, ..., 0]; @@ -344,9 +347,9 @@ pub trait Poseidon: PrimeField64 { result[0] = state[0]; for r in 1..12 { - if r < WIDTH { + if r < SPONGE_WIDTH { for c in 1..12 { - if c < WIDTH { + if c < SPONGE_WIDTH { // NB: FAST_PARTIAL_ROUND_INITIAL_MATRIX is stored in // row-major order so that this dot product is cache // friendly. @@ -364,17 +367,17 @@ pub trait Poseidon: PrimeField64 { /// Recursive version of `mds_partial_layer_init`. fn mds_partial_layer_init_circuit( builder: &mut CircuitBuilder, - state: &[ExtensionTarget; WIDTH], - ) -> [ExtensionTarget; WIDTH] + state: &[ExtensionTarget; SPONGE_WIDTH], + ) -> [ExtensionTarget; SPONGE_WIDTH] where Self: RichField + Extendable, { - let mut result = [builder.zero_extension(); WIDTH]; + let mut result = [builder.zero_extension(); SPONGE_WIDTH]; result[0] = state[0]; - for r in 1..WIDTH { - for c in 1..WIDTH { + for r in 1..SPONGE_WIDTH { + for c in 1..SPONGE_WIDTH { let t = ::FAST_PARTIAL_ROUND_INITIAL_MATRIX[r - 1][c - 1]; let t = Self::Extension::from_canonical_u64(t); let t = builder.constant_extension(t); @@ -394,12 +397,12 @@ pub trait Poseidon: PrimeField64 { /// (t-1)x(t-1) identity matrix. #[inline(always)] #[unroll_for_loops] - fn mds_partial_layer_fast(state: &[Self; WIDTH], r: usize) -> [Self; WIDTH] { + fn mds_partial_layer_fast(state: &[Self; SPONGE_WIDTH], r: usize) -> [Self; SPONGE_WIDTH] { // Set d = [M_00 | w^] dot [state] let mut d_sum = (0u128, 0u32); // u160 accumulator for i in 1..12 { - if i < WIDTH { + if i < SPONGE_WIDTH { let t = Self::FAST_PARTIAL_ROUND_W_HATS[r][i - 1] as u128; let si = state[i].to_noncanonical_u64() as u128; d_sum = add_u160_u128(d_sum, si * t); @@ -411,10 +414,10 @@ pub trait Poseidon: PrimeField64 { let d = reduce_u160::(d_sum); // result = [d] concat [state[0] * v + state[shift up by 1]] - let mut result = [Self::ZERO; WIDTH]; + let mut result = [Self::ZERO; SPONGE_WIDTH]; result[0] = d; for i in 1..12 { - if i < WIDTH { + if i < SPONGE_WIDTH { let t = Self::from_canonical_u64(Self::FAST_PARTIAL_ROUND_VS[r][i - 1]); result[i] = state[i].multiply_accumulate(state[0], t); } @@ -424,21 +427,21 @@ pub trait Poseidon: PrimeField64 { /// Same as `mds_partial_layer_fast` for field extensions of `Self`. fn mds_partial_layer_fast_field, const D: usize>( - state: &[F; WIDTH], + state: &[F; SPONGE_WIDTH], r: usize, - ) -> [F; WIDTH] { + ) -> [F; SPONGE_WIDTH] { let s0 = state[0]; let mds0to0 = Self::MDS_MATRIX_CIRC[0] + Self::MDS_MATRIX_DIAG[0]; let mut d = s0 * F::from_canonical_u64(mds0to0); - for i in 1..WIDTH { + for i in 1..SPONGE_WIDTH { let t = F::from_canonical_u64(Self::FAST_PARTIAL_ROUND_W_HATS[r][i - 1]); d += state[i] * t; } // result = [d] concat [state[0] * v + state[shift up by 1]] - let mut result = [F::ZERO; WIDTH]; + let mut result = [F::ZERO; SPONGE_WIDTH]; result[0] = d; - for i in 1..WIDTH { + for i in 1..SPONGE_WIDTH { let t = F::from_canonical_u64(Self::FAST_PARTIAL_ROUND_VS[r][i - 1]); result[i] = state[0] * t + state[i]; } @@ -448,25 +451,25 @@ pub trait Poseidon: PrimeField64 { /// Recursive version of `mds_partial_layer_fast`. fn mds_partial_layer_fast_circuit( builder: &mut CircuitBuilder, - state: &[ExtensionTarget; WIDTH], + state: &[ExtensionTarget; SPONGE_WIDTH], r: usize, - ) -> [ExtensionTarget; WIDTH] + ) -> [ExtensionTarget; SPONGE_WIDTH] where Self: RichField + Extendable, { let s0 = state[0]; let mds0to0 = Self::MDS_MATRIX_CIRC[0] + Self::MDS_MATRIX_DIAG[0]; let mut d = builder.mul_const_extension(Self::from_canonical_u64(mds0to0), s0); - for i in 1..WIDTH { + for i in 1..SPONGE_WIDTH { let t = ::FAST_PARTIAL_ROUND_W_HATS[r][i - 1]; let t = Self::Extension::from_canonical_u64(t); let t = builder.constant_extension(t); d = builder.mul_add_extension(t, state[i], d); } - let mut result = [builder.zero_extension(); WIDTH]; + let mut result = [builder.zero_extension(); SPONGE_WIDTH]; result[0] = d; - for i in 1..WIDTH { + for i in 1..SPONGE_WIDTH { let t = ::FAST_PARTIAL_ROUND_VS[r][i - 1]; let t = Self::Extension::from_canonical_u64(t); let t = builder.constant_extension(t); @@ -477,10 +480,10 @@ pub trait Poseidon: PrimeField64 { #[inline(always)] #[unroll_for_loops] - fn constant_layer(state: &mut [Self; WIDTH], round_ctr: usize) { + fn constant_layer(state: &mut [Self; SPONGE_WIDTH], round_ctr: usize) { for i in 0..12 { - if i < WIDTH { - let round_constant = ALL_ROUND_CONSTANTS[i + WIDTH * round_ctr]; + if i < SPONGE_WIDTH { + let round_constant = ALL_ROUND_CONSTANTS[i + SPONGE_WIDTH * round_ctr]; unsafe { state[i] = state[i].add_canonical_u64(round_constant); } @@ -490,24 +493,24 @@ pub trait Poseidon: PrimeField64 { /// Same as `constant_layer` for field extensions of `Self`. fn constant_layer_field, const D: usize>( - state: &mut [F; WIDTH], + state: &mut [F; SPONGE_WIDTH], round_ctr: usize, ) { - for i in 0..WIDTH { - state[i] += F::from_canonical_u64(ALL_ROUND_CONSTANTS[i + WIDTH * round_ctr]); + for i in 0..SPONGE_WIDTH { + state[i] += F::from_canonical_u64(ALL_ROUND_CONSTANTS[i + SPONGE_WIDTH * round_ctr]); } } /// Recursive version of `constant_layer`. fn constant_layer_circuit( builder: &mut CircuitBuilder, - state: &mut [ExtensionTarget; WIDTH], + state: &mut [ExtensionTarget; SPONGE_WIDTH], round_ctr: usize, ) where Self: RichField + Extendable, { - for i in 0..WIDTH { - let c = ALL_ROUND_CONSTANTS[i + WIDTH * round_ctr]; + for i in 0..SPONGE_WIDTH { + let c = ALL_ROUND_CONSTANTS[i + SPONGE_WIDTH * round_ctr]; let c = Self::Extension::from_canonical_u64(c); let c = builder.constant_extension(c); state[i] = builder.add_extension(state[i], c); @@ -537,9 +540,9 @@ pub trait Poseidon: PrimeField64 { #[inline(always)] #[unroll_for_loops] - fn sbox_layer(state: &mut [Self; WIDTH]) { + fn sbox_layer(state: &mut [Self; SPONGE_WIDTH]) { for i in 0..12 { - if i < WIDTH { + if i < SPONGE_WIDTH { state[i] = Self::sbox_monomial(state[i]); } } @@ -547,9 +550,9 @@ pub trait Poseidon: PrimeField64 { /// Same as `sbox_layer` for field extensions of `Self`. fn sbox_layer_field, const D: usize>( - state: &mut [F; WIDTH], + state: &mut [F; SPONGE_WIDTH], ) { - for i in 0..WIDTH { + for i in 0..SPONGE_WIDTH { state[i] = Self::sbox_monomial(state[i]); } } @@ -557,17 +560,17 @@ pub trait Poseidon: PrimeField64 { /// Recursive version of `sbox_layer`. fn sbox_layer_circuit( builder: &mut CircuitBuilder, - state: &mut [ExtensionTarget; WIDTH], + state: &mut [ExtensionTarget; SPONGE_WIDTH], ) where Self: RichField + Extendable, { - for i in 0..WIDTH { + for i in 0..SPONGE_WIDTH { state[i] = ::sbox_monomial_circuit(builder, state[i]); } } #[inline] - fn full_rounds(state: &mut [Self; WIDTH], round_ctr: &mut usize) { + fn full_rounds(state: &mut [Self; SPONGE_WIDTH], round_ctr: &mut usize) { for _ in 0..HALF_N_FULL_ROUNDS { Self::constant_layer(state, *round_ctr); Self::sbox_layer(state); @@ -577,7 +580,7 @@ pub trait Poseidon: PrimeField64 { } #[inline] - fn partial_rounds(state: &mut [Self; WIDTH], round_ctr: &mut usize) { + fn partial_rounds(state: &mut [Self; SPONGE_WIDTH], round_ctr: &mut usize) { Self::partial_first_constant_layer(state); *state = Self::mds_partial_layer_init(state); @@ -592,7 +595,7 @@ pub trait Poseidon: PrimeField64 { } #[inline] - fn poseidon(input: [Self; WIDTH]) -> [Self; WIDTH] { + fn poseidon(input: [Self; SPONGE_WIDTH]) -> [Self; SPONGE_WIDTH] { let mut state = input; let mut round_ctr = 0; @@ -606,7 +609,7 @@ pub trait Poseidon: PrimeField64 { // For testing only, to ensure that various tricks are correct. #[inline] - fn partial_rounds_naive(state: &mut [Self; WIDTH], round_ctr: &mut usize) { + fn partial_rounds_naive(state: &mut [Self; SPONGE_WIDTH], round_ctr: &mut usize) { for _ in 0..N_PARTIAL_ROUNDS { Self::constant_layer(state, *round_ctr); state[0] = Self::sbox_monomial(state[0]); @@ -616,7 +619,7 @@ pub trait Poseidon: PrimeField64 { } #[inline] - fn poseidon_naive(input: [Self; WIDTH]) -> [Self; WIDTH] { + fn poseidon_naive(input: [Self; SPONGE_WIDTH]) -> [Self; SPONGE_WIDTH] { let mut state = input; let mut round_ctr = 0; @@ -630,7 +633,7 @@ pub trait Poseidon: PrimeField64 { } pub struct PoseidonPermutation; -impl PlonkyPermutation for PoseidonPermutation { +impl PlonkyPermutation for PoseidonPermutation { fn permute(input: [F; SPONGE_WIDTH]) -> [F; SPONGE_WIDTH] { F::poseidon(input) } @@ -639,21 +642,21 @@ impl PlonkyPermutation for PoseidonPermutation { /// Poseidon hash function. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct PoseidonHash; -impl Hasher for PoseidonHash { +impl Hasher for PoseidonHash { const HASH_SIZE: usize = 4 * 8; type Hash = HashOut; type Permutation = PoseidonPermutation; fn hash_no_pad(input: &[F]) -> Self::Hash { - hash_n_to_hash_no_pad::(input) + hash_n_to_hash_no_pad::(input) } fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash { - compress::(left, right) + compress::(left, right) } } -impl AlgebraicHasher for PoseidonHash { +impl AlgebraicHasher for PoseidonHash { fn permute_swapped( inputs: [Target; SPONGE_WIDTH], swap: BoolTarget, @@ -688,8 +691,7 @@ impl AlgebraicHasher for PoseidonHash { #[cfg(test)] pub(crate) mod test_helpers { use crate::field::types::Field; - use crate::hash::hashing::SPONGE_WIDTH; - use crate::hash::poseidon::Poseidon; + use crate::hash::poseidon::{Poseidon, SPONGE_WIDTH}; pub(crate) fn check_test_vectors( test_vectors: Vec<([u64; SPONGE_WIDTH], [u64; SPONGE_WIDTH])>, diff --git a/plonky2/src/iop/challenger.rs b/plonky2/src/iop/challenger.rs index b5661a91..07b99981 100644 --- a/plonky2/src/iop/challenger.rs +++ b/plonky2/src/iop/challenger.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use crate::field::extension::{Extendable, FieldExtension}; use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget, RichField}; -use crate::hash::hashing::{PlonkyPermutation, SPONGE_RATE, SPONGE_WIDTH}; +use crate::hash::hashing::{HashConfig, PlonkyPermutation}; use crate::hash::merkle_tree::MerkleCap; use crate::iop::ext_target::ExtensionTarget; use crate::iop::target::Target; @@ -13,8 +13,11 @@ use crate::plonk::config::{AlgebraicHasher, GenericHashOut, Hasher}; /// Observes prover messages, and generates challenges by hashing the transcript, a la Fiat-Shamir. #[derive(Clone)] -pub struct Challenger> { - pub(crate) sponge_state: [F; SPONGE_WIDTH], +pub struct Challenger> +where + [(); HC::WIDTH]:, +{ + pub(crate) sponge_state: [F; HC::WIDTH], pub(crate) input_buffer: Vec, output_buffer: Vec, _phantom: PhantomData, @@ -28,23 +31,32 @@ pub struct Challenger> { /// design, but it can be viewed as a duplex sponge whose inputs are sometimes zero (when we perform /// multiple squeezes) and whose outputs are sometimes ignored (when we perform multiple /// absorptions). Thus the security properties of a duplex sponge still apply to our design. -impl> Challenger { - pub fn new() -> Challenger { +impl> Challenger +where + [(); HC::WIDTH]:, +{ + pub fn new() -> Challenger + where + [(); HC::WIDTH]:, + { Challenger { - sponge_state: [F::ZERO; SPONGE_WIDTH], - input_buffer: Vec::with_capacity(SPONGE_RATE), - output_buffer: Vec::with_capacity(SPONGE_RATE), + sponge_state: [F::ZERO; HC::WIDTH], + input_buffer: Vec::with_capacity(HC::RATE), + output_buffer: Vec::with_capacity(HC::RATE), _phantom: Default::default(), } } - pub fn observe_element(&mut self, element: F) { + pub fn observe_element(&mut self, element: F) + where + [(); HC::WIDTH]:, + { // Any buffered outputs are now invalid, since they wouldn't reflect this input. self.output_buffer.clear(); self.input_buffer.push(element); - if self.input_buffer.len() == SPONGE_RATE { + if self.input_buffer.len() == HC::RATE { self.duplexing(); } } @@ -52,11 +64,15 @@ impl> Challenger { pub fn observe_extension_element(&mut self, element: &F::Extension) where F: RichField + Extendable, + [(); HC::WIDTH]:, { self.observe_elements(&element.to_basefield_array()); } - pub fn observe_elements(&mut self, elements: &[F]) { + pub fn observe_elements(&mut self, elements: &[F]) + where + [(); HC::WIDTH]:, + { for &element in elements { self.observe_element(element); } @@ -65,23 +81,33 @@ impl> Challenger { pub fn observe_extension_elements(&mut self, elements: &[F::Extension]) where F: RichField + Extendable, + [(); HC::WIDTH]:, { for element in elements { self.observe_extension_element(element); } } - pub fn observe_hash>(&mut self, hash: OH::Hash) { + pub fn observe_hash>(&mut self, hash: OH::Hash) + where + [(); OHC::WIDTH]:, + { self.observe_elements(&hash.to_vec()) } - pub fn observe_cap>(&mut self, cap: &MerkleCap) { + pub fn observe_cap>(&mut self, cap: &MerkleCap) + where + [(); OHC::WIDTH]:, + { for &hash in &cap.0 { - self.observe_hash::(hash); + self.observe_hash::(hash); } } - pub fn get_challenge(&mut self) -> F { + pub fn get_challenge(&mut self) -> F + where + [(); HC::WIDTH]:, + { // 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() { @@ -93,11 +119,17 @@ impl> Challenger { .expect("Output buffer should be non-empty") } - pub fn get_n_challenges(&mut self, n: usize) -> Vec { + pub fn get_n_challenges(&mut self, n: usize) -> Vec + where + [(); HC::WIDTH]:, + { (0..n).map(|_| self.get_challenge()).collect() } - pub fn get_hash(&mut self) -> HashOut { + pub fn get_hash(&mut self) -> HashOut + where + [(); HC::WIDTH]:, + { HashOut { elements: [ self.get_challenge(), @@ -111,6 +143,7 @@ impl> Challenger { pub fn get_extension_challenge(&mut self) -> F::Extension where F: RichField + Extendable, + [(); HC::WIDTH]:, { let mut arr = [F::ZERO; D]; arr.copy_from_slice(&self.get_n_challenges(D)); @@ -120,6 +153,7 @@ impl> Challenger { pub fn get_n_extension_challenges(&mut self, n: usize) -> Vec where F: RichField + Extendable, + [(); HC::WIDTH]:, { (0..n) .map(|_| self.get_extension_challenge::()) @@ -128,8 +162,11 @@ impl> Challenger { /// Absorb any buffered inputs. After calling this, the input buffer will be empty, and the /// output buffer will be full. - fn duplexing(&mut self) { - assert!(self.input_buffer.len() <= SPONGE_RATE); + fn duplexing(&mut self) + where + [(); HC::WIDTH]:, + { + assert!(self.input_buffer.len() <= HC::RATE); // Overwrite the first r elements with the inputs. This differs from a standard sponge, // where we would xor or add in the inputs. This is a well-known variant, though, @@ -143,10 +180,10 @@ impl> Challenger { self.output_buffer.clear(); self.output_buffer - .extend_from_slice(&self.sponge_state[0..SPONGE_RATE]); + .extend_from_slice(&self.sponge_state[0..HC::RATE]); } - pub fn compact(&mut self) -> [F; SPONGE_WIDTH] { + pub fn compact(&mut self) -> [F; HC::WIDTH] { if !self.input_buffer.is_empty() { self.duplexing(); } @@ -155,37 +192,54 @@ impl> Challenger { } } -impl> Default for Challenger { - fn default() -> Self { +impl> Default for Challenger +where + [(); HC::WIDTH]:, +{ + fn default() -> Self + where + [(); HC::WIDTH]:, + { Self::new() } } /// A recursive version of `Challenger`. The main difference is that `RecursiveChallenger`'s input -/// buffer can grow beyond `SPONGE_RATE`. This is so that `observe_element` etc do not need access +/// buffer can grow beyond `HC::RATE`. This is so that `observe_element` etc do not need access /// to the `CircuitBuilder`. -pub struct RecursiveChallenger, H: AlgebraicHasher, const D: usize> +pub struct RecursiveChallenger< + F: RichField + Extendable, + HC: HashConfig, + H: AlgebraicHasher, + const D: usize, +> where + [(); HC::WIDTH]:, { - sponge_state: [Target; SPONGE_WIDTH], + sponge_state: [Target; HC::WIDTH], input_buffer: Vec, output_buffer: Vec, __: PhantomData<(F, H)>, } -impl, H: AlgebraicHasher, const D: usize> - RecursiveChallenger +impl, HC: HashConfig, H: AlgebraicHasher, const D: usize> + RecursiveChallenger +where + [(); HC::WIDTH]:, { - pub fn new(builder: &mut CircuitBuilder) -> Self { + pub fn new(builder: &mut CircuitBuilder) -> Self + where + [(); HC::WIDTH]:, + { let zero = builder.zero(); Self { - sponge_state: [zero; SPONGE_WIDTH], + sponge_state: [zero; HC::WIDTH], input_buffer: Vec::new(), output_buffer: Vec::new(), __: PhantomData, } } - pub fn from_state(sponge_state: [Target; SPONGE_WIDTH]) -> Self { + pub fn from_state(sponge_state: [Target; HC::WIDTH]) -> Self { Self { sponge_state, input_buffer: vec![], @@ -194,46 +248,67 @@ impl, H: AlgebraicHasher, const D: usize> } } - pub(crate) fn observe_element(&mut self, target: Target) { + pub(crate) fn observe_element(&mut self, target: Target) + where + [(); HC::WIDTH]:, + { // Any buffered outputs are now invalid, since they wouldn't reflect this input. self.output_buffer.clear(); self.input_buffer.push(target); } - pub fn observe_elements(&mut self, targets: &[Target]) { + pub fn observe_elements(&mut self, targets: &[Target]) + where + [(); HC::WIDTH]:, + { for &target in targets { self.observe_element(target); } } - pub fn observe_hash(&mut self, hash: &HashOutTarget) { + pub fn observe_hash(&mut self, hash: &HashOutTarget) + where + [(); HC::WIDTH]:, + { self.observe_elements(&hash.elements) } - pub fn observe_cap(&mut self, cap: &MerkleCapTarget) { + pub fn observe_cap(&mut self, cap: &MerkleCapTarget) + where + [(); HC::WIDTH]:, + { for hash in &cap.0 { self.observe_hash(hash) } } - pub fn observe_extension_element(&mut self, element: ExtensionTarget) { + pub fn observe_extension_element(&mut self, element: ExtensionTarget) + where + [(); HC::WIDTH]:, + { self.observe_elements(&element.0); } - pub fn observe_extension_elements(&mut self, elements: &[ExtensionTarget]) { + pub fn observe_extension_elements(&mut self, elements: &[ExtensionTarget]) + where + [(); HC::WIDTH]:, + { for &element in elements { self.observe_extension_element(element); } } - pub fn get_challenge(&mut self, builder: &mut CircuitBuilder) -> Target { + pub fn get_challenge(&mut self, builder: &mut CircuitBuilder) -> Target + where + [(); HC::WIDTH]:, + { self.absorb_buffered_inputs(builder); if self.output_buffer.is_empty() { // Evaluate the permutation to produce `r` new outputs. - self.sponge_state = builder.permute::(self.sponge_state); - self.output_buffer = self.sponge_state[0..SPONGE_RATE].to_vec(); + self.sponge_state = builder.permute::(self.sponge_state); + self.output_buffer = self.sponge_state[0..HC::RATE].to_vec(); } self.output_buffer @@ -241,15 +316,17 @@ impl, H: AlgebraicHasher, const D: usize> .expect("Output buffer should be non-empty") } - pub fn get_n_challenges( - &mut self, - builder: &mut CircuitBuilder, - n: usize, - ) -> Vec { + pub fn get_n_challenges(&mut self, builder: &mut CircuitBuilder, n: usize) -> Vec + where + [(); HC::WIDTH]:, + { (0..n).map(|_| self.get_challenge(builder)).collect() } - pub fn get_hash(&mut self, builder: &mut CircuitBuilder) -> HashOutTarget { + pub fn get_hash(&mut self, builder: &mut CircuitBuilder) -> HashOutTarget + where + [(); HC::WIDTH]:, + { HashOutTarget { elements: [ self.get_challenge(builder), @@ -263,18 +340,24 @@ impl, H: AlgebraicHasher, const D: usize> pub fn get_extension_challenge( &mut self, builder: &mut CircuitBuilder, - ) -> ExtensionTarget { + ) -> ExtensionTarget + where + [(); HC::WIDTH]:, + { self.get_n_challenges(builder, D).try_into().unwrap() } /// Absorb any buffered inputs. After calling this, the input buffer will be empty, and the /// output buffer will be full. - fn absorb_buffered_inputs(&mut self, builder: &mut CircuitBuilder) { + fn absorb_buffered_inputs(&mut self, builder: &mut CircuitBuilder) + where + [(); HC::WIDTH]:, + { if self.input_buffer.is_empty() { return; } - for input_chunk in self.input_buffer.chunks(SPONGE_RATE) { + for input_chunk in self.input_buffer.chunks(HC::RATE) { // Overwrite the first r elements with the inputs. This differs from a standard sponge, // where we would xor or add in the inputs. This is a well-known variant, though, // sometimes called "overwrite mode". @@ -283,15 +366,15 @@ impl, H: AlgebraicHasher, const D: usize> } // Apply the permutation. - self.sponge_state = builder.permute::(self.sponge_state); + self.sponge_state = builder.permute::(self.sponge_state); } - self.output_buffer = self.sponge_state[0..SPONGE_RATE].to_vec(); + self.output_buffer = self.sponge_state[0..HC::RATE].to_vec(); self.input_buffer.clear(); } - pub fn compact(&mut self, builder: &mut CircuitBuilder) -> [Target; SPONGE_WIDTH] { + pub fn compact(&mut self, builder: &mut CircuitBuilder) -> [Target; HC::WIDTH] { self.absorb_buffered_inputs(builder); self.output_buffer.clear(); self.sponge_state @@ -307,14 +390,17 @@ mod tests { use crate::iop::witness::{PartialWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; #[test] fn no_duplicate_challenges() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - let mut challenger = Challenger::>::InnerHasher>::new(); + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + let mut challenger = + Challenger::>::InnerHasher>::new(); let mut challenges = Vec::new(); for i in 1..10 { @@ -335,7 +421,9 @@ mod tests { fn test_consistency() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; // These are mostly arbitrary, but we want to test some rounds with enough inputs/outputs to // trigger multiple absorptions/squeezes. @@ -348,7 +436,8 @@ mod tests { .map(|&n| F::rand_vec(n)) .collect(); - let mut challenger = Challenger::>::InnerHasher>::new(); + let mut challenger = + Challenger::>::InnerHasher>::new(); let mut outputs_per_round: Vec> = Vec::new(); for (r, inputs) in inputs_per_round.iter().enumerate() { challenger.observe_elements(inputs); @@ -358,7 +447,9 @@ mod tests { let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); let mut recursive_challenger = - RecursiveChallenger::>::InnerHasher, D>::new(&mut builder); + RecursiveChallenger::>::InnerHasher, D>::new( + &mut builder, + ); let mut recursive_outputs_per_round: Vec> = Vec::new(); for (r, inputs) in inputs_per_round.iter().enumerate() { recursive_challenger.observe_elements(&builder.constants(inputs)); @@ -366,7 +457,7 @@ mod tests { recursive_challenger.get_n_challenges(&mut builder, num_outputs_per_round[r]), ); } - let circuit = builder.build::(); + let circuit = builder.build::(); let inputs = PartialWitness::new(); let witness = generate_partial_witness(inputs, &circuit.prover_only, &circuit.common); let recursive_output_values_per_round: Vec> = recursive_outputs_per_round diff --git a/plonky2/src/iop/generator.rs b/plonky2/src/iop/generator.rs index a65d1748..b2ddd2ce 100644 --- a/plonky2/src/iop/generator.rs +++ b/plonky2/src/iop/generator.rs @@ -6,6 +6,7 @@ use core::marker::PhantomData; use crate::field::extension::Extendable; use crate::field::types::Field; use crate::hash::hash_types::RichField; +use crate::hash::hashing::HashConfig; use crate::iop::ext_target::ExtensionTarget; use crate::iop::target::Target; use crate::iop::wire::Wire; @@ -18,11 +19,13 @@ use crate::plonk::config::GenericConfig; pub(crate) fn generate_partial_witness< 'a, F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, >( inputs: PartialWitness, - prover_data: &'a ProverOnlyCircuitData, + prover_data: &'a ProverOnlyCircuitData, common_data: &'a CommonCircuitData, ) -> PartitionWitness<'a, F> { let config = &common_data.config; diff --git a/plonky2/src/iop/witness.rs b/plonky2/src/iop/witness.rs index 14213d0d..9879be0b 100644 --- a/plonky2/src/iop/witness.rs +++ b/plonky2/src/iop/witness.rs @@ -9,6 +9,7 @@ use crate::field::types::Field; use crate::fri::structure::{FriOpenings, FriOpeningsTarget}; use crate::fri::witness_util::set_fri_proof_target; use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget, RichField}; +use crate::hash::hashing::HashConfig; use crate::hash::merkle_tree::MerkleCap; use crate::iop::ext_target::ExtensionTarget; use crate::iop::target::{BoolTarget, Target}; @@ -27,10 +28,10 @@ pub trait WitnessWrite { .for_each(|(&t, x)| self.set_target(t, x)); } - fn set_cap_target>( + fn set_cap_target>( &mut self, ct: &MerkleCapTarget, - value: &MerkleCap, + value: &MerkleCap, ) where F: RichField, { @@ -71,13 +72,18 @@ pub trait WitnessWrite { /// Set the targets in a `ProofWithPublicInputsTarget` to their corresponding values in a /// `ProofWithPublicInputs`. - fn set_proof_with_pis_target, const D: usize>( + fn set_proof_with_pis_target< + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + >( &mut self, proof_with_pis_target: &ProofWithPublicInputsTarget, - proof_with_pis: &ProofWithPublicInputs, + proof_with_pis: &ProofWithPublicInputs, ) where F: RichField + Extendable, - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, { let ProofWithPublicInputs { proof, @@ -97,13 +103,18 @@ pub trait WitnessWrite { } /// Set the targets in a `ProofTarget` to their corresponding values in a `Proof`. - fn set_proof_target, const D: usize>( + fn set_proof_target< + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + >( &mut self, proof_target: &ProofTarget, - proof: &Proof, + proof: &Proof, ) where F: RichField + Extendable, - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, { self.set_cap_target(&proof_target.wires_cap, &proof.wires_cap); self.set_cap_target( @@ -136,13 +147,18 @@ pub trait WitnessWrite { } } - fn set_verifier_data_target, const D: usize>( + fn set_verifier_data_target< + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + >( &mut self, vdt: &VerifierCircuitTarget, - vd: &VerifierOnlyCircuitData, + vd: &VerifierOnlyCircuitData, ) where F: RichField + Extendable, - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, { self.set_cap_target(&vdt.constants_sigmas_cap, &vd.constants_sigmas_cap); self.set_hash_target(vdt.circuit_digest, vd.circuit_digest); @@ -224,10 +240,14 @@ pub trait Witness: WitnessWrite { } } - fn get_merkle_cap_target>(&self, cap_target: MerkleCapTarget) -> MerkleCap + fn get_merkle_cap_target>( + &self, + cap_target: MerkleCapTarget, + ) -> MerkleCap where F: RichField, - H: AlgebraicHasher, + HC: HashConfig, + H: AlgebraicHasher, { let cap = cap_target .0 diff --git a/plonky2/src/lib.rs b/plonky2/src/lib.rs index c357c27a..17a7316d 100644 --- a/plonky2/src/lib.rs +++ b/plonky2/src/lib.rs @@ -1,5 +1,7 @@ #![allow(clippy::too_many_arguments)] #![allow(clippy::needless_range_loop)] +#![allow(clippy::upper_case_acronyms)] +#![feature(generic_const_exprs)] #![cfg_attr(not(feature = "std"), no_std)] extern crate alloc; diff --git a/plonky2/src/plonk/circuit_builder.rs b/plonky2/src/plonk/circuit_builder.rs index 21305f4d..67c31df9 100644 --- a/plonky2/src/plonk/circuit_builder.rs +++ b/plonky2/src/plonk/circuit_builder.rs @@ -28,6 +28,7 @@ use crate::gates::noop::NoopGate; use crate::gates::public_input::PublicInputGate; use crate::gates::selectors::selector_polynomials; use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget, RichField}; +use crate::hash::hashing::HashConfig; use crate::hash::merkle_proofs::MerkleProofTarget; use crate::hash::merkle_tree::MerkleCap; use crate::iop::ext_target::ExtensionTarget; @@ -434,19 +435,21 @@ impl, const D: usize> CircuitBuilder { } } - pub fn constant_merkle_cap>>( + pub fn constant_merkle_cap>>( &mut self, - cap: &MerkleCap, + cap: &MerkleCap, ) -> MerkleCapTarget { MerkleCapTarget(cap.0.iter().map(|h| self.constant_hash(*h)).collect()) } - pub fn constant_verifier_data>( + pub fn constant_verifier_data>( &mut self, - verifier_data: &VerifierOnlyCircuitData, + verifier_data: &VerifierOnlyCircuitData, ) -> VerifierCircuitTarget where - C::Hasher: AlgebraicHasher, + HCO: HashConfig, + HCI: HashConfig, + C::Hasher: AlgebraicHasher, { VerifierCircuitTarget { constants_sigmas_cap: self.constant_merkle_cap(&verifier_data.constants_sigmas_cap), @@ -737,7 +740,13 @@ impl, const D: usize> CircuitBuilder { } /// Builds a "full circuit", with both prover and verifier data. - pub fn build>(mut self) -> CircuitData { + pub fn build>( + mut self, + ) -> CircuitData + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { let mut timing = TimingTree::new("preprocess", Level::Trace); #[cfg(feature = "std")] let start = Instant::now(); @@ -748,7 +757,7 @@ impl, const D: usize> CircuitBuilder { // those hash wires match the claimed public inputs. let num_public_inputs = self.public_inputs.len(); let public_inputs_hash = - self.hash_n_to_hash_no_pad::(self.public_inputs.clone()); + self.hash_n_to_hash_no_pad::(self.public_inputs.clone()); let pi_gate = self.add_gate(PublicInputGate, vec![]); for (&hash_part, wire) in public_inputs_hash .elements @@ -825,7 +834,7 @@ impl, const D: usize> CircuitBuilder { let fft_root_table = fft_root_table(max_fft_points); let constants_sigmas_vecs = [constant_vecs, sigma_vecs.clone()].concat(); - let constants_sigmas_commitment = PolynomialBatch::from_values( + let constants_sigmas_commitment = PolynomialBatch::::from_values( constants_sigmas_vecs, rate_bits, PlonkOracle::CONSTANTS_SIGMAS.blinding, @@ -913,7 +922,7 @@ impl, const D: usize> CircuitBuilder { assert_eq!(goal_data, common, "The expected circuit data passed to cyclic recursion method did not match the actual circuit"); } - let prover_only = ProverOnlyCircuitData { + let prover_only = ProverOnlyCircuitData:: { generators: self.generators, generator_indices_by_watches, constants_sigmas_commitment, @@ -925,7 +934,7 @@ impl, const D: usize> CircuitBuilder { circuit_digest, }; - let verifier_only = VerifierOnlyCircuitData { + let verifier_only = VerifierOnlyCircuitData:: { constants_sigmas_cap, circuit_digest, }; @@ -941,16 +950,28 @@ impl, const D: usize> CircuitBuilder { } /// Builds a "prover circuit", with data needed to generate proofs but not verify them. - pub fn build_prover>(self) -> ProverCircuitData { + pub fn build_prover>( + self, + ) -> ProverCircuitData + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { // TODO: Can skip parts of this. - let circuit_data = self.build(); + let circuit_data = self.build::(); circuit_data.prover_data() } /// Builds a "verifier circuit", with data needed to verify proofs but not generate them. - pub fn build_verifier>(self) -> VerifierCircuitData { + pub fn build_verifier>( + self, + ) -> VerifierCircuitData + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { // TODO: Can skip parts of this. - let circuit_data = self.build(); + let circuit_data = self.build::(); circuit_data.verifier_data() } } diff --git a/plonky2/src/plonk/circuit_data.rs b/plonky2/src/plonk/circuit_data.rs index 78d8125c..9f0eab71 100644 --- a/plonky2/src/plonk/circuit_data.rs +++ b/plonky2/src/plonk/circuit_data.rs @@ -19,6 +19,7 @@ use crate::fri::{FriConfig, FriParams}; use crate::gates::gate::GateRef; use crate::gates::selectors::SelectorsInfo; use crate::hash::hash_types::{HashOutTarget, MerkleCapTarget, RichField}; +use crate::hash::hashing::HashConfig; use crate::hash::merkle_tree::MerkleCap; use crate::iop::ext_target::ExtensionTarget; use crate::iop::generator::WitnessGenerator; @@ -106,17 +107,35 @@ impl CircuitConfig { } /// Circuit data required by the prover or the verifier. -pub struct CircuitData, C: GenericConfig, const D: usize> { - pub prover_only: ProverOnlyCircuitData, - pub verifier_only: VerifierOnlyCircuitData, +pub struct CircuitData< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +> { + pub prover_only: ProverOnlyCircuitData, + pub verifier_only: VerifierOnlyCircuitData, pub common: CommonCircuitData, } -impl, C: GenericConfig, const D: usize> - CircuitData +impl< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + > CircuitData { - pub fn prove(&self, inputs: PartialWitness) -> Result> { - prove( + pub fn prove( + &self, + inputs: PartialWitness, + ) -> Result> + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { + prove::( &self.prover_only, &self.common, inputs, @@ -124,32 +143,48 @@ impl, C: GenericConfig, const D: usize> ) } - pub fn verify(&self, proof_with_pis: ProofWithPublicInputs) -> Result<()> { - verify(proof_with_pis, &self.verifier_only, &self.common) + pub fn verify(&self, proof_with_pis: ProofWithPublicInputs) -> Result<()> + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { + verify::(proof_with_pis, &self.verifier_only, &self.common) } pub fn verify_compressed( &self, - compressed_proof_with_pis: CompressedProofWithPublicInputs, - ) -> Result<()> { + compressed_proof_with_pis: CompressedProofWithPublicInputs, + ) -> Result<()> + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { compressed_proof_with_pis.verify(&self.verifier_only, &self.common) } pub fn compress( &self, - proof: ProofWithPublicInputs, - ) -> Result> { + proof: ProofWithPublicInputs, + ) -> Result> + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { proof.compress(&self.verifier_only.circuit_digest, &self.common) } pub fn decompress( &self, - proof: CompressedProofWithPublicInputs, - ) -> Result> { + proof: CompressedProofWithPublicInputs, + ) -> Result> + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { proof.decompress(&self.verifier_only.circuit_digest, &self.common) } - pub fn verifier_data(&self) -> VerifierCircuitData { + pub fn verifier_data(&self) -> VerifierCircuitData { let CircuitData { verifier_only, common, @@ -161,7 +196,7 @@ impl, C: GenericConfig, const D: usize> } } - pub fn prover_data(self) -> ProverCircuitData { + pub fn prover_data(self) -> ProverCircuitData { let CircuitData { prover_only, common, @@ -183,18 +218,32 @@ impl, C: GenericConfig, const D: usize> /// construct a more minimal prover structure and convert back and forth. pub struct ProverCircuitData< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, > { - pub prover_only: ProverOnlyCircuitData, + pub prover_only: ProverOnlyCircuitData, pub common: CommonCircuitData, } -impl, C: GenericConfig, const D: usize> - ProverCircuitData +impl< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + > ProverCircuitData { - pub fn prove(&self, inputs: PartialWitness) -> Result> { - prove( + pub fn prove( + &self, + inputs: PartialWitness, + ) -> Result> + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { + prove::( &self.prover_only, &self.common, inputs, @@ -207,24 +256,39 @@ impl, C: GenericConfig, const D: usize> #[derive(Debug)] pub struct VerifierCircuitData< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, > { - pub verifier_only: VerifierOnlyCircuitData, + pub verifier_only: VerifierOnlyCircuitData, pub common: CommonCircuitData, } -impl, C: GenericConfig, const D: usize> - VerifierCircuitData +impl< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + > VerifierCircuitData { - pub fn verify(&self, proof_with_pis: ProofWithPublicInputs) -> Result<()> { - verify(proof_with_pis, &self.verifier_only, &self.common) + pub fn verify(&self, proof_with_pis: ProofWithPublicInputs) -> Result<()> + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { + verify::(proof_with_pis, &self.verifier_only, &self.common) } pub fn verify_compressed( &self, - compressed_proof_with_pis: CompressedProofWithPublicInputs, - ) -> Result<()> { + compressed_proof_with_pis: CompressedProofWithPublicInputs, + ) -> Result<()> + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { compressed_proof_with_pis.verify(&self.verifier_only, &self.common) } } @@ -232,7 +296,9 @@ impl, C: GenericConfig, const D: usize> /// Circuit data required by the prover, but not the verifier. pub struct ProverOnlyCircuitData< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, > { pub generators: Vec>>, @@ -240,7 +306,7 @@ pub struct ProverOnlyCircuitData< /// they watch. pub generator_indices_by_watches: BTreeMap>, /// Commitments to the constants polynomials and sigma polynomials. - pub constants_sigmas_commitment: PolynomialBatch, + pub constants_sigmas_commitment: PolynomialBatch, /// The transpose of the list of sigma polynomials. pub sigmas: Vec>, /// Subgroup of order `degree`. @@ -254,17 +320,22 @@ pub struct ProverOnlyCircuitData< pub fft_root_table: Option>, /// A digest of the "circuit" (i.e. the instance, minus public inputs), which can be used to /// seed Fiat-Shamir. - pub circuit_digest: <>::Hasher as Hasher>::Hash, + pub circuit_digest: <>::Hasher as Hasher>::Hash, } /// Circuit data required by the verifier, but not the prover. #[derive(Debug, Clone, Eq, PartialEq)] -pub struct VerifierOnlyCircuitData, const D: usize> { +pub struct VerifierOnlyCircuitData< + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +> { /// A commitment to each constant polynomial and each permutation polynomial. - pub constants_sigmas_cap: MerkleCap, + pub constants_sigmas_cap: MerkleCap, /// A digest of the "circuit" (i.e. the instance, minus public inputs), which can be used to /// seed Fiat-Shamir. - pub circuit_digest: <>::Hasher as Hasher>::Hash, + pub circuit_digest: <>::Hasher as Hasher>::Hash, } /// Circuit data required by both the prover and the verifier. diff --git a/plonky2/src/plonk/config.rs b/plonky2/src/plonk/config.rs index cacc8421..c68998f6 100644 --- a/plonky2/src/plonk/config.rs +++ b/plonky2/src/plonk/config.rs @@ -9,7 +9,7 @@ use crate::field::extension::quadratic::QuadraticExtension; use crate::field::extension::{Extendable, FieldExtension}; use crate::field::goldilocks_field::GoldilocksField; use crate::hash::hash_types::{HashOut, RichField}; -use crate::hash::hashing::{PlonkyPermutation, SPONGE_WIDTH}; +use crate::hash::hashing::{HashConfig, PlonkyPermutation}; use crate::hash::keccak::KeccakHash; use crate::hash::poseidon::PoseidonHash; use crate::iop::target::{BoolTarget, Target}; @@ -25,7 +25,7 @@ pub trait GenericHashOut: } /// Trait for hash functions. -pub trait Hasher: Sized + Clone + Debug + Eq + PartialEq { +pub trait Hasher: Sized + Clone + Debug + Eq + PartialEq { /// Size of `Hash` in bytes. const HASH_SIZE: usize; @@ -33,17 +33,22 @@ pub trait Hasher: Sized + Clone + Debug + Eq + PartialEq { type Hash: GenericHashOut; /// Permutation used in the sponge construction. - type Permutation: PlonkyPermutation; + type Permutation: PlonkyPermutation; /// Hash a message without any padding step. Note that this can enable length-extension attacks. /// However, it is still collision-resistant in cases where the input has a fixed length. - fn hash_no_pad(input: &[F]) -> Self::Hash; + fn hash_no_pad(input: &[F]) -> Self::Hash + where + [(); HC::WIDTH]:; /// Pad the message using the `pad10*1` rule, then hash it. - fn hash_pad(input: &[F]) -> Self::Hash { + fn hash_pad(input: &[F]) -> Self::Hash + where + [(); HC::WIDTH]:, + { let mut padded_input = input.to_vec(); padded_input.push(F::ONE); - while (padded_input.len() + 1) % SPONGE_WIDTH != 0 { + while (padded_input.len() + 1) % HC::WIDTH != 0 { padded_input.push(F::ZERO); } padded_input.push(F::ONE); @@ -52,7 +57,10 @@ pub trait Hasher: Sized + Clone + Debug + Eq + PartialEq { /// Hash the slice if necessary to reduce its length to ~256 bits. If it already fits, this is a /// no-op. - fn hash_or_noop(inputs: &[F]) -> Self::Hash { + fn hash_or_noop(inputs: &[F]) -> Self::Hash + where + [(); HC::WIDTH]:, + { if inputs.len() * 8 <= Self::HASH_SIZE { let mut inputs_bytes = vec![0u8; Self::HASH_SIZE]; for i in 0..inputs.len() { @@ -65,27 +73,27 @@ pub trait Hasher: Sized + Clone + Debug + Eq + PartialEq { } } - fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash; + fn two_to_one(left: Self::Hash, right: Self::Hash) -> Self::Hash + where + [(); HC::WIDTH]:; } /// Trait for algebraic hash functions, built from a permutation using the sponge construction. -pub trait AlgebraicHasher: Hasher> { - // TODO: Adding a `const WIDTH: usize` here yields a compiler error down the line. - // Maybe try again in a while. - +pub trait AlgebraicHasher: Hasher> { /// Circuit to conditionally swap two chunks of the inputs (useful in verifying Merkle proofs), /// then apply the permutation. fn permute_swapped( - inputs: [Target; SPONGE_WIDTH], + inputs: [Target; HC::WIDTH], swap: BoolTarget, builder: &mut CircuitBuilder, - ) -> [Target; SPONGE_WIDTH] + ) -> [Target; HC::WIDTH] where + [(); HC::WIDTH]:, F: RichField + Extendable; } /// Generic configuration trait. -pub trait GenericConfig: +pub trait GenericConfig: Debug + Clone + Sync + Sized + Send + Eq + PartialEq { /// Main field. @@ -93,25 +101,37 @@ pub trait GenericConfig: /// Field extension of degree D of the main field. type FE: FieldExtension; /// Hash function used for building Merkle trees. - type Hasher: Hasher; + type Hasher: Hasher; /// Algebraic hash function used for the challenger and hashing public inputs. - type InnerHasher: AlgebraicHasher; + type InnerHasher: AlgebraicHasher; } +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct PoseidonHashConfig; +impl HashConfig for PoseidonHashConfig { + const RATE: usize = 8; + const WIDTH: usize = 12; +} /// Configuration using Poseidon over the Goldilocks field. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct PoseidonGoldilocksConfig; -impl GenericConfig<2> for PoseidonGoldilocksConfig { +impl GenericConfig for PoseidonGoldilocksConfig { type F = GoldilocksField; type FE = QuadraticExtension; type Hasher = PoseidonHash; type InnerHasher = PoseidonHash; } +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct KeccakHashConfig; +impl HashConfig for KeccakHashConfig { + const RATE: usize = 8; + const WIDTH: usize = 12; +} /// Configuration using truncated Keccak over the Goldilocks field. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct KeccakGoldilocksConfig; -impl GenericConfig<2> for KeccakGoldilocksConfig { +impl GenericConfig for KeccakGoldilocksConfig { type F = GoldilocksField; type FE = QuadraticExtension; type Hasher = KeccakHash<25>; diff --git a/plonky2/src/plonk/get_challenges.rs b/plonky2/src/plonk/get_challenges.rs index 1f6bd7ae..5932b6ff 100644 --- a/plonky2/src/plonk/get_challenges.rs +++ b/plonky2/src/plonk/get_challenges.rs @@ -9,6 +9,7 @@ use crate::fri::proof::{CompressedFriProof, FriChallenges, FriProof, FriProofTar use crate::fri::verifier::{compute_evaluation, fri_combine_initial, PrecomputedReducedOpenings}; use crate::gadgets::polynomial::PolynomialCoeffsExtTarget; use crate::hash::hash_types::{HashOutTarget, MerkleCapTarget, RichField}; +use crate::hash::hashing::HashConfig; use crate::hash::merkle_tree::MerkleCap; use crate::iop::challenger::{Challenger, RecursiveChallenger}; use crate::iop::target::Target; @@ -22,35 +23,45 @@ use crate::plonk::proof::{ }; use crate::util::reverse_bits; -fn get_challenges, C: GenericConfig, const D: usize>( - public_inputs_hash: <>::InnerHasher as Hasher>::Hash, - wires_cap: &MerkleCap, - plonk_zs_partial_products_cap: &MerkleCap, - quotient_polys_cap: &MerkleCap, +fn get_challenges< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +>( + public_inputs_hash: <>::InnerHasher as Hasher>::Hash, + wires_cap: &MerkleCap, + plonk_zs_partial_products_cap: &MerkleCap, + quotient_polys_cap: &MerkleCap, openings: &OpeningSet, - commit_phase_merkle_caps: &[MerkleCap], + commit_phase_merkle_caps: &[MerkleCap], final_poly: &PolynomialCoeffs, pow_witness: F, - circuit_digest: &<>::Hasher as Hasher>::Hash, + circuit_digest: &<>::Hasher as Hasher>::Hash, common_data: &CommonCircuitData, -) -> anyhow::Result> { +) -> anyhow::Result> +where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, +{ let config = &common_data.config; let num_challenges = config.num_challenges; - let mut challenger = Challenger::::new(); + let mut challenger = Challenger::::new(); // Observe the instance. - challenger.observe_hash::(*circuit_digest); - challenger.observe_hash::(public_inputs_hash); + challenger.observe_hash::(*circuit_digest); + challenger.observe_hash::(public_inputs_hash); - challenger.observe_cap(wires_cap); + challenger.observe_cap::(wires_cap); let plonk_betas = challenger.get_n_challenges(num_challenges); let plonk_gammas = challenger.get_n_challenges(num_challenges); - challenger.observe_cap(plonk_zs_partial_products_cap); + challenger.observe_cap::(plonk_zs_partial_products_cap); let plonk_alphas = challenger.get_n_challenges(num_challenges); - challenger.observe_cap(quotient_polys_cap); + challenger.observe_cap::(quotient_polys_cap); let plonk_zeta = challenger.get_extension_challenge::(); challenger.observe_openings(&openings.to_fri_openings()); @@ -60,7 +71,7 @@ fn get_challenges, C: GenericConfig, cons plonk_gammas, plonk_alphas, plonk_zeta, - fri_challenges: challenger.fri_challenges::( + fri_challenges: challenger.fri_challenges::( commit_phase_merkle_caps, final_poly, pow_witness, @@ -70,14 +81,23 @@ fn get_challenges, C: GenericConfig, cons }) } -impl, C: GenericConfig, const D: usize> - ProofWithPublicInputs +impl< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + > ProofWithPublicInputs { pub(crate) fn fri_query_indices( &self, - circuit_digest: &<>::Hasher as Hasher>::Hash, + circuit_digest: &<>::Hasher as Hasher>::Hash, common_data: &CommonCircuitData, - ) -> anyhow::Result> { + ) -> anyhow::Result> + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { Ok(self .get_challenges(self.get_public_inputs_hash(), circuit_digest, common_data)? .fri_challenges @@ -87,10 +107,14 @@ impl, C: GenericConfig, const D: usize> /// Computes all Fiat-Shamir challenges used in the Plonk proof. pub(crate) fn get_challenges( &self, - public_inputs_hash: <>::InnerHasher as Hasher>::Hash, - circuit_digest: &<>::Hasher as Hasher>::Hash, + public_inputs_hash: <>::InnerHasher as Hasher>::Hash, + circuit_digest: &<>::Hasher as Hasher>::Hash, common_data: &CommonCircuitData, - ) -> anyhow::Result> { + ) -> anyhow::Result> + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { let Proof { wires_cap, plonk_zs_partial_products_cap, @@ -105,7 +129,7 @@ impl, C: GenericConfig, const D: usize> }, } = &self.proof; - get_challenges::( + get_challenges::( public_inputs_hash, wires_cap, plonk_zs_partial_products_cap, @@ -120,16 +144,25 @@ impl, C: GenericConfig, const D: usize> } } -impl, C: GenericConfig, const D: usize> - CompressedProofWithPublicInputs +impl< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + > CompressedProofWithPublicInputs { /// Computes all Fiat-Shamir challenges used in the Plonk proof. pub(crate) fn get_challenges( &self, - public_inputs_hash: <>::InnerHasher as Hasher>::Hash, - circuit_digest: &<>::Hasher as Hasher>::Hash, + public_inputs_hash: <>::InnerHasher as Hasher>::Hash, + circuit_digest: &<>::Hasher as Hasher>::Hash, common_data: &CommonCircuitData, - ) -> anyhow::Result> { + ) -> anyhow::Result> + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { let CompressedProof { wires_cap, plonk_zs_partial_products_cap, @@ -144,7 +177,7 @@ impl, C: GenericConfig, const D: usize> }, } = &self.proof; - get_challenges::( + get_challenges::( public_inputs_hash, wires_cap, plonk_zs_partial_products_cap, @@ -189,7 +222,7 @@ impl, C: GenericConfig, const D: usize> for &(mut x_index) in fri_query_indices { let mut subgroup_x = F::MULTIPLICATIVE_GROUP_GENERATOR * F::primitive_root_of_unity(log_n).exp_u64(reverse_bits(x_index, log_n) as u64); - let mut old_eval = fri_combine_initial::( + let mut old_eval = fri_combine_initial::( &common_data.get_fri_instance(*plonk_zeta), &self .proof @@ -235,7 +268,7 @@ impl, C: GenericConfig, const D: usize> } impl, const D: usize> CircuitBuilder { - fn get_challenges>( + fn get_challenges>( &mut self, public_inputs_hash: HashOutTarget, wires_cap: &MerkleCapTarget, @@ -249,12 +282,14 @@ impl, const D: usize> CircuitBuilder { inner_common_data: &CommonCircuitData, ) -> ProofChallengesTarget where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let config = &inner_common_data.config; let num_challenges = config.num_challenges; - let mut challenger = RecursiveChallenger::::new(self); + let mut challenger = RecursiveChallenger::::new(self); // Observe the instance. challenger.observe_hash(&inner_circuit_digest); @@ -289,7 +324,12 @@ impl, const D: usize> CircuitBuilder { } impl ProofWithPublicInputsTarget { - pub(crate) fn get_challenges, C: GenericConfig>( + pub(crate) fn get_challenges< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + >( &self, builder: &mut CircuitBuilder, public_inputs_hash: HashOutTarget, @@ -297,7 +337,9 @@ impl ProofWithPublicInputsTarget { inner_common_data: &CommonCircuitData, ) -> ProofChallengesTarget where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let ProofTarget { wires_cap, @@ -313,7 +355,7 @@ impl ProofWithPublicInputsTarget { }, } = &self.proof; - builder.get_challenges::( + builder.get_challenges::( public_inputs_hash, wires_cap, plonk_zs_partial_products_cap, diff --git a/plonky2/src/plonk/proof.rs b/plonky2/src/plonk/proof.rs index 67884e01..476ff18a 100644 --- a/plonky2/src/plonk/proof.rs +++ b/plonky2/src/plonk/proof.rs @@ -15,6 +15,7 @@ use crate::fri::structure::{ }; use crate::fri::FriParams; use crate::hash::hash_types::{MerkleCapTarget, RichField}; +use crate::hash::hashing::HashConfig; use crate::hash::merkle_tree::MerkleCap; use crate::iop::ext_target::ExtensionTarget; use crate::iop::target::Target; @@ -27,17 +28,23 @@ use crate::util::serialization::{Buffer, Read}; #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct Proof, C: GenericConfig, const D: usize> { +pub struct Proof< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +> { /// Merkle cap of LDEs of wire values. - pub wires_cap: MerkleCap, + pub wires_cap: MerkleCap, /// Merkle cap of LDEs of Z, in the context of Plonk's permutation argument. - pub plonk_zs_partial_products_cap: MerkleCap, + pub plonk_zs_partial_products_cap: MerkleCap, /// Merkle cap of LDEs of the quotient polynomial components. - pub quotient_polys_cap: MerkleCap, + pub quotient_polys_cap: MerkleCap, /// Purported values of each polynomial at the challenge point. pub openings: OpeningSet, /// A batch FRI argument for all openings. - pub opening_proof: FriProof, + pub opening_proof: FriProof, } #[derive(Clone, Debug)] @@ -49,9 +56,20 @@ pub struct ProofTarget { pub opening_proof: FriProofTarget, } -impl, C: GenericConfig, const D: usize> Proof { +impl< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + > Proof +{ /// Compress the proof. - pub fn compress(self, indices: &[usize], params: &FriParams) -> CompressedProof { + pub fn compress( + self, + indices: &[usize], + params: &FriParams, + ) -> CompressedProof { let Proof { wires_cap, plonk_zs_partial_products_cap, @@ -74,21 +92,32 @@ impl, C: GenericConfig, const D: usize> P #[serde(bound = "")] pub struct ProofWithPublicInputs< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, > { - pub proof: Proof, + pub proof: Proof, pub public_inputs: Vec, } -impl, C: GenericConfig, const D: usize> - ProofWithPublicInputs +impl< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + > ProofWithPublicInputs { pub fn compress( self, - circuit_digest: &<>::Hasher as Hasher>::Hash, + circuit_digest: &<>::Hasher as Hasher>::Hash, common_data: &CommonCircuitData, - ) -> anyhow::Result> { + ) -> anyhow::Result> + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { let indices = self.fri_query_indices(circuit_digest, common_data)?; let compressed_proof = self.proof.compress(&indices, &common_data.fri_params); Ok(CompressedProofWithPublicInputs { @@ -99,7 +128,10 @@ impl, C: GenericConfig, const D: usize> pub(crate) fn get_public_inputs_hash( &self, - ) -> <>::InnerHasher as Hasher>::Hash { + ) -> <>::InnerHasher as Hasher>::Hash + where + [(); HCI::WIDTH]:, + { C::InnerHasher::hash_no_pad(&self.public_inputs) } @@ -126,22 +158,32 @@ impl, C: GenericConfig, const D: usize> #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct CompressedProof, C: GenericConfig, const D: usize> -{ +pub struct CompressedProof< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +> { /// Merkle cap of LDEs of wire values. - pub wires_cap: MerkleCap, + pub wires_cap: MerkleCap, /// Merkle cap of LDEs of Z, in the context of Plonk's permutation argument. - pub plonk_zs_partial_products_cap: MerkleCap, + pub plonk_zs_partial_products_cap: MerkleCap, /// Merkle cap of LDEs of the quotient polynomial components. - pub quotient_polys_cap: MerkleCap, + pub quotient_polys_cap: MerkleCap, /// Purported values of each polynomial at the challenge point. pub openings: OpeningSet, /// A compressed batch FRI argument for all openings. - pub opening_proof: CompressedFriProof, + pub opening_proof: CompressedFriProof, } -impl, C: GenericConfig, const D: usize> - CompressedProof +impl< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + > CompressedProof { /// Decompress the proof. pub(crate) fn decompress( @@ -149,7 +191,10 @@ impl, C: GenericConfig, const D: usize> challenges: &ProofChallenges, fri_inferred_elements: FriInferredElements, params: &FriParams, - ) -> Proof { + ) -> Proof + where + [(); HCO::WIDTH]:, + { let CompressedProof { wires_cap, plonk_zs_partial_products_cap, @@ -172,21 +217,32 @@ impl, C: GenericConfig, const D: usize> #[serde(bound = "")] pub struct CompressedProofWithPublicInputs< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, > { - pub proof: CompressedProof, + pub proof: CompressedProof, pub public_inputs: Vec, } -impl, C: GenericConfig, const D: usize> - CompressedProofWithPublicInputs +impl< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + > CompressedProofWithPublicInputs { pub fn decompress( self, - circuit_digest: &<>::Hasher as Hasher>::Hash, + circuit_digest: &<>::Hasher as Hasher>::Hash, common_data: &CommonCircuitData, - ) -> anyhow::Result> { + ) -> anyhow::Result> + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { let challenges = self.get_challenges(self.get_public_inputs_hash(), circuit_digest, common_data)?; let fri_inferred_elements = self.get_inferred_elements(&challenges, common_data); @@ -201,9 +257,13 @@ impl, C: GenericConfig, const D: usize> pub(crate) fn verify( self, - verifier_data: &VerifierOnlyCircuitData, + verifier_data: &VerifierOnlyCircuitData, common_data: &CommonCircuitData, - ) -> anyhow::Result<()> { + ) -> anyhow::Result<()> + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { ensure!( self.public_inputs.len() == common_data.num_public_inputs, "Number of public inputs doesn't match circuit data." @@ -218,7 +278,7 @@ impl, C: GenericConfig, const D: usize> let decompressed_proof = self.proof .decompress(&challenges, fri_inferred_elements, &common_data.fri_params); - verify_with_challenges( + verify_with_challenges::( decompressed_proof, public_inputs_hash, challenges, @@ -229,7 +289,10 @@ impl, C: GenericConfig, const D: usize> pub(crate) fn get_public_inputs_hash( &self, - ) -> <>::InnerHasher as Hasher>::Hash { + ) -> <>::InnerHasher as Hasher>::Hash + where + [(); HCI::WIDTH]:, + { C::InnerHasher::hash_no_pad(&self.public_inputs) } @@ -302,16 +365,16 @@ pub struct OpeningSet, const D: usize> { } impl, const D: usize> OpeningSet { - pub fn new>( + pub fn new>( zeta: F::Extension, g: F::Extension, - constants_sigmas_commitment: &PolynomialBatch, - wires_commitment: &PolynomialBatch, - zs_partial_products_commitment: &PolynomialBatch, - quotient_polys_commitment: &PolynomialBatch, + constants_sigmas_commitment: &PolynomialBatch, + wires_commitment: &PolynomialBatch, + zs_partial_products_commitment: &PolynomialBatch, + quotient_polys_commitment: &PolynomialBatch, common_data: &CommonCircuitData, ) -> Self { - let eval_commitment = |z: F::Extension, c: &PolynomialBatch| { + let eval_commitment = |z: F::Extension, c: &PolynomialBatch| { c.polynomials .par_iter() .map(|p| p.to_extension().eval(z)) @@ -398,14 +461,16 @@ mod tests { use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; use crate::plonk::verifier::verify; #[test] fn test_proof_compression() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let mut config = CircuitConfig::standard_recursion_config(); config.fri_config.reduction_strategy = FriReductionStrategy::Fixed(vec![1, 1]); @@ -426,7 +491,7 @@ mod tests { for _ in 0..100 { builder.add_gate(NoopGate, vec![]); } - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof.clone(), &data.verifier_only, &data.common)?; diff --git a/plonky2/src/plonk/prover.rs b/plonky2/src/plonk/prover.rs index f2b61226..a0b6313a 100644 --- a/plonky2/src/plonk/prover.rs +++ b/plonky2/src/plonk/prover.rs @@ -11,6 +11,7 @@ use crate::field::types::Field; use crate::field::zero_poly_coset::ZeroPolyOnCoset; use crate::fri::oracle::PolynomialBatch; use crate::hash::hash_types::RichField; +use crate::hash::hashing::HashConfig; use crate::iop::challenger::Challenger; use crate::iop::generator::generate_partial_witness; use crate::iop::witness::{MatrixWitness, PartialWitness, Witness}; @@ -25,12 +26,24 @@ use crate::util::partial_products::{partial_products_and_z_gx, quotient_chunk_pr use crate::util::timing::TimingTree; use crate::util::{ceil_div_usize, log2_ceil, transpose}; -pub fn prove, C: GenericConfig, const D: usize>( - prover_data: &ProverOnlyCircuitData, +pub fn prove< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +>( + prover_data: &ProverOnlyCircuitData, common_data: &CommonCircuitData, inputs: PartialWitness, timing: &mut TimingTree, -) -> Result> { +) -> Result> +where + C::Hasher: Hasher, + C::InnerHasher: Hasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, +{ let config = &common_data.config; let num_challenges = config.num_challenges; let quotient_degree = common_data.quotient_degree(); @@ -64,7 +77,7 @@ pub fn prove, C: GenericConfig, const D: let wires_commitment = timed!( timing, "compute wires commitment", - PolynomialBatch::from_values( + PolynomialBatch::::from_values( wires_values, config.fri_config.rate_bits, config.zero_knowledge && PlonkOracle::WIRES.blinding, @@ -74,13 +87,13 @@ pub fn prove, C: GenericConfig, const D: ) ); - let mut challenger = Challenger::::new(); + let mut challenger = Challenger::::new(); // Observe the instance. - challenger.observe_hash::(prover_data.circuit_digest); - challenger.observe_hash::(public_inputs_hash); + challenger.observe_hash::(prover_data.circuit_digest); + challenger.observe_hash::(public_inputs_hash); - challenger.observe_cap(&wires_commitment.merkle_tree.cap); + challenger.observe_cap::(&wires_commitment.merkle_tree.cap); let betas = challenger.get_n_challenges(num_challenges); let gammas = challenger.get_n_challenges(num_challenges); @@ -104,7 +117,7 @@ pub fn prove, C: GenericConfig, const D: let partial_products_and_zs_commitment = timed!( timing, "commit to partial products and Z's", - PolynomialBatch::from_values( + PolynomialBatch::::from_values( zs_partial_products, config.fri_config.rate_bits, config.zero_knowledge && PlonkOracle::ZS_PARTIAL_PRODUCTS.blinding, @@ -114,14 +127,14 @@ pub fn prove, C: GenericConfig, const D: ) ); - challenger.observe_cap(&partial_products_and_zs_commitment.merkle_tree.cap); + challenger.observe_cap::(&partial_products_and_zs_commitment.merkle_tree.cap); let alphas = challenger.get_n_challenges(num_challenges); let quotient_polys = timed!( timing, "compute quotient polys", - compute_quotient_polys( + compute_quotient_polys::( common_data, prover_data, &public_inputs_hash, @@ -152,7 +165,7 @@ pub fn prove, C: GenericConfig, const D: let quotient_polys_commitment = timed!( timing, "commit to quotient polys", - PolynomialBatch::from_coeffs( + PolynomialBatch::::from_coeffs( all_quotient_poly_chunks, config.fri_config.rate_bits, config.zero_knowledge && PlonkOracle::QUOTIENT.blinding, @@ -162,7 +175,7 @@ pub fn prove, C: GenericConfig, const D: ) ); - challenger.observe_cap("ient_polys_commitment.merkle_tree.cap); + challenger.observe_cap::("ient_polys_commitment.merkle_tree.cap); let zeta = challenger.get_extension_challenge::(); // To avoid leaking witness data, we want to ensure that our opening locations, `zeta` and @@ -177,7 +190,7 @@ pub fn prove, C: GenericConfig, const D: let openings = timed!( timing, "construct the opening set", - OpeningSet::new( + OpeningSet::new::( zeta, g, &prover_data.constants_sigmas_commitment, @@ -192,7 +205,7 @@ pub fn prove, C: GenericConfig, const D: let opening_proof = timed!( timing, "compute opening proofs", - PolynomialBatch::prove_openings( + PolynomialBatch::::prove_openings( &common_data.get_fri_instance(zeta), &[ &prover_data.constants_sigmas_commitment, @@ -206,14 +219,14 @@ pub fn prove, C: GenericConfig, const D: ) ); - let proof = Proof { + let proof = Proof:: { wires_cap: wires_commitment.merkle_tree.cap, plonk_zs_partial_products_cap: partial_products_and_zs_commitment.merkle_tree.cap, quotient_polys_cap: quotient_polys_commitment.merkle_tree.cap, openings, opening_proof, }; - Ok(ProofWithPublicInputs { + Ok(ProofWithPublicInputs:: { proof, public_inputs, }) @@ -222,13 +235,15 @@ pub fn prove, C: GenericConfig, const D: /// Compute the partial products used in the `Z` polynomials. fn all_wires_permutation_partial_products< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, >( witness: &MatrixWitness, betas: &[F], gammas: &[F], - prover_data: &ProverOnlyCircuitData, + prover_data: &ProverOnlyCircuitData, common_data: &CommonCircuitData, ) -> Vec>> { (0..common_data.config.num_challenges) @@ -249,13 +264,15 @@ fn all_wires_permutation_partial_products< /// where `f, g` are the products in the definition of `Z`: `Z(g^i) = f / g`. fn wires_permutation_partial_products_and_zs< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, >( witness: &MatrixWitness, beta: F, gamma: F, - prover_data: &ProverOnlyCircuitData, + prover_data: &ProverOnlyCircuitData, common_data: &CommonCircuitData, ) -> Vec> { let degree = common_data.quotient_degree_factor; @@ -311,14 +328,16 @@ const BATCH_SIZE: usize = 32; fn compute_quotient_polys< 'a, F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, >( common_data: &CommonCircuitData, - prover_data: &'a ProverOnlyCircuitData, - public_inputs_hash: &<>::InnerHasher as Hasher>::Hash, - wires_commitment: &'a PolynomialBatch, - zs_partial_products_commitment: &'a PolynomialBatch, + prover_data: &'a ProverOnlyCircuitData, + public_inputs_hash: &<>::InnerHasher as Hasher>::Hash, + wires_commitment: &'a PolynomialBatch, + zs_partial_products_commitment: &'a PolynomialBatch, betas: &[F], gammas: &[F], alphas: &[F], diff --git a/plonky2/src/plonk/validate_shape.rs b/plonky2/src/plonk/validate_shape.rs index 0b4bf4a8..13005cc5 100644 --- a/plonky2/src/plonk/validate_shape.rs +++ b/plonky2/src/plonk/validate_shape.rs @@ -2,17 +2,20 @@ use anyhow::ensure; use crate::field::extension::Extendable; use crate::hash::hash_types::RichField; +use crate::hash::hashing::HashConfig; use crate::plonk::circuit_data::CommonCircuitData; use crate::plonk::config::GenericConfig; use crate::plonk::proof::{OpeningSet, Proof, ProofWithPublicInputs}; -pub(crate) fn validate_proof_with_pis_shape( - proof_with_pis: &ProofWithPublicInputs, +pub(crate) fn validate_proof_with_pis_shape( + proof_with_pis: &ProofWithPublicInputs, common_data: &CommonCircuitData, ) -> anyhow::Result<()> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { let ProofWithPublicInputs { proof, @@ -26,13 +29,15 @@ where Ok(()) } -fn validate_proof_shape( - proof: &Proof, +fn validate_proof_shape( + proof: &Proof, common_data: &CommonCircuitData, ) -> anyhow::Result<()> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { let config = &common_data.config; let Proof { diff --git a/plonky2/src/plonk/verifier.rs b/plonky2/src/plonk/verifier.rs index 7e68e59e..1417aeff 100644 --- a/plonky2/src/plonk/verifier.rs +++ b/plonky2/src/plonk/verifier.rs @@ -4,6 +4,7 @@ use crate::field::extension::Extendable; use crate::field::types::Field; use crate::fri::verifier::verify_fri_proof; use crate::hash::hash_types::RichField; +use crate::hash::hashing::HashConfig; use crate::plonk::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData}; use crate::plonk::config::{GenericConfig, Hasher}; use crate::plonk::plonk_common::reduce_with_powers; @@ -12,11 +13,21 @@ use crate::plonk::validate_shape::validate_proof_with_pis_shape; use crate::plonk::vanishing_poly::eval_vanishing_poly; use crate::plonk::vars::EvaluationVars; -pub(crate) fn verify, C: GenericConfig, const D: usize>( - proof_with_pis: ProofWithPublicInputs, - verifier_data: &VerifierOnlyCircuitData, +pub(crate) fn verify< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +>( + proof_with_pis: ProofWithPublicInputs, + verifier_data: &VerifierOnlyCircuitData, common_data: &CommonCircuitData, -) -> Result<()> { +) -> Result<()> +where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, +{ validate_proof_with_pis_shape(&proof_with_pis, common_data)?; let public_inputs_hash = proof_with_pis.get_public_inputs_hash(); @@ -26,7 +37,7 @@ pub(crate) fn verify, C: GenericConfig, c common_data, )?; - verify_with_challenges( + verify_with_challenges::( proof_with_pis.proof, public_inputs_hash, challenges, @@ -37,15 +48,20 @@ pub(crate) fn verify, C: GenericConfig, c pub(crate) fn verify_with_challenges< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, >( - proof: Proof, - public_inputs_hash: <>::InnerHasher as Hasher>::Hash, + proof: Proof, + public_inputs_hash: <>::InnerHasher as Hasher>::Hash, challenges: ProofChallenges, - verifier_data: &VerifierOnlyCircuitData, + verifier_data: &VerifierOnlyCircuitData, common_data: &CommonCircuitData, -) -> Result<()> { +) -> Result<()> +where + [(); HCO::WIDTH]:, +{ let local_constants = &proof.openings.constants; let local_wires = &proof.openings.wires; let vars = EvaluationVars { @@ -97,7 +113,7 @@ pub(crate) fn verify_with_challenges< proof.quotient_polys_cap, ]; - verify_fri_proof::( + verify_fri_proof::( &common_data.get_fri_instance(challenges.plonk_zeta), &proof.openings.to_fri_openings(), &challenges.fri_challenges, diff --git a/plonky2/src/recursion/conditional_recursive_verifier.rs b/plonky2/src/recursion/conditional_recursive_verifier.rs index 6331118b..5d7151be 100644 --- a/plonky2/src/recursion/conditional_recursive_verifier.rs +++ b/plonky2/src/recursion/conditional_recursive_verifier.rs @@ -8,6 +8,7 @@ use crate::fri::proof::{ }; use crate::gadgets::polynomial::PolynomialCoeffsExtTarget; use crate::hash::hash_types::{HashOutTarget, MerkleCapTarget, RichField}; +use crate::hash::hashing::HashConfig; use crate::hash::merkle_proofs::MerkleProofTarget; use crate::iop::ext_target::ExtensionTarget; use crate::iop::target::{BoolTarget, Target}; @@ -20,7 +21,11 @@ use crate::with_context; impl, const D: usize> CircuitBuilder { /// Verify `proof0` if `condition` else verify `proof1`. /// `proof0` and `proof1` are assumed to use the same `CommonCircuitData`. - pub fn conditionally_verify_proof>( + pub fn conditionally_verify_proof< + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + >( &mut self, condition: BoolTarget, proof_with_pis0: &ProofWithPublicInputsTarget, @@ -29,7 +34,9 @@ impl, const D: usize> CircuitBuilder { inner_verifier_data1: &VerifierCircuitTarget, inner_common_data: &CommonCircuitData, ) where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let selected_proof = self.select_proof_with_pis(condition, proof_with_pis0, proof_with_pis1); @@ -46,11 +53,19 @@ impl, const D: usize> CircuitBuilder { ), }; - self.verify_proof::(&selected_proof, &selected_verifier_data, inner_common_data); + self.verify_proof::( + &selected_proof, + &selected_verifier_data, + inner_common_data, + ); } /// Conditionally verify a proof with a new generated dummy proof. - pub fn conditionally_verify_proof_or_dummy + 'static>( + pub fn conditionally_verify_proof_or_dummy< + HCO, + HCI, + C: GenericConfig + 'static, + >( &mut self, condition: BoolTarget, proof_with_pis: &ProofWithPublicInputsTarget, @@ -58,11 +73,15 @@ impl, const D: usize> CircuitBuilder { inner_common_data: &CommonCircuitData, ) -> anyhow::Result<()> where - C::Hasher: AlgebraicHasher, + HCO: HashConfig + 'static, + HCI: HashConfig + 'static, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let (dummy_proof_with_pis_target, dummy_verifier_data_target) = - self.dummy_proof_and_vk::(inner_common_data)?; - self.conditionally_verify_proof::( + self.dummy_proof_and_vk::(inner_common_data)?; + self.conditionally_verify_proof::( condition, proof_with_pis, inner_verifier_data, @@ -342,7 +361,7 @@ mod tests { use crate::gates::noop::NoopGate; use crate::iop::witness::{PartialWitness, WitnessWrite}; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; use crate::recursion::dummy_circuit::{dummy_circuit, dummy_proof}; #[test] @@ -350,7 +369,9 @@ mod tests { init_logger(); const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); // Generate proof. @@ -363,7 +384,7 @@ mod tests { for _ in 0..64 { builder.add_gate(NoopGate, vec![]); } - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; data.verify(proof.clone())?; @@ -377,7 +398,7 @@ mod tests { let pt = builder.add_virtual_proof_with_pis(&data.common); pw.set_proof_with_pis_target(&pt, &proof); let dummy_pt = builder.add_virtual_proof_with_pis(&data.common); - pw.set_proof_with_pis_target::(&dummy_pt, &dummy_proof); + pw.set_proof_with_pis_target::(&dummy_pt, &dummy_proof); let inner_data = builder.add_virtual_verifier_data(data.common.config.fri_config.cap_height); pw.set_verifier_data_target(&inner_data, &data.verifier_only); @@ -385,7 +406,7 @@ mod tests { builder.add_virtual_verifier_data(data.common.config.fri_config.cap_height); pw.set_verifier_data_target(&dummy_inner_data, &dummy_data.verifier_only); let b = builder.constant_bool(F::rand().0 % 2 == 0); - builder.conditionally_verify_proof::( + builder.conditionally_verify_proof::( b, &pt, &inner_data, @@ -395,7 +416,7 @@ mod tests { ); builder.print_gate_counts(100); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; data.verify(proof) } diff --git a/plonky2/src/recursion/cyclic_recursion.rs b/plonky2/src/recursion/cyclic_recursion.rs index 9b305626..b0f49a8b 100644 --- a/plonky2/src/recursion/cyclic_recursion.rs +++ b/plonky2/src/recursion/cyclic_recursion.rs @@ -4,6 +4,7 @@ use anyhow::{ensure, Result}; use crate::field::extension::Extendable; use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget, RichField}; +use crate::hash::hashing::HashConfig; use crate::hash::merkle_tree::MerkleCap; use crate::iop::target::{BoolTarget, Target}; use crate::plonk::circuit_builder::CircuitBuilder; @@ -13,10 +14,12 @@ use crate::plonk::circuit_data::{ use crate::plonk::config::{AlgebraicHasher, GenericConfig}; use crate::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; -impl, const D: usize> VerifierOnlyCircuitData { +impl, const D: usize> + VerifierOnlyCircuitData +{ fn from_slice(slice: &[C::F], common_data: &CommonCircuitData) -> Result where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, { // The structure of the public inputs is `[..., circuit_digest, constants_sigmas_cap]`. let cap_len = common_data.config.fri_config.num_cap_elements(); @@ -79,7 +82,11 @@ impl, const D: usize> CircuitBuilder { /// that the verification key matches. /// /// WARNING: Do not register any public input after calling this! TODO: relax this - pub fn conditionally_verify_cyclic_proof>( + pub fn conditionally_verify_cyclic_proof< + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + >( &mut self, condition: BoolTarget, cyclic_proof_with_pis: &ProofWithPublicInputsTarget, @@ -88,7 +95,9 @@ impl, const D: usize> CircuitBuilder { common_data: &CommonCircuitData, ) -> Result<()> where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let verifier_data = self .verifier_data_public_input @@ -116,7 +125,7 @@ impl, const D: usize> CircuitBuilder { ); // Verify the cyclic proof if `condition` is set to true, otherwise verify the other proof. - self.conditionally_verify_proof::( + self.conditionally_verify_proof::( condition, cyclic_proof_with_pis, &verifier_data, @@ -133,18 +142,26 @@ impl, const D: usize> CircuitBuilder { Ok(()) } - pub fn conditionally_verify_cyclic_proof_or_dummy + 'static>( + pub fn conditionally_verify_cyclic_proof_or_dummy< + HCO, + HCI, + C: GenericConfig + 'static, + >( &mut self, condition: BoolTarget, cyclic_proof_with_pis: &ProofWithPublicInputsTarget, common_data: &CommonCircuitData, ) -> Result<()> where - C::Hasher: AlgebraicHasher, + HCO: HashConfig + 'static, + HCI: HashConfig + 'static, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let (dummy_proof_with_pis_target, dummy_verifier_data_target) = - self.dummy_proof_and_vk::(common_data)?; - self.conditionally_verify_cyclic_proof::( + self.dummy_proof_and_vk::(common_data)?; + self.conditionally_verify_cyclic_proof::( condition, cyclic_proof_with_pis, &dummy_proof_with_pis_target, @@ -159,17 +176,22 @@ impl, const D: usize> CircuitBuilder { /// Checks that the purported verifier data in the public inputs match the real verifier data. pub fn check_cyclic_proof_verifier_data< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, >( - proof: &ProofWithPublicInputs, - verifier_data: &VerifierOnlyCircuitData, + proof: &ProofWithPublicInputs, + verifier_data: &VerifierOnlyCircuitData, common_data: &CommonCircuitData, ) -> Result<()> where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { - let pis = VerifierOnlyCircuitData::::from_slice(&proof.public_inputs, common_data)?; + let pis = + VerifierOnlyCircuitData::::from_slice(&proof.public_inputs, common_data)?; ensure!(verifier_data.constants_sigmas_cap == pis.constants_sigmas_cap); ensure!(verifier_data.circuit_digest == pis.circuit_digest); @@ -184,45 +206,51 @@ mod tests { use crate::field::types::{Field, PrimeField64}; use crate::gates::noop::NoopGate; use crate::hash::hash_types::{HashOutTarget, RichField}; - use crate::hash::hashing::hash_n_to_hash_no_pad; + use crate::hash::hashing::{hash_n_to_hash_no_pad, HashConfig}; use crate::hash::poseidon::{PoseidonHash, PoseidonPermutation}; use crate::iop::witness::{PartialWitness, WitnessWrite}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::{CircuitConfig, CommonCircuitData}; - use crate::plonk::config::{AlgebraicHasher, GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{ + AlgebraicHasher, GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig, + }; use crate::recursion::cyclic_recursion::check_cyclic_proof_verifier_data; use crate::recursion::dummy_circuit::cyclic_base_proof; // Generates `CommonCircuitData` usable for recursion. fn common_data_for_recursion< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, >() -> CommonCircuitData where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let config = CircuitConfig::standard_recursion_config(); let builder = CircuitBuilder::::new(config); - let data = builder.build::(); + let data = builder.build::(); let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); let proof = builder.add_virtual_proof_with_pis(&data.common); let verifier_data = builder.add_virtual_verifier_data(data.common.config.fri_config.cap_height); - builder.verify_proof::(&proof, &verifier_data, &data.common); - let data = builder.build::(); + builder.verify_proof::(&proof, &verifier_data, &data.common); + let data = builder.build::(); let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); let proof = builder.add_virtual_proof_with_pis(&data.common); let verifier_data = builder.add_virtual_verifier_data(data.common.config.fri_config.cap_height); - builder.verify_proof::(&proof, &verifier_data, &data.common); + builder.verify_proof::(&proof, &verifier_data, &data.common); while builder.num_gates() < 1 << 12 { builder.add_gate(NoopGate, vec![]); } - builder.build::().common + builder.build::().common } /// Uses cyclic recursion to build a hash chain. @@ -235,7 +263,9 @@ mod tests { fn test_cyclic_recursion() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); @@ -245,12 +275,13 @@ mod tests { let initial_hash_target = builder.add_virtual_hash(); builder.register_public_inputs(&initial_hash_target.elements); let current_hash_in = builder.add_virtual_hash(); - let current_hash_out = - builder.hash_n_to_hash_no_pad::(current_hash_in.elements.to_vec()); + let current_hash_out = builder.hash_n_to_hash_no_pad::( + current_hash_in.elements.to_vec(), + ); builder.register_public_inputs(¤t_hash_out.elements); let counter = builder.add_virtual_public_input(); - let mut common_data = common_data_for_recursion::(); + let mut common_data = common_data_for_recursion::(); let verifier_data_target = builder.add_verifier_data_public_inputs(); common_data.num_public_inputs = builder.num_public_inputs(); @@ -277,19 +308,19 @@ mod tests { let new_counter = builder.mul_add(condition.target, inner_cyclic_counter, one); builder.connect(counter, new_counter); - builder.conditionally_verify_cyclic_proof_or_dummy::( + builder.conditionally_verify_cyclic_proof_or_dummy::( condition, &inner_cyclic_proof_with_pis, &common_data, )?; - let cyclic_circuit_data = builder.build::(); + let cyclic_circuit_data = builder.build::(); let mut pw = PartialWitness::new(); let initial_hash = [F::ZERO, F::ONE, F::TWO, F::from_canonical_usize(3)]; let initial_hash_pis = initial_hash.into_iter().enumerate().collect(); pw.set_bool_target(condition, false); - pw.set_proof_with_pis_target::( + pw.set_proof_with_pis_target::( &inner_cyclic_proof_with_pis, &cyclic_base_proof( &common_data, @@ -347,7 +378,8 @@ mod tests { fn iterate_poseidon(initial_state: [F; 4], n: usize) -> [F; 4] { let mut current = initial_state; for _ in 0..n { - current = hash_n_to_hash_no_pad::(¤t).elements; + current = hash_n_to_hash_no_pad::(¤t) + .elements; } current } diff --git a/plonky2/src/recursion/dummy_circuit.rs b/plonky2/src/recursion/dummy_circuit.rs index 53fa0bb0..1de83247 100644 --- a/plonky2/src/recursion/dummy_circuit.rs +++ b/plonky2/src/recursion/dummy_circuit.rs @@ -7,6 +7,7 @@ use plonky2_util::ceil_div_usize; use crate::gates::noop::NoopGate; use crate::hash::hash_types::RichField; +use crate::hash::hashing::HashConfig; use crate::iop::generator::{GeneratedValues, SimpleGenerator}; use crate::iop::target::Target; use crate::iop::witness::{PartialWitness, PartitionWitness, WitnessWrite}; @@ -22,15 +23,19 @@ use crate::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; /// public inputs which encode the cyclic verification key must be set properly, and this method /// takes care of that. It also allows the user to specify any other public inputs which should be /// set in this base proof. -pub fn cyclic_base_proof( +pub fn cyclic_base_proof( common_data: &CommonCircuitData, - verifier_data: &VerifierOnlyCircuitData, + verifier_data: &VerifierOnlyCircuitData, mut nonzero_public_inputs: HashMap, -) -> ProofWithPublicInputs +) -> ProofWithPublicInputs where F: RichField + Extendable, - C: GenericConfig, - C::Hasher: AlgebraicHasher, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let pis_len = common_data.num_public_inputs; let cap_elements = common_data.config.fri_config.num_cap_elements(); @@ -46,19 +51,29 @@ where // TODO: A bit wasteful to build a dummy circuit here. We could potentially use a proof that // just consists of zeros, apart from public inputs. - dummy_proof(&dummy_circuit(common_data), nonzero_public_inputs).unwrap() + dummy_proof::( + &dummy_circuit::(common_data), + nonzero_public_inputs, + ) + .unwrap() } /// Generate a proof for a dummy circuit. The `public_inputs` parameter let the caller specify /// certain public inputs (identified by their indices) which should be given specific values. /// The rest will default to zero. -pub(crate) fn dummy_proof( - circuit: &CircuitData, - nonzero_public_inputs: HashMap, -) -> anyhow::Result> -where +pub(crate) fn dummy_proof< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +>( + circuit: &CircuitData, + nonzero_public_inputs: HashMap, +) -> anyhow::Result> +where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let mut pw = PartialWitness::new(); for i in 0..circuit.common.num_public_inputs { @@ -71,11 +86,17 @@ where /// Generate a circuit matching a given `CommonCircuitData`. pub(crate) fn dummy_circuit< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, >( common_data: &CommonCircuitData, -) -> CircuitData { +) -> CircuitData +where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, +{ let config = common_data.config.clone(); assert!( !common_data.config.zero_knowledge, @@ -98,21 +119,26 @@ pub(crate) fn dummy_circuit< builder.add_virtual_public_input(); } - let circuit = builder.build::(); + let circuit = builder.build::(); assert_eq!(&circuit.common, common_data); circuit } impl, const D: usize> CircuitBuilder { - pub(crate) fn dummy_proof_and_vk + 'static>( + pub(crate) fn dummy_proof_and_vk + 'static>( &mut self, common_data: &CommonCircuitData, ) -> anyhow::Result<(ProofWithPublicInputsTarget, VerifierCircuitTarget)> where - C::Hasher: AlgebraicHasher, + HCO: HashConfig + 'static, + HCI: HashConfig + 'static, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { - let dummy_circuit = dummy_circuit::(common_data); - let dummy_proof_with_pis = dummy_proof(&dummy_circuit, HashMap::new())?; + let dummy_circuit = dummy_circuit::(common_data); + let dummy_proof_with_pis = + dummy_proof::(&dummy_circuit, HashMap::new())?; let dummy_proof_with_pis_target = self.add_virtual_proof_with_pis(common_data); let dummy_verifier_data_target = self.add_virtual_verifier_data(self.config.fri_config.cap_height); @@ -129,22 +155,26 @@ impl, const D: usize> CircuitBuilder { } #[derive(Debug)] -pub(crate) struct DummyProofGenerator +pub(crate) struct DummyProofGenerator where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { pub(crate) proof_with_pis_target: ProofWithPublicInputsTarget, - pub(crate) proof_with_pis: ProofWithPublicInputs, + pub(crate) proof_with_pis: ProofWithPublicInputs, pub(crate) verifier_data_target: VerifierCircuitTarget, - pub(crate) verifier_data: VerifierOnlyCircuitData, + pub(crate) verifier_data: VerifierOnlyCircuitData, } -impl SimpleGenerator for DummyProofGenerator +impl SimpleGenerator for DummyProofGenerator where F: RichField + Extendable, - C: GenericConfig + 'static, - C::Hasher: AlgebraicHasher, + HCO: HashConfig + 'static, + HCI: HashConfig + 'static, + C: GenericConfig + 'static, + C::Hasher: AlgebraicHasher, { fn dependencies(&self) -> Vec { vec![] diff --git a/plonky2/src/recursion/recursive_verifier.rs b/plonky2/src/recursion/recursive_verifier.rs index 91beb049..e611abb1 100644 --- a/plonky2/src/recursion/recursive_verifier.rs +++ b/plonky2/src/recursion/recursive_verifier.rs @@ -1,5 +1,6 @@ use crate::field::extension::Extendable; use crate::hash::hash_types::{HashOutTarget, RichField}; +use crate::hash::hashing::HashConfig; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::{CommonCircuitData, VerifierCircuitTarget}; use crate::plonk::config::{AlgebraicHasher, GenericConfig}; @@ -14,28 +15,30 @@ use crate::with_context; impl, const D: usize> CircuitBuilder { /// Recursively verifies an inner proof. - pub fn verify_proof>( + pub fn verify_proof>( &mut self, proof_with_pis: &ProofWithPublicInputsTarget, inner_verifier_data: &VerifierCircuitTarget, inner_common_data: &CommonCircuitData, ) where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { assert_eq!( proof_with_pis.public_inputs.len(), inner_common_data.num_public_inputs ); let public_inputs_hash = - self.hash_n_to_hash_no_pad::(proof_with_pis.public_inputs.clone()); - let challenges = proof_with_pis.get_challenges::( + self.hash_n_to_hash_no_pad::(proof_with_pis.public_inputs.clone()); + let challenges = proof_with_pis.get_challenges::( self, public_inputs_hash, inner_verifier_data.circuit_digest, inner_common_data, ); - self.verify_proof_with_challenges::( + self.verify_proof_with_challenges::( &proof_with_pis.proof, public_inputs_hash, challenges, @@ -45,7 +48,11 @@ impl, const D: usize> CircuitBuilder { } /// Recursively verifies an inner proof. - fn verify_proof_with_challenges>( + fn verify_proof_with_challenges< + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + >( &mut self, proof: &ProofTarget, public_inputs_hash: HashOutTarget, @@ -53,7 +60,8 @@ impl, const D: usize> CircuitBuilder { inner_verifier_data: &VerifierCircuitTarget, inner_common_data: &CommonCircuitData, ) where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, { let one = self.one_extension(); @@ -115,7 +123,7 @@ impl, const D: usize> CircuitBuilder { with_context!( self, "verify FRI proof", - self.verify_fri_proof::( + self.verify_fri_proof::( &fri_instance, &proof.openings.to_fri_openings(), &challenges.fri_challenges, @@ -187,7 +195,10 @@ mod tests { use crate::gates::noop::NoopGate; use crate::iop::witness::{PartialWitness, WitnessWrite}; use crate::plonk::circuit_data::{CircuitConfig, VerifierOnlyCircuitData}; - use crate::plonk::config::{GenericConfig, KeccakGoldilocksConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{ + GenericConfig, KeccakGoldilocksConfig, KeccakHashConfig, PoseidonGoldilocksConfig, + PoseidonHashConfig, + }; use crate::plonk::proof::{CompressedProofWithPublicInputs, ProofWithPublicInputs}; use crate::plonk::prover::prove; use crate::util::timing::TimingTree; @@ -197,12 +208,15 @@ mod tests { init_logger(); const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let config = CircuitConfig::standard_recursion_zk_config(); - let (proof, vd, cd) = dummy_proof::(&config, 4_000)?; - let (proof, vd, cd) = - recursive_proof::(proof, vd, cd, &config, None, true, true)?; + let (proof, vd, cd) = dummy_proof::(&config, 4_000)?; + let (proof, vd, cd) = recursive_proof::( + proof, vd, cd, &config, None, true, true, + )?; test_serialization(&proof, &vd, &cd)?; Ok(()) @@ -213,22 +227,32 @@ mod tests { init_logger(); const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); // Start with a degree 2^14 proof - let (proof, vd, cd) = dummy_proof::(&config, 16_000)?; + let (proof, vd, cd) = dummy_proof::(&config, 16_000)?; assert_eq!(cd.degree_bits(), 14); // Shrink it to 2^13. - let (proof, vd, cd) = - recursive_proof::(proof, vd, cd, &config, Some(13), false, false)?; + let (proof, vd, cd) = recursive_proof::( + proof, + vd, + cd, + &config, + Some(13), + false, + false, + )?; assert_eq!(cd.degree_bits(), 13); // Shrink it to 2^12. - let (proof, vd, cd) = - recursive_proof::(proof, vd, cd, &config, None, true, true)?; + let (proof, vd, cd) = recursive_proof::( + proof, vd, cd, &config, None, true, true, + )?; assert_eq!(cd.degree_bits(), 12); test_serialization(&proof, &vd, &cd)?; @@ -245,16 +269,28 @@ mod tests { const D: usize = 2; type C = PoseidonGoldilocksConfig; type KC = KeccakGoldilocksConfig; - type F = >::F; + type HCCO = PoseidonHashConfig; + type HCCI = HCCO; + type HCKCO = KeccakHashConfig; + type HCKCI = HCCI; + type F = >::F; let standard_config = CircuitConfig::standard_recursion_config(); // An initial dummy proof. - let (proof, vd, cd) = dummy_proof::(&standard_config, 4_000)?; + let (proof, vd, cd) = dummy_proof::(&standard_config, 4_000)?; assert_eq!(cd.degree_bits(), 12); // A standard recursive proof. - let (proof, vd, cd) = recursive_proof(proof, vd, cd, &standard_config, None, false, false)?; + let (proof, vd, cd) = recursive_proof::( + proof, + vd, + cd, + &standard_config, + None, + false, + false, + )?; assert_eq!(cd.degree_bits(), 12); // A high-rate recursive proof, designed to be verifiable with fewer routed wires. @@ -267,8 +303,15 @@ mod tests { }, ..standard_config }; - let (proof, vd, cd) = - recursive_proof::(proof, vd, cd, &high_rate_config, None, true, true)?; + let (proof, vd, cd) = recursive_proof::( + proof, + vd, + cd, + &high_rate_config, + None, + true, + true, + )?; assert_eq!(cd.degree_bits(), 12); // A final proof, optimized for size. @@ -283,8 +326,15 @@ mod tests { }, ..high_rate_config }; - let (proof, vd, cd) = - recursive_proof::(proof, vd, cd, &final_config, None, true, true)?; + let (proof, vd, cd) = recursive_proof::( + proof, + vd, + cd, + &final_config, + None, + true, + true, + )?; assert_eq!(cd.degree_bits(), 12, "final proof too large"); test_serialization(&proof, &vd, &cd)?; @@ -298,39 +348,55 @@ mod tests { const D: usize = 2; type PC = PoseidonGoldilocksConfig; type KC = KeccakGoldilocksConfig; - type F = >::F; + type HCCO = PoseidonHashConfig; + type HCCI = HCCO; + type HCKCO = KeccakHashConfig; + type HCKCI = HCCI; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); - let (proof, vd, cd) = dummy_proof::(&config, 4_000)?; + let (proof, vd, cd) = dummy_proof::(&config, 4_000)?; - let (proof, vd, cd) = - recursive_proof::(proof, vd, cd, &config, None, false, false)?; + let (proof, vd, cd) = recursive_proof::( + proof, vd, cd, &config, None, false, false, + )?; test_serialization(&proof, &vd, &cd)?; - let (proof, vd, cd) = - recursive_proof::(proof, vd, cd, &config, None, false, false)?; + let (proof, vd, cd) = recursive_proof::( + proof, vd, cd, &config, None, false, false, + )?; test_serialization(&proof, &vd, &cd)?; Ok(()) } - type Proof = ( - ProofWithPublicInputs, - VerifierOnlyCircuitData, + type Proof = ( + ProofWithPublicInputs, + VerifierOnlyCircuitData, CommonCircuitData, ); /// Creates a dummy proof which should have roughly `num_dummy_gates` gates. - fn dummy_proof, C: GenericConfig, const D: usize>( + fn dummy_proof< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + >( config: &CircuitConfig, num_dummy_gates: u64, - ) -> Result> { + ) -> Result> + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { let mut builder = CircuitBuilder::::new(config.clone()); for _ in 0..num_dummy_gates { builder.add_gate(NoopGate, vec![]); } - let data = builder.build::(); + let data = builder.build::(); let inputs = PartialWitness::new(); let proof = data.prove(inputs)?; data.verify(proof.clone())?; @@ -340,20 +406,28 @@ mod tests { fn recursive_proof< F: RichField + Extendable, - C: GenericConfig, - InnerC: GenericConfig, + HCOO: HashConfig, + HCOI: HashConfig, + HCIO: HashConfig, + HCII: HashConfig, + C: GenericConfig, + InnerC: GenericConfig, const D: usize, >( - inner_proof: ProofWithPublicInputs, - inner_vd: VerifierOnlyCircuitData, + inner_proof: ProofWithPublicInputs, + inner_vd: VerifierOnlyCircuitData, inner_cd: CommonCircuitData, config: &CircuitConfig, min_degree_bits: Option, print_gate_counts: bool, print_timing: bool, - ) -> Result> + ) -> Result> where - InnerC::Hasher: AlgebraicHasher, + InnerC::Hasher: AlgebraicHasher, + [(); HCOO::WIDTH]:, + [(); HCOI::WIDTH]:, + [(); HCIO::WIDTH]:, + [(); HCII::WIDTH]:, { let mut builder = CircuitBuilder::::new(config.clone()); let mut pw = PartialWitness::new(); @@ -367,7 +441,7 @@ mod tests { ); pw.set_hash_target(inner_data.circuit_digest, inner_vd.circuit_digest); - builder.verify_proof::(&pt, &inner_data, &inner_cd); + builder.verify_proof::(&pt, &inner_data, &inner_cd); if print_gate_counts { builder.print_gate_counts(0); @@ -383,7 +457,7 @@ mod tests { } } - let data = builder.build::(); + let data = builder.build::(); let mut timing = TimingTree::new("prove", Level::Debug); let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?; @@ -399,13 +473,19 @@ mod tests { /// Test serialization and print some size info. fn test_serialization< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, >( - proof: &ProofWithPublicInputs, - vd: &VerifierOnlyCircuitData, + proof: &ProofWithPublicInputs, + vd: &VerifierOnlyCircuitData, cd: &CommonCircuitData, - ) -> Result<()> { + ) -> Result<()> + where + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, + { let proof_bytes = proof.to_bytes(); info!("Proof length: {} bytes", proof_bytes.len()); let proof_from_bytes = ProofWithPublicInputs::from_bytes(proof_bytes, cd)?; diff --git a/plonky2/src/util/reducing.rs b/plonky2/src/util/reducing.rs index aaf905d5..9bf4326b 100644 --- a/plonky2/src/util/reducing.rs +++ b/plonky2/src/util/reducing.rs @@ -280,14 +280,16 @@ mod tests { use crate::field::types::Sample; use crate::iop::witness::{PartialWitness, WitnessWrite}; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; use crate::plonk::verifier::verify; fn test_reduce_gadget_base(n: usize) -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - type FF = >::FE; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); @@ -309,7 +311,7 @@ mod tests { builder.connect_extension(manual_reduce, circuit_reduce); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) @@ -318,8 +320,10 @@ mod tests { fn test_reduce_gadget(n: usize) -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; - type FF = >::FE; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); @@ -339,7 +343,7 @@ mod tests { builder.connect_extension(manual_reduce, circuit_reduce); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/plonky2/src/util/serialization.rs b/plonky2/src/util/serialization.rs index b33ec52e..cf33caa5 100644 --- a/plonky2/src/util/serialization.rs +++ b/plonky2/src/util/serialization.rs @@ -14,6 +14,7 @@ use crate::fri::proof::{ FriQueryStep, }; use crate::hash::hash_types::RichField; +use crate::hash::hashing::HashConfig; use crate::hash::merkle_proofs::MerkleProof; use crate::hash::merkle_tree::MerkleCap; use crate::plonk::circuit_data::CommonCircuitData; @@ -119,10 +120,11 @@ pub trait Read { /// Reads a hash value from `self`. #[inline] - fn read_hash(&mut self) -> IoResult + fn read_hash(&mut self) -> IoResult where F: RichField, - H: Hasher, + HC: HashConfig, + H: Hasher, { let mut buf = vec![0; H::HASH_SIZE]; self.read_exact(&mut buf)?; @@ -131,28 +133,31 @@ pub trait Read { /// Reads a value of type [`MerkleCap`] from `self` with the given `cap_height`. #[inline] - fn read_merkle_cap(&mut self, cap_height: usize) -> IoResult> + fn read_merkle_cap(&mut self, cap_height: usize) -> IoResult> where F: RichField, - H: Hasher, + HC: HashConfig, + H: Hasher, { let cap_length = 1 << cap_height; Ok(MerkleCap( (0..cap_length) - .map(|_| self.read_hash::()) + .map(|_| self.read_hash::()) .collect::, _>>()?, )) } /// Reads a value of type [`OpeningSet`] from `self` with the given `common_data`. #[inline] - fn read_opening_set( + fn read_opening_set( &mut self, common_data: &CommonCircuitData, ) -> IoResult> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { let config = &common_data.config; let constants = self.read_field_ext_vec::(common_data.num_constants)?; @@ -178,28 +183,31 @@ pub trait Read { /// Reads a value of type [`MerkleProof`] from `self`. #[inline] - fn read_merkle_proof(&mut self) -> IoResult> + fn read_merkle_proof(&mut self) -> IoResult> where F: RichField, - H: Hasher, + HC: HashConfig, + H: Hasher, { let length = self.read_u8()?; Ok(MerkleProof { siblings: (0..length) - .map(|_| self.read_hash::()) + .map(|_| self.read_hash::()) .collect::>()?, }) } /// Reads a value of type [`FriInitialTreeProof`] from `self` with the given `common_data`. #[inline] - fn read_fri_initial_proof( + fn read_fri_initial_proof( &mut self, common_data: &CommonCircuitData, - ) -> IoResult> + ) -> IoResult> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { let config = &common_data.config; let salt = salt_size(common_data.fri_params.hiding); @@ -231,14 +239,16 @@ pub trait Read { /// Reads a value of type [`FriQueryStep`] from `self` with the given `arity` and `compressed` /// flag. #[inline] - fn read_fri_query_step( + fn read_fri_query_step( &mut self, arity: usize, compressed: bool, - ) -> IoResult> + ) -> IoResult> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { let evals = self.read_field_ext_vec::(arity - usize::from(compressed))?; let merkle_proof = self.read_merkle_proof()?; @@ -250,23 +260,26 @@ pub trait Read { /// Reads a vector of [`FriQueryRound`]s from `self` with `common_data`. #[inline] - fn read_fri_query_rounds( + fn read_fri_query_rounds( &mut self, common_data: &CommonCircuitData, - ) -> IoResult>> + ) -> IoResult>> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { let config = &common_data.config; let mut fqrs = Vec::with_capacity(config.fri_config.num_query_rounds); for _ in 0..config.fri_config.num_query_rounds { - let initial_trees_proof = self.read_fri_initial_proof::(common_data)?; + let initial_trees_proof = + self.read_fri_initial_proof::(common_data)?; let steps = common_data .fri_params .reduction_arity_bits .iter() - .map(|&ar| self.read_fri_query_step::(1 << ar, false)) + .map(|&ar| self.read_fri_query_step::(1 << ar, false)) .collect::>()?; fqrs.push(FriQueryRound { initial_trees_proof, @@ -278,19 +291,21 @@ pub trait Read { /// Reads a value of type [`FriProof`] from `self` with `common_data`. #[inline] - fn read_fri_proof( + fn read_fri_proof( &mut self, common_data: &CommonCircuitData, - ) -> IoResult> + ) -> IoResult> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { let config = &common_data.config; let commit_phase_merkle_caps = (0..common_data.fri_params.reduction_arity_bits.len()) .map(|_| self.read_merkle_cap(config.fri_config.cap_height)) .collect::, _>>()?; - let query_round_proofs = self.read_fri_query_rounds::(common_data)?; + let query_round_proofs = self.read_fri_query_rounds::(common_data)?; let final_poly = PolynomialCoeffs::new( self.read_field_ext_vec::(common_data.fri_params.final_poly_len())?, ); @@ -305,20 +320,22 @@ pub trait Read { /// Reads a value of type [`Proof`] from `self` with `common_data`. #[inline] - fn read_proof( + fn read_proof( &mut self, common_data: &CommonCircuitData, - ) -> IoResult> + ) -> IoResult> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { let config = &common_data.config; let wires_cap = self.read_merkle_cap(config.fri_config.cap_height)?; let plonk_zs_partial_products_cap = self.read_merkle_cap(config.fri_config.cap_height)?; let quotient_polys_cap = self.read_merkle_cap(config.fri_config.cap_height)?; - let openings = self.read_opening_set::(common_data)?; - let opening_proof = self.read_fri_proof::(common_data)?; + let openings = self.read_opening_set::(common_data)?; + let opening_proof = self.read_fri_proof::(common_data)?; Ok(Proof { wires_cap, plonk_zs_partial_products_cap, @@ -330,14 +347,16 @@ pub trait Read { /// Reads a value of type [`ProofWithPublicInputs`] from `self` with `common_data`. #[inline] - fn read_proof_with_public_inputs( + fn read_proof_with_public_inputs( &mut self, common_data: &CommonCircuitData, - ) -> IoResult> + ) -> IoResult> where Self: Remaining, F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { let proof = self.read_proof(common_data)?; let public_inputs = self.read_field_vec(self.remaining() / size_of::())?; @@ -349,13 +368,15 @@ pub trait Read { /// Reads a value of type [`CompressedFriQueryRounds`] from `self` with `common_data`. #[inline] - fn read_compressed_fri_query_rounds( + fn read_compressed_fri_query_rounds( &mut self, common_data: &CommonCircuitData, - ) -> IoResult> + ) -> IoResult> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { let config = &common_data.config; let original_indices = (0..config.fri_config.num_query_rounds) @@ -366,7 +387,10 @@ pub trait Read { indices.dedup(); let mut pairs = Vec::new(); for &i in &indices { - pairs.push((i, self.read_fri_initial_proof::(common_data)?)); + pairs.push(( + i, + self.read_fri_initial_proof::(common_data)?, + )); } let initial_trees_proofs = HashMap::from_iter(pairs); @@ -377,7 +401,7 @@ pub trait Read { }); indices.dedup(); let query_steps = (0..indices.len()) - .map(|_| self.read_fri_query_step::(1 << a, true)) + .map(|_| self.read_fri_query_step::(1 << a, true)) .collect::, _>>()?; steps.push( indices @@ -397,19 +421,22 @@ pub trait Read { /// Reads a value of type [`CompressedFriProof`] from `self` with `common_data`. #[inline] - fn read_compressed_fri_proof( + fn read_compressed_fri_proof( &mut self, common_data: &CommonCircuitData, - ) -> IoResult> + ) -> IoResult> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { let config = &common_data.config; let commit_phase_merkle_caps = (0..common_data.fri_params.reduction_arity_bits.len()) .map(|_| self.read_merkle_cap(config.fri_config.cap_height)) .collect::, _>>()?; - let query_round_proofs = self.read_compressed_fri_query_rounds::(common_data)?; + let query_round_proofs = + self.read_compressed_fri_query_rounds::(common_data)?; let final_poly = PolynomialCoeffs::new( self.read_field_ext_vec::(common_data.fri_params.final_poly_len())?, ); @@ -424,20 +451,22 @@ pub trait Read { /// Reads a value of type [`CompressedProof`] from `self` with `common_data`. #[inline] - fn read_compressed_proof( + fn read_compressed_proof( &mut self, common_data: &CommonCircuitData, - ) -> IoResult> + ) -> IoResult> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { let config = &common_data.config; let wires_cap = self.read_merkle_cap(config.fri_config.cap_height)?; let plonk_zs_partial_products_cap = self.read_merkle_cap(config.fri_config.cap_height)?; let quotient_polys_cap = self.read_merkle_cap(config.fri_config.cap_height)?; - let openings = self.read_opening_set::(common_data)?; - let opening_proof = self.read_compressed_fri_proof::(common_data)?; + let openings = self.read_opening_set::(common_data)?; + let opening_proof = self.read_compressed_fri_proof::(common_data)?; Ok(CompressedProof { wires_cap, plonk_zs_partial_products_cap, @@ -449,14 +478,16 @@ pub trait Read { /// Reads a value of type [`CompressedProofWithPublicInputs`] from `self` with `common_data`. #[inline] - fn read_compressed_proof_with_public_inputs( + fn read_compressed_proof_with_public_inputs( &mut self, common_data: &CommonCircuitData, - ) -> IoResult> + ) -> IoResult> where Self: Remaining, F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { let proof = self.read_compressed_proof(common_data)?; let public_inputs = self.read_field_vec(self.remaining() / size_of::())?; @@ -534,23 +565,25 @@ pub trait Write { /// Writes a hash `h` to `self`. #[inline] - fn write_hash(&mut self, h: H::Hash) -> IoResult<()> + fn write_hash(&mut self, h: H::Hash) -> IoResult<()> where F: RichField, - H: Hasher, + HC: HashConfig, + H: Hasher, { self.write_all(&h.to_bytes()) } /// Writes `cap`, a value of type [`MerkleCap`], to `self`. #[inline] - fn write_merkle_cap(&mut self, cap: &MerkleCap) -> IoResult<()> + fn write_merkle_cap(&mut self, cap: &MerkleCap) -> IoResult<()> where F: RichField, - H: Hasher, + HC: HashConfig, + H: Hasher, { for &a in &cap.0 { - self.write_hash::(a)?; + self.write_hash::(a)?; } Ok(()) } @@ -572,10 +605,11 @@ pub trait Write { /// Writes a value `p` of type [`MerkleProof`] to `self.` #[inline] - fn write_merkle_proof(&mut self, p: &MerkleProof) -> IoResult<()> + fn write_merkle_proof(&mut self, p: &MerkleProof) -> IoResult<()> where F: RichField, - H: Hasher, + HC: HashConfig, + H: Hasher, { let length = p.siblings.len(); self.write_u8( @@ -584,20 +618,22 @@ pub trait Write { .expect("Merkle proof length must fit in u8."), )?; for &h in &p.siblings { - self.write_hash::(h)?; + self.write_hash::(h)?; } Ok(()) } /// Writes a value `fitp` of type [`FriInitialTreeProof`] to `self.` #[inline] - fn write_fri_initial_proof( + fn write_fri_initial_proof( &mut self, - fitp: &FriInitialTreeProof, + fitp: &FriInitialTreeProof, ) -> IoResult<()> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { for (v, p) in &fitp.evals_proofs { self.write_field_vec(v)?; @@ -608,13 +644,15 @@ pub trait Write { /// Writes a value `fqs` of type [`FriQueryStep`] to `self.` #[inline] - fn write_fri_query_step( + fn write_fri_query_step( &mut self, - fqs: &FriQueryStep, + fqs: &FriQueryStep, ) -> IoResult<()> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { self.write_field_ext_vec::(&fqs.evals)?; self.write_merkle_proof(&fqs.merkle_proof) @@ -622,18 +660,20 @@ pub trait Write { /// Writes a value `fqrs` of type [`FriQueryRound`] to `self.` #[inline] - fn write_fri_query_rounds( + fn write_fri_query_rounds( &mut self, - fqrs: &[FriQueryRound], + fqrs: &[FriQueryRound], ) -> IoResult<()> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { for fqr in fqrs { - self.write_fri_initial_proof::(&fqr.initial_trees_proof)?; + self.write_fri_initial_proof::(&fqr.initial_trees_proof)?; for fqs in &fqr.steps { - self.write_fri_query_step::(fqs)?; + self.write_fri_query_step::(fqs)?; } } Ok(()) @@ -641,45 +681,54 @@ pub trait Write { /// Writes a value `fq` of type [`FriProof`] to `self.` #[inline] - fn write_fri_proof( + fn write_fri_proof( &mut self, - fp: &FriProof, + fp: &FriProof, ) -> IoResult<()> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { for cap in &fp.commit_phase_merkle_caps { self.write_merkle_cap(cap)?; } - self.write_fri_query_rounds::(&fp.query_round_proofs)?; + self.write_fri_query_rounds::(&fp.query_round_proofs)?; self.write_field_ext_vec::(&fp.final_poly.coeffs)?; self.write_field(fp.pow_witness) } /// Writes a value `proof` of type [`Proof`] to `self.` #[inline] - fn write_proof(&mut self, proof: &Proof) -> IoResult<()> + fn write_proof( + &mut self, + proof: &Proof, + ) -> IoResult<()> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { self.write_merkle_cap(&proof.wires_cap)?; self.write_merkle_cap(&proof.plonk_zs_partial_products_cap)?; self.write_merkle_cap(&proof.quotient_polys_cap)?; self.write_opening_set(&proof.openings)?; - self.write_fri_proof::(&proof.opening_proof) + self.write_fri_proof::(&proof.opening_proof) } /// Writes a value `proof_with_pis` of type [`ProofWithPublicInputs`] to `self.` #[inline] - fn write_proof_with_public_inputs( + fn write_proof_with_public_inputs( &mut self, - proof_with_pis: &ProofWithPublicInputs, + proof_with_pis: &ProofWithPublicInputs, ) -> IoResult<()> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { let ProofWithPublicInputs { proof, @@ -691,13 +740,15 @@ pub trait Write { /// Writes a value `cfqrs` of type [`CompressedFriQueryRounds`] to `self.` #[inline] - fn write_compressed_fri_query_rounds( + fn write_compressed_fri_query_rounds( &mut self, - cfqrs: &CompressedFriQueryRounds, + cfqrs: &CompressedFriQueryRounds, ) -> IoResult<()> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { for &i in &cfqrs.indices { self.write_u32(i as u32)?; @@ -705,13 +756,13 @@ pub trait Write { let mut initial_trees_proofs = cfqrs.initial_trees_proofs.iter().collect::>(); initial_trees_proofs.sort_by_key(|&x| x.0); for (_, itp) in initial_trees_proofs { - self.write_fri_initial_proof::(itp)?; + self.write_fri_initial_proof::(itp)?; } for h in &cfqrs.steps { let mut fri_query_steps = h.iter().collect::>(); fri_query_steps.sort_by_key(|&x| x.0); for (_, fqs) in fri_query_steps { - self.write_fri_query_step::(fqs)?; + self.write_fri_query_step::(fqs)?; } } Ok(()) @@ -719,48 +770,54 @@ pub trait Write { /// Writes a value `fq` of type [`CompressedFriProof`] to `self.` #[inline] - fn write_compressed_fri_proof( + fn write_compressed_fri_proof( &mut self, - fp: &CompressedFriProof, + fp: &CompressedFriProof, ) -> IoResult<()> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { for cap in &fp.commit_phase_merkle_caps { self.write_merkle_cap(cap)?; } - self.write_compressed_fri_query_rounds::(&fp.query_round_proofs)?; + self.write_compressed_fri_query_rounds::(&fp.query_round_proofs)?; self.write_field_ext_vec::(&fp.final_poly.coeffs)?; self.write_field(fp.pow_witness) } /// Writes a value `proof` of type [`CompressedProof`] to `self.` #[inline] - fn write_compressed_proof( + fn write_compressed_proof( &mut self, - proof: &CompressedProof, + proof: &CompressedProof, ) -> IoResult<()> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { self.write_merkle_cap(&proof.wires_cap)?; self.write_merkle_cap(&proof.plonk_zs_partial_products_cap)?; self.write_merkle_cap(&proof.quotient_polys_cap)?; self.write_opening_set(&proof.openings)?; - self.write_compressed_fri_proof::(&proof.opening_proof) + self.write_compressed_fri_proof::(&proof.opening_proof) } /// Writes a value `proof_with_pis` of type [`CompressedProofWithPublicInputs`] to `self.` #[inline] - fn write_compressed_proof_with_public_inputs( + fn write_compressed_proof_with_public_inputs( &mut self, - proof_with_pis: &CompressedProofWithPublicInputs, + proof_with_pis: &CompressedProofWithPublicInputs, ) -> IoResult<()> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, { let CompressedProofWithPublicInputs { proof, diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index 9397d6d7..d5a9ec34 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -127,11 +127,12 @@ mod tests { use plonky2::field::extension::Extendable; use plonky2::field::types::Field; use plonky2::hash::hash_types::RichField; + use plonky2::hash::hashing::HashConfig; use plonky2::iop::witness::PartialWitness; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; use plonky2::plonk::config::{ - AlgebraicHasher, GenericConfig, Hasher, PoseidonGoldilocksConfig, + AlgebraicHasher, GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig, }; use plonky2::util::timing::TimingTree; @@ -155,7 +156,9 @@ mod tests { fn test_fibonacci_stark() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = FibonacciStark; let config = StarkConfig::standard_fast_config(); @@ -163,7 +166,7 @@ mod tests { let public_inputs = [F::ZERO, F::ONE, fibonacci(num_rows - 1, F::ZERO, F::ONE)]; let stark = S::new(num_rows); let trace = stark.generate_trace(public_inputs[0], public_inputs[1]); - let proof = prove::( + let proof = prove::( stark, &config, trace, @@ -178,7 +181,9 @@ mod tests { fn test_fibonacci_stark_degree() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = FibonacciStark; let num_rows = 1 << 5; @@ -190,12 +195,14 @@ mod tests { fn test_fibonacci_stark_circuit() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = FibonacciStark; let num_rows = 1 << 5; let stark = S::new(num_rows); - test_stark_circuit_constraints::(stark) + test_stark_circuit_constraints::(stark) } #[test] @@ -203,7 +210,9 @@ mod tests { init_logger(); const D: usize = 2; type C = PoseidonGoldilocksConfig; - type F = >::F; + type HCO = PoseidonHashConfig; + type HCI = HCO; + type F = >::F; type S = FibonacciStark; let config = StarkConfig::standard_fast_config(); @@ -211,7 +220,7 @@ mod tests { let public_inputs = [F::ZERO, F::ONE, fibonacci(num_rows - 1, F::ZERO, F::ONE)]; let stark = S::new(num_rows); let trace = stark.generate_trace(public_inputs[0], public_inputs[1]); - let proof = prove::( + let proof = prove::( stark, &config, trace, @@ -220,26 +229,33 @@ mod tests { )?; verify_stark_proof(stark, proof.clone(), &config)?; - recursive_proof::(stark, proof, &config, true) + recursive_proof::(stark, proof, &config, true) } fn recursive_proof< F: RichField + Extendable, - C: GenericConfig, + HCOO: HashConfig, + HCOI: HashConfig, + HCIO: HashConfig, + HCII: HashConfig, + C: GenericConfig, S: Stark + Copy, - InnerC: GenericConfig, + InnerC: GenericConfig, const D: usize, >( stark: S, - inner_proof: StarkProofWithPublicInputs, + inner_proof: StarkProofWithPublicInputs, inner_config: &StarkConfig, print_gate_counts: bool, ) -> Result<()> where - InnerC::Hasher: AlgebraicHasher, + InnerC::Hasher: AlgebraicHasher, [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, - [(); C::Hasher::HASH_SIZE]:, + [(); HCOO::WIDTH]:, + [(); HCOI::WIDTH]:, + [(); HCIO::WIDTH]:, + [(); HCII::WIDTH]:, { let circuit_config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(circuit_config); @@ -248,13 +264,18 @@ mod tests { let pt = add_virtual_stark_proof_with_pis(&mut builder, stark, inner_config, degree_bits); set_stark_proof_with_pis_target(&mut pw, &pt, &inner_proof); - verify_stark_proof_circuit::(&mut builder, stark, pt, inner_config); + verify_stark_proof_circuit::( + &mut builder, + stark, + pt, + inner_config, + ); if print_gate_counts { builder.print_gate_counts(0); } - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; data.verify(proof) } diff --git a/starky/src/get_challenges.rs b/starky/src/get_challenges.rs index b34b427d..2e6c86b6 100644 --- a/starky/src/get_challenges.rs +++ b/starky/src/get_challenges.rs @@ -5,6 +5,7 @@ use plonky2::field::polynomial::PolynomialCoeffs; use plonky2::fri::proof::{FriProof, FriProofTarget}; use plonky2::gadgets::polynomial::PolynomialCoeffsExtTarget; use plonky2::hash::hash_types::{MerkleCapTarget, RichField}; +use plonky2::hash::hashing::HashConfig; use plonky2::hash::merkle_tree::MerkleCap; use plonky2::iop::challenger::{Challenger, RecursiveChallenger}; use plonky2::iop::target::Target; @@ -18,13 +19,13 @@ use crate::permutation::{ use crate::proof::*; use crate::stark::Stark; -fn get_challenges( +fn get_challenges( stark: &S, - trace_cap: &MerkleCap, - permutation_zs_cap: Option<&MerkleCap>, - quotient_polys_cap: &MerkleCap, + trace_cap: &MerkleCap, + permutation_zs_cap: Option<&MerkleCap>, + quotient_polys_cap: &MerkleCap, openings: &StarkOpeningSet, - commit_phase_merkle_caps: &[MerkleCap], + commit_phase_merkle_caps: &[MerkleCap], final_poly: &PolynomialCoeffs, pow_witness: F, config: &StarkConfig, @@ -32,12 +33,16 @@ fn get_challenges( ) -> StarkProofChallenges where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let num_challenges = config.num_challenges; - let mut challenger = Challenger::::new(); + let mut challenger = Challenger::::new(); challenger.observe_cap(trace_cap); @@ -62,7 +67,7 @@ where permutation_challenge_sets, stark_alphas, stark_zeta, - fri_challenges: challenger.fri_challenges::( + fri_challenges: challenger.fri_challenges::( commit_phase_merkle_caps, final_poly, pow_witness, @@ -72,10 +77,14 @@ where } } -impl StarkProofWithPublicInputs +impl StarkProofWithPublicInputs where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { // TODO: Should be used later in compression? #![allow(dead_code)] @@ -111,7 +120,7 @@ where }, } = &self.proof; - get_challenges::( + get_challenges::( stark, trace_cap, permutation_zs_cap.as_ref(), @@ -129,7 +138,9 @@ where #[allow(clippy::too_many_arguments)] pub(crate) fn get_challenges_target< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, const D: usize, >( @@ -145,11 +156,13 @@ pub(crate) fn get_challenges_target< config: &StarkConfig, ) -> StarkProofChallengesTarget where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let num_challenges = config.num_challenges; - let mut challenger = RecursiveChallenger::::new(builder); + let mut challenger = RecursiveChallenger::::new(builder); challenger.observe_cap(trace_cap); @@ -188,7 +201,9 @@ where impl StarkProofWithPublicInputsTarget { pub(crate) fn get_challenges< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, >( &self, @@ -197,7 +212,9 @@ impl StarkProofWithPublicInputsTarget { config: &StarkConfig, ) -> StarkProofChallengesTarget where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let StarkProofTarget { trace_cap, @@ -213,7 +230,7 @@ impl StarkProofWithPublicInputsTarget { }, } = &self.proof; - get_challenges_target::( + get_challenges_target::( builder, stark, trace_cap, @@ -229,13 +246,13 @@ impl StarkProofWithPublicInputsTarget { } // TODO: Deal with the compressed stuff. -// impl, C: GenericConfig, const D: usize> -// CompressedProofWithPublicInputs +// impl, C: GenericConfig, const D: usize> +// CompressedProofWithPublicInputs // { // /// Computes all Fiat-Shamir challenges used in the Plonk proof. // pub(crate) fn get_challenges( // &self, -// common_data: &CommonCircuitData, +// common_data: &CommonCircuitData, // ) -> anyhow::Result> { // let CompressedProof { // wires_cap, @@ -268,7 +285,7 @@ impl StarkProofWithPublicInputsTarget { // pub(crate) fn get_inferred_elements( // &self, // challenges: &ProofChallenges, -// common_data: &CommonCircuitData, +// common_data: &CommonCircuitData, // ) -> FriInferredElements { // let ProofChallenges { // plonk_zeta, @@ -291,7 +308,7 @@ impl StarkProofWithPublicInputsTarget { // for &(mut x_index) in fri_query_indices { // let mut subgroup_x = F::MULTIPLICATIVE_GROUP_GENERATOR // * F::primitive_root_of_unity(log_n).exp_u64(reverse_bits(x_index, log_n) as u64); -// let mut old_eval = fri_combine_initial::( +// let mut old_eval = fri_combine_initial::( // &common_data.get_fri_instance(*plonk_zeta), // &self // .proof diff --git a/starky/src/lib.rs b/starky/src/lib.rs index 89a57d77..06b23007 100644 --- a/starky/src/lib.rs +++ b/starky/src/lib.rs @@ -1,6 +1,7 @@ #![allow(incomplete_features)] #![allow(clippy::too_many_arguments)] #![allow(clippy::type_complexity)] +#![allow(clippy::upper_case_acronyms)] #![feature(generic_const_exprs)] #![cfg_attr(not(feature = "std"), no_std)] diff --git a/starky/src/permutation.rs b/starky/src/permutation.rs index 4f5d2921..1bf6386b 100644 --- a/starky/src/permutation.rs +++ b/starky/src/permutation.rs @@ -10,6 +10,7 @@ use plonky2::field::packed::PackedField; use plonky2::field::polynomial::PolynomialValues; use plonky2::field::types::Field; use plonky2::hash::hash_types::RichField; +use plonky2::hash::hashing::HashConfig; use plonky2::iop::challenger::{Challenger, RecursiveChallenger}; use plonky2::iop::ext_target::ExtensionTarget; use plonky2::iop::target::Target; @@ -149,29 +150,38 @@ fn poly_product_elementwise( product } -fn get_permutation_challenge>( - challenger: &mut Challenger, -) -> PermutationChallenge { +fn get_permutation_challenge>( + challenger: &mut Challenger, +) -> PermutationChallenge +where + [(); HC::WIDTH]:, +{ let beta = challenger.get_challenge(); let gamma = challenger.get_challenge(); PermutationChallenge { beta, gamma } } -fn get_permutation_challenge_set>( - challenger: &mut Challenger, +fn get_permutation_challenge_set>( + challenger: &mut Challenger, num_challenges: usize, -) -> PermutationChallengeSet { +) -> PermutationChallengeSet +where + [(); HC::WIDTH]:, +{ let challenges = (0..num_challenges) .map(|_| get_permutation_challenge(challenger)) .collect(); PermutationChallengeSet { challenges } } -pub(crate) fn get_n_permutation_challenge_sets>( - challenger: &mut Challenger, +pub(crate) fn get_n_permutation_challenge_sets>( + challenger: &mut Challenger, num_challenges: usize, num_sets: usize, -) -> Vec> { +) -> Vec> +where + [(); HC::WIDTH]:, +{ (0..num_sets) .map(|_| get_permutation_challenge_set(challenger, num_challenges)) .collect() @@ -179,12 +189,16 @@ pub(crate) fn get_n_permutation_challenge_sets>( fn get_permutation_challenge_target< F: RichField + Extendable, - H: AlgebraicHasher, + HC: HashConfig, + H: AlgebraicHasher, const D: usize, >( builder: &mut CircuitBuilder, - challenger: &mut RecursiveChallenger, -) -> PermutationChallenge { + challenger: &mut RecursiveChallenger, +) -> PermutationChallenge +where + [(); HC::WIDTH]:, +{ let beta = challenger.get_challenge(builder); let gamma = challenger.get_challenge(builder); PermutationChallenge { beta, gamma } @@ -192,13 +206,17 @@ fn get_permutation_challenge_target< fn get_permutation_challenge_set_target< F: RichField + Extendable, - H: AlgebraicHasher, + HC: HashConfig, + H: AlgebraicHasher, const D: usize, >( builder: &mut CircuitBuilder, - challenger: &mut RecursiveChallenger, + challenger: &mut RecursiveChallenger, num_challenges: usize, -) -> PermutationChallengeSet { +) -> PermutationChallengeSet +where + [(); HC::WIDTH]:, +{ let challenges = (0..num_challenges) .map(|_| get_permutation_challenge_target(builder, challenger)) .collect(); @@ -207,14 +225,18 @@ fn get_permutation_challenge_set_target< pub(crate) fn get_n_permutation_challenge_sets_target< F: RichField + Extendable, - H: AlgebraicHasher, + HC: HashConfig, + H: AlgebraicHasher, const D: usize, >( builder: &mut CircuitBuilder, - challenger: &mut RecursiveChallenger, + challenger: &mut RecursiveChallenger, num_challenges: usize, num_sets: usize, -) -> Vec> { +) -> Vec> +where + [(); HC::WIDTH]:, +{ (0..num_sets) .map(|_| get_permutation_challenge_set_target(builder, challenger, num_challenges)) .collect() diff --git a/starky/src/proof.rs b/starky/src/proof.rs index 6bd5f787..b6641c32 100644 --- a/starky/src/proof.rs +++ b/starky/src/proof.rs @@ -11,6 +11,7 @@ use plonky2::fri::structure::{ FriOpeningBatch, FriOpeningBatchTarget, FriOpenings, FriOpeningsTarget, }; use plonky2::hash::hash_types::{MerkleCapTarget, RichField}; +use plonky2::hash::hashing::HashConfig; use plonky2::hash::merkle_tree::MerkleCap; use plonky2::iop::ext_target::ExtensionTarget; use plonky2::iop::target::Target; @@ -21,20 +22,33 @@ use crate::config::StarkConfig; use crate::permutation::PermutationChallengeSet; #[derive(Debug, Clone)] -pub struct StarkProof, C: GenericConfig, const D: usize> { +pub struct StarkProof< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, +> { /// Merkle cap of LDEs of trace values. - pub trace_cap: MerkleCap, + pub trace_cap: MerkleCap, /// Merkle cap of LDEs of permutation Z values. - pub permutation_zs_cap: Option>, + pub permutation_zs_cap: Option>, /// Merkle cap of LDEs of trace values. - pub quotient_polys_cap: MerkleCap, + pub quotient_polys_cap: MerkleCap, /// Purported values of each polynomial at the challenge point. pub openings: StarkOpeningSet, /// A batch FRI argument for all openings. - pub opening_proof: FriProof, + pub opening_proof: FriProof, } -impl, C: GenericConfig, const D: usize> StarkProof { +impl< + F: RichField + Extendable, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, + const D: usize, + > StarkProof +{ /// Recover the length of the trace from a STARK proof and a STARK config. pub fn recover_degree_bits(&self, config: &StarkConfig) -> usize { let initial_merkle_proof = &self.opening_proof.query_round_proofs[0] @@ -69,10 +83,12 @@ impl StarkProofTarget { #[derive(Debug, Clone)] pub struct StarkProofWithPublicInputs< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, > { - pub proof: StarkProof, + pub proof: StarkProof, // TODO: Maybe make it generic over a `S: Stark` and replace with `[F; S::PUBLIC_INPUTS]`. pub public_inputs: Vec, } @@ -84,23 +100,27 @@ pub struct StarkProofWithPublicInputsTarget { pub struct CompressedStarkProof< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, > { /// Merkle cap of LDEs of trace values. - pub trace_cap: MerkleCap, + pub trace_cap: MerkleCap, /// Purported values of each polynomial at the challenge point. pub openings: StarkOpeningSet, /// A batch FRI argument for all openings. - pub opening_proof: CompressedFriProof, + pub opening_proof: CompressedFriProof, } pub struct CompressedStarkProofWithPublicInputs< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, const D: usize, > { - pub proof: CompressedStarkProof, + pub proof: CompressedStarkProof, pub public_inputs: Vec, } @@ -135,14 +155,14 @@ pub struct StarkOpeningSet, const D: usize> { } impl, const D: usize> StarkOpeningSet { - pub fn new>( + pub fn new>( zeta: F::Extension, g: F, - trace_commitment: &PolynomialBatch, - permutation_zs_commitment: Option<&PolynomialBatch>, - quotient_commitment: &PolynomialBatch, + trace_commitment: &PolynomialBatch, + permutation_zs_commitment: Option<&PolynomialBatch>, + quotient_commitment: &PolynomialBatch, ) -> Self { - let eval_commitment = |z: F::Extension, c: &PolynomialBatch| { + let eval_commitment = |z: F::Extension, c: &PolynomialBatch| { c.polynomials .par_iter() .map(|p| p.to_extension().eval(z)) diff --git a/starky/src/prover.rs b/starky/src/prover.rs index 2f541d56..885f244e 100644 --- a/starky/src/prover.rs +++ b/starky/src/prover.rs @@ -11,8 +11,9 @@ use plonky2::field::types::Field; use plonky2::field::zero_poly_coset::ZeroPolyOnCoset; use plonky2::fri::oracle::PolynomialBatch; use plonky2::hash::hash_types::RichField; +use plonky2::hash::hashing::HashConfig; use plonky2::iop::challenger::Challenger; -use plonky2::plonk::config::{GenericConfig, Hasher}; +use plonky2::plonk::config::GenericConfig; use plonky2::timed; use plonky2::util::timing::TimingTree; use plonky2::util::{log2_ceil, log2_strict, transpose}; @@ -29,20 +30,23 @@ use crate::stark::Stark; use crate::vanishing_poly::eval_vanishing_poly; use crate::vars::StarkEvaluationVars; -pub fn prove( +pub fn prove( stark: S, config: &StarkConfig, trace_poly_values: Vec>, public_inputs: [F; S::PUBLIC_INPUTS], timing: &mut TimingTree, -) -> Result> +) -> Result> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, - [(); C::Hasher::HASH_SIZE]:, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { let degree = trace_poly_values[0].len(); let degree_bits = log2_strict(degree); @@ -57,7 +61,7 @@ where let trace_commitment = timed!( timing, "compute trace commitment", - PolynomialBatch::::from_values( + PolynomialBatch::::from_values( // TODO: Cloning this isn't great; consider having `from_values` accept a reference, // or having `compute_permutation_z_polys` read trace values from the `PolynomialBatch`. trace_poly_values.clone(), @@ -112,7 +116,7 @@ where } let alphas = challenger.get_n_challenges(config.num_challenges); - let quotient_polys = compute_quotient_polys::::Packing, C, S, D>( + let quotient_polys = compute_quotient_polys::::Packing, HCO, HCI, C, S, D>( &stark, &trace_commitment, &permutation_zs_commitment_challenges, @@ -196,11 +200,11 @@ where /// Computes the quotient polynomials `(sum alpha^i C_i(x)) / Z_H(x)` for `alpha` in `alphas`, /// where the `C_i`s are the Stark constraints. -fn compute_quotient_polys<'a, F, P, C, S, const D: usize>( +fn compute_quotient_polys<'a, F, P, HCO, HCI, C, S, const D: usize>( stark: &S, - trace_commitment: &'a PolynomialBatch, + trace_commitment: &'a PolynomialBatch, permutation_zs_commitment_challenges: &'a Option<( - PolynomialBatch, + PolynomialBatch, Vec>, )>, public_inputs: [F; S::PUBLIC_INPUTS], @@ -211,7 +215,9 @@ fn compute_quotient_polys<'a, F, P, C, S, const D: usize>( where F: RichField + Extendable, P: PackedField, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, diff --git a/starky/src/recursive_verifier.rs b/starky/src/recursive_verifier.rs index 11d83479..0de9e652 100644 --- a/starky/src/recursive_verifier.rs +++ b/starky/src/recursive_verifier.rs @@ -7,6 +7,7 @@ use plonky2::field::extension::Extendable; use plonky2::field::types::Field; use plonky2::fri::witness_util::set_fri_proof_target; use plonky2::hash::hash_types::RichField; +use plonky2::hash::hashing::HashConfig; use plonky2::iop::ext_target::ExtensionTarget; use plonky2::iop::witness::Witness; use plonky2::plonk::circuit_builder::CircuitBuilder; @@ -27,7 +28,9 @@ use crate::vars::StarkEvaluationTargets; pub fn verify_stark_proof_circuit< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, const D: usize, >( @@ -36,19 +39,21 @@ pub fn verify_stark_proof_circuit< proof_with_pis: StarkProofWithPublicInputsTarget, inner_config: &StarkConfig, ) where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { assert_eq!(proof_with_pis.public_inputs.len(), S::PUBLIC_INPUTS); let degree_bits = proof_with_pis.proof.recover_degree_bits(inner_config); let challenges = with_context!( builder, "compute challenges", - proof_with_pis.get_challenges::(builder, &stark, inner_config) + proof_with_pis.get_challenges::(builder, &stark, inner_config) ); - verify_stark_proof_with_challenges_circuit::( + verify_stark_proof_with_challenges_circuit::( builder, stark, proof_with_pis, @@ -61,7 +66,9 @@ pub fn verify_stark_proof_circuit< /// Recursively verifies an inner proof. fn verify_stark_proof_with_challenges_circuit< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, const D: usize, >( @@ -72,9 +79,10 @@ fn verify_stark_proof_with_challenges_circuit< inner_config: &StarkConfig, degree_bits: usize, ) where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, + [(); HCO::WIDTH]:, { check_permutation_options(&stark, &proof_with_pis, &challenges).unwrap(); let one = builder.one_extension(); @@ -161,7 +169,7 @@ fn verify_stark_proof_with_challenges_circuit< F::primitive_root_of_unity(degree_bits), inner_config, ); - builder.verify_fri_proof::( + builder.verify_fri_proof::( &fri_instance, &proof.openings.to_fri_openings(), &challenges.fri_challenges, @@ -259,13 +267,22 @@ fn add_stark_opening_set_target, S: Stark, co } } -pub fn set_stark_proof_with_pis_target, W, const D: usize>( +pub fn set_stark_proof_with_pis_target< + F, + HCO, + HCI, + C: GenericConfig, + W, + const D: usize, +>( witness: &mut W, stark_proof_with_pis_target: &StarkProofWithPublicInputsTarget, - stark_proof_with_pis: &StarkProofWithPublicInputs, + stark_proof_with_pis: &StarkProofWithPublicInputs, ) where F: RichField + Extendable, - C::Hasher: AlgebraicHasher, + HCO: HashConfig, + HCI: HashConfig, + C::Hasher: AlgebraicHasher, W: Witness, { let StarkProofWithPublicInputs { @@ -285,13 +302,22 @@ pub fn set_stark_proof_with_pis_target, W, const D set_stark_proof_target(witness, pt, proof); } -pub fn set_stark_proof_target, W, const D: usize>( +pub fn set_stark_proof_target< + F, + HCO, + HCI, + C: GenericConfig, + W, + const D: usize, +>( witness: &mut W, proof_target: &StarkProofTarget, - proof: &StarkProof, + proof: &StarkProof, ) where F: RichField + Extendable, - C::Hasher: AlgebraicHasher, + HCO: HashConfig, + HCI: HashConfig, + C::Hasher: AlgebraicHasher, W: Witness, { witness.set_cap_target(&proof_target.trace_cap, &proof.trace_cap); diff --git a/starky/src/stark_testing.rs b/starky/src/stark_testing.rs index 02c6bcd0..e815a1be 100644 --- a/starky/src/stark_testing.rs +++ b/starky/src/stark_testing.rs @@ -6,10 +6,11 @@ use plonky2::field::extension::{Extendable, FieldExtension}; use plonky2::field::polynomial::{PolynomialCoeffs, PolynomialValues}; use plonky2::field::types::{Field, Sample}; use plonky2::hash::hash_types::RichField; +use plonky2::hash::hashing::HashConfig; use plonky2::iop::witness::{PartialWitness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; -use plonky2::plonk::config::{GenericConfig, Hasher}; +use plonky2::plonk::config::GenericConfig; use plonky2::util::{log2_ceil, log2_strict, transpose}; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; @@ -80,7 +81,9 @@ where /// Tests that the circuit constraints imposed by the given STARK are coherent with the native constraints. pub fn test_stark_circuit_constraints< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, const D: usize, >( @@ -89,7 +92,8 @@ pub fn test_stark_circuit_constraints< where [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, - [(); C::Hasher::HASH_SIZE]:, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { // Compute native constraint evaluation on random values. let vars = StarkEvaluationVars { @@ -151,7 +155,7 @@ where let native_eval_t = builder.constant_extension(native_eval); builder.connect_extension(circuit_eval, native_eval_t); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; data.verify(proof) } diff --git a/starky/src/verifier.rs b/starky/src/verifier.rs index 6930c7cb..0b53cec9 100644 --- a/starky/src/verifier.rs +++ b/starky/src/verifier.rs @@ -7,7 +7,8 @@ use plonky2::field::extension::{Extendable, FieldExtension}; use plonky2::field::types::Field; use plonky2::fri::verifier::verify_fri_proof; use plonky2::hash::hash_types::RichField; -use plonky2::plonk::config::{GenericConfig, Hasher}; +use plonky2::hash::hashing::HashConfig; +use plonky2::plonk::config::GenericConfig; use plonky2::plonk::plonk_common::reduce_with_powers; use crate::config::StarkConfig; @@ -20,18 +21,21 @@ use crate::vars::StarkEvaluationVars; pub fn verify_stark_proof< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, const D: usize, >( stark: S, - proof_with_pis: StarkProofWithPublicInputs, + proof_with_pis: StarkProofWithPublicInputs, config: &StarkConfig, ) -> Result<()> where [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, - [(); C::Hasher::HASH_SIZE]:, + [(); HCO::WIDTH]:, + [(); HCI::WIDTH]:, { ensure!(proof_with_pis.public_inputs.len() == S::PUBLIC_INPUTS); let degree_bits = proof_with_pis.proof.recover_degree_bits(config); @@ -41,12 +45,14 @@ where pub(crate) fn verify_stark_proof_with_challenges< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, const D: usize, >( stark: S, - proof_with_pis: StarkProofWithPublicInputs, + proof_with_pis: StarkProofWithPublicInputs, challenges: StarkProofChallenges, degree_bits: usize, config: &StarkConfig, @@ -54,7 +60,7 @@ pub(crate) fn verify_stark_proof_with_challenges< where [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, - [(); C::Hasher::HASH_SIZE]:, + [(); HCO::WIDTH]:, { validate_proof_shape(&stark, &proof_with_pis, config)?; check_permutation_options(&stark, &proof_with_pis, &challenges)?; @@ -130,7 +136,7 @@ where .chain(once(proof.quotient_polys_cap)) .collect_vec(); - verify_fri_proof::( + verify_fri_proof::( &stark.fri_instance( challenges.stark_zeta, F::primitive_root_of_unity(degree_bits), @@ -146,17 +152,18 @@ where Ok(()) } -fn validate_proof_shape( +fn validate_proof_shape( stark: &S, - proof_with_pis: &StarkProofWithPublicInputs, + proof_with_pis: &StarkProofWithPublicInputs, config: &StarkConfig, ) -> anyhow::Result<()> where F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, [(); S::COLUMNS]:, - [(); C::Hasher::HASH_SIZE]:, { let StarkProofWithPublicInputs { proof, @@ -234,12 +241,14 @@ fn eval_l_0_and_l_last(log_n: usize, x: F) -> (F, F) { /// the Stark uses a permutation argument. fn check_permutation_options< F: RichField + Extendable, - C: GenericConfig, + HCO: HashConfig, + HCI: HashConfig, + C: GenericConfig, S: Stark, const D: usize, >( stark: &S, - proof_with_pis: &StarkProofWithPublicInputs, + proof_with_pis: &StarkProofWithPublicInputs, challenges: &StarkProofChallenges, ) -> Result<()> { let options_is_some = [ From f1a99e69b2f6ec2828040048acf79232074aad59 Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Thu, 2 Feb 2023 18:12:22 -0500 Subject: [PATCH 15/20] Add patch section to workspace config file --- Cargo.toml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 34b7e449..5f079d40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,12 @@ opt-level = 3 [profile.bench] opt-level = 3 + + +[patch.crates-io] +plonky2_evm = { path = "evm" } +plonky2_field = { path = "field" } +plonky2_maybe_rayon = { path = "maybe_rayon" } +plonky2 = { path = "plonky2" } +starky = { path = "starky" } +plonky2_util = { path = "util" } From a926dcad22b70b6f11eca9faa7feb1691618444a Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Sat, 1 Apr 2023 07:24:02 +0200 Subject: [PATCH 16/20] Transaction validity checks (#949) --- evm/src/cpu/kernel/asm/core/process_txn.asm | 43 ++++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/evm/src/cpu/kernel/asm/core/process_txn.asm b/evm/src/cpu/kernel/asm/core/process_txn.asm index b044e9ed..4c0d05c6 100644 --- a/evm/src/cpu/kernel/asm/core/process_txn.asm +++ b/evm/src/cpu/kernel/asm/core/process_txn.asm @@ -20,11 +20,44 @@ global process_normalized_txn: %mload_txn_field(@TXN_FIELD_GAS_LIMIT) %assert_ge - // TODO: Check that txn nonce matches account nonce. - // TODO: Assert nonce is correct. - // TODO: Assert sender has no code. - // TODO: Assert sender balance >= gas_limit * gas_price + value. - // TODO: Assert chain ID matches block metadata? + %mload_txn_field(@TXN_FIELD_ORIGIN) + // stack: sender, retdest + + // Check that txn nonce matches account nonce. + DUP1 %nonce + // stack: sender_nonce, sender, retdest + %mload_txn_field(@TXN_FIELD_NONCE) + // stack: tx_nonce, sender_nonce, sender, retdest + %assert_eq + // stack: sender, retdest + + // Assert sender has no code. + DUP1 %ext_code_empty %assert_nonzero + // stack: sender, retdest + + // Assert sender balance >= gas_limit * gas_price + value. + %balance + // stack: sender_balance, retdest + %mload_txn_field(@TXN_FIELD_COMPUTED_FEE_PER_GAS) + %mload_txn_field(@TXN_FIELD_GAS_LIMIT) + MUL + %mload_txn_field(@TXN_FIELD_VALUE) + ADD + %assert_le + // stack: retdest + + // Assert chain ID matches block metadata + %mload_txn_field(@TXN_FIELD_CHAIN_ID_PRESENT) + // stack: chain_id_present, retdest + DUP1 + %mload_txn_field(@TXN_FIELD_CHAIN_ID) + // stack: tx_chain_id, chain_id_present, chain_id_present, retdest + MUL SWAP1 + // stack: chain_id_present, filtered_tx_chain_id, retdest + %mload_global_metadata(@GLOBAL_METADATA_BLOCK_CHAIN_ID) + MUL + // stack: filtered_block_chain_id, filtered_tx_chain_id, retdest + %assert_eq // stack: retdest global buy_gas: From 8e04cbfe8d57319526e55063df066f4fe978c67b Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Sat, 1 Apr 2023 07:29:22 +0200 Subject: [PATCH 17/20] Self-destruct list (#948) --- evm/src/cpu/kernel/aggregator.rs | 2 +- evm/src/cpu/kernel/asm/core/process_txn.asm | 2 + .../cpu/kernel/asm/core/selfdestruct_list.asm | 12 ++++++ .../cpu/kernel/asm/core/selfdestruct_set.asm | 43 ------------------- evm/src/cpu/kernel/asm/core/terminate.asm | 2 +- .../cpu/kernel/constants/global_metadata.rs | 8 ++-- evm/src/memory/segments.rs | 8 ++-- 7 files changed, 24 insertions(+), 53 deletions(-) create mode 100644 evm/src/cpu/kernel/asm/core/selfdestruct_list.asm delete mode 100644 evm/src/cpu/kernel/asm/core/selfdestruct_set.asm diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index 79d22f87..023a0c88 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -37,7 +37,7 @@ pub(crate) fn combined_kernel() -> Kernel { include_str!("asm/core/transfer.asm"), include_str!("asm/core/util.asm"), include_str!("asm/core/access_lists.asm"), - include_str!("asm/core/selfdestruct_set.asm"), + include_str!("asm/core/selfdestruct_list.asm"), include_str!("asm/curve/bls381/util.asm"), include_str!("asm/curve/bn254/curve_arithmetic/constants.asm"), include_str!("asm/curve/bn254/curve_arithmetic/curve_add.asm"), diff --git a/evm/src/cpu/kernel/asm/core/process_txn.asm b/evm/src/cpu/kernel/asm/core/process_txn.asm index 4c0d05c6..b97a2d93 100644 --- a/evm/src/cpu/kernel/asm/core/process_txn.asm +++ b/evm/src/cpu/kernel/asm/core/process_txn.asm @@ -146,6 +146,7 @@ global process_contract_creation_txn_after_constructor: POP // TODO: Success will go into the receipt when we support that. // stack: leftover_gas, new_ctx, address, retdest %pay_coinbase_and_refund_sender + // TODO: Delete accounts in self-destruct list and empty touched addresses. // stack: new_ctx, address, retdest POP POP @@ -229,6 +230,7 @@ global process_message_txn_after_call: POP // TODO: Success will go into the receipt when we support that. // stack: leftover_gas, new_ctx, retdest %pay_coinbase_and_refund_sender + // TODO: Delete accounts in self-destruct list and empty touched addresses. // stack: new_ctx, retdest POP JUMP diff --git a/evm/src/cpu/kernel/asm/core/selfdestruct_list.asm b/evm/src/cpu/kernel/asm/core/selfdestruct_list.asm new file mode 100644 index 00000000..cc6f5b42 --- /dev/null +++ b/evm/src/cpu/kernel/asm/core/selfdestruct_list.asm @@ -0,0 +1,12 @@ +/// Self-destruct list. +/// Implemented as an append-only array, with the length stored in the global metadata. + +%macro insert_selfdestruct_list + // stack: addr + %mload_global_metadata(@GLOBAL_METADATA_SELFDESTRUCT_LIST_LEN) + %stack (len, addr) -> (len, addr, len) + %mstore_kernel(@SEGMENT_SELFDESTRUCT_LIST) // Store new address at the end of the array. + // stack: len + %increment + %mstore_global_metadata(@GLOBAL_METADATA_SELFDESTRUCT_LIST_LEN) // Store new length. +%endmacro diff --git a/evm/src/cpu/kernel/asm/core/selfdestruct_set.asm b/evm/src/cpu/kernel/asm/core/selfdestruct_set.asm deleted file mode 100644 index ad62c6f1..00000000 --- a/evm/src/cpu/kernel/asm/core/selfdestruct_set.asm +++ /dev/null @@ -1,43 +0,0 @@ -/// Self-destruct set. -/// Essentially the same code as in `access_lists.asm`, with the exception that the insert function doesn't return anything. -/// TODO: Would it make sense to merge this with `access_lists.asm`? -/// TODO: Look into using a more efficient data structure. - -%macro insert_selfdestruct_set - %stack (addr) -> (addr, %%after) - %jump(insert_selfdestruct_set) -%%after: - // stack: (empty) -%endmacro - -/// Inserts the address into the self-destruct set if it is not already present. -global insert_selfdestruct_set: - // stack: addr, retdest - %mload_global_metadata(@GLOBAL_METADATA_SELFDESTRUCT_SET_LEN) - // stack: len, addr, retdest - PUSH 0 -insert_selfdestruct_set_loop: - %stack (i, len, addr, retdest) -> (i, len, i, len, addr, retdest) - EQ %jumpi(insert_address) - // stack: i, len, addr, retdest - DUP1 %mload_kernel(@SEGMENT_SELFDESTRUCT_SET) - // stack: loaded_addr, i, len, addr, retdest - DUP4 - // stack: addr, loaded_addr, i, len, addr, retdest - EQ %jumpi(insert_address_found) - // stack: i, len, addr, retdest - %increment - %jump(insert_selfdestruct_set_loop) - -insert_address: - %stack (i, len, addr, retdest) -> (i, addr, len, retdest) - %mstore_kernel(@SEGMENT_SELFDESTRUCT_SET) // Store new address at the end of the array. - // stack: len, retdest - %increment - %mstore_global_metadata(@GLOBAL_METADATA_SELFDESTRUCT_SET_LEN) // Store new length. - JUMP - -insert_address_found: - // stack: i, len, addr, retdest - %pop3 - JUMP diff --git a/evm/src/cpu/kernel/asm/core/terminate.asm b/evm/src/cpu/kernel/asm/core/terminate.asm index 27758e6a..7903e591 100644 --- a/evm/src/cpu/kernel/asm/core/terminate.asm +++ b/evm/src/cpu/kernel/asm/core/terminate.asm @@ -46,7 +46,7 @@ global sys_selfdestruct: // Insert address into the selfdestruct set. // stack: balance, address, recipient, kexit_info - DUP2 %insert_selfdestruct_set + DUP2 %insert_selfdestruct_list // Set the balance of the address to 0. // stack: balance, address, recipient, kexit_info diff --git a/evm/src/cpu/kernel/constants/global_metadata.rs b/evm/src/cpu/kernel/constants/global_metadata.rs index a9e1a9fd..4c6873c8 100644 --- a/evm/src/cpu/kernel/constants/global_metadata.rs +++ b/evm/src/cpu/kernel/constants/global_metadata.rs @@ -49,8 +49,8 @@ pub(crate) enum GlobalMetadata { AccessedAddressesLen = 23, /// Length of the storage keys access list. AccessedStorageKeysLen = 24, - /// Length of the self-destruct set. - SelfDestructSetLen = 25, + /// Length of the self-destruct list. + SelfDestructListLen = 25, } impl GlobalMetadata { @@ -82,7 +82,7 @@ impl GlobalMetadata { Self::RefundCounter, Self::AccessedAddressesLen, Self::AccessedStorageKeysLen, - Self::SelfDestructSetLen, + Self::SelfDestructListLen, ] } @@ -113,7 +113,7 @@ impl GlobalMetadata { Self::RefundCounter => "GLOBAL_METADATA_REFUND_COUNTER", Self::AccessedAddressesLen => "GLOBAL_METADATA_ACCESSED_ADDRESSES_LEN", Self::AccessedStorageKeysLen => "GLOBAL_METADATA_ACCESSED_STORAGE_KEYS_LEN", - Self::SelfDestructSetLen => "GLOBAL_METADATA_SELFDESTRUCT_SET_LEN", + Self::SelfDestructListLen => "GLOBAL_METADATA_SELFDESTRUCT_LIST_LEN", } } } diff --git a/evm/src/memory/segments.rs b/evm/src/memory/segments.rs index 0b74550d..ac33af7a 100644 --- a/evm/src/memory/segments.rs +++ b/evm/src/memory/segments.rs @@ -49,7 +49,7 @@ pub enum Segment { /// List of storage keys that have been accessed in the current transaction. AccessedStorageKeys = 24, /// List of addresses that have called SELFDESTRUCT in the current transaction. - SelfDestructSet = 25, + SelfDestructList = 25, } impl Segment { @@ -82,7 +82,7 @@ impl Segment { Self::BnPairing, Self::AccessedAddresses, Self::AccessedStorageKeys, - Self::SelfDestructSet, + Self::SelfDestructList, ] } @@ -114,7 +114,7 @@ impl Segment { Segment::BnPairing => "SEGMENT_KERNEL_BN_PAIRING", Segment::AccessedAddresses => "SEGMENT_ACCESSED_ADDRESSES", Segment::AccessedStorageKeys => "SEGMENT_ACCESSED_STORAGE_KEYS", - Segment::SelfDestructSet => "SEGMENT_SELFDESTRUCT_SET", + Segment::SelfDestructList => "SEGMENT_SELFDESTRUCT_LIST", } } @@ -146,7 +146,7 @@ impl Segment { Segment::BnPairing => 256, Segment::AccessedAddresses => 256, Segment::AccessedStorageKeys => 256, - Segment::SelfDestructSet => 256, + Segment::SelfDestructList => 256, } } } From 46d5e62a132ea5b7f40daa0a236889f60742b22f Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Sat, 1 Apr 2023 07:34:38 +0200 Subject: [PATCH 18/20] Copy txn data to calldata (#935) --- evm/src/cpu/kernel/asm/core/call.asm | 8 ++++++++ evm/src/cpu/kernel/asm/core/process_txn.asm | 8 +++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/asm/core/call.asm b/evm/src/cpu/kernel/asm/core/call.asm index 28f0f6e2..2c8eec75 100644 --- a/evm/src/cpu/kernel/asm/core/call.asm +++ b/evm/src/cpu/kernel/asm/core/call.asm @@ -169,6 +169,14 @@ global after_call_instruction: // stack: new_ctx %endmacro +%macro set_new_ctx_calldata_size + // stack: calldata_size, new_ctx + %stack (calldata_size, new_ctx) + -> (new_ctx, @SEGMENT_CONTEXT_METADATA, @CTX_METADATA_CALLDATA_SIZE, calldata_size, new_ctx) + MSTORE_GENERAL + // stack: new_ctx +%endmacro + %macro set_new_ctx_gas_limit // stack: gas_limit, new_ctx %stack (gas_limit, new_ctx) diff --git a/evm/src/cpu/kernel/asm/core/process_txn.asm b/evm/src/cpu/kernel/asm/core/process_txn.asm index b97a2d93..a626cd39 100644 --- a/evm/src/cpu/kernel/asm/core/process_txn.asm +++ b/evm/src/cpu/kernel/asm/core/process_txn.asm @@ -220,8 +220,14 @@ global process_message_txn_code_loaded: %non_intrinisic_gas %set_new_ctx_gas_limit // stack: new_ctx, retdest - // TODO: Copy TXN_DATA to CALLDATA + // Set calldatasize and copy txn data to calldata. + %mload_txn_field(@TXN_FIELD_DATA_LEN) + %stack (calldata_size, new_ctx, retdest) -> (calldata_size, new_ctx, calldata_size, retdest) + %set_new_ctx_calldata_size + %stack (new_ctx, calldata_size, retdest) -> (new_ctx, @SEGMENT_CALLDATA, 0, 0, @SEGMENT_TXN_DATA, 0, calldata_size, process_message_txn_code_loaded_finish, new_ctx, retdest) + %jump(memcpy) +process_message_txn_code_loaded_finish: %enter_new_ctx // (Old context) stack: new_ctx, retdest From 9ee47ab745f1e06e91ebe721b159f5259a6a6a87 Mon Sep 17 00:00:00 2001 From: Robin Salen Date: Sat, 1 Apr 2023 09:34:13 -0400 Subject: [PATCH 19/20] Move HashConfig into GenericConfig associated types --- evm/src/arithmetic/arithmetic_stark.rs | 20 +- evm/src/cpu/cpu_stark.rs | 12 +- evm/src/cross_table_lookup.rs | 10 +- evm/src/fixed_recursive_verifier.rs | 181 +++++++-------- evm/src/get_challenges.rs | 53 ++--- evm/src/keccak/keccak_stark.rs | 22 +- evm/src/keccak_sponge/keccak_sponge_stark.rs | 12 +- evm/src/logic.rs | 12 +- evm/src/memory/memory_stark.rs | 12 +- evm/src/proof.rs | 72 ++---- evm/src/prover.rs | 96 ++++---- evm/src/recursive_verifier.rs | 125 +++++------ evm/src/stark_testing.rs | 10 +- evm/src/verifier.rs | 32 +-- evm/tests/add11_yml.rs | 6 +- evm/tests/basic_smart_contract.rs | 6 +- evm/tests/empty_txn_list.rs | 8 +- evm/tests/simple_transfer.rs | 6 +- plonky2/examples/bench_recursion.rs | 82 +++---- plonky2/examples/factorial.rs | 8 +- plonky2/examples/fibonacci.rs | 8 +- plonky2/examples/square_root.rs | 8 +- plonky2/src/fri/challenges.rs | 10 +- plonky2/src/fri/oracle.rs | 34 +-- plonky2/src/fri/prover.rs | 102 +++------ plonky2/src/fri/recursive_verifier.rs | 26 +-- plonky2/src/fri/validate_shape.rs | 9 +- plonky2/src/fri/verifier.rs | 42 ++-- plonky2/src/gadgets/arithmetic_extension.rs | 29 +-- plonky2/src/gadgets/interpolation.rs | 10 +- plonky2/src/gadgets/random_access.rs | 10 +- plonky2/src/gadgets/select.rs | 10 +- plonky2/src/gadgets/split_base.rs | 14 +- plonky2/src/gates/arithmetic_base.rs | 8 +- plonky2/src/gates/arithmetic_extension.rs | 8 +- plonky2/src/gates/base_sum.rs | 8 +- plonky2/src/gates/constant.rs | 8 +- plonky2/src/gates/coset_interpolation.rs | 16 +- plonky2/src/gates/exponentiation.rs | 14 +- plonky2/src/gates/gate_testing.rs | 12 +- plonky2/src/gates/multiplication_extension.rs | 8 +- plonky2/src/gates/noop.rs | 8 +- plonky2/src/gates/poseidon.rs | 14 +- plonky2/src/gates/poseidon_mds.rs | 12 +- plonky2/src/gates/public_input.rs | 8 +- plonky2/src/gates/random_access.rs | 14 +- plonky2/src/gates/reducing.rs | 8 +- plonky2/src/gates/reducing_extension.rs | 8 +- plonky2/src/hash/merkle_proofs.rs | 17 +- plonky2/src/hash/merkle_tree.rs | 32 +-- plonky2/src/hash/path_compression.rs | 15 +- plonky2/src/iop/challenger.rs | 36 +-- plonky2/src/iop/generator.rs | 7 +- plonky2/src/iop/witness.rs | 33 +-- plonky2/src/plonk/circuit_builder.rs | 44 ++-- plonky2/src/plonk/circuit_data.rs | 140 +++++------- plonky2/src/plonk/config.rs | 18 +- plonky2/src/plonk/get_challenges.rs | 109 ++++----- plonky2/src/plonk/proof.rs | 143 +++++------- plonky2/src/plonk/prover.rs | 73 +++--- plonky2/src/plonk/validate_shape.rs | 17 +- plonky2/src/plonk/verifier.rs | 32 +-- .../conditional_recursive_verifier.rs | 50 ++--- plonky2/src/recursion/cyclic_recursion.rs | 87 +++----- plonky2/src/recursion/dummy_circuit.rs | 77 +++---- plonky2/src/recursion/recursive_verifier.rs | 187 ++++++---------- plonky2/src/util/reducing.rs | 18 +- plonky2/src/util/serialization.rs | 209 +++++++----------- starky/src/fibonacci_stark.rs | 57 ++--- starky/src/get_challenges.rs | 68 +++--- starky/src/proof.rs | 56 ++--- starky/src/prover.rs | 26 +-- starky/src/recursive_verifier.rs | 54 ++--- starky/src/stark_testing.rs | 10 +- starky/src/verifier.rs | 34 ++- 75 files changed, 1094 insertions(+), 1806 deletions(-) diff --git a/evm/src/arithmetic/arithmetic_stark.rs b/evm/src/arithmetic/arithmetic_stark.rs index 397bceb4..0a89f3c6 100644 --- a/evm/src/arithmetic/arithmetic_stark.rs +++ b/evm/src/arithmetic/arithmetic_stark.rs @@ -171,7 +171,7 @@ mod tests { use anyhow::Result; use ethereum_types::U256; use plonky2::field::types::{Field, PrimeField64}; - use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; @@ -183,9 +183,7 @@ mod tests { fn degree() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = ArithmeticStark; let stark = S { @@ -198,24 +196,20 @@ mod tests { fn circuit() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = ArithmeticStark; let stark = S { f: Default::default(), }; - test_stark_circuit_constraints::(stark) + test_stark_circuit_constraints::(stark) } #[test] fn basic_trace() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = ArithmeticStark; let stark = S { @@ -301,9 +295,7 @@ mod tests { fn big_traces() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = ArithmeticStark; let stark = S { diff --git a/evm/src/cpu/cpu_stark.rs b/evm/src/cpu/cpu_stark.rs index e6891bba..d922c473 100644 --- a/evm/src/cpu/cpu_stark.rs +++ b/evm/src/cpu/cpu_stark.rs @@ -199,7 +199,7 @@ impl, const D: usize> Stark for CpuStark Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = CpuStark; let stark = S { @@ -223,14 +221,12 @@ mod tests { fn test_stark_circuit() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = CpuStark; let stark = S { f: Default::default(), }; - test_stark_circuit_constraints::(stark) + test_stark_circuit_constraints::(stark) } } diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index 75dd1025..28dae98c 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -323,18 +323,14 @@ where impl<'a, F: RichField + Extendable, const D: usize> CtlCheckVars<'a, F, F::Extension, F::Extension, D> { - pub(crate) fn from_proofs< - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - >( - proofs: &[StarkProofWithMetadata; NUM_TABLES], + pub(crate) fn from_proofs>( + proofs: &[StarkProofWithMetadata; NUM_TABLES], cross_table_lookups: &'a [CrossTableLookup], ctl_challenges: &'a GrandProductChallengeSet, num_permutation_zs: &[usize; NUM_TABLES], ) -> [Vec; NUM_TABLES] where - [(); HCO::WIDTH]:, + [(); C::HCO::WIDTH]:, { let mut ctl_zs = proofs .iter() diff --git a/evm/src/fixed_recursive_verifier.rs b/evm/src/fixed_recursive_verifier.rs index c64edbb4..d6c22080 100644 --- a/evm/src/fixed_recursive_verifier.rs +++ b/evm/src/fixed_recursive_verifier.rs @@ -45,33 +45,29 @@ const THRESHOLD_DEGREE_BITS: usize = 13; /// `degree_bits`, this contains a chain of recursive circuits for shrinking that STARK from /// `degree_bits` to a constant `THRESHOLD_DEGREE_BITS`. It also contains a special root circuit /// for combining each STARK's shrunk wrapper proof into a single proof. -pub struct AllRecursiveCircuits +pub struct AllRecursiveCircuits where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - [(); HCO::WIDTH]:, + C: GenericConfig, + [(); C::HCO::WIDTH]:, { /// The EVM root circuit, which aggregates the (shrunk) per-table recursive proofs. - pub root: RootCircuitData, - pub aggregation: AggregationCircuitData, + pub root: RootCircuitData, + pub aggregation: AggregationCircuitData, /// The block circuit, which verifies an aggregation root proof and a previous block proof. - pub block: BlockCircuitData, + pub block: BlockCircuitData, /// Holds chains of circuits for each table and for each initial `degree_bits`. - by_table: [RecursiveCircuitsForTable; NUM_TABLES], + by_table: [RecursiveCircuitsForTable; NUM_TABLES], } /// Data for the EVM root circuit, which is used to combine each STARK's shrunk wrapper proof /// into a single proof. -pub struct RootCircuitData +pub struct RootCircuitData where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { - circuit: CircuitData, + circuit: CircuitData, proof_with_pis: [ProofWithPublicInputsTarget; NUM_TABLES], /// For each table, various inner circuits may be used depending on the initial table size. /// This target holds the index of the circuit (within `final_circuits()`) that was used. @@ -83,14 +79,12 @@ where /// Data for the aggregation circuit, which is used to compress two proofs into one. Each inner /// proof can be either an EVM root proof or another aggregation proof. -pub struct AggregationCircuitData +pub struct AggregationCircuitData where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { - circuit: CircuitData, + circuit: CircuitData, lhs: AggregationChildTarget, rhs: AggregationChildTarget, cyclic_vk: VerifierCircuitTarget, @@ -102,35 +96,31 @@ pub struct AggregationChildTarget { evm_proof: ProofWithPublicInputsTarget, } -pub struct BlockCircuitData +pub struct BlockCircuitData where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { - circuit: CircuitData, + circuit: CircuitData, has_parent_block: BoolTarget, parent_block_proof: ProofWithPublicInputsTarget, agg_root_proof: ProofWithPublicInputsTarget, cyclic_vk: VerifierCircuitTarget, } -impl AllRecursiveCircuits +impl AllRecursiveCircuits where F: RichField + Extendable, - HCO: HashConfig + 'static, - HCI: HashConfig + 'static, - C: GenericConfig + 'static, - C::Hasher: AlgebraicHasher, + C: GenericConfig + 'static, + C::Hasher: AlgebraicHasher, [(); C::Hasher::HASH_SIZE]:, [(); CpuStark::::COLUMNS]:, [(); KeccakStark::::COLUMNS]:, [(); KeccakSpongeStark::::COLUMNS]:, [(); LogicStark::::COLUMNS]:, [(); MemoryStark::::COLUMNS]:, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { /// Preprocess all recursive circuits used by the system. pub fn new( @@ -187,9 +177,9 @@ where } fn create_root_circuit( - by_table: &[RecursiveCircuitsForTable; NUM_TABLES], + by_table: &[RecursiveCircuitsForTable; NUM_TABLES], stark_config: &StarkConfig, - ) -> RootCircuitData { + ) -> RootCircuitData { let inner_common_data: [_; NUM_TABLES] = core::array::from_fn(|i| &by_table[i].final_circuits()[0].common); @@ -197,11 +187,14 @@ where let recursive_proofs = core::array::from_fn(|i| builder.add_virtual_proof_with_pis(inner_common_data[i])); let pis: [_; NUM_TABLES] = core::array::from_fn(|i| { - PublicInputs::::from_vec(&recursive_proofs[i].public_inputs, stark_config) + PublicInputs::::from_vec( + &recursive_proofs[i].public_inputs, + stark_config, + ) }); let index_verifier_data = core::array::from_fn(|_i| builder.add_virtual_target()); - let mut challenger = RecursiveChallenger::::new(&mut builder); + let mut challenger = RecursiveChallenger::::new(&mut builder); for pi in &pis { for h in &pi.trace_cap { challenger.observe_elements(h); @@ -227,12 +220,12 @@ where } let state = challenger.compact(&mut builder); - for k in 0..HCO::WIDTH { + for k in 0..C::HCO::WIDTH { builder.connect(state[k], pis[0].challenger_state_before[k]); } // Check that the challenger state is consistent between proofs. for i in 1..NUM_TABLES { - for k in 0..HCO::WIDTH { + for k in 0..C::HCO::WIDTH { builder.connect( pis[i].challenger_state_before[k], pis[i - 1].challenger_state_after[k], @@ -268,7 +261,7 @@ where let inner_verifier_data = builder.random_access_verifier_data(index_verifier_data[i], possible_vks); - builder.verify_proof::( + builder.verify_proof::( &recursive_proofs[i], &inner_verifier_data, inner_common_data[i], @@ -280,7 +273,7 @@ where let cyclic_vk = builder.add_verifier_data_public_inputs(); RootCircuitData { - circuit: builder.build::(), + circuit: builder.build::(), proof_with_pis: recursive_proofs, index_verifier_data, cyclic_vk, @@ -288,8 +281,8 @@ where } fn create_aggregation_circuit( - root: &RootCircuitData, - ) -> AggregationCircuitData { + root: &RootCircuitData, + ) -> AggregationCircuitData { let mut builder = CircuitBuilder::::new(root.circuit.common.config.clone()); let cyclic_vk = builder.add_verifier_data_public_inputs(); let lhs = Self::add_agg_child(&mut builder, root); @@ -300,7 +293,7 @@ where builder.add_gate(NoopGate, vec![]); } - let circuit = builder.build::(); + let circuit = builder.build::(); AggregationCircuitData { circuit, lhs, @@ -311,7 +304,7 @@ where fn add_agg_child( builder: &mut CircuitBuilder, - root: &RootCircuitData, + root: &RootCircuitData, ) -> AggregationChildTarget { let common = &root.circuit.common; let root_vk = builder.constant_verifier_data(&root.circuit.verifier_only); @@ -319,7 +312,7 @@ where let agg_proof = builder.add_virtual_proof_with_pis(common); let evm_proof = builder.add_virtual_proof_with_pis(common); builder - .conditionally_verify_cyclic_proof::( + .conditionally_verify_cyclic_proof::( is_agg, &agg_proof, &evm_proof, &root_vk, common, ) .expect("Failed to build cyclic recursion circuit"); @@ -330,9 +323,7 @@ where } } - fn create_block_circuit( - agg: &AggregationCircuitData, - ) -> BlockCircuitData { + fn create_block_circuit(agg: &AggregationCircuitData) -> BlockCircuitData { // The block circuit is similar to the agg circuit; both verify two inner proofs. // We need to adjust a few things, but it's easier than making a new CommonCircuitData. let expected_common_data = CommonCircuitData { @@ -350,7 +341,7 @@ where let cyclic_vk = builder.add_verifier_data_public_inputs(); builder - .conditionally_verify_cyclic_proof_or_dummy::( + .conditionally_verify_cyclic_proof_or_dummy::( has_parent_block, &parent_block_proof, &expected_common_data, @@ -358,13 +349,9 @@ where .expect("Failed to build cyclic recursion circuit"); let agg_verifier_data = builder.constant_verifier_data(&agg.circuit.verifier_only); - builder.verify_proof::( - &agg_root_proof, - &agg_verifier_data, - &agg.circuit.common, - ); + builder.verify_proof::(&agg_root_proof, &agg_verifier_data, &agg.circuit.common); - let circuit = builder.build::(); + let circuit = builder.build::(); BlockCircuitData { circuit, has_parent_block, @@ -381,8 +368,8 @@ where config: &StarkConfig, generation_inputs: GenerationInputs, timing: &mut TimingTree, - ) -> anyhow::Result> { - let all_proof = prove::(all_stark, config, generation_inputs, timing)?; + ) -> anyhow::Result> { + let all_proof = prove::(all_stark, config, generation_inputs, timing)?; let mut root_inputs = PartialWitness::new(); for table in 0..NUM_TABLES { @@ -411,20 +398,17 @@ where self.root.circuit.prove(root_inputs) } - pub fn verify_root( - &self, - agg_proof: ProofWithPublicInputs, - ) -> anyhow::Result<()> { + pub fn verify_root(&self, agg_proof: ProofWithPublicInputs) -> anyhow::Result<()> { self.root.circuit.verify(agg_proof) } pub fn prove_aggregation( &self, lhs_is_agg: bool, - lhs_proof: &ProofWithPublicInputs, + lhs_proof: &ProofWithPublicInputs, rhs_is_agg: bool, - rhs_proof: &ProofWithPublicInputs, - ) -> anyhow::Result> { + rhs_proof: &ProofWithPublicInputs, + ) -> anyhow::Result> { let mut agg_inputs = PartialWitness::new(); agg_inputs.set_bool_target(self.aggregation.lhs.is_agg, lhs_is_agg); @@ -445,7 +429,7 @@ where pub fn verify_aggregation( &self, - agg_proof: &ProofWithPublicInputs, + agg_proof: &ProofWithPublicInputs, ) -> anyhow::Result<()> { self.aggregation.circuit.verify(agg_proof.clone())?; check_cyclic_proof_verifier_data( @@ -457,9 +441,9 @@ where pub fn prove_block( &self, - opt_parent_block_proof: Option<&ProofWithPublicInputs>, - agg_root_proof: &ProofWithPublicInputs, - ) -> anyhow::Result> { + opt_parent_block_proof: Option<&ProofWithPublicInputs>, + agg_root_proof: &ProofWithPublicInputs, + ) -> anyhow::Result> { let mut block_inputs = PartialWitness::new(); block_inputs.set_bool_target( @@ -479,10 +463,7 @@ where self.block.circuit.prove(block_inputs) } - pub fn verify_block( - &self, - block_proof: &ProofWithPublicInputs, - ) -> anyhow::Result<()> { + pub fn verify_block(&self, block_proof: &ProofWithPublicInputs) -> anyhow::Result<()> { self.block.circuit.verify(block_proof.clone())?; check_cyclic_proof_verifier_data( block_proof, @@ -492,29 +473,25 @@ where } } -struct RecursiveCircuitsForTable +struct RecursiveCircuitsForTable where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - [(); HCO::WIDTH]:, + C: GenericConfig, + [(); C::HCO::WIDTH]:, { /// A map from `log_2(height)` to a chain of shrinking recursion circuits starting at that /// height. - by_stark_size: BTreeMap>, + by_stark_size: BTreeMap>, } -impl RecursiveCircuitsForTable +impl RecursiveCircuitsForTable where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - C::Hasher: AlgebraicHasher, + C: GenericConfig, + C::Hasher: AlgebraicHasher, [(); C::Hasher::HASH_SIZE]:, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { fn new>( table: Table, @@ -545,7 +522,7 @@ where /// For each initial `degree_bits`, get the final circuit at the end of that shrinking chain. /// Each of these final circuits should have degree `THRESHOLD_DEGREE_BITS`. - fn final_circuits(&self) -> Vec<&CircuitData> { + fn final_circuits(&self) -> Vec<&CircuitData> { self.by_stark_size .values() .map(|chain| { @@ -561,28 +538,24 @@ where /// A chain of shrinking wrapper circuits, ending with a final circuit with `degree_bits` /// `THRESHOLD_DEGREE_BITS`. -struct RecursiveCircuitsForTableSize +struct RecursiveCircuitsForTableSize where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - [(); HCO::WIDTH]:, + C: GenericConfig, + [(); C::HCO::WIDTH]:, { - initial_wrapper: StarkWrapperCircuit, - shrinking_wrappers: Vec>, + initial_wrapper: StarkWrapperCircuit, + shrinking_wrappers: Vec>, } -impl RecursiveCircuitsForTableSize +impl RecursiveCircuitsForTableSize where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - C::Hasher: AlgebraicHasher, + C: GenericConfig, + C::Hasher: AlgebraicHasher, [(); C::Hasher::HASH_SIZE]:, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { fn new>( table: Table, @@ -609,7 +582,7 @@ where loop { let last = shrinking_wrappers .last() - .map(|wrapper: &PlonkWrapperCircuit| &wrapper.circuit) + .map(|wrapper: &PlonkWrapperCircuit| &wrapper.circuit) .unwrap_or(&initial_wrapper.circuit); let last_degree_bits = last.common.degree_bits(); assert!(last_degree_bits >= THRESHOLD_DEGREE_BITS); @@ -620,10 +593,10 @@ where let mut builder = CircuitBuilder::new(shrinking_config()); let proof_with_pis_target = builder.add_virtual_proof_with_pis(&last.common); let last_vk = builder.constant_verifier_data(&last.verifier_only); - builder.verify_proof::(&proof_with_pis_target, &last_vk, &last.common); + builder.verify_proof::(&proof_with_pis_target, &last_vk, &last.common); builder.register_public_inputs(&proof_with_pis_target.public_inputs); // carry PIs forward add_common_recursion_gates(&mut builder); - let circuit = builder.build::(); + let circuit = builder.build::(); assert!( circuit.common.degree_bits() < last_degree_bits, @@ -645,9 +618,9 @@ where fn shrink( &self, - stark_proof_with_metadata: &StarkProofWithMetadata, + stark_proof_with_metadata: &StarkProofWithMetadata, ctl_challenges: &GrandProductChallengeSet, - ) -> anyhow::Result> { + ) -> anyhow::Result> { let mut proof = self .initial_wrapper .prove(stark_proof_with_metadata, ctl_challenges)?; diff --git a/evm/src/get_challenges.rs b/evm/src/get_challenges.rs index 6d441634..6bccb48d 100644 --- a/evm/src/get_challenges.rs +++ b/evm/src/get_challenges.rs @@ -14,15 +14,9 @@ use crate::permutation::{ }; use crate::proof::*; -impl< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - > AllProof +impl, C: GenericConfig, const D: usize> AllProof where - [(); HCO::WIDTH]:, + [(); C::HCO::WIDTH]:, { /// Computes all Fiat-Shamir challenges used in the STARK proof. pub(crate) fn get_challenges( @@ -31,10 +25,10 @@ where config: &StarkConfig, ) -> AllProofChallenges where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { - let mut challenger = Challenger::::new(); + let mut challenger = Challenger::::new(); for proof in &self.stark_proofs { challenger.observe_cap(&proof.proof.trace_cap); @@ -67,12 +61,12 @@ where &self, all_stark: &AllStark, config: &StarkConfig, - ) -> AllChallengerState + ) -> AllChallengerState where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { - let mut challenger = Challenger::::new(); + let mut challenger = Challenger::::new(); for proof in &self.stark_proofs { challenger.observe_cap(&proof.proof.trace_cap); @@ -104,24 +98,22 @@ where } } -impl StarkProof +impl StarkProof where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { /// Computes all Fiat-Shamir challenges used in the STARK proof. pub(crate) fn get_challenges( &self, - challenger: &mut Challenger, + challenger: &mut Challenger, stark_use_permutation: bool, stark_permutation_batch_size: usize, config: &StarkConfig, ) -> StarkProofChallenges where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let degree_bits = self.recover_degree_bits(config); @@ -162,7 +154,7 @@ where permutation_challenge_sets, stark_alphas, stark_zeta, - fri_challenges: challenger.fri_challenges::( + fri_challenges: challenger.fri_challenges::( commit_phase_merkle_caps, final_poly, *pow_witness, @@ -174,23 +166,18 @@ where } impl StarkProofTarget { - pub(crate) fn get_challenges< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - >( + pub(crate) fn get_challenges, C: GenericConfig>( &self, builder: &mut CircuitBuilder, - challenger: &mut RecursiveChallenger, + challenger: &mut RecursiveChallenger, stark_use_permutation: bool, stark_permutation_batch_size: usize, config: &StarkConfig, ) -> StarkProofChallengesTarget where - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let StarkProofTarget { permutation_ctl_zs_cap, diff --git a/evm/src/keccak/keccak_stark.rs b/evm/src/keccak/keccak_stark.rs index 34d68d11..c8fe8086 100644 --- a/evm/src/keccak/keccak_stark.rs +++ b/evm/src/keccak/keccak_stark.rs @@ -607,7 +607,7 @@ mod tests { use plonky2::field::types::{Field, PrimeField64}; use plonky2::fri::oracle::PolynomialBatch; use plonky2::iop::challenger::Challenger; - use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use plonky2::timed; use plonky2::util::timing::TimingTree; use tiny_keccak::keccakf; @@ -624,9 +624,7 @@ mod tests { fn test_stark_degree() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = KeccakStark; let stark = S { @@ -639,15 +637,13 @@ mod tests { fn test_stark_circuit() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = KeccakStark; let stark = S { f: Default::default(), }; - test_stark_circuit_constraints::(stark) + test_stark_circuit_constraints::(stark) } #[test] @@ -656,9 +652,7 @@ mod tests { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = KeccakStark; let stark = S { @@ -691,9 +685,7 @@ mod tests { const NUM_PERMS: usize = 85; const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = KeccakStark; let stark = S::default(); let config = StarkConfig::standard_fast_config(); @@ -716,7 +708,7 @@ mod tests { let trace_commitments = timed!( timing, "compute trace commitment", - PolynomialBatch::::from_values( + PolynomialBatch::::from_values( cloned_trace_poly_values, config.fri_config.rate_bits, false, diff --git a/evm/src/keccak_sponge/keccak_sponge_stark.rs b/evm/src/keccak_sponge/keccak_sponge_stark.rs index 57033b52..3fe59f74 100644 --- a/evm/src/keccak_sponge/keccak_sponge_stark.rs +++ b/evm/src/keccak_sponge/keccak_sponge_stark.rs @@ -411,7 +411,7 @@ mod tests { use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; use plonky2::field::types::PrimeField64; - use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::keccak_sponge::columns::KeccakSpongeColumnsView; use crate::keccak_sponge::keccak_sponge_stark::{KeccakSpongeOp, KeccakSpongeStark}; @@ -423,9 +423,7 @@ mod tests { fn test_stark_degree() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = KeccakSpongeStark; let stark = S::default(); @@ -436,13 +434,11 @@ mod tests { fn test_stark_circuit() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = KeccakSpongeStark; let stark = S::default(); - test_stark_circuit_constraints::(stark) + test_stark_circuit_constraints::(stark) } #[test] diff --git a/evm/src/logic.rs b/evm/src/logic.rs index f007eb2c..b7429610 100644 --- a/evm/src/logic.rs +++ b/evm/src/logic.rs @@ -303,7 +303,7 @@ impl, const D: usize> Stark for LogicStark Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = LogicStark; let stark = S { @@ -327,14 +325,12 @@ mod tests { fn test_stark_circuit() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = LogicStark; let stark = S { f: Default::default(), }; - test_stark_circuit_constraints::(stark) + test_stark_circuit_constraints::(stark) } } diff --git a/evm/src/memory/memory_stark.rs b/evm/src/memory/memory_stark.rs index 4fed6ac4..a0481029 100644 --- a/evm/src/memory/memory_stark.rs +++ b/evm/src/memory/memory_stark.rs @@ -462,7 +462,7 @@ impl, const D: usize> Stark for MemoryStark Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = MemoryStark; let stark = S { @@ -486,14 +484,12 @@ pub(crate) mod tests { fn test_stark_circuit() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = MemoryStark; let stark = S { f: Default::default(), }; - test_stark_circuit_constraints::(stark) + test_stark_circuit_constraints::(stark) } } diff --git a/evm/src/proof.rs b/evm/src/proof.rs index f1464cb2..b243c9be 100644 --- a/evm/src/proof.rs +++ b/evm/src/proof.rs @@ -21,29 +21,18 @@ use crate::permutation::GrandProductChallengeSet; /// A STARK proof for each table, plus some metadata used to create recursive wrapper proofs. #[derive(Debug, Clone)] -pub struct AllProof< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, -> where - [(); HCO::WIDTH]:, +pub struct AllProof, C: GenericConfig, const D: usize> +where + [(); C::HCO::WIDTH]:, { - pub stark_proofs: [StarkProofWithMetadata; NUM_TABLES], + pub stark_proofs: [StarkProofWithMetadata; NUM_TABLES], pub(crate) ctl_challenges: GrandProductChallengeSet, pub public_values: PublicValues, } -impl< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - > AllProof +impl, C: GenericConfig, const D: usize> AllProof where - [(); HCO::WIDTH]:, + [(); C::HCO::WIDTH]:, { pub fn degree_bits(&self, config: &StarkConfig) -> [usize; NUM_TABLES] { core::array::from_fn(|i| self.stark_proofs[i].proof.recover_degree_bits(config)) @@ -117,48 +106,33 @@ pub struct BlockMetadataTarget { } #[derive(Debug, Clone)] -pub struct StarkProof< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, -> { +pub struct StarkProof, C: GenericConfig, const D: usize> { /// Merkle cap of LDEs of trace values. - pub trace_cap: MerkleCap, + pub trace_cap: MerkleCap, /// Merkle cap of LDEs of permutation Z values. - pub permutation_ctl_zs_cap: MerkleCap, + pub permutation_ctl_zs_cap: MerkleCap, /// Merkle cap of LDEs of trace values. - pub quotient_polys_cap: MerkleCap, + pub quotient_polys_cap: MerkleCap, /// Purported values of each polynomial at the challenge point. pub openings: StarkOpeningSet, /// A batch FRI argument for all openings. - pub opening_proof: FriProof, + pub opening_proof: FriProof, } /// A `StarkProof` along with some metadata about the initial Fiat-Shamir state, which is used when /// creating a recursive wrapper proof around a STARK proof. #[derive(Debug, Clone)] -pub struct StarkProofWithMetadata +pub struct StarkProofWithMetadata where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - [(); HCO::WIDTH]:, + C: GenericConfig, + [(); C::HCO::WIDTH]:, { - pub(crate) init_challenger_state: [F; HCO::WIDTH], - pub(crate) proof: StarkProof, + pub(crate) init_challenger_state: [F; C::HCO::WIDTH], + pub(crate) proof: StarkProof, } -impl< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - > StarkProof -{ +impl, C: GenericConfig, const D: usize> StarkProof { /// Recover the length of the trace from a STARK proof and a STARK config. pub fn recover_degree_bits(&self, config: &StarkConfig) -> usize { let initial_merkle_proof = &self.opening_proof.query_round_proofs[0] @@ -232,22 +206,22 @@ pub struct StarkOpeningSet, const D: usize> { } impl, const D: usize> StarkOpeningSet { - pub fn new>( + pub fn new>( zeta: F::Extension, g: F, - trace_commitment: &PolynomialBatch, - permutation_ctl_zs_commitment: &PolynomialBatch, - quotient_commitment: &PolynomialBatch, + trace_commitment: &PolynomialBatch, + permutation_ctl_zs_commitment: &PolynomialBatch, + quotient_commitment: &PolynomialBatch, degree_bits: usize, num_permutation_zs: usize, ) -> Self { - let eval_commitment = |z: F::Extension, c: &PolynomialBatch| { + let eval_commitment = |z: F::Extension, c: &PolynomialBatch| { c.polynomials .par_iter() .map(|p| p.to_extension().eval(z)) .collect::>() }; - let eval_commitment_base = |z: F, c: &PolynomialBatch| { + let eval_commitment_base = |z: F, c: &PolynomialBatch| { c.polynomials .par_iter() .map(|p| p.eval(z)) diff --git a/evm/src/prover.rs b/evm/src/prover.rs index bed796fd..63e44b3b 100644 --- a/evm/src/prover.rs +++ b/evm/src/prover.rs @@ -42,25 +42,23 @@ use crate::vanishing_poly::eval_vanishing_poly; use crate::vars::StarkEvaluationVars; /// Generate traces, then create all STARK proofs. -pub fn prove( +pub fn prove( all_stark: &AllStark, config: &StarkConfig, inputs: GenerationInputs, timing: &mut TimingTree, -) -> Result> +) -> Result> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, [(); CpuStark::::COLUMNS]:, [(); KeccakStark::::COLUMNS]:, [(); KeccakSpongeStark::::COLUMNS]:, [(); LogicStark::::COLUMNS]:, [(); MemoryStark::::COLUMNS]:, [(); C::Hasher::HASH_SIZE]:, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let (proof, _outputs) = prove_with_outputs(all_stark, config, inputs, timing)?; Ok(proof) @@ -68,25 +66,23 @@ where /// Generate traces, then create all STARK proofs. Returns information about the post-state, /// intended for debugging, in addition to the proof. -pub fn prove_with_outputs( +pub fn prove_with_outputs( all_stark: &AllStark, config: &StarkConfig, inputs: GenerationInputs, timing: &mut TimingTree, -) -> Result<(AllProof, GenerationOutputs)> +) -> Result<(AllProof, GenerationOutputs)> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, [(); C::Hasher::HASH_SIZE]:, [(); CpuStark::::COLUMNS]:, [(); KeccakStark::::COLUMNS]:, [(); KeccakSpongeStark::::COLUMNS]:, [(); LogicStark::::COLUMNS]:, [(); MemoryStark::::COLUMNS]:, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { timed!(timing, "build kernel", Lazy::force(&KERNEL)); let (traces, public_values, outputs) = timed!( @@ -99,26 +95,24 @@ where } /// Compute all STARK proofs. -pub(crate) fn prove_with_traces( +pub(crate) fn prove_with_traces( all_stark: &AllStark, config: &StarkConfig, trace_poly_values: [Vec>; NUM_TABLES], public_values: PublicValues, timing: &mut TimingTree, -) -> Result> +) -> Result> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, [(); CpuStark::::COLUMNS]:, [(); KeccakStark::::COLUMNS]:, [(); KeccakSpongeStark::::COLUMNS]:, [(); LogicStark::::COLUMNS]:, [(); MemoryStark::::COLUMNS]:, [(); C::Hasher::HASH_SIZE]:, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let rate_bits = config.fri_config.rate_bits; let cap_height = config.fri_config.cap_height; @@ -133,7 +127,7 @@ where timed!( timing, &format!("compute trace commitment for {:?}", table), - PolynomialBatch::::from_values( + PolynomialBatch::::from_values( // TODO: Cloning this isn't great; consider having `from_values` accept a reference, // or having `compute_permutation_z_polys` read trace values from the `PolynomialBatch`. trace.clone(), @@ -152,7 +146,7 @@ where .iter() .map(|c| c.merkle_tree.cap.clone()) .collect::>(); - let mut challenger = Challenger::::new(); + let mut challenger = Challenger::::new(); for cap in &trace_caps { challenger.observe_cap(cap); } @@ -189,28 +183,26 @@ where }) } -fn prove_with_commitments( +fn prove_with_commitments( all_stark: &AllStark, config: &StarkConfig, trace_poly_values: [Vec>; NUM_TABLES], - trace_commitments: Vec>, + trace_commitments: Vec>, ctl_data_per_table: [CtlData; NUM_TABLES], - challenger: &mut Challenger, + challenger: &mut Challenger, timing: &mut TimingTree, -) -> Result<[StarkProofWithMetadata; NUM_TABLES]> +) -> Result<[StarkProofWithMetadata; NUM_TABLES]> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, [(); C::Hasher::HASH_SIZE]:, [(); CpuStark::::COLUMNS]:, [(); KeccakStark::::COLUMNS]:, [(); KeccakSpongeStark::::COLUMNS]:, [(); LogicStark::::COLUMNS]:, [(); MemoryStark::::COLUMNS]:, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let cpu_proof = timed!( timing, @@ -287,24 +279,22 @@ where } /// Compute proof for a single STARK table. -pub(crate) fn prove_single_table( +pub(crate) fn prove_single_table( stark: &S, config: &StarkConfig, trace_poly_values: &[PolynomialValues], - trace_commitment: &PolynomialBatch, + trace_commitment: &PolynomialBatch, ctl_data: &CtlData, - challenger: &mut Challenger, + challenger: &mut Challenger, timing: &mut TimingTree, -) -> Result> +) -> Result> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, [(); S::COLUMNS]:, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let degree = trace_poly_values[0].len(); let degree_bits = log2_strict(degree); @@ -377,7 +367,7 @@ where let quotient_polys = timed!( timing, "compute quotient polys", - compute_quotient_polys::::Packing, HCO, HCI, C, S, D>( + compute_quotient_polys::::Packing, C, S, D>( stark, trace_commitment, &permutation_ctl_zs_commitment, @@ -474,10 +464,10 @@ where /// Computes the quotient polynomials `(sum alpha^i C_i(x)) / Z_H(x)` for `alpha` in `alphas`, /// where the `C_i`s are the Stark constraints. -fn compute_quotient_polys<'a, F, P, HCO, HCI, C, S, const D: usize>( +fn compute_quotient_polys<'a, F, P, C, S, const D: usize>( stark: &S, - trace_commitment: &'a PolynomialBatch, - permutation_ctl_zs_commitment: &'a PolynomialBatch, + trace_commitment: &'a PolynomialBatch, + permutation_ctl_zs_commitment: &'a PolynomialBatch, permutation_challenges: Option<&'a Vec>>, ctl_data: &CtlData, alphas: Vec, @@ -488,9 +478,7 @@ fn compute_quotient_polys<'a, F, P, HCO, HCI, C, S, const D: usize>( where F: RichField + Extendable, P: PackedField, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, [(); S::COLUMNS]:, { @@ -613,10 +601,10 @@ where /// Check that all constraints evaluate to zero on `H`. /// Can also be used to check the degree of the constraints by evaluating on a larger subgroup. -fn check_constraints<'a, F, HCO, HCI, C, S, const D: usize>( +fn check_constraints<'a, F, C, S, const D: usize>( stark: &S, - trace_commitment: &'a PolynomialBatch, - permutation_ctl_zs_commitment: &'a PolynomialBatch, + trace_commitment: &'a PolynomialBatch, + permutation_ctl_zs_commitment: &'a PolynomialBatch, permutation_challenges: Option<&'a Vec>>, ctl_data: &CtlData, alphas: Vec, @@ -625,9 +613,7 @@ fn check_constraints<'a, F, HCO, HCI, C, S, const D: usize>( config: &StarkConfig, ) where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, [(); S::COLUMNS]:, { @@ -645,7 +631,7 @@ fn check_constraints<'a, F, HCO, HCI, C, S, const D: usize>( let subgroup = F::two_adic_subgroup(degree_bits + rate_bits); // Get the evaluations of a batch of polynomials over our subgroup. - let get_subgroup_evals = |comm: &PolynomialBatch| -> Vec> { + let get_subgroup_evals = |comm: &PolynomialBatch| -> Vec> { let values = comm .polynomials .par_iter() diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index ea6f9b47..14e31341 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -43,12 +43,10 @@ use crate::vars::StarkEvaluationTargets; /// Table-wise recursive proofs of an `AllProof`. pub struct RecursiveAllProof< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, > { - pub recursive_proofs: [ProofWithPublicInputs; NUM_TABLES], + pub recursive_proofs: [ProofWithPublicInputs; NUM_TABLES], } pub(crate) struct PublicInputs @@ -102,30 +100,28 @@ where } } -impl< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - > RecursiveAllProof +impl, C: GenericConfig, const D: usize> + RecursiveAllProof { /// Verify every recursive proof. pub fn verify( self, - verifier_data: &[VerifierCircuitData; NUM_TABLES], + verifier_data: &[VerifierCircuitData; NUM_TABLES], cross_table_lookups: Vec>, inner_config: &StarkConfig, ) -> Result<()> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let pis: [_; NUM_TABLES] = core::array::from_fn(|i| { - PublicInputs::::from_vec(&self.recursive_proofs[i].public_inputs, inner_config) + PublicInputs::::from_vec( + &self.recursive_proofs[i].public_inputs, + inner_config, + ) }); - let mut challenger = Challenger::::new(); + let mut challenger = Challenger::::new(); for pi in &pis { for h in &pi.trace_cap { challenger.observe_elements(h); @@ -161,36 +157,32 @@ impl< } /// Represents a circuit which recursively verifies a STARK proof. -pub(crate) struct StarkWrapperCircuit +pub(crate) struct StarkWrapperCircuit where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - [(); HCO::WIDTH]:, + C: GenericConfig, + [(); C::HCO::WIDTH]:, { - pub(crate) circuit: CircuitData, + pub(crate) circuit: CircuitData, pub(crate) stark_proof_target: StarkProofTarget, pub(crate) ctl_challenges_target: GrandProductChallengeSet, - pub(crate) init_challenger_state_target: [Target; HCO::WIDTH], + pub(crate) init_challenger_state_target: [Target; C::HCO::WIDTH], pub(crate) zero_target: Target, } -impl StarkWrapperCircuit +impl StarkWrapperCircuit where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C: GenericConfig, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { pub(crate) fn prove( &self, - proof_with_metadata: &StarkProofWithMetadata, + proof_with_metadata: &StarkProofWithMetadata, ctl_challenges: &GrandProductChallengeSet, - ) -> Result> { + ) -> Result> { let mut inputs = PartialWitness::new(); set_stark_proof_target( @@ -220,31 +212,27 @@ where } /// Represents a circuit which recursively verifies a PLONK proof. -pub(crate) struct PlonkWrapperCircuit +pub(crate) struct PlonkWrapperCircuit where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { - pub(crate) circuit: CircuitData, + pub(crate) circuit: CircuitData, pub(crate) proof_with_pis_target: ProofWithPublicInputsTarget, } -impl PlonkWrapperCircuit +impl PlonkWrapperCircuit where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C: GenericConfig, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { pub(crate) fn prove( &self, - proof: &ProofWithPublicInputs, - ) -> Result> { + proof: &ProofWithPublicInputs, + ) -> Result> { let mut inputs = PartialWitness::new(); inputs.set_proof_with_pis_target(&self.proof_with_pis_target, proof); self.circuit.prove(inputs) @@ -254,9 +242,7 @@ where /// Returns the recursive Stark circuit. pub(crate) fn recursive_stark_circuit< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, const D: usize, >( @@ -267,12 +253,12 @@ pub(crate) fn recursive_stark_circuit< inner_config: &StarkConfig, circuit_config: &CircuitConfig, min_degree_bits: usize, -) -> StarkWrapperCircuit +) -> StarkWrapperCircuit where [(); S::COLUMNS]:, - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let mut builder = CircuitBuilder::::new(circuit_config.clone()); let zero_target = builder.zero(); @@ -311,8 +297,8 @@ where let init_challenger_state_target = core::array::from_fn(|_| builder.add_virtual_public_input()); let mut challenger = - RecursiveChallenger::::from_state(init_challenger_state_target); - let challenges = proof_target.get_challenges::( + RecursiveChallenger::::from_state(init_challenger_state_target); + let challenges = proof_target.get_challenges::( &mut builder, &mut challenger, num_permutation_zs > 0, @@ -324,7 +310,7 @@ where builder.register_public_inputs(&proof_target.openings.ctl_zs_last); - verify_stark_proof_with_challenges_circuit::( + verify_stark_proof_with_challenges_circuit::( &mut builder, stark, &proof_target, @@ -340,7 +326,7 @@ where builder.add_gate(NoopGate, vec![]); } - let circuit = builder.build::(); + let circuit = builder.build::(); StarkWrapperCircuit { circuit, stark_proof_target: proof_target, @@ -364,9 +350,7 @@ pub(crate) fn add_common_recursion_gates, const D: /// Recursively verifies an inner proof. fn verify_stark_proof_with_challenges_circuit< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, const D: usize, >( @@ -377,9 +361,9 @@ fn verify_stark_proof_with_challenges_circuit< ctl_vars: &[CtlCheckVarsTarget], inner_config: &StarkConfig, ) where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, [(); S::COLUMNS]:, - [(); HCO::WIDTH]:, + [(); C::HCO::WIDTH]:, { let zero = builder.zero(); let one = builder.one_extension(); @@ -463,7 +447,7 @@ fn verify_stark_proof_with_challenges_circuit< ctl_zs_last.len(), inner_config, ); - builder.verify_fri_proof::( + builder.verify_fri_proof::( &fri_instance, &proof.openings.to_fri_openings(zero), &challenges.fri_challenges, @@ -591,23 +575,14 @@ fn add_virtual_stark_opening_set, S: Stark, c } } -pub(crate) fn set_stark_proof_target< - F, - HCO, - HCI, - C: GenericConfig, - W, - const D: usize, ->( +pub(crate) fn set_stark_proof_target, W, const D: usize>( witness: &mut W, proof_target: &StarkProofTarget, - proof: &StarkProof, + proof: &StarkProof, zero: Target, ) where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, W: Witness, { witness.set_cap_target(&proof_target.trace_cap, &proof.trace_cap); diff --git a/evm/src/stark_testing.rs b/evm/src/stark_testing.rs index e1c36f9d..c8d5fed5 100644 --- a/evm/src/stark_testing.rs +++ b/evm/src/stark_testing.rs @@ -79,9 +79,7 @@ where /// Tests that the circuit constraints imposed by the given STARK are coherent with the native constraints. pub fn test_stark_circuit_constraints< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, const D: usize, >( @@ -89,8 +87,8 @@ pub fn test_stark_circuit_constraints< ) -> Result<()> where [(); S::COLUMNS]:, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { // Compute native constraint evaluation on random values. let vars = StarkEvaluationVars { @@ -148,7 +146,7 @@ where let native_eval_t = builder.constant_extension(native_eval); builder.connect_extension(circuit_eval, native_eval_t); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; data.verify(proof) } diff --git a/evm/src/verifier.rs b/evm/src/verifier.rs index 850fb51b..eb91cfe9 100644 --- a/evm/src/verifier.rs +++ b/evm/src/verifier.rs @@ -26,15 +26,9 @@ use crate::stark::Stark; use crate::vanishing_poly::eval_vanishing_poly; use crate::vars::StarkEvaluationVars; -pub fn verify_proof< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, ->( +pub fn verify_proof, C: GenericConfig, const D: usize>( all_stark: &AllStark, - all_proof: AllProof, + all_proof: AllProof, config: &StarkConfig, ) -> Result<()> where @@ -43,8 +37,8 @@ where [(); KeccakSpongeStark::::COLUMNS]:, [(); LogicStark::::COLUMNS]:, [(); MemoryStark::::COLUMNS]:, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let AllProofChallenges { stark_challenges, @@ -114,21 +108,19 @@ where pub(crate) fn verify_stark_proof_with_challenges< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, const D: usize, >( stark: &S, - proof: &StarkProof, + proof: &StarkProof, challenges: &StarkProofChallenges, ctl_vars: &[CtlCheckVars], config: &StarkConfig, ) -> Result<()> where [(); S::COLUMNS]:, - [(); HCO::WIDTH]:, + [(); C::HCO::WIDTH]:, { log::debug!("Checking proof: {}", type_name::()); validate_proof_shape(stark, proof, config, ctl_vars.len())?; @@ -199,7 +191,7 @@ where proof.quotient_polys_cap.clone(), ]; - verify_fri_proof::( + verify_fri_proof::( &stark.fri_instance( challenges.stark_zeta, F::primitive_root_of_unity(degree_bits), @@ -217,17 +209,15 @@ where Ok(()) } -fn validate_proof_shape( +fn validate_proof_shape( stark: &S, - proof: &StarkProof, + proof: &StarkProof, config: &StarkConfig, num_ctl_zs: usize, ) -> anyhow::Result<()> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, [(); S::COLUMNS]:, { diff --git a/evm/tests/add11_yml.rs b/evm/tests/add11_yml.rs index 7b9fbc99..983d5468 100644 --- a/evm/tests/add11_yml.rs +++ b/evm/tests/add11_yml.rs @@ -10,7 +10,7 @@ use ethereum_types::Address; use hex_literal::hex; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; -use plonky2::plonk::config::{PoseidonGoldilocksConfig, PoseidonHashConfig}; +use plonky2::plonk::config::PoseidonGoldilocksConfig; use plonky2::util::timing::TimingTree; use plonky2_evm::all_stark::AllStark; use plonky2_evm::config::StarkConfig; @@ -24,8 +24,6 @@ use plonky2_evm::Node; type F = GoldilocksField; const D: usize = 2; type C = PoseidonGoldilocksConfig; -type HCO = PoseidonHashConfig; -type HCI = HCO; /// The `add11_yml` test case from https://github.com/ethereum/tests #[test] @@ -100,7 +98,7 @@ fn add11_yml() -> anyhow::Result<()> { }; let mut timing = TimingTree::new("prove", log::Level::Debug); - let proof = prove::(&all_stark, &config, inputs, &mut timing)?; + let proof = prove::(&all_stark, &config, inputs, &mut timing)?; timing.filter(Duration::from_millis(100)).print(); let beneficiary_account_after = AccountRlp { diff --git a/evm/tests/basic_smart_contract.rs b/evm/tests/basic_smart_contract.rs index 0ced7334..b93f48ec 100644 --- a/evm/tests/basic_smart_contract.rs +++ b/evm/tests/basic_smart_contract.rs @@ -10,7 +10,7 @@ use ethereum_types::{Address, U256}; use hex_literal::hex; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; -use plonky2::plonk::config::{PoseidonGoldilocksConfig, PoseidonHashConfig}; +use plonky2::plonk::config::PoseidonGoldilocksConfig; use plonky2::util::timing::TimingTree; use plonky2_evm::all_stark::AllStark; use plonky2_evm::config::StarkConfig; @@ -25,8 +25,6 @@ use plonky2_evm::Node; type F = GoldilocksField; const D: usize = 2; type C = PoseidonGoldilocksConfig; -type HCO = PoseidonHashConfig; -type HCI = HCO; /// Test a simple token transfer to a new address. #[test] @@ -114,7 +112,7 @@ fn test_basic_smart_contract() -> anyhow::Result<()> { }; let mut timing = TimingTree::new("prove", log::Level::Debug); - let proof = prove::(&all_stark, &config, inputs, &mut timing)?; + let proof = prove::(&all_stark, &config, inputs, &mut timing)?; timing.filter(Duration::from_millis(100)).print(); let expected_state_trie_after: HashedPartialTrie = { diff --git a/evm/tests/empty_txn_list.rs b/evm/tests/empty_txn_list.rs index 2adadc8a..9a4eb5e0 100644 --- a/evm/tests/empty_txn_list.rs +++ b/evm/tests/empty_txn_list.rs @@ -7,7 +7,7 @@ use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; -use plonky2::plonk::config::{PoseidonGoldilocksConfig, PoseidonHashConfig}; +use plonky2::plonk::config::PoseidonGoldilocksConfig; use plonky2::util::timing::TimingTree; use plonky2_evm::all_stark::AllStark; use plonky2_evm::config::StarkConfig; @@ -21,8 +21,6 @@ use plonky2_evm::Node; type F = GoldilocksField; const D: usize = 2; type C = PoseidonGoldilocksConfig; -type HCO = PoseidonHashConfig; -type HCI = HCO; /// Execute the empty list of transactions, i.e. a no-op. #[test] @@ -64,7 +62,7 @@ fn test_empty_txn_list() -> anyhow::Result<()> { // TODO: This is redundant; prove_root below calls this prove method internally. // Just keeping it for now because the root proof returned by prove_root doesn't contain public // values yet, and we want those for the assertions below. - let proof = prove::(&all_stark, &config, inputs.clone(), &mut timing)?; + let proof = prove::(&all_stark, &config, inputs.clone(), &mut timing)?; timing.filter(Duration::from_millis(100)).print(); assert_eq!( @@ -94,7 +92,7 @@ fn test_empty_txn_list() -> anyhow::Result<()> { verify_proof(&all_stark, proof, &config)?; - let all_circuits = AllRecursiveCircuits::::new(&all_stark, 9..19, &config); + let all_circuits = AllRecursiveCircuits::::new(&all_stark, 9..19, &config); let root_proof = all_circuits.prove_root(&all_stark, &config, inputs, &mut timing)?; all_circuits.verify_root(root_proof.clone())?; diff --git a/evm/tests/simple_transfer.rs b/evm/tests/simple_transfer.rs index fb1635d8..250631e3 100644 --- a/evm/tests/simple_transfer.rs +++ b/evm/tests/simple_transfer.rs @@ -10,7 +10,7 @@ use ethereum_types::{Address, U256}; use hex_literal::hex; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; -use plonky2::plonk::config::{PoseidonGoldilocksConfig, PoseidonHashConfig}; +use plonky2::plonk::config::PoseidonGoldilocksConfig; use plonky2::util::timing::TimingTree; use plonky2_evm::all_stark::AllStark; use plonky2_evm::config::StarkConfig; @@ -24,8 +24,6 @@ use plonky2_evm::Node; type F = GoldilocksField; const D: usize = 2; type C = PoseidonGoldilocksConfig; -type HCO = PoseidonHashConfig; -type HCI = HCO; /// Test a simple token transfer to a new address. #[test] @@ -89,7 +87,7 @@ fn test_simple_transfer() -> anyhow::Result<()> { }; let mut timing = TimingTree::new("prove", log::Level::Debug); - let proof = prove::(&all_stark, &config, inputs, &mut timing)?; + let proof = prove::(&all_stark, &config, inputs, &mut timing)?; timing.filter(Duration::from_millis(100)).print(); let expected_state_trie_after: HashedPartialTrie = { diff --git a/plonky2/examples/bench_recursion.rs b/plonky2/examples/bench_recursion.rs index 1afaf930..bb1ff9d1 100644 --- a/plonky2/examples/bench_recursion.rs +++ b/plonky2/examples/bench_recursion.rs @@ -18,9 +18,7 @@ use plonky2::hash::hashing::HashConfig; use plonky2::iop::witness::{PartialWitness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::{CircuitConfig, CommonCircuitData, VerifierOnlyCircuitData}; -use plonky2::plonk::config::{ - AlgebraicHasher, GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig, -}; +use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, PoseidonGoldilocksConfig}; use plonky2::plonk::proof::{CompressedProofWithPublicInputs, ProofWithPublicInputs}; use plonky2::plonk::prover::prove; use plonky2::util::timing::TimingTree; @@ -31,9 +29,9 @@ use rand::{RngCore, SeedableRng}; use rand_chacha::ChaCha8Rng; use structopt::StructOpt; -type ProofTuple = ( - ProofWithPublicInputs, - VerifierOnlyCircuitData, +type ProofTuple = ( + ProofWithPublicInputs, + VerifierOnlyCircuitData, CommonCircuitData, ); @@ -65,19 +63,13 @@ struct Options { } /// Creates a dummy proof which should have `2 ** log2_size` rows. -fn dummy_proof< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, ->( +fn dummy_proof, C: GenericConfig, const D: usize>( config: &CircuitConfig, log2_size: usize, -) -> Result> +) -> Result> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { // 'size' is in degree, but we want number of noop gates. A non-zero amount of padding will be added and size will be rounded to the next power of two. To hit our target size, we go just under the previous power of two and hope padding is less than half the proof. let num_dummy_gates = match log2_size { @@ -93,11 +85,11 @@ where } builder.print_gate_counts(0); - let data = builder.build::(); + let data = builder.build::(); let inputs = PartialWitness::new(); let mut timing = TimingTree::new("prove", Level::Debug); - let proof = prove::(&data.prover_only, &data.common, inputs, &mut timing)?; + let proof = prove::(&data.prover_only, &data.common, inputs, &mut timing)?; timing.print(); data.verify(proof.clone())?; @@ -106,24 +98,20 @@ where fn recursive_proof< F: RichField + Extendable, - HCOO: HashConfig, - HCOI: HashConfig, - HCIO: HashConfig, - HCII: HashConfig, - C: GenericConfig, - InnerC: GenericConfig, + C: GenericConfig, + InnerC: GenericConfig, const D: usize, >( - inner: &ProofTuple, + inner: &ProofTuple, config: &CircuitConfig, min_degree_bits: Option, -) -> Result> +) -> Result> where - InnerC::Hasher: AlgebraicHasher, - [(); HCOO::WIDTH]:, - [(); HCOI::WIDTH]:, - [(); HCIO::WIDTH]:, - [(); HCII::WIDTH]:, + InnerC::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, + [(); InnerC::HCO::WIDTH]:, + [(); InnerC::HCI::WIDTH]:, { let (inner_proof, inner_vd, inner_cd) = inner; let mut builder = CircuitBuilder::::new(config.clone()); @@ -131,7 +119,7 @@ where let inner_data = builder.add_virtual_verifier_data(inner_cd.config.fri_config.cap_height); - builder.verify_proof::(&pt, &inner_data, inner_cd); + builder.verify_proof::(&pt, &inner_data, inner_cd); builder.print_gate_counts(0); if let Some(min_degree_bits) = min_degree_bits { @@ -145,14 +133,14 @@ where } } - let data = builder.build::(); + let data = builder.build::(); let mut pw = PartialWitness::new(); pw.set_proof_with_pis_target(&pt, inner_proof); pw.set_verifier_data_target(&inner_data, inner_vd); let mut timing = TimingTree::new("prove", Level::Debug); - let proof = prove::(&data.prover_only, &data.common, pw, &mut timing)?; + let proof = prove::(&data.prover_only, &data.common, pw, &mut timing)?; timing.print(); data.verify(proof.clone())?; @@ -161,20 +149,14 @@ where } /// Test serialization and print some size info. -fn test_serialization< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, ->( - proof: &ProofWithPublicInputs, - vd: &VerifierOnlyCircuitData, +fn test_serialization, C: GenericConfig, const D: usize>( + proof: &ProofWithPublicInputs, + vd: &VerifierOnlyCircuitData, cd: &CommonCircuitData, ) -> Result<()> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let proof_bytes = proof.to_bytes(); info!("Proof length: {} bytes", proof_bytes.len()); @@ -204,12 +186,10 @@ where fn benchmark(config: &CircuitConfig, log2_inner_size: usize) -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; // Start with a dummy proof of specified size - let inner = dummy_proof::(config, log2_inner_size)?; + let inner = dummy_proof::(config, log2_inner_size)?; let (_, _, cd) = &inner; info!( "Initial proof degree {} = 2^{}", @@ -218,7 +198,7 @@ fn benchmark(config: &CircuitConfig, log2_inner_size: usize) -> Result<()> { ); // Recursively verify the proof - let middle = recursive_proof::(&inner, config, None)?; + let middle = recursive_proof::(&inner, config, None)?; let (_, _, cd) = &middle; info!( "Single recursion proof degree {} = 2^{}", @@ -227,7 +207,7 @@ fn benchmark(config: &CircuitConfig, log2_inner_size: usize) -> Result<()> { ); // Add a second layer of recursion to shrink the proof size further - let outer = recursive_proof::(&middle, config, None)?; + let outer = recursive_proof::(&middle, config, None)?; let (proof, vd, cd) = &outer; info!( "Double recursion proof degree {} = 2^{}", diff --git a/plonky2/examples/factorial.rs b/plonky2/examples/factorial.rs index cde1d0d7..7be28bd6 100644 --- a/plonky2/examples/factorial.rs +++ b/plonky2/examples/factorial.rs @@ -5,7 +5,7 @@ use plonky2::field::types::Field; use plonky2::iop::witness::{PartialWitness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; -use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; +use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; /// An example of using Plonky2 to prove a statement of the form /// "I know n * (n + 1) * ... * (n + 99)". @@ -13,9 +13,7 @@ use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHa fn main() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); @@ -35,7 +33,7 @@ fn main() -> Result<()> { let mut pw = PartialWitness::new(); pw.set_target(initial, F::ONE); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; println!( diff --git a/plonky2/examples/fibonacci.rs b/plonky2/examples/fibonacci.rs index cc7ffd05..e3d865b9 100644 --- a/plonky2/examples/fibonacci.rs +++ b/plonky2/examples/fibonacci.rs @@ -5,7 +5,7 @@ use plonky2::field::types::Field; use plonky2::iop::witness::{PartialWitness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; -use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; +use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; /// An example of using Plonky2 to prove a statement of the form /// "I know the 100th element of the Fibonacci sequence, starting with constants a and b." @@ -13,9 +13,7 @@ use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHa fn main() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); @@ -41,7 +39,7 @@ fn main() -> Result<()> { pw.set_target(initial_a, F::ZERO); pw.set_target(initial_b, F::ONE); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; println!( diff --git a/plonky2/examples/square_root.rs b/plonky2/examples/square_root.rs index d26ef8b4..9c253b69 100644 --- a/plonky2/examples/square_root.rs +++ b/plonky2/examples/square_root.rs @@ -10,7 +10,7 @@ use plonky2::iop::target::Target; use plonky2::iop::witness::{PartialWitness, PartitionWitness, Witness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; -use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; +use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use plonky2_field::extension::Extendable; /// A generator used by the prover to calculate the square root (`x`) of a given value @@ -44,9 +44,7 @@ impl, const D: usize> SimpleGenerator fn main() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); @@ -75,7 +73,7 @@ fn main() -> Result<()> { let mut pw = PartialWitness::new(); pw.set_target(x_squared, x_squared_value); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw.clone())?; let x_squared_actual = proof.public_inputs[0]; diff --git a/plonky2/src/fri/challenges.rs b/plonky2/src/fri/challenges.rs index 23c0d1c4..984b7093 100644 --- a/plonky2/src/fri/challenges.rs +++ b/plonky2/src/fri/challenges.rs @@ -26,9 +26,9 @@ where } } - pub fn fri_challenges, const D: usize>( + pub fn fri_challenges, const D: usize>( &mut self, - commit_phase_merkle_caps: &[MerkleCap], + commit_phase_merkle_caps: &[MerkleCap], final_poly: &PolynomialCoeffs, pow_witness: F, degree_bits: usize, @@ -36,8 +36,8 @@ where ) -> FriChallenges where F: RichField + Extendable, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let num_fri_queries = config.num_query_rounds; let lde_size = 1 << (degree_bits + config.rate_bits); @@ -48,7 +48,7 @@ where let fri_betas = commit_phase_merkle_caps .iter() .map(|cap| { - self.observe_cap::(cap); + self.observe_cap::(cap); self.get_extension_challenge::() }) .collect(); diff --git a/plonky2/src/fri/oracle.rs b/plonky2/src/fri/oracle.rs index eed0a449..7855167a 100644 --- a/plonky2/src/fri/oracle.rs +++ b/plonky2/src/fri/oracle.rs @@ -27,27 +27,17 @@ use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place, transp pub const SALT_SIZE: usize = 4; /// Represents a FRI oracle, i.e. a batch of polynomials which have been Merklized. -pub struct PolynomialBatch< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, -> { +pub struct PolynomialBatch, C: GenericConfig, const D: usize> +{ pub polynomials: Vec>, - pub merkle_tree: MerkleTree, + pub merkle_tree: MerkleTree, pub degree_log: usize, pub rate_bits: usize, pub blinding: bool, } -impl< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - > PolynomialBatch +impl, C: GenericConfig, const D: usize> + PolynomialBatch { /// Creates a list polynomial commitment for the polynomials interpolating the values in `values`. pub fn from_values( @@ -59,7 +49,7 @@ impl< fft_root_table: Option<&FftRootTable>, ) -> Self where - [(); HCO::WIDTH]:, + [(); C::HCO::WIDTH]:, { let coeffs = timed!( timing, @@ -87,7 +77,7 @@ impl< fft_root_table: Option<&FftRootTable>, ) -> Self where - [(); HCO::WIDTH]:, + [(); C::HCO::WIDTH]:, { let degree = polynomials[0].len(); let lde_values = timed!( @@ -178,13 +168,13 @@ impl< pub fn prove_openings( instance: &FriInstanceInfo, oracles: &[&Self], - challenger: &mut Challenger, + challenger: &mut Challenger, fri_params: &FriParams, timing: &mut TimingTree, - ) -> FriProof + ) -> FriProof where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { assert!(D > 1, "Not implemented for D=1."); let alpha = challenger.get_extension_challenge::(); @@ -223,7 +213,7 @@ impl< lde_final_poly.coset_fft(F::coset_shift().into()) ); - let fri_proof = fri_proof::( + let fri_proof = fri_proof::( &oracles .par_iter() .map(|c| &c.merkle_tree) diff --git a/plonky2/src/fri/prover.rs b/plonky2/src/fri/prover.rs index a2a27c18..b7ed8af5 100644 --- a/plonky2/src/fri/prover.rs +++ b/plonky2/src/fri/prover.rs @@ -17,25 +17,19 @@ use crate::util::reverse_index_bits_in_place; use crate::util::timing::TimingTree; /// Builds a FRI proof. -pub fn fri_proof< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, ->( - initial_merkle_trees: &[&MerkleTree], +pub fn fri_proof, C: GenericConfig, const D: usize>( + initial_merkle_trees: &[&MerkleTree], // Coefficients of the polynomial on which the LDT is performed. Only the first `1/rate` coefficients are non-zero. lde_polynomial_coeffs: PolynomialCoeffs, // Evaluation of the polynomial on the large domain. lde_polynomial_values: PolynomialValues, - challenger: &mut Challenger, + challenger: &mut Challenger, fri_params: &FriParams, timing: &mut TimingTree, -) -> FriProof +) -> FriProof where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let n = lde_polynomial_values.len(); assert_eq!(lde_polynomial_coeffs.len(), n); @@ -44,7 +38,7 @@ where let (trees, final_coeffs) = timed!( timing, "fold codewords in the commitment phase", - fri_committed_trees::( + fri_committed_trees::( lde_polynomial_coeffs, lde_polynomial_values, challenger, @@ -56,17 +50,12 @@ where let pow_witness = timed!( timing, "find proof-of-work witness", - fri_proof_of_work::(challenger, &fri_params.config) + fri_proof_of_work::(challenger, &fri_params.config) ); // Query phase - let query_round_proofs = fri_prover_query_rounds::( - initial_merkle_trees, - &trees, - challenger, - n, - fri_params, - ); + let query_round_proofs = + fri_prover_query_rounds::(initial_merkle_trees, &trees, challenger, n, fri_params); FriProof { commit_phase_merkle_caps: trees.iter().map(|t| t.cap.clone()).collect(), @@ -76,25 +65,19 @@ where } } -type FriCommitedTrees = ( - Vec>::Hasher>>, +type FriCommitedTrees = ( + Vec>::HCO, >::Hasher>>, PolynomialCoeffs<>::Extension>, ); -fn fri_committed_trees< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, ->( +fn fri_committed_trees, C: GenericConfig, const D: usize>( mut coeffs: PolynomialCoeffs, mut values: PolynomialValues, - challenger: &mut Challenger, + challenger: &mut Challenger, fri_params: &FriParams, -) -> FriCommitedTrees +) -> FriCommitedTrees where - [(); HCO::WIDTH]:, + [(); C::HCO::WIDTH]:, { let mut trees = Vec::new(); @@ -109,7 +92,7 @@ where .map(|chunk: &[F::Extension]| flatten(chunk)) .collect(); let tree = - MerkleTree::::new(chunked_values, fri_params.config.cap_height); + MerkleTree::::new(chunked_values, fri_params.config.cap_height); challenger.observe_cap(&tree.cap); trees.push(tree); @@ -137,19 +120,13 @@ where } /// Performs the proof-of-work (a.k.a. grinding) step of the FRI protocol. Returns the PoW witness. -fn fri_proof_of_work< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, ->( - challenger: &mut Challenger, +fn fri_proof_of_work, C: GenericConfig, const D: usize>( + challenger: &mut Challenger, config: &FriConfig, ) -> F where - [(); HCI::WIDTH]:, - [(); HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, { let min_leading_zeros = config.proof_of_work_bits + (64 - F::order().bits()) as u32; @@ -181,10 +158,10 @@ where let mut duplex_state = duplex_intermediate_state; duplex_state[witness_input_pos] = F::from_canonical_u64(candidate); duplex_state = - <>::Hasher as Hasher>::Permutation::permute( + <>::Hasher as Hasher>::Permutation::permute( duplex_state, ); - let pow_response = duplex_state[HCO::RATE - 1]; + let pow_response = duplex_state[C::HCO::RATE - 1]; let leading_zeros = pow_response.to_canonical_u64().leading_zeros(); leading_zeros >= min_leading_zeros }) @@ -201,49 +178,40 @@ where fn fri_prover_query_rounds< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, >( - initial_merkle_trees: &[&MerkleTree], - trees: &[MerkleTree], - challenger: &mut Challenger, + initial_merkle_trees: &[&MerkleTree], + trees: &[MerkleTree], + challenger: &mut Challenger, n: usize, fri_params: &FriParams, -) -> Vec> +) -> Vec> where - [(); HCO::WIDTH]:, + [(); C::HCO::WIDTH]:, { challenger .get_n_challenges(fri_params.config.num_query_rounds) .into_par_iter() .map(|rand| { let x_index = rand.to_canonical_u64() as usize % n; - fri_prover_query_round::( - initial_merkle_trees, - trees, - x_index, - fri_params, - ) + fri_prover_query_round::(initial_merkle_trees, trees, x_index, fri_params) }) .collect() } fn fri_prover_query_round< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, >( - initial_merkle_trees: &[&MerkleTree], - trees: &[MerkleTree], + initial_merkle_trees: &[&MerkleTree], + trees: &[MerkleTree], mut x_index: usize, fri_params: &FriParams, -) -> FriQueryRound +) -> FriQueryRound where - [(); HCO::WIDTH]:, + [(); C::HCO::WIDTH]:, { let mut query_steps = Vec::new(); let initial_proof = initial_merkle_trees diff --git a/plonky2/src/fri/recursive_verifier.rs b/plonky2/src/fri/recursive_verifier.rs index 033eeb30..d456b2a4 100644 --- a/plonky2/src/fri/recursive_verifier.rs +++ b/plonky2/src/fri/recursive_verifier.rs @@ -99,11 +99,7 @@ impl, const D: usize> CircuitBuilder { ); } - pub fn verify_fri_proof< - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - >( + pub fn verify_fri_proof>( &mut self, instance: &FriInstanceInfoTarget, openings: &FriOpeningsTarget, @@ -112,8 +108,8 @@ impl, const D: usize> CircuitBuilder { proof: &FriProofTarget, params: &FriParams, ) where - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, { if let Some(max_arity_bits) = params.max_arity_bits() { self.check_recursion_config(max_arity_bits); @@ -166,7 +162,7 @@ impl, const D: usize> CircuitBuilder { self, level, &format!("verify one (of {num_queries}) query rounds"), - self.fri_verifier_query_round::( + self.fri_verifier_query_round::( instance, challenges, &precomputed_reduced_evals, @@ -254,11 +250,7 @@ impl, const D: usize> CircuitBuilder { sum } - fn fri_verifier_query_round< - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - >( + fn fri_verifier_query_round>( &mut self, instance: &FriInstanceInfoTarget, challenges: &FriChallengesTarget, @@ -270,8 +262,8 @@ impl, const D: usize> CircuitBuilder { round_proof: &FriQueryRoundTarget, params: &FriParams, ) where - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, { let n_log = log2_strict(n); @@ -285,7 +277,7 @@ impl, const D: usize> CircuitBuilder { with_context!( self, "check FRI initial proof", - self.fri_verify_initial_proof::( + self.fri_verify_initial_proof::( &x_index_bits, &round_proof.initial_trees_proof, initial_merkle_caps, @@ -345,7 +337,7 @@ impl, const D: usize> CircuitBuilder { with_context!( self, "verify FRI round Merkle proof.", - self.verify_merkle_proof_to_cap_with_cap_index::( + self.verify_merkle_proof_to_cap_with_cap_index::( flatten_target(evals), &coset_index_bits, cap_index, diff --git a/plonky2/src/fri/validate_shape.rs b/plonky2/src/fri/validate_shape.rs index e15a2c75..6a4e7cc5 100644 --- a/plonky2/src/fri/validate_shape.rs +++ b/plonky2/src/fri/validate_shape.rs @@ -5,20 +5,17 @@ use crate::fri::proof::{FriProof, FriQueryRound, FriQueryStep}; use crate::fri::structure::FriInstanceInfo; use crate::fri::FriParams; use crate::hash::hash_types::RichField; -use crate::hash::hashing::HashConfig; use crate::plonk::config::GenericConfig; use crate::plonk::plonk_common::salt_size; -pub(crate) fn validate_fri_proof_shape( - proof: &FriProof, +pub(crate) fn validate_fri_proof_shape( + proof: &FriProof, instance: &FriInstanceInfo, params: &FriParams, ) -> anyhow::Result<()> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { let FriProof { commit_phase_merkle_caps, diff --git a/plonky2/src/fri/verifier.rs b/plonky2/src/fri/verifier.rs index e37866e8..2e30214e 100644 --- a/plonky2/src/fri/verifier.rs +++ b/plonky2/src/fri/verifier.rs @@ -59,24 +59,18 @@ pub(crate) fn fri_verify_proof_of_work, const D: us Ok(()) } -pub fn verify_fri_proof< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, ->( +pub fn verify_fri_proof, C: GenericConfig, const D: usize>( instance: &FriInstanceInfo, openings: &FriOpenings, challenges: &FriChallenges, - initial_merkle_caps: &[MerkleCap], - proof: &FriProof, + initial_merkle_caps: &[MerkleCap], + proof: &FriProof, params: &FriParams, ) -> Result<()> where - [(); HCO::WIDTH]:, + [(); C::HCO::WIDTH]:, { - validate_fri_proof_shape::(proof, instance, params)?; + validate_fri_proof_shape::(proof, instance, params)?; // Size of the LDE domain. let n = params.lde_size(); @@ -97,7 +91,7 @@ where .iter() .zip(&proof.query_round_proofs) { - fri_verifier_query_round::( + fri_verifier_query_round::( instance, challenges, &precomputed_reduced_evals, @@ -130,13 +124,11 @@ where pub(crate) fn fri_combine_initial< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, >( instance: &FriInstanceInfo, - proof: &FriInitialTreeProof, + proof: &FriInitialTreeProof, alpha: F::Extension, subgroup_x: F, precomputed_reduced_evals: &PrecomputedReducedOpenings, @@ -173,25 +165,23 @@ pub(crate) fn fri_combine_initial< fn fri_verifier_query_round< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, >( instance: &FriInstanceInfo, challenges: &FriChallenges, precomputed_reduced_evals: &PrecomputedReducedOpenings, - initial_merkle_caps: &[MerkleCap], - proof: &FriProof, + initial_merkle_caps: &[MerkleCap], + proof: &FriProof, mut x_index: usize, n: usize, - round_proof: &FriQueryRound, + round_proof: &FriQueryRound, params: &FriParams, ) -> Result<()> where - [(); HCO::WIDTH]:, + [(); C::HCO::WIDTH]:, { - fri_verify_initial_proof::( + fri_verify_initial_proof::( x_index, &round_proof.initial_trees_proof, initial_merkle_caps, @@ -203,7 +193,7 @@ where // old_eval is the last derived evaluation; it will be checked for consistency with its // committed "parent" value in the next iteration. - let mut old_eval = fri_combine_initial::( + let mut old_eval = fri_combine_initial::( instance, &round_proof.initial_trees_proof, challenges.fri_alpha, @@ -232,7 +222,7 @@ where challenges.fri_betas[i], ); - verify_merkle_proof_to_cap::( + verify_merkle_proof_to_cap::( flatten(evals), coset_index, &proof.commit_phase_merkle_caps[i], diff --git a/plonky2/src/gadgets/arithmetic_extension.rs b/plonky2/src/gadgets/arithmetic_extension.rs index c3ded869..6fcab718 100644 --- a/plonky2/src/gadgets/arithmetic_extension.rs +++ b/plonky2/src/gadgets/arithmetic_extension.rs @@ -576,20 +576,15 @@ mod tests { use crate::iop::witness::{PartialWitness, WitnessWrite}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{ - GenericConfig, KeccakGoldilocksConfig, KeccakHashConfig, PoseidonGoldilocksConfig, - PoseidonHashConfig, - }; + use crate::plonk::config::{GenericConfig, KeccakGoldilocksConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; #[test] fn test_mul_many() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - type FF = >::FE; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); @@ -614,7 +609,7 @@ mod tests { builder.connect_extension(mul0, mul1); builder.connect_extension(mul1, mul2); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) @@ -624,10 +619,8 @@ mod tests { fn test_div_extension() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - type FF = >::FE; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_zk_config(); @@ -643,7 +636,7 @@ mod tests { let comp_zt = builder.div_extension(xt, yt); builder.connect_extension(zt, comp_zt); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) @@ -653,10 +646,8 @@ mod tests { fn test_mul_algebra() -> Result<()> { const D: usize = 2; type C = KeccakGoldilocksConfig; - type HCO = KeccakHashConfig; - type HCI = PoseidonHashConfig; - type F = >::F; - type FF = >::FE; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); @@ -683,7 +674,7 @@ mod tests { pw.set_extension_target(zt.0[i], z.0[i]); } - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/plonky2/src/gadgets/interpolation.rs b/plonky2/src/gadgets/interpolation.rs index d31e7393..daf51d21 100644 --- a/plonky2/src/gadgets/interpolation.rs +++ b/plonky2/src/gadgets/interpolation.rs @@ -47,17 +47,15 @@ mod tests { use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; #[test] fn test_interpolate() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - type FF = >::FE; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); let mut builder = CircuitBuilder::::new(config); @@ -104,7 +102,7 @@ mod tests { builder.connect_extension(eval_coset_gate, true_eval_target); } - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/plonky2/src/gadgets/random_access.rs b/plonky2/src/gadgets/random_access.rs index 39e8af87..85d2c714 100644 --- a/plonky2/src/gadgets/random_access.rs +++ b/plonky2/src/gadgets/random_access.rs @@ -107,16 +107,14 @@ mod tests { use crate::field::types::{Field, Sample}; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; fn test_random_access_given_len(len_log: usize) -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - type FF = >::FE; + type F = >::F; + type FF = >::FE; let len = 1 << len_log; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); @@ -131,7 +129,7 @@ mod tests { builder.connect_extension(elem, res); } - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/plonky2/src/gadgets/select.rs b/plonky2/src/gadgets/select.rs index 7526fe9a..b34092ed 100644 --- a/plonky2/src/gadgets/select.rs +++ b/plonky2/src/gadgets/select.rs @@ -44,17 +44,15 @@ mod tests { use crate::iop::witness::{PartialWitness, WitnessWrite}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; #[test] fn test_select() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - type FF = >::FE; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); let mut pw = PartialWitness::::new(); let mut builder = CircuitBuilder::::new(config); @@ -74,7 +72,7 @@ mod tests { builder.connect_extension(should_be_x, xt); builder.connect_extension(should_be_y, yt); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/plonky2/src/gadgets/split_base.rs b/plonky2/src/gadgets/split_base.rs index fa073fae..dd0edf5d 100644 --- a/plonky2/src/gadgets/split_base.rs +++ b/plonky2/src/gadgets/split_base.rs @@ -113,16 +113,14 @@ mod tests { use super::*; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; #[test] fn test_split_base() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); let mut builder = CircuitBuilder::::new(config); @@ -139,7 +137,7 @@ mod tests { builder.connect(limbs[3], one); builder.assert_leading_zeros(xt, 64 - 9); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; @@ -150,9 +148,7 @@ mod tests { fn test_base_sum() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); let pw = PartialWitness::new(); let mut builder = CircuitBuilder::::new(config); @@ -176,7 +172,7 @@ mod tests { builder.connect(x, y); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; diff --git a/plonky2/src/gates/arithmetic_base.rs b/plonky2/src/gates/arithmetic_base.rs index efd932e2..13b4a2c5 100644 --- a/plonky2/src/gates/arithmetic_base.rs +++ b/plonky2/src/gates/arithmetic_base.rs @@ -218,7 +218,7 @@ mod tests { use crate::gates::arithmetic_base::ArithmeticGate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -230,10 +230,8 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let gate = ArithmeticGate::new_from_config(&CircuitConfig::standard_recursion_config()); - test_eval_fns::(gate) + test_eval_fns::(gate) } } diff --git a/plonky2/src/gates/arithmetic_extension.rs b/plonky2/src/gates/arithmetic_extension.rs index 442e41e7..4632dbd4 100644 --- a/plonky2/src/gates/arithmetic_extension.rs +++ b/plonky2/src/gates/arithmetic_extension.rs @@ -211,7 +211,7 @@ mod tests { use crate::gates::arithmetic_extension::ArithmeticExtensionGate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -224,11 +224,9 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let gate = ArithmeticExtensionGate::new_from_config(&CircuitConfig::standard_recursion_config()); - test_eval_fns::(gate) + test_eval_fns::(gate) } } diff --git a/plonky2/src/gates/base_sum.rs b/plonky2/src/gates/base_sum.rs index ba0b13dd..5883d71c 100644 --- a/plonky2/src/gates/base_sum.rs +++ b/plonky2/src/gates/base_sum.rs @@ -204,7 +204,7 @@ mod tests { use crate::field::goldilocks_field::GoldilocksField; use crate::gates::base_sum::BaseSumGate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -215,9 +215,7 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - test_eval_fns::(BaseSumGate::<6>::new(11)) + type F = >::F; + test_eval_fns::(BaseSumGate::<6>::new(11)) } } diff --git a/plonky2/src/gates/constant.rs b/plonky2/src/gates/constant.rs index fe54596e..bf365b04 100644 --- a/plonky2/src/gates/constant.rs +++ b/plonky2/src/gates/constant.rs @@ -122,7 +122,7 @@ mod tests { use crate::gates::constant::ConstantGate; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -135,11 +135,9 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let num_consts = CircuitConfig::standard_recursion_config().num_constants; let gate = ConstantGate { num_consts }; - test_eval_fns::(gate) + test_eval_fns::(gate) } } diff --git a/plonky2/src/gates/coset_interpolation.rs b/plonky2/src/gates/coset_interpolation.rs index e7d8b14a..da94d1c0 100644 --- a/plonky2/src/gates/coset_interpolation.rs +++ b/plonky2/src/gates/coset_interpolation.rs @@ -606,7 +606,7 @@ mod tests { use crate::field::types::{Field, Sample}; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::hash::hash_types::HashOut; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn test_degree_and_wires_minimized() { @@ -747,13 +747,9 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; for degree in 2..=4 { - test_eval_fns::(CosetInterpolationGate::with_max_degree( - 2, degree, - ))?; + test_eval_fns::(CosetInterpolationGate::with_max_degree(2, degree))?; } Ok(()) } @@ -762,10 +758,8 @@ mod tests { fn test_gate_constraint() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - type FF = >::FE; + type F = >::F; + type FF = >::FE; /// Returns the local wires for an interpolation gate for given coeffs, points and eval point. fn get_wires(shift: F, values: PolynomialValues, eval_point: FF) -> Vec { diff --git a/plonky2/src/gates/exponentiation.rs b/plonky2/src/gates/exponentiation.rs index 5a09fe78..218f77e8 100644 --- a/plonky2/src/gates/exponentiation.rs +++ b/plonky2/src/gates/exponentiation.rs @@ -294,7 +294,7 @@ mod tests { use crate::field::types::Sample; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::hash::hash_types::HashOut; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::util::log2_ceil; const MAX_POWER_BITS: usize = 17; @@ -329,10 +329,8 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - test_eval_fns::(ExponentiationGate::new_from_config( + type F = >::F; + test_eval_fns::(ExponentiationGate::new_from_config( &CircuitConfig::standard_recursion_config(), )) } @@ -341,10 +339,8 @@ mod tests { fn test_gate_constraint() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - type FF = >::FE; + type F = >::F; + type FF = >::FE; /// Returns the local wires for an exponentiation gate given the base, power, and power bit /// values. diff --git a/plonky2/src/gates/gate_testing.rs b/plonky2/src/gates/gate_testing.rs index 181cba5d..2fa982bb 100644 --- a/plonky2/src/gates/gate_testing.rs +++ b/plonky2/src/gates/gate_testing.rs @@ -89,17 +89,15 @@ fn random_low_degree_values(rate_bits: usize) -> Vec { pub fn test_eval_fns< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, G: Gate, const D: usize, >( gate: G, ) -> Result<()> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { // Test that `eval_unfiltered` and `eval_unfiltered_base` are coherent. let wires_base = F::rand_vec(gate.num_wires()); @@ -164,7 +162,7 @@ where let evals_t = gate.eval_unfiltered_circuit(&mut builder, vars_t); pw.set_extension_targets(&evals_t, &evals); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; - verify::(proof, &data.verifier_only, &data.common) + verify::(proof, &data.verifier_only, &data.common) } diff --git a/plonky2/src/gates/multiplication_extension.rs b/plonky2/src/gates/multiplication_extension.rs index 8db53870..1f900441 100644 --- a/plonky2/src/gates/multiplication_extension.rs +++ b/plonky2/src/gates/multiplication_extension.rs @@ -187,7 +187,7 @@ mod tests { use super::*; use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -199,10 +199,8 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let gate = MulExtensionGate::new_from_config(&CircuitConfig::standard_recursion_config()); - test_eval_fns::(gate) + test_eval_fns::(gate) } } diff --git a/plonky2/src/gates/noop.rs b/plonky2/src/gates/noop.rs index e2111564..f6f9853a 100644 --- a/plonky2/src/gates/noop.rs +++ b/plonky2/src/gates/noop.rs @@ -60,7 +60,7 @@ mod tests { use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::noop::NoopGate; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -71,9 +71,7 @@ mod tests { fn eval_fns() -> anyhow::Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - test_eval_fns::(NoopGate) + type F = >::F; + test_eval_fns::(NoopGate) } } diff --git a/plonky2/src/gates/poseidon.rs b/plonky2/src/gates/poseidon.rs index d5db9390..80184797 100644 --- a/plonky2/src/gates/poseidon.rs +++ b/plonky2/src/gates/poseidon.rs @@ -515,7 +515,7 @@ mod tests { use crate::iop::witness::{PartialWitness, Witness, WitnessWrite}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn wire_indices() { @@ -543,9 +543,7 @@ mod tests { fn generated_output() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let config = CircuitConfig { num_wires: 143, @@ -555,7 +553,7 @@ mod tests { type Gate = PoseidonGate; let gate = Gate::new(); let row = builder.add_gate(gate, vec![]); - let circuit = builder.build_prover::(); + let circuit = builder.build_prover::(); let permutation_inputs = (0..SPONGE_WIDTH) .map(F::from_canonical_usize) @@ -603,10 +601,8 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let gate = PoseidonGate::::new(); - test_eval_fns::(gate) + test_eval_fns::(gate) } } diff --git a/plonky2/src/gates/poseidon_mds.rs b/plonky2/src/gates/poseidon_mds.rs index 7958d1b4..cddd0f9e 100644 --- a/plonky2/src/gates/poseidon_mds.rs +++ b/plonky2/src/gates/poseidon_mds.rs @@ -243,15 +243,13 @@ impl + Poseidon, const D: usize> SimpleGenerator mod tests { use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::poseidon_mds::PoseidonMdsGate; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let gate = PoseidonMdsGate::::new(); test_low_degree(gate) } @@ -260,10 +258,8 @@ mod tests { fn eval_fns() -> anyhow::Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let gate = PoseidonMdsGate::::new(); - test_eval_fns::(gate) + test_eval_fns::(gate) } } diff --git a/plonky2/src/gates/public_input.rs b/plonky2/src/gates/public_input.rs index c8d2cfbe..10c42f00 100644 --- a/plonky2/src/gates/public_input.rs +++ b/plonky2/src/gates/public_input.rs @@ -104,7 +104,7 @@ mod tests { use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::public_input::PublicInputGate; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -115,9 +115,7 @@ mod tests { fn eval_fns() -> anyhow::Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - test_eval_fns::(PublicInputGate) + type F = >::F; + test_eval_fns::(PublicInputGate) } } diff --git a/plonky2/src/gates/random_access.rs b/plonky2/src/gates/random_access.rs index e8c29713..80874505 100644 --- a/plonky2/src/gates/random_access.rs +++ b/plonky2/src/gates/random_access.rs @@ -389,7 +389,7 @@ mod tests { use crate::field::types::Sample; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::hash::hash_types::HashOut; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -400,20 +400,16 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - test_eval_fns::(RandomAccessGate::new(4, 4, 1)) + type F = >::F; + test_eval_fns::(RandomAccessGate::new(4, 4, 1)) } #[test] fn test_gate_constraint() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - type FF = >::FE; + type F = >::F; + type FF = >::FE; /// Returns the local wires for a random access gate given the vectors, elements to compare, /// and indices. diff --git a/plonky2/src/gates/reducing.rs b/plonky2/src/gates/reducing.rs index ad14a7fc..9bdadce8 100644 --- a/plonky2/src/gates/reducing.rs +++ b/plonky2/src/gates/reducing.rs @@ -216,7 +216,7 @@ mod tests { use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::reducing::ReducingGate; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -227,9 +227,7 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - test_eval_fns::(ReducingGate::new(22)) + type F = >::F; + test_eval_fns::(ReducingGate::new(22)) } } diff --git a/plonky2/src/gates/reducing_extension.rs b/plonky2/src/gates/reducing_extension.rs index 2b37e5b5..0ad48bb0 100644 --- a/plonky2/src/gates/reducing_extension.rs +++ b/plonky2/src/gates/reducing_extension.rs @@ -210,7 +210,7 @@ mod tests { use crate::field::goldilocks_field::GoldilocksField; use crate::gates::gate_testing::{test_eval_fns, test_low_degree}; use crate::gates::reducing_extension::ReducingExtensionGate; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn low_degree() { @@ -221,9 +221,7 @@ mod tests { fn eval_fns() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - test_eval_fns::(ReducingExtensionGate::new(22)) + type F = >::F; + test_eval_fns::(ReducingExtensionGate::new(22)) } } diff --git a/plonky2/src/hash/merkle_proofs.rs b/plonky2/src/hash/merkle_proofs.rs index 7798bd16..3d523312 100644 --- a/plonky2/src/hash/merkle_proofs.rs +++ b/plonky2/src/hash/merkle_proofs.rs @@ -187,7 +187,7 @@ mod tests { use crate::iop::witness::{PartialWitness, WitnessWrite}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; fn random_data(n: usize, k: usize) -> Vec> { @@ -198,9 +198,7 @@ mod tests { fn test_recursive_merkle_proof() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); let mut pw = PartialWitness::new(); let mut builder = CircuitBuilder::::new(config); @@ -209,9 +207,10 @@ mod tests { let n = 1 << log_n; let cap_height = 1; let leaves = random_data::(n, 7); - let tree = MerkleTree::>::Hasher>::new( - leaves, cap_height, - ); + let tree = + MerkleTree::>::HCO, >::Hasher>::new( + leaves, cap_height, + ); let i: usize = OsRng.gen_range(0..n); let proof = tree.prove(i); @@ -233,11 +232,11 @@ mod tests { pw.set_target(data[j], tree.leaves[i][j]); } - builder.verify_merkle_proof_to_cap::>::InnerHasher>( + builder.verify_merkle_proof_to_cap::<>::HCI, >::InnerHasher>( data, &i_bits, &cap_t, &proof_t, ); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/plonky2/src/hash/merkle_tree.rs b/plonky2/src/hash/merkle_tree.rs index 25055fdb..f49d9f19 100644 --- a/plonky2/src/hash/merkle_tree.rs +++ b/plonky2/src/hash/merkle_tree.rs @@ -223,26 +223,20 @@ mod tests { use super::*; use crate::field::extension::Extendable; use crate::hash::merkle_proofs::verify_merkle_proof_to_cap; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; fn random_data(n: usize, k: usize) -> Vec> { (0..n).map(|_| F::rand_vec(k)).collect() } - fn verify_all_leaves< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - >( + fn verify_all_leaves, C: GenericConfig, const D: usize>( leaves: Vec>, cap_height: usize, ) -> Result<()> where - [(); HCO::WIDTH]:, + [(); C::HCO::WIDTH]:, { - let tree = MerkleTree::::new(leaves.clone(), cap_height); + let tree = MerkleTree::::new(leaves.clone(), cap_height); for (i, leaf) in leaves.into_iter().enumerate() { let proof = tree.prove(i); verify_merkle_proof_to_cap(leaf, i, &tree.cap, &proof)?; @@ -255,15 +249,13 @@ mod tests { fn test_cap_height_too_big() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let log_n = 8; let cap_height = log_n + 1; // Should panic if `cap_height > len_n`. let leaves = random_data::(1 << log_n, 7); - let _ = MerkleTree::>::Hasher>::new( + let _ = MerkleTree::>::HCO, >::Hasher>::new( leaves, cap_height, ); } @@ -272,15 +264,13 @@ mod tests { fn test_cap_height_eq_log2_len() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let log_n = 8; let n = 1 << log_n; let leaves = random_data::(n, 7); - verify_all_leaves::(leaves, log_n)?; + verify_all_leaves::(leaves, log_n)?; Ok(()) } @@ -289,15 +279,13 @@ mod tests { fn test_merkle_trees() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let log_n = 8; let n = 1 << log_n; let leaves = random_data::(n, 7); - verify_all_leaves::(leaves, 1)?; + verify_all_leaves::(leaves, 1)?; Ok(()) } diff --git a/plonky2/src/hash/path_compression.rs b/plonky2/src/hash/path_compression.rs index de507641..853ffc85 100644 --- a/plonky2/src/hash/path_compression.rs +++ b/plonky2/src/hash/path_compression.rs @@ -124,22 +124,21 @@ mod tests { use super::*; use crate::field::types::Sample; use crate::hash::merkle_tree::MerkleTree; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn test_path_compression() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let h = 10; let cap_height = 3; let vs = (0..1 << h).map(|_| vec![F::rand()]).collect::>(); - let mt = MerkleTree::>::Hasher>::new( - vs.clone(), - cap_height, - ); + let mt = + MerkleTree::>::HCO, >::Hasher>::new( + vs.clone(), + cap_height, + ); let mut rng = OsRng; let k = rng.gen_range(1..=1 << h); diff --git a/plonky2/src/iop/challenger.rs b/plonky2/src/iop/challenger.rs index 07b99981..499538a9 100644 --- a/plonky2/src/iop/challenger.rs +++ b/plonky2/src/iop/challenger.rs @@ -390,17 +390,18 @@ mod tests { use crate::iop::witness::{PartialWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; #[test] fn no_duplicate_challenges() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - let mut challenger = - Challenger::>::InnerHasher>::new(); + type F = >::F; + let mut challenger = Challenger::< + F, + >::HCI, + >::InnerHasher, + >::new(); let mut challenges = Vec::new(); for i in 1..10 { @@ -421,9 +422,7 @@ mod tests { fn test_consistency() { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; // These are mostly arbitrary, but we want to test some rounds with enough inputs/outputs to // trigger multiple absorptions/squeezes. @@ -436,8 +435,11 @@ mod tests { .map(|&n| F::rand_vec(n)) .collect(); - let mut challenger = - Challenger::>::InnerHasher>::new(); + let mut challenger = Challenger::< + F, + >::HCI, + >::InnerHasher, + >::new(); let mut outputs_per_round: Vec> = Vec::new(); for (r, inputs) in inputs_per_round.iter().enumerate() { challenger.observe_elements(inputs); @@ -446,10 +448,12 @@ mod tests { let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); - let mut recursive_challenger = - RecursiveChallenger::>::InnerHasher, D>::new( - &mut builder, - ); + let mut recursive_challenger = RecursiveChallenger::< + F, + >::HCI, + >::InnerHasher, + D, + >::new(&mut builder); let mut recursive_outputs_per_round: Vec> = Vec::new(); for (r, inputs) in inputs_per_round.iter().enumerate() { recursive_challenger.observe_elements(&builder.constants(inputs)); @@ -457,7 +461,7 @@ mod tests { recursive_challenger.get_n_challenges(&mut builder, num_outputs_per_round[r]), ); } - let circuit = builder.build::(); + let circuit = builder.build::(); let inputs = PartialWitness::new(); let witness = generate_partial_witness(inputs, &circuit.prover_only, &circuit.common); let recursive_output_values_per_round: Vec> = recursive_outputs_per_round diff --git a/plonky2/src/iop/generator.rs b/plonky2/src/iop/generator.rs index b2ddd2ce..a65d1748 100644 --- a/plonky2/src/iop/generator.rs +++ b/plonky2/src/iop/generator.rs @@ -6,7 +6,6 @@ use core::marker::PhantomData; use crate::field::extension::Extendable; use crate::field::types::Field; use crate::hash::hash_types::RichField; -use crate::hash::hashing::HashConfig; use crate::iop::ext_target::ExtensionTarget; use crate::iop::target::Target; use crate::iop::wire::Wire; @@ -19,13 +18,11 @@ use crate::plonk::config::GenericConfig; pub(crate) fn generate_partial_witness< 'a, F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, >( inputs: PartialWitness, - prover_data: &'a ProverOnlyCircuitData, + prover_data: &'a ProverOnlyCircuitData, common_data: &'a CommonCircuitData, ) -> PartitionWitness<'a, F> { let config = &common_data.config; diff --git a/plonky2/src/iop/witness.rs b/plonky2/src/iop/witness.rs index 9879be0b..21531d71 100644 --- a/plonky2/src/iop/witness.rs +++ b/plonky2/src/iop/witness.rs @@ -72,18 +72,13 @@ pub trait WitnessWrite { /// Set the targets in a `ProofWithPublicInputsTarget` to their corresponding values in a /// `ProofWithPublicInputs`. - fn set_proof_with_pis_target< - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - >( + fn set_proof_with_pis_target, const D: usize>( &mut self, proof_with_pis_target: &ProofWithPublicInputsTarget, - proof_with_pis: &ProofWithPublicInputs, + proof_with_pis: &ProofWithPublicInputs, ) where F: RichField + Extendable, - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, { let ProofWithPublicInputs { proof, @@ -103,18 +98,13 @@ pub trait WitnessWrite { } /// Set the targets in a `ProofTarget` to their corresponding values in a `Proof`. - fn set_proof_target< - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - >( + fn set_proof_target, const D: usize>( &mut self, proof_target: &ProofTarget, - proof: &Proof, + proof: &Proof, ) where F: RichField + Extendable, - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, { self.set_cap_target(&proof_target.wires_cap, &proof.wires_cap); self.set_cap_target( @@ -147,18 +137,13 @@ pub trait WitnessWrite { } } - fn set_verifier_data_target< - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - >( + fn set_verifier_data_target, const D: usize>( &mut self, vdt: &VerifierCircuitTarget, - vd: &VerifierOnlyCircuitData, + vd: &VerifierOnlyCircuitData, ) where F: RichField + Extendable, - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, { self.set_cap_target(&vdt.constants_sigmas_cap, &vd.constants_sigmas_cap); self.set_hash_target(vdt.circuit_digest, vd.circuit_digest); diff --git a/plonky2/src/plonk/circuit_builder.rs b/plonky2/src/plonk/circuit_builder.rs index 67c31df9..15c01ab0 100644 --- a/plonky2/src/plonk/circuit_builder.rs +++ b/plonky2/src/plonk/circuit_builder.rs @@ -442,14 +442,12 @@ impl, const D: usize> CircuitBuilder { MerkleCapTarget(cap.0.iter().map(|h| self.constant_hash(*h)).collect()) } - pub fn constant_verifier_data>( + pub fn constant_verifier_data>( &mut self, - verifier_data: &VerifierOnlyCircuitData, + verifier_data: &VerifierOnlyCircuitData, ) -> VerifierCircuitTarget where - HCO: HashConfig, - HCI: HashConfig, - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, { VerifierCircuitTarget { constants_sigmas_cap: self.constant_merkle_cap(&verifier_data.constants_sigmas_cap), @@ -740,12 +738,10 @@ impl, const D: usize> CircuitBuilder { } /// Builds a "full circuit", with both prover and verifier data. - pub fn build>( - mut self, - ) -> CircuitData + pub fn build>(mut self) -> CircuitData where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let mut timing = TimingTree::new("preprocess", Level::Trace); #[cfg(feature = "std")] @@ -757,7 +753,7 @@ impl, const D: usize> CircuitBuilder { // those hash wires match the claimed public inputs. let num_public_inputs = self.public_inputs.len(); let public_inputs_hash = - self.hash_n_to_hash_no_pad::(self.public_inputs.clone()); + self.hash_n_to_hash_no_pad::(self.public_inputs.clone()); let pi_gate = self.add_gate(PublicInputGate, vec![]); for (&hash_part, wire) in public_inputs_hash .elements @@ -834,7 +830,7 @@ impl, const D: usize> CircuitBuilder { let fft_root_table = fft_root_table(max_fft_points); let constants_sigmas_vecs = [constant_vecs, sigma_vecs.clone()].concat(); - let constants_sigmas_commitment = PolynomialBatch::::from_values( + let constants_sigmas_commitment = PolynomialBatch::::from_values( constants_sigmas_vecs, rate_bits, PlonkOracle::CONSTANTS_SIGMAS.blinding, @@ -922,7 +918,7 @@ impl, const D: usize> CircuitBuilder { assert_eq!(goal_data, common, "The expected circuit data passed to cyclic recursion method did not match the actual circuit"); } - let prover_only = ProverOnlyCircuitData:: { + let prover_only = ProverOnlyCircuitData:: { generators: self.generators, generator_indices_by_watches, constants_sigmas_commitment, @@ -934,7 +930,7 @@ impl, const D: usize> CircuitBuilder { circuit_digest, }; - let verifier_only = VerifierOnlyCircuitData:: { + let verifier_only = VerifierOnlyCircuitData:: { constants_sigmas_cap, circuit_digest, }; @@ -950,28 +946,24 @@ impl, const D: usize> CircuitBuilder { } /// Builds a "prover circuit", with data needed to generate proofs but not verify them. - pub fn build_prover>( - self, - ) -> ProverCircuitData + pub fn build_prover>(self) -> ProverCircuitData where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { // TODO: Can skip parts of this. - let circuit_data = self.build::(); + let circuit_data = self.build::(); circuit_data.prover_data() } /// Builds a "verifier circuit", with data needed to verify proofs but not generate them. - pub fn build_verifier>( - self, - ) -> VerifierCircuitData + pub fn build_verifier>(self) -> VerifierCircuitData where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { // TODO: Can skip parts of this. - let circuit_data = self.build::(); + let circuit_data = self.build::(); circuit_data.verifier_data() } } diff --git a/plonky2/src/plonk/circuit_data.rs b/plonky2/src/plonk/circuit_data.rs index 9f0eab71..2346b9db 100644 --- a/plonky2/src/plonk/circuit_data.rs +++ b/plonky2/src/plonk/circuit_data.rs @@ -107,35 +107,21 @@ impl CircuitConfig { } /// Circuit data required by the prover or the verifier. -pub struct CircuitData< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, -> { - pub prover_only: ProverOnlyCircuitData, - pub verifier_only: VerifierOnlyCircuitData, +pub struct CircuitData, C: GenericConfig, const D: usize> { + pub prover_only: ProverOnlyCircuitData, + pub verifier_only: VerifierOnlyCircuitData, pub common: CommonCircuitData, } -impl< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - > CircuitData +impl, C: GenericConfig, const D: usize> + CircuitData { - pub fn prove( - &self, - inputs: PartialWitness, - ) -> Result> + pub fn prove(&self, inputs: PartialWitness) -> Result> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { - prove::( + prove::( &self.prover_only, &self.common, inputs, @@ -143,48 +129,48 @@ impl< ) } - pub fn verify(&self, proof_with_pis: ProofWithPublicInputs) -> Result<()> + pub fn verify(&self, proof_with_pis: ProofWithPublicInputs) -> Result<()> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { - verify::(proof_with_pis, &self.verifier_only, &self.common) + verify::(proof_with_pis, &self.verifier_only, &self.common) } pub fn verify_compressed( &self, - compressed_proof_with_pis: CompressedProofWithPublicInputs, + compressed_proof_with_pis: CompressedProofWithPublicInputs, ) -> Result<()> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { compressed_proof_with_pis.verify(&self.verifier_only, &self.common) } pub fn compress( &self, - proof: ProofWithPublicInputs, - ) -> Result> + proof: ProofWithPublicInputs, + ) -> Result> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { proof.compress(&self.verifier_only.circuit_digest, &self.common) } pub fn decompress( &self, - proof: CompressedProofWithPublicInputs, - ) -> Result> + proof: CompressedProofWithPublicInputs, + ) -> Result> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { proof.decompress(&self.verifier_only.circuit_digest, &self.common) } - pub fn verifier_data(&self) -> VerifierCircuitData { + pub fn verifier_data(&self) -> VerifierCircuitData { let CircuitData { verifier_only, common, @@ -196,7 +182,7 @@ impl< } } - pub fn prover_data(self) -> ProverCircuitData { + pub fn prover_data(self) -> ProverCircuitData { let CircuitData { prover_only, common, @@ -218,32 +204,22 @@ impl< /// construct a more minimal prover structure and convert back and forth. pub struct ProverCircuitData< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, > { - pub prover_only: ProverOnlyCircuitData, + pub prover_only: ProverOnlyCircuitData, pub common: CommonCircuitData, } -impl< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - > ProverCircuitData +impl, C: GenericConfig, const D: usize> + ProverCircuitData { - pub fn prove( - &self, - inputs: PartialWitness, - ) -> Result> + pub fn prove(&self, inputs: PartialWitness) -> Result> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { - prove::( + prove::( &self.prover_only, &self.common, inputs, @@ -256,38 +232,31 @@ impl< #[derive(Debug)] pub struct VerifierCircuitData< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, > { - pub verifier_only: VerifierOnlyCircuitData, + pub verifier_only: VerifierOnlyCircuitData, pub common: CommonCircuitData, } -impl< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - > VerifierCircuitData +impl, C: GenericConfig, const D: usize> + VerifierCircuitData { - pub fn verify(&self, proof_with_pis: ProofWithPublicInputs) -> Result<()> + pub fn verify(&self, proof_with_pis: ProofWithPublicInputs) -> Result<()> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { - verify::(proof_with_pis, &self.verifier_only, &self.common) + verify::(proof_with_pis, &self.verifier_only, &self.common) } pub fn verify_compressed( &self, - compressed_proof_with_pis: CompressedProofWithPublicInputs, + compressed_proof_with_pis: CompressedProofWithPublicInputs, ) -> Result<()> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { compressed_proof_with_pis.verify(&self.verifier_only, &self.common) } @@ -296,9 +265,7 @@ impl< /// Circuit data required by the prover, but not the verifier. pub struct ProverOnlyCircuitData< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, > { pub generators: Vec>>, @@ -306,7 +273,7 @@ pub struct ProverOnlyCircuitData< /// they watch. pub generator_indices_by_watches: BTreeMap>, /// Commitments to the constants polynomials and sigma polynomials. - pub constants_sigmas_commitment: PolynomialBatch, + pub constants_sigmas_commitment: PolynomialBatch, /// The transpose of the list of sigma polynomials. pub sigmas: Vec>, /// Subgroup of order `degree`. @@ -320,22 +287,17 @@ pub struct ProverOnlyCircuitData< pub fft_root_table: Option>, /// A digest of the "circuit" (i.e. the instance, minus public inputs), which can be used to /// seed Fiat-Shamir. - pub circuit_digest: <>::Hasher as Hasher>::Hash, + pub circuit_digest: <>::Hasher as Hasher>::Hash, } /// Circuit data required by the verifier, but not the prover. #[derive(Debug, Clone, Eq, PartialEq)] -pub struct VerifierOnlyCircuitData< - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, -> { +pub struct VerifierOnlyCircuitData, const D: usize> { /// A commitment to each constant polynomial and each permutation polynomial. - pub constants_sigmas_cap: MerkleCap, + pub constants_sigmas_cap: MerkleCap, /// A digest of the "circuit" (i.e. the instance, minus public inputs), which can be used to /// seed Fiat-Shamir. - pub circuit_digest: <>::Hasher as Hasher>::Hash, + pub circuit_digest: <>::Hasher as Hasher>::Hash, } /// Circuit data required by both the prover and the verifier. diff --git a/plonky2/src/plonk/config.rs b/plonky2/src/plonk/config.rs index c68998f6..60f9a7b8 100644 --- a/plonky2/src/plonk/config.rs +++ b/plonky2/src/plonk/config.rs @@ -93,17 +93,21 @@ pub trait AlgebraicHasher: Hasher: +pub trait GenericConfig: Debug + Clone + Sync + Sized + Send + Eq + PartialEq { /// Main field. type F: RichField + Extendable; /// Field extension of degree D of the main field. type FE: FieldExtension; + /// Hash configuration for this GenericConfig's `Hasher`. + type HCO: HashConfig; + /// Hash configuration for this GenericConfig's `InnerHasher`. + type HCI: HashConfig; /// Hash function used for building Merkle trees. - type Hasher: Hasher; + type Hasher: Hasher; /// Algebraic hash function used for the challenger and hashing public inputs. - type InnerHasher: AlgebraicHasher; + type InnerHasher: AlgebraicHasher; } #[derive(Clone, Debug, Eq, PartialEq)] @@ -115,9 +119,11 @@ impl HashConfig for PoseidonHashConfig { /// Configuration using Poseidon over the Goldilocks field. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct PoseidonGoldilocksConfig; -impl GenericConfig for PoseidonGoldilocksConfig { +impl GenericConfig<2> for PoseidonGoldilocksConfig { type F = GoldilocksField; type FE = QuadraticExtension; + type HCO = PoseidonHashConfig; + type HCI = PoseidonHashConfig; type Hasher = PoseidonHash; type InnerHasher = PoseidonHash; } @@ -131,9 +137,11 @@ impl HashConfig for KeccakHashConfig { /// Configuration using truncated Keccak over the Goldilocks field. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct KeccakGoldilocksConfig; -impl GenericConfig for KeccakGoldilocksConfig { +impl GenericConfig<2> for KeccakGoldilocksConfig { type F = GoldilocksField; type FE = QuadraticExtension; + type HCO = KeccakHashConfig; + type HCI = PoseidonHashConfig; type Hasher = KeccakHash<25>; type InnerHasher = PoseidonHash; } diff --git a/plonky2/src/plonk/get_challenges.rs b/plonky2/src/plonk/get_challenges.rs index 5932b6ff..d0682572 100644 --- a/plonky2/src/plonk/get_challenges.rs +++ b/plonky2/src/plonk/get_challenges.rs @@ -23,45 +23,39 @@ use crate::plonk::proof::{ }; use crate::util::reverse_bits; -fn get_challenges< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, ->( - public_inputs_hash: <>::InnerHasher as Hasher>::Hash, - wires_cap: &MerkleCap, - plonk_zs_partial_products_cap: &MerkleCap, - quotient_polys_cap: &MerkleCap, +fn get_challenges, C: GenericConfig, const D: usize>( + public_inputs_hash: <>::InnerHasher as Hasher>::Hash, + wires_cap: &MerkleCap, + plonk_zs_partial_products_cap: &MerkleCap, + quotient_polys_cap: &MerkleCap, openings: &OpeningSet, - commit_phase_merkle_caps: &[MerkleCap], + commit_phase_merkle_caps: &[MerkleCap], final_poly: &PolynomialCoeffs, pow_witness: F, - circuit_digest: &<>::Hasher as Hasher>::Hash, + circuit_digest: &<>::Hasher as Hasher>::Hash, common_data: &CommonCircuitData, ) -> anyhow::Result> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let config = &common_data.config; let num_challenges = config.num_challenges; - let mut challenger = Challenger::::new(); + let mut challenger = Challenger::::new(); // Observe the instance. - challenger.observe_hash::(*circuit_digest); - challenger.observe_hash::(public_inputs_hash); + challenger.observe_hash::(*circuit_digest); + challenger.observe_hash::(public_inputs_hash); - challenger.observe_cap::(wires_cap); + challenger.observe_cap::(wires_cap); let plonk_betas = challenger.get_n_challenges(num_challenges); let plonk_gammas = challenger.get_n_challenges(num_challenges); - challenger.observe_cap::(plonk_zs_partial_products_cap); + challenger.observe_cap::(plonk_zs_partial_products_cap); let plonk_alphas = challenger.get_n_challenges(num_challenges); - challenger.observe_cap::(quotient_polys_cap); + challenger.observe_cap::(quotient_polys_cap); let plonk_zeta = challenger.get_extension_challenge::(); challenger.observe_openings(&openings.to_fri_openings()); @@ -71,7 +65,7 @@ where plonk_gammas, plonk_alphas, plonk_zeta, - fri_challenges: challenger.fri_challenges::( + fri_challenges: challenger.fri_challenges::( commit_phase_merkle_caps, final_poly, pow_witness, @@ -81,22 +75,17 @@ where }) } -impl< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - > ProofWithPublicInputs +impl, C: GenericConfig, const D: usize> + ProofWithPublicInputs { pub(crate) fn fri_query_indices( &self, - circuit_digest: &<>::Hasher as Hasher>::Hash, + circuit_digest: &<>::Hasher as Hasher>::Hash, common_data: &CommonCircuitData, ) -> anyhow::Result> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { Ok(self .get_challenges(self.get_public_inputs_hash(), circuit_digest, common_data)? @@ -107,13 +96,13 @@ impl< /// Computes all Fiat-Shamir challenges used in the Plonk proof. pub(crate) fn get_challenges( &self, - public_inputs_hash: <>::InnerHasher as Hasher>::Hash, - circuit_digest: &<>::Hasher as Hasher>::Hash, + public_inputs_hash: <>::InnerHasher as Hasher>::Hash, + circuit_digest: &<>::Hasher as Hasher>::Hash, common_data: &CommonCircuitData, ) -> anyhow::Result> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let Proof { wires_cap, @@ -129,7 +118,7 @@ impl< }, } = &self.proof; - get_challenges::( + get_challenges::( public_inputs_hash, wires_cap, plonk_zs_partial_products_cap, @@ -144,24 +133,19 @@ impl< } } -impl< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - > CompressedProofWithPublicInputs +impl, C: GenericConfig, const D: usize> + CompressedProofWithPublicInputs { /// Computes all Fiat-Shamir challenges used in the Plonk proof. pub(crate) fn get_challenges( &self, - public_inputs_hash: <>::InnerHasher as Hasher>::Hash, - circuit_digest: &<>::Hasher as Hasher>::Hash, + public_inputs_hash: <>::InnerHasher as Hasher>::Hash, + circuit_digest: &<>::Hasher as Hasher>::Hash, common_data: &CommonCircuitData, ) -> anyhow::Result> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let CompressedProof { wires_cap, @@ -177,7 +161,7 @@ impl< }, } = &self.proof; - get_challenges::( + get_challenges::( public_inputs_hash, wires_cap, plonk_zs_partial_products_cap, @@ -222,7 +206,7 @@ impl< for &(mut x_index) in fri_query_indices { let mut subgroup_x = F::MULTIPLICATIVE_GROUP_GENERATOR * F::primitive_root_of_unity(log_n).exp_u64(reverse_bits(x_index, log_n) as u64); - let mut old_eval = fri_combine_initial::( + let mut old_eval = fri_combine_initial::( &common_data.get_fri_instance(*plonk_zeta), &self .proof @@ -268,7 +252,7 @@ impl< } impl, const D: usize> CircuitBuilder { - fn get_challenges>( + fn get_challenges>( &mut self, public_inputs_hash: HashOutTarget, wires_cap: &MerkleCapTarget, @@ -282,14 +266,14 @@ impl, const D: usize> CircuitBuilder { inner_common_data: &CommonCircuitData, ) -> ProofChallengesTarget where - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let config = &inner_common_data.config; let num_challenges = config.num_challenges; - let mut challenger = RecursiveChallenger::::new(self); + let mut challenger = RecursiveChallenger::::new(self); // Observe the instance. challenger.observe_hash(&inner_circuit_digest); @@ -324,12 +308,7 @@ impl, const D: usize> CircuitBuilder { } impl ProofWithPublicInputsTarget { - pub(crate) fn get_challenges< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - >( + pub(crate) fn get_challenges, C: GenericConfig>( &self, builder: &mut CircuitBuilder, public_inputs_hash: HashOutTarget, @@ -337,9 +316,9 @@ impl ProofWithPublicInputsTarget { inner_common_data: &CommonCircuitData, ) -> ProofChallengesTarget where - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let ProofTarget { wires_cap, @@ -355,7 +334,7 @@ impl ProofWithPublicInputsTarget { }, } = &self.proof; - builder.get_challenges::( + builder.get_challenges::( public_inputs_hash, wires_cap, plonk_zs_partial_products_cap, diff --git a/plonky2/src/plonk/proof.rs b/plonky2/src/plonk/proof.rs index 476ff18a..6332252f 100644 --- a/plonky2/src/plonk/proof.rs +++ b/plonky2/src/plonk/proof.rs @@ -28,23 +28,17 @@ use crate::util::serialization::{Buffer, Read}; #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct Proof< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, -> { +pub struct Proof, C: GenericConfig, const D: usize> { /// Merkle cap of LDEs of wire values. - pub wires_cap: MerkleCap, + pub wires_cap: MerkleCap, /// Merkle cap of LDEs of Z, in the context of Plonk's permutation argument. - pub plonk_zs_partial_products_cap: MerkleCap, + pub plonk_zs_partial_products_cap: MerkleCap, /// Merkle cap of LDEs of the quotient polynomial components. - pub quotient_polys_cap: MerkleCap, + pub quotient_polys_cap: MerkleCap, /// Purported values of each polynomial at the challenge point. pub openings: OpeningSet, /// A batch FRI argument for all openings. - pub opening_proof: FriProof, + pub opening_proof: FriProof, } #[derive(Clone, Debug)] @@ -56,20 +50,9 @@ pub struct ProofTarget { pub opening_proof: FriProofTarget, } -impl< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - > Proof -{ +impl, C: GenericConfig, const D: usize> Proof { /// Compress the proof. - pub fn compress( - self, - indices: &[usize], - params: &FriParams, - ) -> CompressedProof { + pub fn compress(self, indices: &[usize], params: &FriParams) -> CompressedProof { let Proof { wires_cap, plonk_zs_partial_products_cap, @@ -92,31 +75,24 @@ impl< #[serde(bound = "")] pub struct ProofWithPublicInputs< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, > { - pub proof: Proof, + pub proof: Proof, pub public_inputs: Vec, } -impl< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - > ProofWithPublicInputs +impl, C: GenericConfig, const D: usize> + ProofWithPublicInputs { pub fn compress( self, - circuit_digest: &<>::Hasher as Hasher>::Hash, + circuit_digest: &<>::Hasher as Hasher>::Hash, common_data: &CommonCircuitData, - ) -> anyhow::Result> + ) -> anyhow::Result> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let indices = self.fri_query_indices(circuit_digest, common_data)?; let compressed_proof = self.proof.compress(&indices, &common_data.fri_params); @@ -128,9 +104,9 @@ impl< pub(crate) fn get_public_inputs_hash( &self, - ) -> <>::InnerHasher as Hasher>::Hash + ) -> <>::InnerHasher as Hasher>::Hash where - [(); HCI::WIDTH]:, + [(); C::HCI::WIDTH]:, { C::InnerHasher::hash_no_pad(&self.public_inputs) } @@ -158,32 +134,22 @@ impl< #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub struct CompressedProof< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, -> { +pub struct CompressedProof, C: GenericConfig, const D: usize> +{ /// Merkle cap of LDEs of wire values. - pub wires_cap: MerkleCap, + pub wires_cap: MerkleCap, /// Merkle cap of LDEs of Z, in the context of Plonk's permutation argument. - pub plonk_zs_partial_products_cap: MerkleCap, + pub plonk_zs_partial_products_cap: MerkleCap, /// Merkle cap of LDEs of the quotient polynomial components. - pub quotient_polys_cap: MerkleCap, + pub quotient_polys_cap: MerkleCap, /// Purported values of each polynomial at the challenge point. pub openings: OpeningSet, /// A compressed batch FRI argument for all openings. - pub opening_proof: CompressedFriProof, + pub opening_proof: CompressedFriProof, } -impl< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - > CompressedProof +impl, C: GenericConfig, const D: usize> + CompressedProof { /// Decompress the proof. pub(crate) fn decompress( @@ -191,9 +157,9 @@ impl< challenges: &ProofChallenges, fri_inferred_elements: FriInferredElements, params: &FriParams, - ) -> Proof + ) -> Proof where - [(); HCO::WIDTH]:, + [(); C::HCO::WIDTH]:, { let CompressedProof { wires_cap, @@ -217,31 +183,24 @@ impl< #[serde(bound = "")] pub struct CompressedProofWithPublicInputs< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, > { - pub proof: CompressedProof, + pub proof: CompressedProof, pub public_inputs: Vec, } -impl< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - > CompressedProofWithPublicInputs +impl, C: GenericConfig, const D: usize> + CompressedProofWithPublicInputs { pub fn decompress( self, - circuit_digest: &<>::Hasher as Hasher>::Hash, + circuit_digest: &<>::Hasher as Hasher>::Hash, common_data: &CommonCircuitData, - ) -> anyhow::Result> + ) -> anyhow::Result> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let challenges = self.get_challenges(self.get_public_inputs_hash(), circuit_digest, common_data)?; @@ -257,12 +216,12 @@ impl< pub(crate) fn verify( self, - verifier_data: &VerifierOnlyCircuitData, + verifier_data: &VerifierOnlyCircuitData, common_data: &CommonCircuitData, ) -> anyhow::Result<()> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { ensure!( self.public_inputs.len() == common_data.num_public_inputs, @@ -278,7 +237,7 @@ impl< let decompressed_proof = self.proof .decompress(&challenges, fri_inferred_elements, &common_data.fri_params); - verify_with_challenges::( + verify_with_challenges::( decompressed_proof, public_inputs_hash, challenges, @@ -289,9 +248,9 @@ impl< pub(crate) fn get_public_inputs_hash( &self, - ) -> <>::InnerHasher as Hasher>::Hash + ) -> <>::InnerHasher as Hasher>::Hash where - [(); HCI::WIDTH]:, + [(); C::HCI::WIDTH]:, { C::InnerHasher::hash_no_pad(&self.public_inputs) } @@ -365,16 +324,16 @@ pub struct OpeningSet, const D: usize> { } impl, const D: usize> OpeningSet { - pub fn new>( + pub fn new>( zeta: F::Extension, g: F::Extension, - constants_sigmas_commitment: &PolynomialBatch, - wires_commitment: &PolynomialBatch, - zs_partial_products_commitment: &PolynomialBatch, - quotient_polys_commitment: &PolynomialBatch, + constants_sigmas_commitment: &PolynomialBatch, + wires_commitment: &PolynomialBatch, + zs_partial_products_commitment: &PolynomialBatch, + quotient_polys_commitment: &PolynomialBatch, common_data: &CommonCircuitData, ) -> Self { - let eval_commitment = |z: F::Extension, c: &PolynomialBatch| { + let eval_commitment = |z: F::Extension, c: &PolynomialBatch| { c.polynomials .par_iter() .map(|p| p.to_extension().eval(z)) @@ -461,16 +420,14 @@ mod tests { use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; #[test] fn test_proof_compression() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let mut config = CircuitConfig::standard_recursion_config(); config.fri_config.reduction_strategy = FriReductionStrategy::Fixed(vec![1, 1]); @@ -491,7 +448,7 @@ mod tests { for _ in 0..100 { builder.add_gate(NoopGate, vec![]); } - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof.clone(), &data.verifier_only, &data.common)?; diff --git a/plonky2/src/plonk/prover.rs b/plonky2/src/plonk/prover.rs index a0b6313a..29d9721f 100644 --- a/plonky2/src/plonk/prover.rs +++ b/plonky2/src/plonk/prover.rs @@ -26,23 +26,17 @@ use crate::util::partial_products::{partial_products_and_z_gx, quotient_chunk_pr use crate::util::timing::TimingTree; use crate::util::{ceil_div_usize, log2_ceil, transpose}; -pub fn prove< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, ->( - prover_data: &ProverOnlyCircuitData, +pub fn prove, C: GenericConfig, const D: usize>( + prover_data: &ProverOnlyCircuitData, common_data: &CommonCircuitData, inputs: PartialWitness, timing: &mut TimingTree, -) -> Result> +) -> Result> where - C::Hasher: Hasher, - C::InnerHasher: Hasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C::Hasher: Hasher, + C::InnerHasher: Hasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let config = &common_data.config; let num_challenges = config.num_challenges; @@ -77,7 +71,7 @@ where let wires_commitment = timed!( timing, "compute wires commitment", - PolynomialBatch::::from_values( + PolynomialBatch::::from_values( wires_values, config.fri_config.rate_bits, config.zero_knowledge && PlonkOracle::WIRES.blinding, @@ -87,13 +81,13 @@ where ) ); - let mut challenger = Challenger::::new(); + let mut challenger = Challenger::::new(); // Observe the instance. - challenger.observe_hash::(prover_data.circuit_digest); - challenger.observe_hash::(public_inputs_hash); + challenger.observe_hash::(prover_data.circuit_digest); + challenger.observe_hash::(public_inputs_hash); - challenger.observe_cap::(&wires_commitment.merkle_tree.cap); + challenger.observe_cap::(&wires_commitment.merkle_tree.cap); let betas = challenger.get_n_challenges(num_challenges); let gammas = challenger.get_n_challenges(num_challenges); @@ -117,7 +111,7 @@ where let partial_products_and_zs_commitment = timed!( timing, "commit to partial products and Z's", - PolynomialBatch::::from_values( + PolynomialBatch::::from_values( zs_partial_products, config.fri_config.rate_bits, config.zero_knowledge && PlonkOracle::ZS_PARTIAL_PRODUCTS.blinding, @@ -127,14 +121,15 @@ where ) ); - challenger.observe_cap::(&partial_products_and_zs_commitment.merkle_tree.cap); + challenger + .observe_cap::(&partial_products_and_zs_commitment.merkle_tree.cap); let alphas = challenger.get_n_challenges(num_challenges); let quotient_polys = timed!( timing, "compute quotient polys", - compute_quotient_polys::( + compute_quotient_polys::( common_data, prover_data, &public_inputs_hash, @@ -165,7 +160,7 @@ where let quotient_polys_commitment = timed!( timing, "commit to quotient polys", - PolynomialBatch::::from_coeffs( + PolynomialBatch::::from_coeffs( all_quotient_poly_chunks, config.fri_config.rate_bits, config.zero_knowledge && PlonkOracle::QUOTIENT.blinding, @@ -175,7 +170,7 @@ where ) ); - challenger.observe_cap::("ient_polys_commitment.merkle_tree.cap); + challenger.observe_cap::("ient_polys_commitment.merkle_tree.cap); let zeta = challenger.get_extension_challenge::(); // To avoid leaking witness data, we want to ensure that our opening locations, `zeta` and @@ -190,7 +185,7 @@ where let openings = timed!( timing, "construct the opening set", - OpeningSet::new::( + OpeningSet::new::( zeta, g, &prover_data.constants_sigmas_commitment, @@ -205,7 +200,7 @@ where let opening_proof = timed!( timing, "compute opening proofs", - PolynomialBatch::::prove_openings( + PolynomialBatch::::prove_openings( &common_data.get_fri_instance(zeta), &[ &prover_data.constants_sigmas_commitment, @@ -219,14 +214,14 @@ where ) ); - let proof = Proof:: { + let proof = Proof:: { wires_cap: wires_commitment.merkle_tree.cap, plonk_zs_partial_products_cap: partial_products_and_zs_commitment.merkle_tree.cap, quotient_polys_cap: quotient_polys_commitment.merkle_tree.cap, openings, opening_proof, }; - Ok(ProofWithPublicInputs:: { + Ok(ProofWithPublicInputs:: { proof, public_inputs, }) @@ -235,15 +230,13 @@ where /// Compute the partial products used in the `Z` polynomials. fn all_wires_permutation_partial_products< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, >( witness: &MatrixWitness, betas: &[F], gammas: &[F], - prover_data: &ProverOnlyCircuitData, + prover_data: &ProverOnlyCircuitData, common_data: &CommonCircuitData, ) -> Vec>> { (0..common_data.config.num_challenges) @@ -264,15 +257,13 @@ fn all_wires_permutation_partial_products< /// where `f, g` are the products in the definition of `Z`: `Z(g^i) = f / g`. fn wires_permutation_partial_products_and_zs< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, >( witness: &MatrixWitness, beta: F, gamma: F, - prover_data: &ProverOnlyCircuitData, + prover_data: &ProverOnlyCircuitData, common_data: &CommonCircuitData, ) -> Vec> { let degree = common_data.quotient_degree_factor; @@ -328,16 +319,14 @@ const BATCH_SIZE: usize = 32; fn compute_quotient_polys< 'a, F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, >( common_data: &CommonCircuitData, - prover_data: &'a ProverOnlyCircuitData, - public_inputs_hash: &<>::InnerHasher as Hasher>::Hash, - wires_commitment: &'a PolynomialBatch, - zs_partial_products_commitment: &'a PolynomialBatch, + prover_data: &'a ProverOnlyCircuitData, + public_inputs_hash: &<>::InnerHasher as Hasher>::Hash, + wires_commitment: &'a PolynomialBatch, + zs_partial_products_commitment: &'a PolynomialBatch, betas: &[F], gammas: &[F], alphas: &[F], diff --git a/plonky2/src/plonk/validate_shape.rs b/plonky2/src/plonk/validate_shape.rs index 13005cc5..0b4bf4a8 100644 --- a/plonky2/src/plonk/validate_shape.rs +++ b/plonky2/src/plonk/validate_shape.rs @@ -2,20 +2,17 @@ use anyhow::ensure; use crate::field::extension::Extendable; use crate::hash::hash_types::RichField; -use crate::hash::hashing::HashConfig; use crate::plonk::circuit_data::CommonCircuitData; use crate::plonk::config::GenericConfig; use crate::plonk::proof::{OpeningSet, Proof, ProofWithPublicInputs}; -pub(crate) fn validate_proof_with_pis_shape( - proof_with_pis: &ProofWithPublicInputs, +pub(crate) fn validate_proof_with_pis_shape( + proof_with_pis: &ProofWithPublicInputs, common_data: &CommonCircuitData, ) -> anyhow::Result<()> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { let ProofWithPublicInputs { proof, @@ -29,15 +26,13 @@ where Ok(()) } -fn validate_proof_shape( - proof: &Proof, +fn validate_proof_shape( + proof: &Proof, common_data: &CommonCircuitData, ) -> anyhow::Result<()> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { let config = &common_data.config; let Proof { diff --git a/plonky2/src/plonk/verifier.rs b/plonky2/src/plonk/verifier.rs index 1417aeff..4c4905df 100644 --- a/plonky2/src/plonk/verifier.rs +++ b/plonky2/src/plonk/verifier.rs @@ -13,20 +13,14 @@ use crate::plonk::validate_shape::validate_proof_with_pis_shape; use crate::plonk::vanishing_poly::eval_vanishing_poly; use crate::plonk::vars::EvaluationVars; -pub(crate) fn verify< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, ->( - proof_with_pis: ProofWithPublicInputs, - verifier_data: &VerifierOnlyCircuitData, +pub(crate) fn verify, C: GenericConfig, const D: usize>( + proof_with_pis: ProofWithPublicInputs, + verifier_data: &VerifierOnlyCircuitData, common_data: &CommonCircuitData, ) -> Result<()> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { validate_proof_with_pis_shape(&proof_with_pis, common_data)?; @@ -37,7 +31,7 @@ where common_data, )?; - verify_with_challenges::( + verify_with_challenges::( proof_with_pis.proof, public_inputs_hash, challenges, @@ -48,19 +42,17 @@ where pub(crate) fn verify_with_challenges< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, >( - proof: Proof, - public_inputs_hash: <>::InnerHasher as Hasher>::Hash, + proof: Proof, + public_inputs_hash: <>::InnerHasher as Hasher>::Hash, challenges: ProofChallenges, - verifier_data: &VerifierOnlyCircuitData, + verifier_data: &VerifierOnlyCircuitData, common_data: &CommonCircuitData, ) -> Result<()> where - [(); HCO::WIDTH]:, + [(); C::HCO::WIDTH]:, { let local_constants = &proof.openings.constants; let local_wires = &proof.openings.wires; @@ -113,7 +105,7 @@ where proof.quotient_polys_cap, ]; - verify_fri_proof::( + verify_fri_proof::( &common_data.get_fri_instance(challenges.plonk_zeta), &proof.openings.to_fri_openings(), &challenges.fri_challenges, diff --git a/plonky2/src/recursion/conditional_recursive_verifier.rs b/plonky2/src/recursion/conditional_recursive_verifier.rs index 5d7151be..20eaf493 100644 --- a/plonky2/src/recursion/conditional_recursive_verifier.rs +++ b/plonky2/src/recursion/conditional_recursive_verifier.rs @@ -21,11 +21,7 @@ use crate::with_context; impl, const D: usize> CircuitBuilder { /// Verify `proof0` if `condition` else verify `proof1`. /// `proof0` and `proof1` are assumed to use the same `CommonCircuitData`. - pub fn conditionally_verify_proof< - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - >( + pub fn conditionally_verify_proof>( &mut self, condition: BoolTarget, proof_with_pis0: &ProofWithPublicInputsTarget, @@ -34,9 +30,9 @@ impl, const D: usize> CircuitBuilder { inner_verifier_data1: &VerifierCircuitTarget, inner_common_data: &CommonCircuitData, ) where - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let selected_proof = self.select_proof_with_pis(condition, proof_with_pis0, proof_with_pis1); @@ -53,19 +49,11 @@ impl, const D: usize> CircuitBuilder { ), }; - self.verify_proof::( - &selected_proof, - &selected_verifier_data, - inner_common_data, - ); + self.verify_proof::(&selected_proof, &selected_verifier_data, inner_common_data); } /// Conditionally verify a proof with a new generated dummy proof. - pub fn conditionally_verify_proof_or_dummy< - HCO, - HCI, - C: GenericConfig + 'static, - >( + pub fn conditionally_verify_proof_or_dummy + 'static>( &mut self, condition: BoolTarget, proof_with_pis: &ProofWithPublicInputsTarget, @@ -73,15 +61,13 @@ impl, const D: usize> CircuitBuilder { inner_common_data: &CommonCircuitData, ) -> anyhow::Result<()> where - HCO: HashConfig + 'static, - HCI: HashConfig + 'static, - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let (dummy_proof_with_pis_target, dummy_verifier_data_target) = - self.dummy_proof_and_vk::(inner_common_data)?; - self.conditionally_verify_proof::( + self.dummy_proof_and_vk::(inner_common_data)?; + self.conditionally_verify_proof::( condition, proof_with_pis, inner_verifier_data, @@ -361,7 +347,7 @@ mod tests { use crate::gates::noop::NoopGate; use crate::iop::witness::{PartialWitness, WitnessWrite}; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::recursion::dummy_circuit::{dummy_circuit, dummy_proof}; #[test] @@ -369,9 +355,7 @@ mod tests { init_logger(); const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); // Generate proof. @@ -384,7 +368,7 @@ mod tests { for _ in 0..64 { builder.add_gate(NoopGate, vec![]); } - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; data.verify(proof.clone())?; @@ -398,7 +382,7 @@ mod tests { let pt = builder.add_virtual_proof_with_pis(&data.common); pw.set_proof_with_pis_target(&pt, &proof); let dummy_pt = builder.add_virtual_proof_with_pis(&data.common); - pw.set_proof_with_pis_target::(&dummy_pt, &dummy_proof); + pw.set_proof_with_pis_target::(&dummy_pt, &dummy_proof); let inner_data = builder.add_virtual_verifier_data(data.common.config.fri_config.cap_height); pw.set_verifier_data_target(&inner_data, &data.verifier_only); @@ -406,7 +390,7 @@ mod tests { builder.add_virtual_verifier_data(data.common.config.fri_config.cap_height); pw.set_verifier_data_target(&dummy_inner_data, &dummy_data.verifier_only); let b = builder.constant_bool(F::rand().0 % 2 == 0); - builder.conditionally_verify_proof::( + builder.conditionally_verify_proof::( b, &pt, &inner_data, @@ -416,7 +400,7 @@ mod tests { ); builder.print_gate_counts(100); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; data.verify(proof) } diff --git a/plonky2/src/recursion/cyclic_recursion.rs b/plonky2/src/recursion/cyclic_recursion.rs index b0f49a8b..c973ba60 100644 --- a/plonky2/src/recursion/cyclic_recursion.rs +++ b/plonky2/src/recursion/cyclic_recursion.rs @@ -14,12 +14,10 @@ use crate::plonk::circuit_data::{ use crate::plonk::config::{AlgebraicHasher, GenericConfig}; use crate::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; -impl, const D: usize> - VerifierOnlyCircuitData -{ +impl, const D: usize> VerifierOnlyCircuitData { fn from_slice(slice: &[C::F], common_data: &CommonCircuitData) -> Result where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, { // The structure of the public inputs is `[..., circuit_digest, constants_sigmas_cap]`. let cap_len = common_data.config.fri_config.num_cap_elements(); @@ -82,11 +80,7 @@ impl, const D: usize> CircuitBuilder { /// that the verification key matches. /// /// WARNING: Do not register any public input after calling this! TODO: relax this - pub fn conditionally_verify_cyclic_proof< - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - >( + pub fn conditionally_verify_cyclic_proof>( &mut self, condition: BoolTarget, cyclic_proof_with_pis: &ProofWithPublicInputsTarget, @@ -95,9 +89,9 @@ impl, const D: usize> CircuitBuilder { common_data: &CommonCircuitData, ) -> Result<()> where - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let verifier_data = self .verifier_data_public_input @@ -125,7 +119,7 @@ impl, const D: usize> CircuitBuilder { ); // Verify the cyclic proof if `condition` is set to true, otherwise verify the other proof. - self.conditionally_verify_proof::( + self.conditionally_verify_proof::( condition, cyclic_proof_with_pis, &verifier_data, @@ -142,26 +136,20 @@ impl, const D: usize> CircuitBuilder { Ok(()) } - pub fn conditionally_verify_cyclic_proof_or_dummy< - HCO, - HCI, - C: GenericConfig + 'static, - >( + pub fn conditionally_verify_cyclic_proof_or_dummy + 'static>( &mut self, condition: BoolTarget, cyclic_proof_with_pis: &ProofWithPublicInputsTarget, common_data: &CommonCircuitData, ) -> Result<()> where - HCO: HashConfig + 'static, - HCI: HashConfig + 'static, - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let (dummy_proof_with_pis_target, dummy_verifier_data_target) = - self.dummy_proof_and_vk::(common_data)?; - self.conditionally_verify_cyclic_proof::( + self.dummy_proof_and_vk::(common_data)?; + self.conditionally_verify_cyclic_proof::( condition, cyclic_proof_with_pis, &dummy_proof_with_pis_target, @@ -176,22 +164,19 @@ impl, const D: usize> CircuitBuilder { /// Checks that the purported verifier data in the public inputs match the real verifier data. pub fn check_cyclic_proof_verifier_data< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, >( - proof: &ProofWithPublicInputs, - verifier_data: &VerifierOnlyCircuitData, + proof: &ProofWithPublicInputs, + verifier_data: &VerifierOnlyCircuitData, common_data: &CommonCircuitData, ) -> Result<()> where - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { - let pis = - VerifierOnlyCircuitData::::from_slice(&proof.public_inputs, common_data)?; + let pis = VerifierOnlyCircuitData::::from_slice(&proof.public_inputs, common_data)?; ensure!(verifier_data.constants_sigmas_cap == pis.constants_sigmas_cap); ensure!(verifier_data.circuit_digest == pis.circuit_digest); @@ -220,37 +205,35 @@ mod tests { // Generates `CommonCircuitData` usable for recursion. fn common_data_for_recursion< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, >() -> CommonCircuitData where - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let config = CircuitConfig::standard_recursion_config(); let builder = CircuitBuilder::::new(config); - let data = builder.build::(); + let data = builder.build::(); let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); let proof = builder.add_virtual_proof_with_pis(&data.common); let verifier_data = builder.add_virtual_verifier_data(data.common.config.fri_config.cap_height); - builder.verify_proof::(&proof, &verifier_data, &data.common); - let data = builder.build::(); + builder.verify_proof::(&proof, &verifier_data, &data.common); + let data = builder.build::(); let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); let proof = builder.add_virtual_proof_with_pis(&data.common); let verifier_data = builder.add_virtual_verifier_data(data.common.config.fri_config.cap_height); - builder.verify_proof::(&proof, &verifier_data, &data.common); + builder.verify_proof::(&proof, &verifier_data, &data.common); while builder.num_gates() < 1 << 12 { builder.add_gate(NoopGate, vec![]); } - builder.build::().common + builder.build::().common } /// Uses cyclic recursion to build a hash chain. @@ -263,9 +246,7 @@ mod tests { fn test_cyclic_recursion() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); @@ -281,7 +262,7 @@ mod tests { builder.register_public_inputs(¤t_hash_out.elements); let counter = builder.add_virtual_public_input(); - let mut common_data = common_data_for_recursion::(); + let mut common_data = common_data_for_recursion::(); let verifier_data_target = builder.add_verifier_data_public_inputs(); common_data.num_public_inputs = builder.num_public_inputs(); @@ -308,19 +289,19 @@ mod tests { let new_counter = builder.mul_add(condition.target, inner_cyclic_counter, one); builder.connect(counter, new_counter); - builder.conditionally_verify_cyclic_proof_or_dummy::( + builder.conditionally_verify_cyclic_proof_or_dummy::( condition, &inner_cyclic_proof_with_pis, &common_data, )?; - let cyclic_circuit_data = builder.build::(); + let cyclic_circuit_data = builder.build::(); let mut pw = PartialWitness::new(); let initial_hash = [F::ZERO, F::ONE, F::TWO, F::from_canonical_usize(3)]; let initial_hash_pis = initial_hash.into_iter().enumerate().collect(); pw.set_bool_target(condition, false); - pw.set_proof_with_pis_target::( + pw.set_proof_with_pis_target::( &inner_cyclic_proof_with_pis, &cyclic_base_proof( &common_data, diff --git a/plonky2/src/recursion/dummy_circuit.rs b/plonky2/src/recursion/dummy_circuit.rs index 1de83247..b0536b9c 100644 --- a/plonky2/src/recursion/dummy_circuit.rs +++ b/plonky2/src/recursion/dummy_circuit.rs @@ -23,19 +23,17 @@ use crate::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; /// public inputs which encode the cyclic verification key must be set properly, and this method /// takes care of that. It also allows the user to specify any other public inputs which should be /// set in this base proof. -pub fn cyclic_base_proof( +pub fn cyclic_base_proof( common_data: &CommonCircuitData, - verifier_data: &VerifierOnlyCircuitData, + verifier_data: &VerifierOnlyCircuitData, mut nonzero_public_inputs: HashMap, -) -> ProofWithPublicInputs +) -> ProofWithPublicInputs where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C: GenericConfig, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let pis_len = common_data.num_public_inputs; let cap_elements = common_data.config.fri_config.num_cap_elements(); @@ -51,8 +49,8 @@ where // TODO: A bit wasteful to build a dummy circuit here. We could potentially use a proof that // just consists of zeros, apart from public inputs. - dummy_proof::( - &dummy_circuit::(common_data), + dummy_proof::( + &dummy_circuit::(common_data), nonzero_public_inputs, ) .unwrap() @@ -63,17 +61,15 @@ where /// The rest will default to zero. pub(crate) fn dummy_proof< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, >( - circuit: &CircuitData, + circuit: &CircuitData, nonzero_public_inputs: HashMap, -) -> anyhow::Result> +) -> anyhow::Result> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let mut pw = PartialWitness::new(); for i in 0..circuit.common.num_public_inputs { @@ -86,16 +82,14 @@ where /// Generate a circuit matching a given `CommonCircuitData`. pub(crate) fn dummy_circuit< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, >( common_data: &CommonCircuitData, -) -> CircuitData +) -> CircuitData where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let config = common_data.config.clone(); assert!( @@ -119,26 +113,23 @@ where builder.add_virtual_public_input(); } - let circuit = builder.build::(); + let circuit = builder.build::(); assert_eq!(&circuit.common, common_data); circuit } impl, const D: usize> CircuitBuilder { - pub(crate) fn dummy_proof_and_vk + 'static>( + pub(crate) fn dummy_proof_and_vk + 'static>( &mut self, common_data: &CommonCircuitData, ) -> anyhow::Result<(ProofWithPublicInputsTarget, VerifierCircuitTarget)> where - HCO: HashConfig + 'static, - HCI: HashConfig + 'static, - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { - let dummy_circuit = dummy_circuit::(common_data); - let dummy_proof_with_pis = - dummy_proof::(&dummy_circuit, HashMap::new())?; + let dummy_circuit = dummy_circuit::(common_data); + let dummy_proof_with_pis = dummy_proof::(&dummy_circuit, HashMap::new())?; let dummy_proof_with_pis_target = self.add_virtual_proof_with_pis(common_data); let dummy_verifier_data_target = self.add_virtual_verifier_data(self.config.fri_config.cap_height); @@ -155,26 +146,22 @@ impl, const D: usize> CircuitBuilder { } #[derive(Debug)] -pub(crate) struct DummyProofGenerator +pub(crate) struct DummyProofGenerator where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { pub(crate) proof_with_pis_target: ProofWithPublicInputsTarget, - pub(crate) proof_with_pis: ProofWithPublicInputs, + pub(crate) proof_with_pis: ProofWithPublicInputs, pub(crate) verifier_data_target: VerifierCircuitTarget, - pub(crate) verifier_data: VerifierOnlyCircuitData, + pub(crate) verifier_data: VerifierOnlyCircuitData, } -impl SimpleGenerator for DummyProofGenerator +impl SimpleGenerator for DummyProofGenerator where F: RichField + Extendable, - HCO: HashConfig + 'static, - HCI: HashConfig + 'static, - C: GenericConfig + 'static, - C::Hasher: AlgebraicHasher, + C: GenericConfig + 'static, + C::Hasher: AlgebraicHasher, { fn dependencies(&self) -> Vec { vec![] diff --git a/plonky2/src/recursion/recursive_verifier.rs b/plonky2/src/recursion/recursive_verifier.rs index e611abb1..240c8c1a 100644 --- a/plonky2/src/recursion/recursive_verifier.rs +++ b/plonky2/src/recursion/recursive_verifier.rs @@ -15,30 +15,30 @@ use crate::with_context; impl, const D: usize> CircuitBuilder { /// Recursively verifies an inner proof. - pub fn verify_proof>( + pub fn verify_proof>( &mut self, proof_with_pis: &ProofWithPublicInputsTarget, inner_verifier_data: &VerifierCircuitTarget, inner_common_data: &CommonCircuitData, ) where - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { assert_eq!( proof_with_pis.public_inputs.len(), inner_common_data.num_public_inputs ); - let public_inputs_hash = - self.hash_n_to_hash_no_pad::(proof_with_pis.public_inputs.clone()); - let challenges = proof_with_pis.get_challenges::( + let public_inputs_hash = self + .hash_n_to_hash_no_pad::(proof_with_pis.public_inputs.clone()); + let challenges = proof_with_pis.get_challenges::( self, public_inputs_hash, inner_verifier_data.circuit_digest, inner_common_data, ); - self.verify_proof_with_challenges::( + self.verify_proof_with_challenges::( &proof_with_pis.proof, public_inputs_hash, challenges, @@ -48,11 +48,7 @@ impl, const D: usize> CircuitBuilder { } /// Recursively verifies an inner proof. - fn verify_proof_with_challenges< - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - >( + fn verify_proof_with_challenges>( &mut self, proof: &ProofTarget, public_inputs_hash: HashOutTarget, @@ -60,8 +56,8 @@ impl, const D: usize> CircuitBuilder { inner_verifier_data: &VerifierCircuitTarget, inner_common_data: &CommonCircuitData, ) where - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, { let one = self.one_extension(); @@ -123,7 +119,7 @@ impl, const D: usize> CircuitBuilder { with_context!( self, "verify FRI proof", - self.verify_fri_proof::( + self.verify_fri_proof::( &fri_instance, &proof.openings.to_fri_openings(), &challenges.fri_challenges, @@ -195,10 +191,7 @@ mod tests { use crate::gates::noop::NoopGate; use crate::iop::witness::{PartialWitness, WitnessWrite}; use crate::plonk::circuit_data::{CircuitConfig, VerifierOnlyCircuitData}; - use crate::plonk::config::{ - GenericConfig, KeccakGoldilocksConfig, KeccakHashConfig, PoseidonGoldilocksConfig, - PoseidonHashConfig, - }; + use crate::plonk::config::{GenericConfig, KeccakGoldilocksConfig, PoseidonGoldilocksConfig}; use crate::plonk::proof::{CompressedProofWithPublicInputs, ProofWithPublicInputs}; use crate::plonk::prover::prove; use crate::util::timing::TimingTree; @@ -208,15 +201,12 @@ mod tests { init_logger(); const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let config = CircuitConfig::standard_recursion_zk_config(); - let (proof, vd, cd) = dummy_proof::(&config, 4_000)?; - let (proof, vd, cd) = recursive_proof::( - proof, vd, cd, &config, None, true, true, - )?; + let (proof, vd, cd) = dummy_proof::(&config, 4_000)?; + let (proof, vd, cd) = + recursive_proof::(proof, vd, cd, &config, None, true, true)?; test_serialization(&proof, &vd, &cd)?; Ok(()) @@ -227,32 +217,22 @@ mod tests { init_logger(); const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); // Start with a degree 2^14 proof - let (proof, vd, cd) = dummy_proof::(&config, 16_000)?; + let (proof, vd, cd) = dummy_proof::(&config, 16_000)?; assert_eq!(cd.degree_bits(), 14); // Shrink it to 2^13. - let (proof, vd, cd) = recursive_proof::( - proof, - vd, - cd, - &config, - Some(13), - false, - false, - )?; + let (proof, vd, cd) = + recursive_proof::(proof, vd, cd, &config, Some(13), false, false)?; assert_eq!(cd.degree_bits(), 13); // Shrink it to 2^12. - let (proof, vd, cd) = recursive_proof::( - proof, vd, cd, &config, None, true, true, - )?; + let (proof, vd, cd) = + recursive_proof::(proof, vd, cd, &config, None, true, true)?; assert_eq!(cd.degree_bits(), 12); test_serialization(&proof, &vd, &cd)?; @@ -269,28 +249,17 @@ mod tests { const D: usize = 2; type C = PoseidonGoldilocksConfig; type KC = KeccakGoldilocksConfig; - type HCCO = PoseidonHashConfig; - type HCCI = HCCO; - type HCKCO = KeccakHashConfig; - type HCKCI = HCCI; - type F = >::F; + type F = >::F; let standard_config = CircuitConfig::standard_recursion_config(); // An initial dummy proof. - let (proof, vd, cd) = dummy_proof::(&standard_config, 4_000)?; + let (proof, vd, cd) = dummy_proof::(&standard_config, 4_000)?; assert_eq!(cd.degree_bits(), 12); // A standard recursive proof. - let (proof, vd, cd) = recursive_proof::( - proof, - vd, - cd, - &standard_config, - None, - false, - false, - )?; + let (proof, vd, cd) = + recursive_proof::(proof, vd, cd, &standard_config, None, false, false)?; assert_eq!(cd.degree_bits(), 12); // A high-rate recursive proof, designed to be verifiable with fewer routed wires. @@ -303,15 +272,8 @@ mod tests { }, ..standard_config }; - let (proof, vd, cd) = recursive_proof::( - proof, - vd, - cd, - &high_rate_config, - None, - true, - true, - )?; + let (proof, vd, cd) = + recursive_proof::(proof, vd, cd, &high_rate_config, None, true, true)?; assert_eq!(cd.degree_bits(), 12); // A final proof, optimized for size. @@ -326,15 +288,8 @@ mod tests { }, ..high_rate_config }; - let (proof, vd, cd) = recursive_proof::( - proof, - vd, - cd, - &final_config, - None, - true, - true, - )?; + let (proof, vd, cd) = + recursive_proof::(proof, vd, cd, &final_config, None, true, true)?; assert_eq!(cd.degree_bits(), 12, "final proof too large"); test_serialization(&proof, &vd, &cd)?; @@ -348,55 +303,43 @@ mod tests { const D: usize = 2; type PC = PoseidonGoldilocksConfig; type KC = KeccakGoldilocksConfig; - type HCCO = PoseidonHashConfig; - type HCCI = HCCO; - type HCKCO = KeccakHashConfig; - type HCKCI = HCCI; - type F = >::F; + type F = >::F; let config = CircuitConfig::standard_recursion_config(); - let (proof, vd, cd) = dummy_proof::(&config, 4_000)?; + let (proof, vd, cd) = dummy_proof::(&config, 4_000)?; - let (proof, vd, cd) = recursive_proof::( - proof, vd, cd, &config, None, false, false, - )?; + let (proof, vd, cd) = + recursive_proof::(proof, vd, cd, &config, None, false, false)?; test_serialization(&proof, &vd, &cd)?; - let (proof, vd, cd) = recursive_proof::( - proof, vd, cd, &config, None, false, false, - )?; + let (proof, vd, cd) = + recursive_proof::(proof, vd, cd, &config, None, false, false)?; test_serialization(&proof, &vd, &cd)?; Ok(()) } - type Proof = ( - ProofWithPublicInputs, - VerifierOnlyCircuitData, + type Proof = ( + ProofWithPublicInputs, + VerifierOnlyCircuitData, CommonCircuitData, ); /// Creates a dummy proof which should have roughly `num_dummy_gates` gates. - fn dummy_proof< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - >( + fn dummy_proof, C: GenericConfig, const D: usize>( config: &CircuitConfig, num_dummy_gates: u64, - ) -> Result> + ) -> Result> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let mut builder = CircuitBuilder::::new(config.clone()); for _ in 0..num_dummy_gates { builder.add_gate(NoopGate, vec![]); } - let data = builder.build::(); + let data = builder.build::(); let inputs = PartialWitness::new(); let proof = data.prove(inputs)?; data.verify(proof.clone())?; @@ -406,28 +349,24 @@ mod tests { fn recursive_proof< F: RichField + Extendable, - HCOO: HashConfig, - HCOI: HashConfig, - HCIO: HashConfig, - HCII: HashConfig, - C: GenericConfig, - InnerC: GenericConfig, + C: GenericConfig, + InnerC: GenericConfig, const D: usize, >( - inner_proof: ProofWithPublicInputs, - inner_vd: VerifierOnlyCircuitData, + inner_proof: ProofWithPublicInputs, + inner_vd: VerifierOnlyCircuitData, inner_cd: CommonCircuitData, config: &CircuitConfig, min_degree_bits: Option, print_gate_counts: bool, print_timing: bool, - ) -> Result> + ) -> Result> where - InnerC::Hasher: AlgebraicHasher, - [(); HCOO::WIDTH]:, - [(); HCOI::WIDTH]:, - [(); HCIO::WIDTH]:, - [(); HCII::WIDTH]:, + InnerC::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, + [(); InnerC::HCO::WIDTH]:, + [(); InnerC::HCI::WIDTH]:, { let mut builder = CircuitBuilder::::new(config.clone()); let mut pw = PartialWitness::new(); @@ -441,7 +380,7 @@ mod tests { ); pw.set_hash_target(inner_data.circuit_digest, inner_vd.circuit_digest); - builder.verify_proof::(&pt, &inner_data, &inner_cd); + builder.verify_proof::(&pt, &inner_data, &inner_cd); if print_gate_counts { builder.print_gate_counts(0); @@ -457,7 +396,7 @@ mod tests { } } - let data = builder.build::(); + let data = builder.build::(); let mut timing = TimingTree::new("prove", Level::Debug); let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?; @@ -473,18 +412,16 @@ mod tests { /// Test serialization and print some size info. fn test_serialization< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, >( - proof: &ProofWithPublicInputs, - vd: &VerifierOnlyCircuitData, + proof: &ProofWithPublicInputs, + vd: &VerifierOnlyCircuitData, cd: &CommonCircuitData, ) -> Result<()> where - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let proof_bytes = proof.to_bytes(); info!("Proof length: {} bytes", proof_bytes.len()); diff --git a/plonky2/src/util/reducing.rs b/plonky2/src/util/reducing.rs index 9bf4326b..aaf905d5 100644 --- a/plonky2/src/util/reducing.rs +++ b/plonky2/src/util/reducing.rs @@ -280,16 +280,14 @@ mod tests { use crate::field::types::Sample; use crate::iop::witness::{PartialWitness, WitnessWrite}; use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig}; + use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use crate::plonk::verifier::verify; fn test_reduce_gadget_base(n: usize) -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - type FF = >::FE; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); @@ -311,7 +309,7 @@ mod tests { builder.connect_extension(manual_reduce, circuit_reduce); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) @@ -320,10 +318,8 @@ mod tests { fn test_reduce_gadget(n: usize) -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; - type FF = >::FE; + type F = >::F; + type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); @@ -343,7 +339,7 @@ mod tests { builder.connect_extension(manual_reduce, circuit_reduce); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; verify(proof, &data.verifier_only, &data.common) diff --git a/plonky2/src/util/serialization.rs b/plonky2/src/util/serialization.rs index cf33caa5..5ef93835 100644 --- a/plonky2/src/util/serialization.rs +++ b/plonky2/src/util/serialization.rs @@ -149,15 +149,13 @@ pub trait Read { /// Reads a value of type [`OpeningSet`] from `self` with the given `common_data`. #[inline] - fn read_opening_set( + fn read_opening_set( &mut self, common_data: &CommonCircuitData, ) -> IoResult> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { let config = &common_data.config; let constants = self.read_field_ext_vec::(common_data.num_constants)?; @@ -199,15 +197,13 @@ pub trait Read { /// Reads a value of type [`FriInitialTreeProof`] from `self` with the given `common_data`. #[inline] - fn read_fri_initial_proof( + fn read_fri_initial_proof( &mut self, common_data: &CommonCircuitData, - ) -> IoResult> + ) -> IoResult> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { let config = &common_data.config; let salt = salt_size(common_data.fri_params.hiding); @@ -239,16 +235,14 @@ pub trait Read { /// Reads a value of type [`FriQueryStep`] from `self` with the given `arity` and `compressed` /// flag. #[inline] - fn read_fri_query_step( + fn read_fri_query_step( &mut self, arity: usize, compressed: bool, - ) -> IoResult> + ) -> IoResult> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { let evals = self.read_field_ext_vec::(arity - usize::from(compressed))?; let merkle_proof = self.read_merkle_proof()?; @@ -260,26 +254,24 @@ pub trait Read { /// Reads a vector of [`FriQueryRound`]s from `self` with `common_data`. #[inline] - fn read_fri_query_rounds( + #[allow(clippy::type_complexity)] + fn read_fri_query_rounds( &mut self, common_data: &CommonCircuitData, - ) -> IoResult>> + ) -> IoResult>> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { let config = &common_data.config; let mut fqrs = Vec::with_capacity(config.fri_config.num_query_rounds); for _ in 0..config.fri_config.num_query_rounds { - let initial_trees_proof = - self.read_fri_initial_proof::(common_data)?; + let initial_trees_proof = self.read_fri_initial_proof::(common_data)?; let steps = common_data .fri_params .reduction_arity_bits .iter() - .map(|&ar| self.read_fri_query_step::(1 << ar, false)) + .map(|&ar| self.read_fri_query_step::(1 << ar, false)) .collect::>()?; fqrs.push(FriQueryRound { initial_trees_proof, @@ -291,21 +283,19 @@ pub trait Read { /// Reads a value of type [`FriProof`] from `self` with `common_data`. #[inline] - fn read_fri_proof( + fn read_fri_proof( &mut self, common_data: &CommonCircuitData, - ) -> IoResult> + ) -> IoResult> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { let config = &common_data.config; let commit_phase_merkle_caps = (0..common_data.fri_params.reduction_arity_bits.len()) .map(|_| self.read_merkle_cap(config.fri_config.cap_height)) .collect::, _>>()?; - let query_round_proofs = self.read_fri_query_rounds::(common_data)?; + let query_round_proofs = self.read_fri_query_rounds::(common_data)?; let final_poly = PolynomialCoeffs::new( self.read_field_ext_vec::(common_data.fri_params.final_poly_len())?, ); @@ -320,22 +310,20 @@ pub trait Read { /// Reads a value of type [`Proof`] from `self` with `common_data`. #[inline] - fn read_proof( + fn read_proof( &mut self, common_data: &CommonCircuitData, - ) -> IoResult> + ) -> IoResult> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { let config = &common_data.config; let wires_cap = self.read_merkle_cap(config.fri_config.cap_height)?; let plonk_zs_partial_products_cap = self.read_merkle_cap(config.fri_config.cap_height)?; let quotient_polys_cap = self.read_merkle_cap(config.fri_config.cap_height)?; - let openings = self.read_opening_set::(common_data)?; - let opening_proof = self.read_fri_proof::(common_data)?; + let openings = self.read_opening_set::(common_data)?; + let opening_proof = self.read_fri_proof::(common_data)?; Ok(Proof { wires_cap, plonk_zs_partial_products_cap, @@ -347,16 +335,14 @@ pub trait Read { /// Reads a value of type [`ProofWithPublicInputs`] from `self` with `common_data`. #[inline] - fn read_proof_with_public_inputs( + fn read_proof_with_public_inputs( &mut self, common_data: &CommonCircuitData, - ) -> IoResult> + ) -> IoResult> where Self: Remaining, F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { let proof = self.read_proof(common_data)?; let public_inputs = self.read_field_vec(self.remaining() / size_of::())?; @@ -368,15 +354,13 @@ pub trait Read { /// Reads a value of type [`CompressedFriQueryRounds`] from `self` with `common_data`. #[inline] - fn read_compressed_fri_query_rounds( + fn read_compressed_fri_query_rounds( &mut self, common_data: &CommonCircuitData, - ) -> IoResult> + ) -> IoResult> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { let config = &common_data.config; let original_indices = (0..config.fri_config.num_query_rounds) @@ -387,10 +371,7 @@ pub trait Read { indices.dedup(); let mut pairs = Vec::new(); for &i in &indices { - pairs.push(( - i, - self.read_fri_initial_proof::(common_data)?, - )); + pairs.push((i, self.read_fri_initial_proof::(common_data)?)); } let initial_trees_proofs = HashMap::from_iter(pairs); @@ -401,7 +382,7 @@ pub trait Read { }); indices.dedup(); let query_steps = (0..indices.len()) - .map(|_| self.read_fri_query_step::(1 << a, true)) + .map(|_| self.read_fri_query_step::(1 << a, true)) .collect::, _>>()?; steps.push( indices @@ -421,22 +402,19 @@ pub trait Read { /// Reads a value of type [`CompressedFriProof`] from `self` with `common_data`. #[inline] - fn read_compressed_fri_proof( + fn read_compressed_fri_proof( &mut self, common_data: &CommonCircuitData, - ) -> IoResult> + ) -> IoResult> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { let config = &common_data.config; let commit_phase_merkle_caps = (0..common_data.fri_params.reduction_arity_bits.len()) .map(|_| self.read_merkle_cap(config.fri_config.cap_height)) .collect::, _>>()?; - let query_round_proofs = - self.read_compressed_fri_query_rounds::(common_data)?; + let query_round_proofs = self.read_compressed_fri_query_rounds::(common_data)?; let final_poly = PolynomialCoeffs::new( self.read_field_ext_vec::(common_data.fri_params.final_poly_len())?, ); @@ -451,22 +429,20 @@ pub trait Read { /// Reads a value of type [`CompressedProof`] from `self` with `common_data`. #[inline] - fn read_compressed_proof( + fn read_compressed_proof( &mut self, common_data: &CommonCircuitData, - ) -> IoResult> + ) -> IoResult> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { let config = &common_data.config; let wires_cap = self.read_merkle_cap(config.fri_config.cap_height)?; let plonk_zs_partial_products_cap = self.read_merkle_cap(config.fri_config.cap_height)?; let quotient_polys_cap = self.read_merkle_cap(config.fri_config.cap_height)?; - let openings = self.read_opening_set::(common_data)?; - let opening_proof = self.read_compressed_fri_proof::(common_data)?; + let openings = self.read_opening_set::(common_data)?; + let opening_proof = self.read_compressed_fri_proof::(common_data)?; Ok(CompressedProof { wires_cap, plonk_zs_partial_products_cap, @@ -478,16 +454,14 @@ pub trait Read { /// Reads a value of type [`CompressedProofWithPublicInputs`] from `self` with `common_data`. #[inline] - fn read_compressed_proof_with_public_inputs( + fn read_compressed_proof_with_public_inputs( &mut self, common_data: &CommonCircuitData, - ) -> IoResult> + ) -> IoResult> where Self: Remaining, F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { let proof = self.read_compressed_proof(common_data)?; let public_inputs = self.read_field_vec(self.remaining() / size_of::())?; @@ -625,15 +599,13 @@ pub trait Write { /// Writes a value `fitp` of type [`FriInitialTreeProof`] to `self.` #[inline] - fn write_fri_initial_proof( + fn write_fri_initial_proof( &mut self, - fitp: &FriInitialTreeProof, + fitp: &FriInitialTreeProof, ) -> IoResult<()> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { for (v, p) in &fitp.evals_proofs { self.write_field_vec(v)?; @@ -644,15 +616,13 @@ pub trait Write { /// Writes a value `fqs` of type [`FriQueryStep`] to `self.` #[inline] - fn write_fri_query_step( + fn write_fri_query_step( &mut self, - fqs: &FriQueryStep, + fqs: &FriQueryStep, ) -> IoResult<()> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { self.write_field_ext_vec::(&fqs.evals)?; self.write_merkle_proof(&fqs.merkle_proof) @@ -660,20 +630,18 @@ pub trait Write { /// Writes a value `fqrs` of type [`FriQueryRound`] to `self.` #[inline] - fn write_fri_query_rounds( + fn write_fri_query_rounds( &mut self, - fqrs: &[FriQueryRound], + fqrs: &[FriQueryRound], ) -> IoResult<()> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { for fqr in fqrs { - self.write_fri_initial_proof::(&fqr.initial_trees_proof)?; + self.write_fri_initial_proof::(&fqr.initial_trees_proof)?; for fqs in &fqr.steps { - self.write_fri_query_step::(fqs)?; + self.write_fri_query_step::(fqs)?; } } Ok(()) @@ -681,54 +649,45 @@ pub trait Write { /// Writes a value `fq` of type [`FriProof`] to `self.` #[inline] - fn write_fri_proof( + fn write_fri_proof( &mut self, - fp: &FriProof, + fp: &FriProof, ) -> IoResult<()> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { for cap in &fp.commit_phase_merkle_caps { self.write_merkle_cap(cap)?; } - self.write_fri_query_rounds::(&fp.query_round_proofs)?; + self.write_fri_query_rounds::(&fp.query_round_proofs)?; self.write_field_ext_vec::(&fp.final_poly.coeffs)?; self.write_field(fp.pow_witness) } /// Writes a value `proof` of type [`Proof`] to `self.` #[inline] - fn write_proof( - &mut self, - proof: &Proof, - ) -> IoResult<()> + fn write_proof(&mut self, proof: &Proof) -> IoResult<()> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { self.write_merkle_cap(&proof.wires_cap)?; self.write_merkle_cap(&proof.plonk_zs_partial_products_cap)?; self.write_merkle_cap(&proof.quotient_polys_cap)?; self.write_opening_set(&proof.openings)?; - self.write_fri_proof::(&proof.opening_proof) + self.write_fri_proof::(&proof.opening_proof) } /// Writes a value `proof_with_pis` of type [`ProofWithPublicInputs`] to `self.` #[inline] - fn write_proof_with_public_inputs( + fn write_proof_with_public_inputs( &mut self, - proof_with_pis: &ProofWithPublicInputs, + proof_with_pis: &ProofWithPublicInputs, ) -> IoResult<()> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { let ProofWithPublicInputs { proof, @@ -740,15 +699,13 @@ pub trait Write { /// Writes a value `cfqrs` of type [`CompressedFriQueryRounds`] to `self.` #[inline] - fn write_compressed_fri_query_rounds( + fn write_compressed_fri_query_rounds( &mut self, - cfqrs: &CompressedFriQueryRounds, + cfqrs: &CompressedFriQueryRounds, ) -> IoResult<()> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { for &i in &cfqrs.indices { self.write_u32(i as u32)?; @@ -756,13 +713,13 @@ pub trait Write { let mut initial_trees_proofs = cfqrs.initial_trees_proofs.iter().collect::>(); initial_trees_proofs.sort_by_key(|&x| x.0); for (_, itp) in initial_trees_proofs { - self.write_fri_initial_proof::(itp)?; + self.write_fri_initial_proof::(itp)?; } for h in &cfqrs.steps { let mut fri_query_steps = h.iter().collect::>(); fri_query_steps.sort_by_key(|&x| x.0); for (_, fqs) in fri_query_steps { - self.write_fri_query_step::(fqs)?; + self.write_fri_query_step::(fqs)?; } } Ok(()) @@ -770,54 +727,48 @@ pub trait Write { /// Writes a value `fq` of type [`CompressedFriProof`] to `self.` #[inline] - fn write_compressed_fri_proof( + fn write_compressed_fri_proof( &mut self, - fp: &CompressedFriProof, + fp: &CompressedFriProof, ) -> IoResult<()> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { for cap in &fp.commit_phase_merkle_caps { self.write_merkle_cap(cap)?; } - self.write_compressed_fri_query_rounds::(&fp.query_round_proofs)?; + self.write_compressed_fri_query_rounds::(&fp.query_round_proofs)?; self.write_field_ext_vec::(&fp.final_poly.coeffs)?; self.write_field(fp.pow_witness) } /// Writes a value `proof` of type [`CompressedProof`] to `self.` #[inline] - fn write_compressed_proof( + fn write_compressed_proof( &mut self, - proof: &CompressedProof, + proof: &CompressedProof, ) -> IoResult<()> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { self.write_merkle_cap(&proof.wires_cap)?; self.write_merkle_cap(&proof.plonk_zs_partial_products_cap)?; self.write_merkle_cap(&proof.quotient_polys_cap)?; self.write_opening_set(&proof.openings)?; - self.write_compressed_fri_proof::(&proof.opening_proof) + self.write_compressed_fri_proof::(&proof.opening_proof) } /// Writes a value `proof_with_pis` of type [`CompressedProofWithPublicInputs`] to `self.` #[inline] - fn write_compressed_proof_with_public_inputs( + fn write_compressed_proof_with_public_inputs( &mut self, - proof_with_pis: &CompressedProofWithPublicInputs, + proof_with_pis: &CompressedProofWithPublicInputs, ) -> IoResult<()> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, { let CompressedProofWithPublicInputs { proof, diff --git a/starky/src/fibonacci_stark.rs b/starky/src/fibonacci_stark.rs index d5a9ec34..86c5ace7 100644 --- a/starky/src/fibonacci_stark.rs +++ b/starky/src/fibonacci_stark.rs @@ -131,9 +131,7 @@ mod tests { use plonky2::iop::witness::PartialWitness; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; - use plonky2::plonk::config::{ - AlgebraicHasher, GenericConfig, PoseidonGoldilocksConfig, PoseidonHashConfig, - }; + use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, PoseidonGoldilocksConfig}; use plonky2::util::timing::TimingTree; use crate::config::StarkConfig; @@ -156,9 +154,7 @@ mod tests { fn test_fibonacci_stark() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = FibonacciStark; let config = StarkConfig::standard_fast_config(); @@ -166,7 +162,7 @@ mod tests { let public_inputs = [F::ZERO, F::ONE, fibonacci(num_rows - 1, F::ZERO, F::ONE)]; let stark = S::new(num_rows); let trace = stark.generate_trace(public_inputs[0], public_inputs[1]); - let proof = prove::( + let proof = prove::( stark, &config, trace, @@ -181,9 +177,7 @@ mod tests { fn test_fibonacci_stark_degree() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = FibonacciStark; let num_rows = 1 << 5; @@ -195,14 +189,12 @@ mod tests { fn test_fibonacci_stark_circuit() -> Result<()> { const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = FibonacciStark; let num_rows = 1 << 5; let stark = S::new(num_rows); - test_stark_circuit_constraints::(stark) + test_stark_circuit_constraints::(stark) } #[test] @@ -210,9 +202,7 @@ mod tests { init_logger(); const D: usize = 2; type C = PoseidonGoldilocksConfig; - type HCO = PoseidonHashConfig; - type HCI = HCO; - type F = >::F; + type F = >::F; type S = FibonacciStark; let config = StarkConfig::standard_fast_config(); @@ -220,7 +210,7 @@ mod tests { let public_inputs = [F::ZERO, F::ONE, fibonacci(num_rows - 1, F::ZERO, F::ONE)]; let stark = S::new(num_rows); let trace = stark.generate_trace(public_inputs[0], public_inputs[1]); - let proof = prove::( + let proof = prove::( stark, &config, trace, @@ -229,33 +219,29 @@ mod tests { )?; verify_stark_proof(stark, proof.clone(), &config)?; - recursive_proof::(stark, proof, &config, true) + recursive_proof::(stark, proof, &config, true) } fn recursive_proof< F: RichField + Extendable, - HCOO: HashConfig, - HCOI: HashConfig, - HCIO: HashConfig, - HCII: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark + Copy, - InnerC: GenericConfig, + InnerC: GenericConfig, const D: usize, >( stark: S, - inner_proof: StarkProofWithPublicInputs, + inner_proof: StarkProofWithPublicInputs, inner_config: &StarkConfig, print_gate_counts: bool, ) -> Result<()> where - InnerC::Hasher: AlgebraicHasher, + InnerC::Hasher: AlgebraicHasher, [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, - [(); HCOO::WIDTH]:, - [(); HCOI::WIDTH]:, - [(); HCIO::WIDTH]:, - [(); HCII::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, + [(); InnerC::HCO::WIDTH]:, + [(); InnerC::HCI::WIDTH]:, { let circuit_config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(circuit_config); @@ -264,18 +250,13 @@ mod tests { let pt = add_virtual_stark_proof_with_pis(&mut builder, stark, inner_config, degree_bits); set_stark_proof_with_pis_target(&mut pw, &pt, &inner_proof); - verify_stark_proof_circuit::( - &mut builder, - stark, - pt, - inner_config, - ); + verify_stark_proof_circuit::(&mut builder, stark, pt, inner_config); if print_gate_counts { builder.print_gate_counts(0); } - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; data.verify(proof) } diff --git a/starky/src/get_challenges.rs b/starky/src/get_challenges.rs index 2e6c86b6..eaa91c12 100644 --- a/starky/src/get_challenges.rs +++ b/starky/src/get_challenges.rs @@ -19,13 +19,13 @@ use crate::permutation::{ use crate::proof::*; use crate::stark::Stark; -fn get_challenges( +fn get_challenges( stark: &S, - trace_cap: &MerkleCap, - permutation_zs_cap: Option<&MerkleCap>, - quotient_polys_cap: &MerkleCap, + trace_cap: &MerkleCap, + permutation_zs_cap: Option<&MerkleCap>, + quotient_polys_cap: &MerkleCap, openings: &StarkOpeningSet, - commit_phase_merkle_caps: &[MerkleCap], + commit_phase_merkle_caps: &[MerkleCap], final_poly: &PolynomialCoeffs, pow_witness: F, config: &StarkConfig, @@ -33,16 +33,14 @@ fn get_challenges( ) -> StarkProofChallenges where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let num_challenges = config.num_challenges; - let mut challenger = Challenger::::new(); + let mut challenger = Challenger::::new(); challenger.observe_cap(trace_cap); @@ -67,7 +65,7 @@ where permutation_challenge_sets, stark_alphas, stark_zeta, - fri_challenges: challenger.fri_challenges::( + fri_challenges: challenger.fri_challenges::( commit_phase_merkle_caps, final_poly, pow_witness, @@ -77,14 +75,12 @@ where } } -impl StarkProofWithPublicInputs +impl StarkProofWithPublicInputs where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C: GenericConfig, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { // TODO: Should be used later in compression? #![allow(dead_code)] @@ -120,7 +116,7 @@ where }, } = &self.proof; - get_challenges::( + get_challenges::( stark, trace_cap, permutation_zs_cap.as_ref(), @@ -138,9 +134,7 @@ where #[allow(clippy::too_many_arguments)] pub(crate) fn get_challenges_target< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, const D: usize, >( @@ -156,13 +150,13 @@ pub(crate) fn get_challenges_target< config: &StarkConfig, ) -> StarkProofChallengesTarget where - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let num_challenges = config.num_challenges; - let mut challenger = RecursiveChallenger::::new(builder); + let mut challenger = RecursiveChallenger::::new(builder); challenger.observe_cap(trace_cap); @@ -201,9 +195,7 @@ where impl StarkProofWithPublicInputsTarget { pub(crate) fn get_challenges< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, >( &self, @@ -212,9 +204,9 @@ impl StarkProofWithPublicInputsTarget { config: &StarkConfig, ) -> StarkProofChallengesTarget where - C::Hasher: AlgebraicHasher, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + C::Hasher: AlgebraicHasher, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let StarkProofTarget { trace_cap, @@ -230,7 +222,7 @@ impl StarkProofWithPublicInputsTarget { }, } = &self.proof; - get_challenges_target::( + get_challenges_target::( builder, stark, trace_cap, @@ -246,13 +238,13 @@ impl StarkProofWithPublicInputsTarget { } // TODO: Deal with the compressed stuff. -// impl, C: GenericConfig, const D: usize> -// CompressedProofWithPublicInputs +// impl, C: GenericConfig, const D: usize> +// CompressedProofWithPublicInputs // { // /// Computes all Fiat-Shamir challenges used in the Plonk proof. // pub(crate) fn get_challenges( // &self, -// common_data: &CommonCircuitData, +// common_data: &CommonCircuitData, // ) -> anyhow::Result> { // let CompressedProof { // wires_cap, @@ -285,7 +277,7 @@ impl StarkProofWithPublicInputsTarget { // pub(crate) fn get_inferred_elements( // &self, // challenges: &ProofChallenges, -// common_data: &CommonCircuitData, +// common_data: &CommonCircuitData, // ) -> FriInferredElements { // let ProofChallenges { // plonk_zeta, @@ -308,7 +300,7 @@ impl StarkProofWithPublicInputsTarget { // for &(mut x_index) in fri_query_indices { // let mut subgroup_x = F::MULTIPLICATIVE_GROUP_GENERATOR // * F::primitive_root_of_unity(log_n).exp_u64(reverse_bits(x_index, log_n) as u64); -// let mut old_eval = fri_combine_initial::( +// let mut old_eval = fri_combine_initial::( // &common_data.get_fri_instance(*plonk_zeta), // &self // .proof diff --git a/starky/src/proof.rs b/starky/src/proof.rs index b6641c32..b19d6ac8 100644 --- a/starky/src/proof.rs +++ b/starky/src/proof.rs @@ -11,7 +11,6 @@ use plonky2::fri::structure::{ FriOpeningBatch, FriOpeningBatchTarget, FriOpenings, FriOpeningsTarget, }; use plonky2::hash::hash_types::{MerkleCapTarget, RichField}; -use plonky2::hash::hashing::HashConfig; use plonky2::hash::merkle_tree::MerkleCap; use plonky2::iop::ext_target::ExtensionTarget; use plonky2::iop::target::Target; @@ -22,33 +21,20 @@ use crate::config::StarkConfig; use crate::permutation::PermutationChallengeSet; #[derive(Debug, Clone)] -pub struct StarkProof< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, -> { +pub struct StarkProof, C: GenericConfig, const D: usize> { /// Merkle cap of LDEs of trace values. - pub trace_cap: MerkleCap, + pub trace_cap: MerkleCap, /// Merkle cap of LDEs of permutation Z values. - pub permutation_zs_cap: Option>, + pub permutation_zs_cap: Option>, /// Merkle cap of LDEs of trace values. - pub quotient_polys_cap: MerkleCap, + pub quotient_polys_cap: MerkleCap, /// Purported values of each polynomial at the challenge point. pub openings: StarkOpeningSet, /// A batch FRI argument for all openings. - pub opening_proof: FriProof, + pub opening_proof: FriProof, } -impl< - F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, - const D: usize, - > StarkProof -{ +impl, C: GenericConfig, const D: usize> StarkProof { /// Recover the length of the trace from a STARK proof and a STARK config. pub fn recover_degree_bits(&self, config: &StarkConfig) -> usize { let initial_merkle_proof = &self.opening_proof.query_round_proofs[0] @@ -83,12 +69,10 @@ impl StarkProofTarget { #[derive(Debug, Clone)] pub struct StarkProofWithPublicInputs< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, > { - pub proof: StarkProof, + pub proof: StarkProof, // TODO: Maybe make it generic over a `S: Stark` and replace with `[F; S::PUBLIC_INPUTS]`. pub public_inputs: Vec, } @@ -100,27 +84,23 @@ pub struct StarkProofWithPublicInputsTarget { pub struct CompressedStarkProof< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, > { /// Merkle cap of LDEs of trace values. - pub trace_cap: MerkleCap, + pub trace_cap: MerkleCap, /// Purported values of each polynomial at the challenge point. pub openings: StarkOpeningSet, /// A batch FRI argument for all openings. - pub opening_proof: CompressedFriProof, + pub opening_proof: CompressedFriProof, } pub struct CompressedStarkProofWithPublicInputs< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, const D: usize, > { - pub proof: CompressedStarkProof, + pub proof: CompressedStarkProof, pub public_inputs: Vec, } @@ -155,14 +135,14 @@ pub struct StarkOpeningSet, const D: usize> { } impl, const D: usize> StarkOpeningSet { - pub fn new>( + pub fn new>( zeta: F::Extension, g: F, - trace_commitment: &PolynomialBatch, - permutation_zs_commitment: Option<&PolynomialBatch>, - quotient_commitment: &PolynomialBatch, + trace_commitment: &PolynomialBatch, + permutation_zs_commitment: Option<&PolynomialBatch>, + quotient_commitment: &PolynomialBatch, ) -> Self { - let eval_commitment = |z: F::Extension, c: &PolynomialBatch| { + let eval_commitment = |z: F::Extension, c: &PolynomialBatch| { c.polynomials .par_iter() .map(|p| p.to_extension().eval(z)) diff --git a/starky/src/prover.rs b/starky/src/prover.rs index 885f244e..535cd76c 100644 --- a/starky/src/prover.rs +++ b/starky/src/prover.rs @@ -30,23 +30,21 @@ use crate::stark::Stark; use crate::vanishing_poly::eval_vanishing_poly; use crate::vars::StarkEvaluationVars; -pub fn prove( +pub fn prove( stark: S, config: &StarkConfig, trace_poly_values: Vec>, public_inputs: [F; S::PUBLIC_INPUTS], timing: &mut TimingTree, -) -> Result> +) -> Result> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { let degree = trace_poly_values[0].len(); let degree_bits = log2_strict(degree); @@ -61,7 +59,7 @@ where let trace_commitment = timed!( timing, "compute trace commitment", - PolynomialBatch::::from_values( + PolynomialBatch::::from_values( // TODO: Cloning this isn't great; consider having `from_values` accept a reference, // or having `compute_permutation_z_polys` read trace values from the `PolynomialBatch`. trace_poly_values.clone(), @@ -116,7 +114,7 @@ where } let alphas = challenger.get_n_challenges(config.num_challenges); - let quotient_polys = compute_quotient_polys::::Packing, HCO, HCI, C, S, D>( + let quotient_polys = compute_quotient_polys::::Packing, C, S, D>( &stark, &trace_commitment, &permutation_zs_commitment_challenges, @@ -200,11 +198,11 @@ where /// Computes the quotient polynomials `(sum alpha^i C_i(x)) / Z_H(x)` for `alpha` in `alphas`, /// where the `C_i`s are the Stark constraints. -fn compute_quotient_polys<'a, F, P, HCO, HCI, C, S, const D: usize>( +fn compute_quotient_polys<'a, F, P, C, S, const D: usize>( stark: &S, - trace_commitment: &'a PolynomialBatch, + trace_commitment: &'a PolynomialBatch, permutation_zs_commitment_challenges: &'a Option<( - PolynomialBatch, + PolynomialBatch, Vec>, )>, public_inputs: [F; S::PUBLIC_INPUTS], @@ -215,9 +213,7 @@ fn compute_quotient_polys<'a, F, P, HCO, HCI, C, S, const D: usize>( where F: RichField + Extendable, P: PackedField, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, diff --git a/starky/src/recursive_verifier.rs b/starky/src/recursive_verifier.rs index 0de9e652..8daeabb8 100644 --- a/starky/src/recursive_verifier.rs +++ b/starky/src/recursive_verifier.rs @@ -28,9 +28,7 @@ use crate::vars::StarkEvaluationTargets; pub fn verify_stark_proof_circuit< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, const D: usize, >( @@ -39,21 +37,21 @@ pub fn verify_stark_proof_circuit< proof_with_pis: StarkProofWithPublicInputsTarget, inner_config: &StarkConfig, ) where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { assert_eq!(proof_with_pis.public_inputs.len(), S::PUBLIC_INPUTS); let degree_bits = proof_with_pis.proof.recover_degree_bits(inner_config); let challenges = with_context!( builder, "compute challenges", - proof_with_pis.get_challenges::(builder, &stark, inner_config) + proof_with_pis.get_challenges::(builder, &stark, inner_config) ); - verify_stark_proof_with_challenges_circuit::( + verify_stark_proof_with_challenges_circuit::( builder, stark, proof_with_pis, @@ -66,9 +64,7 @@ pub fn verify_stark_proof_circuit< /// Recursively verifies an inner proof. fn verify_stark_proof_with_challenges_circuit< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, const D: usize, >( @@ -79,10 +75,10 @@ fn verify_stark_proof_with_challenges_circuit< inner_config: &StarkConfig, degree_bits: usize, ) where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, - [(); HCO::WIDTH]:, + [(); C::HCO::WIDTH]:, { check_permutation_options(&stark, &proof_with_pis, &challenges).unwrap(); let one = builder.one_extension(); @@ -169,7 +165,7 @@ fn verify_stark_proof_with_challenges_circuit< F::primitive_root_of_unity(degree_bits), inner_config, ); - builder.verify_fri_proof::( + builder.verify_fri_proof::( &fri_instance, &proof.openings.to_fri_openings(), &challenges.fri_challenges, @@ -267,22 +263,13 @@ fn add_stark_opening_set_target, S: Stark, co } } -pub fn set_stark_proof_with_pis_target< - F, - HCO, - HCI, - C: GenericConfig, - W, - const D: usize, ->( +pub fn set_stark_proof_with_pis_target, W, const D: usize>( witness: &mut W, stark_proof_with_pis_target: &StarkProofWithPublicInputsTarget, - stark_proof_with_pis: &StarkProofWithPublicInputs, + stark_proof_with_pis: &StarkProofWithPublicInputs, ) where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, W: Witness, { let StarkProofWithPublicInputs { @@ -302,22 +289,13 @@ pub fn set_stark_proof_with_pis_target< set_stark_proof_target(witness, pt, proof); } -pub fn set_stark_proof_target< - F, - HCO, - HCI, - C: GenericConfig, - W, - const D: usize, ->( +pub fn set_stark_proof_target, W, const D: usize>( witness: &mut W, proof_target: &StarkProofTarget, - proof: &StarkProof, + proof: &StarkProof, ) where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, W: Witness, { witness.set_cap_target(&proof_target.trace_cap, &proof.trace_cap); diff --git a/starky/src/stark_testing.rs b/starky/src/stark_testing.rs index e815a1be..227a8574 100644 --- a/starky/src/stark_testing.rs +++ b/starky/src/stark_testing.rs @@ -81,9 +81,7 @@ where /// Tests that the circuit constraints imposed by the given STARK are coherent with the native constraints. pub fn test_stark_circuit_constraints< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, const D: usize, >( @@ -92,8 +90,8 @@ pub fn test_stark_circuit_constraints< where [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { // Compute native constraint evaluation on random values. let vars = StarkEvaluationVars { @@ -155,7 +153,7 @@ where let native_eval_t = builder.constant_extension(native_eval); builder.connect_extension(circuit_eval, native_eval_t); - let data = builder.build::(); + let data = builder.build::(); let proof = data.prove(pw)?; data.verify(proof) } diff --git a/starky/src/verifier.rs b/starky/src/verifier.rs index 0b53cec9..a6e0de54 100644 --- a/starky/src/verifier.rs +++ b/starky/src/verifier.rs @@ -21,21 +21,19 @@ use crate::vars::StarkEvaluationVars; pub fn verify_stark_proof< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, const D: usize, >( stark: S, - proof_with_pis: StarkProofWithPublicInputs, + proof_with_pis: StarkProofWithPublicInputs, config: &StarkConfig, ) -> Result<()> where [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, - [(); HCO::WIDTH]:, - [(); HCI::WIDTH]:, + [(); C::HCO::WIDTH]:, + [(); C::HCI::WIDTH]:, { ensure!(proof_with_pis.public_inputs.len() == S::PUBLIC_INPUTS); let degree_bits = proof_with_pis.proof.recover_degree_bits(config); @@ -45,14 +43,12 @@ where pub(crate) fn verify_stark_proof_with_challenges< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, const D: usize, >( stark: S, - proof_with_pis: StarkProofWithPublicInputs, + proof_with_pis: StarkProofWithPublicInputs, challenges: StarkProofChallenges, degree_bits: usize, config: &StarkConfig, @@ -60,7 +56,7 @@ pub(crate) fn verify_stark_proof_with_challenges< where [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, - [(); HCO::WIDTH]:, + [(); C::HCO::WIDTH]:, { validate_proof_shape(&stark, &proof_with_pis, config)?; check_permutation_options(&stark, &proof_with_pis, &challenges)?; @@ -136,7 +132,7 @@ where .chain(once(proof.quotient_polys_cap)) .collect_vec(); - verify_fri_proof::( + verify_fri_proof::( &stark.fri_instance( challenges.stark_zeta, F::primitive_root_of_unity(degree_bits), @@ -152,16 +148,14 @@ where Ok(()) } -fn validate_proof_shape( +fn validate_proof_shape( stark: &S, - proof_with_pis: &StarkProofWithPublicInputs, + proof_with_pis: &StarkProofWithPublicInputs, config: &StarkConfig, ) -> anyhow::Result<()> where F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, [(); S::COLUMNS]:, { @@ -241,14 +235,12 @@ fn eval_l_0_and_l_last(log_n: usize, x: F) -> (F, F) { /// the Stark uses a permutation argument. fn check_permutation_options< F: RichField + Extendable, - HCO: HashConfig, - HCI: HashConfig, - C: GenericConfig, + C: GenericConfig, S: Stark, const D: usize, >( stark: &S, - proof_with_pis: &StarkProofWithPublicInputs, + proof_with_pis: &StarkProofWithPublicInputs, challenges: &StarkProofChallenges, ) -> Result<()> { let options_is_some = [ From 209c1ff1e3111e0c113852f397a0b059cf102020 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Sat, 1 Apr 2023 17:33:57 -0700 Subject: [PATCH 20/20] Remove extra conditions Since the structs themselves have `[(); HC::WIDTH]:`. --- plonky2/src/iop/challenger.rs | 120 ++++++++-------------------------- 1 file changed, 29 insertions(+), 91 deletions(-) diff --git a/plonky2/src/iop/challenger.rs b/plonky2/src/iop/challenger.rs index 499538a9..6a39b351 100644 --- a/plonky2/src/iop/challenger.rs +++ b/plonky2/src/iop/challenger.rs @@ -35,10 +35,7 @@ impl> Challenger where [(); HC::WIDTH]:, { - pub fn new() -> Challenger - where - [(); HC::WIDTH]:, - { + pub fn new() -> Challenger { Challenger { sponge_state: [F::ZERO; HC::WIDTH], input_buffer: Vec::with_capacity(HC::RATE), @@ -47,10 +44,7 @@ where } } - pub fn observe_element(&mut self, element: F) - where - [(); HC::WIDTH]:, - { + pub fn observe_element(&mut self, element: F) { // Any buffered outputs are now invalid, since they wouldn't reflect this input. self.output_buffer.clear(); @@ -64,15 +58,11 @@ where pub fn observe_extension_element(&mut self, element: &F::Extension) where F: RichField + Extendable, - [(); HC::WIDTH]:, { self.observe_elements(&element.to_basefield_array()); } - pub fn observe_elements(&mut self, elements: &[F]) - where - [(); HC::WIDTH]:, - { + pub fn observe_elements(&mut self, elements: &[F]) { for &element in elements { self.observe_element(element); } @@ -88,26 +78,20 @@ where } } - pub fn observe_hash>(&mut self, hash: OH::Hash) - where - [(); OHC::WIDTH]:, - { + pub fn observe_hash>(&mut self, hash: OH::Hash) { self.observe_elements(&hash.to_vec()) } - pub fn observe_cap>(&mut self, cap: &MerkleCap) - where - [(); OHC::WIDTH]:, - { + pub fn observe_cap>( + &mut self, + cap: &MerkleCap, + ) { for &hash in &cap.0 { self.observe_hash::(hash); } } - pub fn get_challenge(&mut self) -> F - where - [(); HC::WIDTH]:, - { + pub fn get_challenge(&mut self) -> F { // 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() { @@ -119,17 +103,11 @@ where .expect("Output buffer should be non-empty") } - pub fn get_n_challenges(&mut self, n: usize) -> Vec - where - [(); HC::WIDTH]:, - { + pub fn get_n_challenges(&mut self, n: usize) -> Vec { (0..n).map(|_| self.get_challenge()).collect() } - pub fn get_hash(&mut self) -> HashOut - where - [(); HC::WIDTH]:, - { + pub fn get_hash(&mut self) -> HashOut { HashOut { elements: [ self.get_challenge(), @@ -143,7 +121,6 @@ where pub fn get_extension_challenge(&mut self) -> F::Extension where F: RichField + Extendable, - [(); HC::WIDTH]:, { let mut arr = [F::ZERO; D]; arr.copy_from_slice(&self.get_n_challenges(D)); @@ -153,7 +130,6 @@ where pub fn get_n_extension_challenges(&mut self, n: usize) -> Vec where F: RichField + Extendable, - [(); HC::WIDTH]:, { (0..n) .map(|_| self.get_extension_challenge::()) @@ -162,10 +138,7 @@ where /// Absorb any buffered inputs. After calling this, the input buffer will be empty, and the /// output buffer will be full. - fn duplexing(&mut self) - where - [(); HC::WIDTH]:, - { + fn duplexing(&mut self) { assert!(self.input_buffer.len() <= HC::RATE); // Overwrite the first r elements with the inputs. This differs from a standard sponge, @@ -196,10 +169,7 @@ impl> Default for Challe where [(); HC::WIDTH]:, { - fn default() -> Self - where - [(); HC::WIDTH]:, - { + fn default() -> Self { Self::new() } } @@ -226,10 +196,7 @@ impl, HC: HashConfig, H: AlgebraicHasher, co where [(); HC::WIDTH]:, { - pub fn new(builder: &mut CircuitBuilder) -> Self - where - [(); HC::WIDTH]:, - { + pub fn new(builder: &mut CircuitBuilder) -> Self { let zero = builder.zero(); Self { sponge_state: [zero; HC::WIDTH], @@ -248,61 +215,40 @@ where } } - pub(crate) fn observe_element(&mut self, target: Target) - where - [(); HC::WIDTH]:, - { + pub(crate) fn observe_element(&mut self, target: Target) { // Any buffered outputs are now invalid, since they wouldn't reflect this input. self.output_buffer.clear(); self.input_buffer.push(target); } - pub fn observe_elements(&mut self, targets: &[Target]) - where - [(); HC::WIDTH]:, - { + pub fn observe_elements(&mut self, targets: &[Target]) { for &target in targets { self.observe_element(target); } } - pub fn observe_hash(&mut self, hash: &HashOutTarget) - where - [(); HC::WIDTH]:, - { + pub fn observe_hash(&mut self, hash: &HashOutTarget) { self.observe_elements(&hash.elements) } - pub fn observe_cap(&mut self, cap: &MerkleCapTarget) - where - [(); HC::WIDTH]:, - { + pub fn observe_cap(&mut self, cap: &MerkleCapTarget) { for hash in &cap.0 { self.observe_hash(hash) } } - pub fn observe_extension_element(&mut self, element: ExtensionTarget) - where - [(); HC::WIDTH]:, - { + pub fn observe_extension_element(&mut self, element: ExtensionTarget) { self.observe_elements(&element.0); } - pub fn observe_extension_elements(&mut self, elements: &[ExtensionTarget]) - where - [(); HC::WIDTH]:, - { + pub fn observe_extension_elements(&mut self, elements: &[ExtensionTarget]) { for &element in elements { self.observe_extension_element(element); } } - pub fn get_challenge(&mut self, builder: &mut CircuitBuilder) -> Target - where - [(); HC::WIDTH]:, - { + pub fn get_challenge(&mut self, builder: &mut CircuitBuilder) -> Target { self.absorb_buffered_inputs(builder); if self.output_buffer.is_empty() { @@ -316,17 +262,15 @@ where .expect("Output buffer should be non-empty") } - pub fn get_n_challenges(&mut self, builder: &mut CircuitBuilder, n: usize) -> Vec - where - [(); HC::WIDTH]:, - { + pub fn get_n_challenges( + &mut self, + builder: &mut CircuitBuilder, + n: usize, + ) -> Vec { (0..n).map(|_| self.get_challenge(builder)).collect() } - pub fn get_hash(&mut self, builder: &mut CircuitBuilder) -> HashOutTarget - where - [(); HC::WIDTH]:, - { + pub fn get_hash(&mut self, builder: &mut CircuitBuilder) -> HashOutTarget { HashOutTarget { elements: [ self.get_challenge(builder), @@ -340,19 +284,13 @@ where pub fn get_extension_challenge( &mut self, builder: &mut CircuitBuilder, - ) -> ExtensionTarget - where - [(); HC::WIDTH]:, - { + ) -> ExtensionTarget { self.get_n_challenges(builder, D).try_into().unwrap() } /// Absorb any buffered inputs. After calling this, the input buffer will be empty, and the /// output buffer will be full. - fn absorb_buffered_inputs(&mut self, builder: &mut CircuitBuilder) - where - [(); HC::WIDTH]:, - { + fn absorb_buffered_inputs(&mut self, builder: &mut CircuitBuilder) { if self.input_buffer.is_empty() { return; }