Validium Docs
  • Overview
  • Connect to Validium
  • Start Coding 🚀
    • Quickstart
      • Overview
      • Deploy using Validium CLI
      • Deploy using Quickstart Repository
      • Deploy your first contract
      • Create an ERC20 token
  • Tooling
    • Block Explorers
    • Hardhat-Validium
      • Overview
      • Installation
      • Guides
        • Getting started
        • Migrating Hardhat project to Validium
        • Compiling non-inlinable libraries
      • Plugins
        • hardhat-zksync
        • hardhat-zksync-solc
        • hardhat-zksync-vyper
        • hardhat-zksync-deploy
        • hardhat-zksync-upgradable
        • hardhat-zksync-verify
        • hardhat-zksync-verify-vyper
        • hardhat-zksync-ethers
        • hardhat-zksync-node
        • Hardhat Community Plugins
    • Foundary
      • Overview
      • Installation
      • Getting Started
      • Migration Guide
        • Overview
        • Compilation
        • Deployment
        • Testing
  • Test and Debug
    • Getting Started
    • Docker L1 - L2 Nodes
    • In-Memory Node
    • Continuous Integration
    • Hardhat
    • Foundry
  • API Reference
    • Overview
    • Conventions
    • ZKs JSON-RPC API
    • Debug JSON-RPC API
    • Ethereum JSON-RPC API
    • PubSub JSON-RPC API
  • Concepts
    • Transaction Lifecycle
    • Blocks and Batches
    • Validium Network Fee Mechanism
    • Finality
    • System Upgrades
    • ZK Chains
    • Data Availability
      • Overview
      • Recreating L2 state from L1 pubdata
      • Validiums
    • Account Abstraction
    • L1 <-> L2 Communication
  • Components
    • Overview
    • Smart & System Contracts
      • Smart Contracts
      • System Contracts
    • Shared Bridges
    • Sequencer / Server
    • Validium Network EVM
      • Overview
      • Bootloader
      • Precompiles
      • Virtual Machine Specification
        • ZKsync Virtual Machine primer
        • VM Formal Specification
    • Prover
      • Overview
      • ZK Terminology
      • Running the Prover
      • Circuits
        • Overview
        • Circuit Testing
        • CodeDecommitter
        • DemuxLogQueue
        • ECRecover
        • KeccakRoundFunction
        • L1MessagesHasher
        • LogSorter
        • Main VM
        • RAMPermutation
        • Sha256RoundFunction
        • StorageApplication
        • Sorting and Deduplicating
          • Overview
          • SortDecommitments
          • StorageSorter
          • LogSorter
      • Boojum Gadgets
      • Boojum Function - `check_if_satisfied`
    • Compiler
      • Compiler Toolchain Overview
        • Compiler Toolchain Overview
        • Solidity Compiler
        • Vyper Compiler
        • LLVM Framework
      • Specification
        • Overview
        • Code Separation
        • System Contracts
        • Exception Handling
        • EVM Legacy Assembly Translator
        • Instructions
          • Instruction Reference
          • EVM
            • Native EVM Instructions
            • Arithmetic
            • Bitwise
            • Block
            • Call
            • Create
            • Environment
            • Logging
            • Logical
            • Memory
            • Return
            • Sha3
            • Stack
          • Extensions
            • Overview
            • Validium Network Extension Simulation (call)
            • Validium Network Extension Simulation (verbatim)
          • EVM Legacy Assembly
          • Yul
        • EraVM Binary Layout
    • Fee Withdrawer
    • Portal - Wallet + Bridge
    • Block Explorer
    • Transaction filtering
Powered by GitBook
On this page
  • CodeDecommitter PI
  • Input
  • Output
  • FSM Input and FSM Output
  • Main circuit logic
  • First part
  • Main part
  • Final part
  1. Components
  2. Prover
  3. Circuits

CodeDecommitter

PreviousCircuit TestingNextDemuxLogQueue

Last updated 8 months ago


CodeDecommitter PI

Input

pub struct CodeDecommitterInputData<F: SmallField> {
    pub memory_queue_initial_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>,
    pub sorted_requests_queue_initial_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>,
}

Output

pub struct CodeDecommitterOutputData<F: SmallField> {
    pub memory_queue_final_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>,
}

FSM Input and FSM Output

pub struct CodeDecommitterFSMInputOutput<F: SmallField> {
    pub internal_fsm: CodeDecommittmentFSM<F>,
    pub decommittment_requests_queue_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>,
    pub memory_queue_state: QueueState<F, FULL_SPONGE_QUEUE_STATE_WIDTH>,
}

