o1-labs / o1js

TypeScript framework for zk-SNARKs and zkApps
https://docs.minaprotocol.com/en/zkapps/how-to-write-a-zkapp
Apache License 2.0
509 stars 116 forks source link

Clarify State Hash Derivation Process for Lambda #1756

Closed MartinMinkov closed 4 days ago

MartinMinkov commented 3 months ago

We need to provide a detailed explanation of how the stateHash is derived in our OCaml code for Lambda's implementation of the Mina-EVM bridge. There's a specific focus on two functions mentioned in our documentation but not fully explained: poseidon_3w_hash and to_roinput.

Objective:

Provide a clear and comprehensive explanation of the stateHash derivation process, including detailed information about the poseidon_3w_hash and to_roinput functions.

Key Points to Address:

Explain the overall process of deriving the stateHash.

Provide details on the poseidon_3w_hash function:

  1. Its purpose and usage in the state hash derivation
  2. Implementation details
  3. Any specific parameters or configurations

Clarify the to_roinput function:

  1. Its role in preparing data for hashing
  2. How it's implemented
  3. What type of input it expects and what it outputs

Describe how these functions interact in the state hash derivation process.

MartinMinkov commented 2 months ago

It's important to note that the documentation mentioning poseidon_3w_hash and to_roinput is incorrect and outdated. These functions are not used in the current implementation of the state hash derivation.

The actual process for deriving the stateHash is as follows:

  1. The state hash is computed in the hashes_abstract function within the Protocol_state module. Here's the relevant code:

    let hashes_abstract ~hash_body
       ({ previous_state_hash; body } : (State_hash.t, _) Poly.t) =
     let state_body_hash : State_body_hash.t = hash_body body in
     let state_hash =
       Random_oracle.hash ~init:Hash_prefix.protocol_state
         [| (previous_state_hash :> Field.t); (state_body_hash :> Field.t) |]
       |> State_hash.of_hash
     in
     { State_hash.State_hashes.state_hash
     ; state_body_hash = Some state_body_hash
     }
  2. The stateHash (referred to as state_hash in the code) is computed using the following steps: a. It takes two inputs: previous_state_hash and body. b. It first calculates the state_body_hash by calling the hash_body function on the body. c. It then uses a Random_oracle.hash function to compute the state_hash. d. The Random_oracle.hash function is initialized with Hash_prefix.protocol_state. e. The hash function takes an array of two elements:

    • The previous_state_hash converted to a Field.t type
    • The state_body_hash converted to a Field.t type

    f. The result is then converted to a State_hash.t type using State_hash.of_hash.

  3. In the context of the blockchain snark, the hash_checked function is used to compute and verify the state hash within the SNARK circuit. This function is called in the step function of the blockchain snark:

    let%bind previous_state_hash, body = Protocol_state.hash_checked t in

    And later:

    let%bind h, _ = Protocol_state.hash_checked t in
    with_label __LOC__ (fun () -> State_hash.assert_equal h new_state_hash)