pub struct CodeDecommittmentFSM<F: SmallField> {
    pub sha256_inner_state: [UInt32<F>; 8], // 8 uint32 words of internal sha256 state
    pub hash_to_compare_against: UInt256<F>,
    pub current_index: UInt32<F>,
    pub current_page: UInt32<F>,
    pub timestamp: UInt32<F>,
    pub num_rounds_left: UInt16<F>,
    pub length_in_bits: UInt32<F>,
    pub state_get_from_queue: Boolean<F>,
    pub state_decommit: Boolean<F>,
    pub finished: Boolean<F>,
}

Main circuit logic

This circuit takes a queue of decommit requests for DecommitSorter circuit. For each decommit request, it checks that the linear hash of all opcodes will be equal to this hash that is stored in the decommit request. Also, it writes code to the corresponding memory page. Briefly, it unpacks the queue from the opcode and updates the memory queue and check correctness.

First part

The circuit begins with allocating input part of the PI.

let CodeDecommitterCircuitInstanceWitness {
    closed_form_input,
    sorted_requests_queue_witness,
    code_words,
} = witness;

let mut structured_input =
    CodeDecommitterCycleInputOutput::alloc_ignoring_outputs(cs, closed_form_input.clone());

We chose what memory_queue state and decommitments_queue state to continue to work with.

let requests_queue_state = QueueState::conditionally_select(
    cs,
    structured_input.start_flag,
    &structured_input
        .observable_input
        .sorted_requests_queue_initial_state,
    &structured_input
        .hidden_fsm_input
        .decommittment_requests_queue_state,
);

let memory_queue_state = QueueState::conditionally_select(
    cs,
    structured_input.start_flag,
    &structured_input.observable_input.memory_queue_initial_state,
    &structured_input.hidden_fsm_input.memory_queue_state,
);

We do the same with inner FSM part.

let initial_state = CodeDecommittmentFSM::conditionally_select(
    cs,
    structured_input.start_flag,
    &starting_fsm_state,
    &structured_input.hidden_fsm_input.internal_fsm,
);

Main part

Here’s the part, where all the main logic is implemented. Firstly, we take a new decommit request if the queue is not empty yet.

let (may_be_new_request, _) =
    unpack_requests_queue.pop_front(cs, state.state_get_from_queue);

Then we update the state of the circuit.

state.num_rounds_left = UInt16::conditionally_select(
    cs,
    state.state_get_from_queue,
    &length_in_rounds,
    &state.num_rounds_left,
);
...

Then we create two write memory queries and push them to memory queue.

let mem_query_0 = MemoryQuery {
    timestamp: state.timestamp,
    memory_page: state.current_page,
    index: state.current_index,
    rw_flag: boolean_true,
    value: code_word_0,
    is_ptr: boolean_false,
};

let mem_query_1 = MemoryQuery {
    timestamp: state.timestamp,
    memory_page: state.current_page,
    index: state.current_index,
    rw_flag: boolean_true,
    value: code_word_1,
    is_ptr: boolean_false,
};

memory_queue.push(cs, mem_query_0, state.state_decommit);
memory_queue.push(cs, mem_query_1, process_second_word);

Now we create a new input for hash to be absorbed.

let mut sha256_input = [zero_u32; 16];
for (dst, src) in sha256_input.iter_mut().zip(
    code_word_0_be_bytes
        .array_chunks::<4>()
        .chain(code_word_1_be_bytes.array_chunks::<4>()),
) {
    *dst = UInt32::from_be_bytes(cs, *src);
}

And absorb it to current state.

let mut new_internal_state = state.sha256_inner_state;
round_function_over_uint32(cs, &mut new_internal_state, &sha256_input);

Also, we update current state.

state.sha256_inner_state = <[UInt32<F>; 8]>::conditionally_select(
    cs,
    state.state_decommit,
    &new_internal_state,
    &state.sha256_inner_state,
);

Finally, we check the hash if necessary.

for (part_of_first, part_of_second) in hash
    .inner
    .iter()
    .zip(state.hash_to_compare_against.inner.iter())
{
    Num::conditionally_enforce_equal(
        cs,
        finalize,
        &part_of_first.into_num(),
        &part_of_second.into_num(),
    );
}

Final part

Now we update PI output parts and compute a commitment. Then we allocate it as public variables.

let compact_form =
    ClosedFormInputCompactForm::from_full_form(cs, &structured_input, round_function);

let input_commitment = commit_variable_length_encodable_item(cs, &compact_form, round_function);
for el in input_commitment.iter() {
    let gate = PublicInputGate::new(el.get_variable());
    gate.add_to_cs(cs);
}

GitHub
GitHub
GitHub
GitrustHub
GitHub
GitHub