Mina代码解析

1. 引言

Mina系列博客有:

代码为:

下载所有子模块:

git submodule update --init --recursive

安装opam依赖项:

./scripts/setup-opam.sh

编译:【若有deprecated报错,安装指定版本的依赖包】

make build

运行:

$ dune exe src/app/cli/src/mina.exe -- h
Mina

  mina.exe SUBCOMMAND

=== subcommands ===

  accounts                    Client commands concerning account management
  daemon                      Mina daemon
  client                      Lightweight client commands
  advanced                    Advanced client commands
  ledger                      Ledger commands
  internal                    Internal commands
  parallel-worker             internal use only
  transaction-snark-profiler  transaction snark profiler
  integration-tests           Integration tests
  version                     print version information
  help                        explain a given subcommand (perhaps recursively)

以berkeley测试版为例:

$ dune exe src/app/cli/src/mina.exe -- daemon --peer-list-url https://storage.googleapis.com/seed-lists/berkeley_seeds.txt --log-level Spam --log-precomputed-blocks true

日志中有:

2022-05-18 07:02:53 UTC [Trace] Creating "genesis_ledger" tar file for $root_hash at $path from database at $dir
        root_hash: "3NK3k3gCGsZUewCqaRZHqVyaGg21MiPL2kAoNjZzfZaPfwmqWNz1"
        path: "/Users/lanyu/.mina-config/genesis/genesis_ledger_f3cd103c5bbbfeb0857cd88a9b91c46c73c4f2606e2f03bda215896b64802329.tar.gz"
        dir: "/var/folders/p5/bmmxtx5x14j_6znwywzj09w40000gn/T/coda_cache_dir/31779af9-9961-38d3-6cb0-240bca103016"

1.1 Pickles proof system中的inductive_rule

Pickles proof system中的inductive_rule表示为:

(* This type models an "inductive rule". It includes
   - the list of previous statements which this one assumes
   - the snarky main function
   - an unchecked version of the main function which computes the "should verify" flags that
     allow predecessor proofs to conditionally fail to verify
*)
type ('prev_vars, 'prev_values, 'widths, 'heights, 'a_var, 'a_value) t =
  { identifier : string
  ; prevs : ('prev_vars, 'prev_values, 'widths, 'heights) H4.T(Tag).t
  ; main : 'prev_vars H1.T(Id).t -> 'a_var -> 'prev_vars H1.T(E01(B)).t
  ; main_value :
      'prev_values H1.T(Id).t -> 'a_value -> 'prev_vars H1.T(E01(Bool)).t
  }

1.2 Pickles tag

Pickles tag结构为:

type ('var, 'value, 'n1, 'n2) tag = ('var * 'value * 'n1 * 'n2) Type_equal.Id.t

(* Type_equal.Id.t为: *)
type 'a t =
    { witness : 'a Witness.t
    ; name : string
    ; to_sexp : 'a -> Sexp.t
    }

type kind = Side_loaded | Compiled

type ('var, 'value, 'n1, 'n2) t =
  { kind : kind; id : ('var, 'value, 'n1, 'n2) tag }

1.3 生成和验证proof的秘钥

获得生成和验证proof所需秘钥的方式有:

let cache =
  let dir d w = Key_cache.Spec.On_disk { directory = d; should_write = w } in
  [ dir manual_install_path false (* "/var/lib/coda" *)
  ; dir brew_install_path false (* "/usr/local/var/coda" 或mac系统为:brew ^ "/var/coda" *)
  ; dir s3_install_path false (* "/tmp/s3_cache_dir" *)
  ; dir autogen_path true (* Filename.temp_dir_name ^/ "coda_cache_dir" *)
  ; Key_cache.Spec.S3
      { bucket_prefix = s3_keys_bucket_prefix; install_path = s3_install_path } (* "https://s3-us-west-2.amazonaws.com/snark-keys.o1test.net" *)
  ]

分为 用于签名证明的Wrap proof system 和 用于区块和交易证明的Step proof system:

  • Cache.Step.read_or_generate
  • Cache.Wrap.read_or_generate

1.4 Mina_lib.create()

Mina_lib.create()返回的coda内容为:

		Deferred.return
            { config
            ; next_producer_timing = None
            ; processes =
                { prover
                ; verifier
                ; snark_worker
                ; uptime_snark_worker_opt
                ; vrf_evaluator
                }
            ; initialization_finish_signal
            ; components =
                { net
                ; transaction_pool
                ; snark_pool
                ; transition_frontier = frontier_broadcast_pipe_r
                ; most_recent_valid_block = most_recent_valid_block_reader
                ; block_produced_bvar
                }
            ; pipes =
                { validated_transitions_reader = valid_transitions_for_api
                ; producer_transition_writer
                ; external_transitions_writer =
                    Strict_pipe.Writer.to_linear_pipe
                      external_transitions_writer
                ; user_command_input_writer
                ; user_command_writer = local_txns_writer
                ; local_snark_work_writer
                }
            ; wallets
            ; block_production_keypairs
            ; coinbase_receiver = ref config.coinbase_receiver
            ; snark_job_state = snark_jobs_state
            ; subscriptions
            ; sync_status
            ; precomputed_block_writer
            ; block_production_status = ref `Free
            }

1.6 snark_intf.ml中的函数

其中:

  • transport函数是指利用同构性,将(var, value1)转换为(var, value2)。
  • transprot_var函数时将(var1, value)转换为(var2, value)。
(** Convert relationships over
        {{:https://en.wikipedia.org/wiki/Isomorphism}isomorphic} types: *)

    val transport :
         ('var, 'value1) t
      -> there:('value2 -> 'value1)
      -> back:('value1 -> 'value2)
      -> ('var, 'value2) t

    val transport_var :
         ('var1, 'value) t
      -> there:('var2 -> 'var1)
      -> back:('var1 -> 'var2)
      -> ('var2, 'value) t

2. snark0.ml代码结构

snarky/src/base/snark0.ml中的代码结构为:

  • 1)Runner(Checked_runner)模块
  • 2)set_eval_constraints、set_reduce_to_prover、make、make’、ignore_state等函数,以及m、m’类型。
  • 3)Make_basic模块
  • 4)Make模块
  • 5)Typ0(Typ)模块
  • 6)Run模块

Mina有2种backend:

  • 1)pallas_based_plonk backend
  • 2)vesta_based_plonk backend

2.1 Runner(Checked_runner)模块

Runner(Checked_runner)模块中主要包含:

  • 1)Constraint模块
  • 2)Make_checked模块
  • 3)Make模块

2.1.1 Constraint模块

Constraint模块中主要有4种类型的约束:【type ('var, 'field) basic = ..,第一个是变量,第二个是值。】

  • 1)Boolean
  • 2)Equal
  • 3)Square
  • 4)R1CS
let eval (type f v) (module Field : Snarky_intf.Field.S with type t = f)
        (get_value : v -> f) (t : (v, f) basic) : bool =
      match t with
      | Boolean v ->
          let x = get_value v in
          Field.(equal x zero || equal x one)
      | Equal (v1, v2) ->
          Field.equal (get_value v1) (get_value v2)
      | R1CS (v1, v2, v3) ->
          Field.(equal (mul (get_value v1) (get_value v2)) (get_value v3))
      | Square (a, c) ->
          Field.equal (Field.square (get_value a)) (get_value c)
      | _ ->
          unhandled "eval"

2.1.2 Make_checked模块

  • 1)run_state结构定义为:
    type 'prover_state run_state = ('prover_state, Backend.Field.t) Run_state.t
    
    (** The internal state used to run a checked computation. *)
    type ('prover_state, 'field) t =
      { system: 'field Constraint_system.t option
      ; input: 'field Vector.t
      ; aux: 'field Vector.t
      ; eval_constraints: bool
      ; num_inputs: int
      ; next_auxiliary: int ref
      ; prover_state: 'prover_state option
      ; stack: string list
      ; handler: Request.Handler.t
      ; is_running: bool
      ; as_prover: bool ref
      ; log_constraint:
          (   ?at_label_boundary:[`Start | `End] * string
           -> ('field Cvar.t, 'field) Constraint.t
           -> unit)
          option }
    
  • 2)Types模块内包含的子模块有:Checked、As_prover、Typ、Provider、Monad_let.Make3,以及get_value、store_field_elt、alloc_var、run_as_prover、as_prover、mk_lazy、with_label、log_constraint、stack_to_string、add_constraint、with_state、with_handler、clear_handler、exists、next_auxiliary、with_lens、constraint_count等函数。部分函数在module type Run_extras中定义。

2.1.3 Make模块

Make模块主要包含了:run递归函数、fake_state函数、flatten_as_prover递归函数、reduce_to_prover函数,以及State子模块中的make函数。部分函数在module type S中定义。

(* INVARIANT: run _ s = (s', _) gives
       (s'.prover_state = Some _) iff (s.prover_state = Some _) *)
  let rec run : type a s.
      (a, s, Field.t) Checked.t -> s run_state -> s run_state * a =
   fun t s ->
    match t with
    | As_prover (x, k) ->
        let s, () = handle_error s (fun () -> as_prover x s) in
        run k s
    | Pure x ->
        (s, x)
    | Direct (d, k) ->
        let s, y = handle_error s (fun () -> d s) in
        let k = handle_error s (fun () -> k y) in
        run k s
    | Reduced (t, d, res, k) ->
        let s, y =
          if
            (not !(s.as_prover))
            && Option.is_some s.prover_state
            && Option.is_none s.system
          then
            (* In reduced mode, we only evaluate prover code and use it to fill
               the public and auxiliary input vectors. Thus, these three
               conditions are important:
               - if there is no prover state, we can't run the prover code
               - if there is an R1CS to be filled, we need to run the original
                 computation to add the constraints to it
               - if we are running a checked computation inside a prover block,
                 we need to be sure that we aren't allocating R1CS variables
                 that aren't present in the original constraint system.
                 See the comment in the [Exists] branch of [flatten_as_prover]
                 below for more context.
            *)
            (handle_error s (fun () -> d s), res)
          else run t s
        in
        let k = handle_error s (fun () -> k y) in
        run k s
    | Lazy (x, k) ->
        let s, y = mk_lazy (run x) s in
        let k = handle_error s (fun () -> k y) in
        run k s
    | With_label (lab, t, k) ->
        let s, y = with_label lab (run t) s in
        let k = handle_error s (fun () -> k y) in
        run k s
    | Add_constraint (c, t) ->
        let s, () = handle_error s (fun () -> add_constraint c s) in
        run t s
    | With_state (p, and_then, t_sub, k) ->
        let t_sub = run t_sub in
        let s, y = handle_error s (fun () -> with_state p and_then t_sub s) in
        let k = handle_error s (fun () -> k y) in
        run k s
    | With_handler (h, t, k) ->
        let s, y = with_handler h (run t) s in
        let k = handle_error s (fun () -> k y) in
        run k s
    | Clear_handler (t, k) ->
        let s, y = clear_handler (run t) s in
        let k = handle_error s (fun () -> k y) in
        run k s
    | Exists (typ, p, k) ->
        let typ =
          { Types.Typ.store= typ.store
          ; read= typ.read
          ; alloc= typ.alloc
          ; check= (fun var -> run (typ.check var)) }
        in
        let s, y = handle_error s (fun () -> exists typ p s) in
        let k = handle_error s (fun () -> k y) in
        run k s
    | Next_auxiliary k ->
        let s, y = next_auxiliary s in
        let k = handle_error s (fun () -> k y) in
        run k s

let fake_state next_auxiliary stack =
    { system= None
    ; input= dummy_vector
    ; aux= dummy_vector
    ; eval_constraints= false
    ; num_inputs= 0
    ; next_auxiliary
    ; prover_state= None
    ; stack
    ; handler= Request.Handler.fail
    ; is_running= true
    ; as_prover= ref false
    ; log_constraint= None }

let rec flatten_as_prover : type a s.
         int ref
      -> string list
      -> (a, s, Field.t) Checked.t
      -> (s run_state -> s run_state) * a =
   fun next_auxiliary stack t ->
    match t with
    | As_prover (x, k) ->
        let f, a = flatten_as_prover next_auxiliary stack k in
        ( (fun s ->
            let s', (_ : unit option) = run_as_prover (Some x) s in
            f s' )
        , a )
    | Pure x ->
        (Fn.id, x)
    | Direct (d, k) ->
        let _, y = d (fake_state next_auxiliary stack) in
        let f, a = flatten_as_prover next_auxiliary stack (k y) in
        ( (fun s ->
            let {prover_state; _} = s in
            let s, _y = d s in
            f (set_prover_state prover_state s) )
        , a )
    | Reduced (t, _d, _res, k) ->
        let f, y = flatten_as_prover next_auxiliary stack t in
        let g, a = flatten_as_prover next_auxiliary stack (k y) in
        ((fun s -> g (f s)), a)
    | Lazy (x, k) ->
        let flattened =
          Lazy.from_fun (fun () ->
              (* We don't know the stack at forcing time, so just announce that
                 we're forcing.
              *)
              let label = "Lazy value forced (reduced):" in
              flatten_as_prover next_auxiliary (label :: stack) x )
        in
        let y = Lazy.map ~f:snd flattened in
        let f s =
          if Lazy.is_val flattened then
            (* The lazy value has been forced somewhere later in the checked
               computation, so we need to do the prover parts of it.
            *)
            let f, _ = Lazy.force flattened in
            let {prover_state; _} = s in
            let prover_state' = Option.map prover_state ~f:ignore in
            let s = f (set_prover_state prover_state' s) in
            set_prover_state prover_state s
          else s
        in
        let g, a = flatten_as_prover next_auxiliary stack (k y) in
        ((fun s -> g (f s)), a)
    | With_label (lab, t, k) ->
        let f, y = flatten_as_prover next_auxiliary (lab :: stack) t in
        let g, a = flatten_as_prover next_auxiliary stack (k y) in
        ((fun s -> g (f s)), a)
    | Add_constraint (c, t) ->
        let f, y = flatten_as_prover next_auxiliary stack t in
        ( (fun s ->
            Option.iter s.log_constraint ~f:(fun f -> f c) ;
            if s.eval_constraints && not (Constraint.eval c (get_value s)) then
              failwithf
                "Constraint unsatisfied:\n%s\n%s\n\nConstraint:\n%s\nData:\n%s"
                (Constraint.annotation c) (stack_to_string stack)
                (Sexp.to_string (Constraint.sexp_of_t c))
                (log_constraint c s) () ;
            f s )
        , y )
    | With_state (p, and_then, t_sub, k) ->
        let f_sub, y = flatten_as_prover next_auxiliary stack t_sub in
        let f, a = flatten_as_prover next_auxiliary stack (k y) in
        ( (fun s ->
            let s, s_sub = run_as_prover (Some p) s in
            let s_sub = f_sub (set_prover_state s_sub s) in
            let s, (_ : unit option) =
              run_as_prover (Option.map ~f:and_then s_sub.prover_state) s
            in
            f s )
        , a )
    | With_handler (h, t, k) ->
        let f, y = flatten_as_prover next_auxiliary stack t in
        let g, a = flatten_as_prover next_auxiliary stack (k y) in
        ( (fun s ->
            let {handler; _} = s in
            let s' = f {s with handler= Request.Handler.push handler h} in
            g {s' with handler} )
        , a )
    | Clear_handler (t, k) ->
        let f, y = flatten_as_prover next_auxiliary stack t in
        let g, a = flatten_as_prover next_auxiliary stack (k y) in
        ( (fun s ->
            let {handler; _} = s in
            let s' = f {s with handler= Request.Handler.fail} in
            g {s' with handler} )
        , a )
    | Exists ({store; alloc; check; _}, p, k) ->
        let var =
          Typ_monads.Alloc.run alloc
            (alloc_var (fake_state next_auxiliary stack))
        in
        let f, () = flatten_as_prover next_auxiliary stack (check var) in
        let handle = {Handle.var; value= None} in
        let g, a = flatten_as_prover next_auxiliary stack (k handle) in
        ( (fun s ->
            if !(s.as_prover) then
              (* If we are running inside a prover block, any call to [exists]
                 will cause a difference between the expected layout in the
                 R1CS and the actual layout that the prover puts data into:

                 R1CS layout:
                        next R1CS variable to be allocated
                                      \/
                 ... [ var{n-1} ] [ var{n} ] [ var{n+1} ] [ var{n+2} ] ...

                 Prover block layout:
                                 prover writes values here due to [exists]
                                         \/         ...        \/
                 ... [ var{n-1} ] [ prover_var{1} ] ... [ prover_var{k} ] [ var{n} ] ...

                 To avoid a divergent layout (and thus unsatisfied constraint
                 system), we run the original checked computation instead.

                 Note: this currently should never happen, because this
                 function is only invoked on a complete end-to-end checked
                 computation using the proving API.
                 By definition, this cannot be wrapped in a prover block.
              *)
              failwith
                "Internal error: attempted to store field elements for a \
                 variable that is not known to the constraint system." ;
            let old = !(s.as_prover) in
            s.as_prover := true ;
            let ps, value =
              As_prover.Provider.run p s.stack (get_value s)
                (Option.value_exn s.prover_state)
                s.handler
            in
            s.as_prover := old ;
            let _var =
              Typ_monads.Store.run (store value) (store_field_elt s)
            in
            let s = f (set_prover_state (Some ()) s) in
            handle.value <- Some value ;
            g (set_prover_state (Some ps) s) )
        , a )
    | Next_auxiliary k ->
        flatten_as_prover next_auxiliary stack (k !next_auxiliary)

2.2 Make_basic模块

Make_basic主要包含:field_vec_id、pack_field_vec、field_vec、cast_field_vec_exn等函数,以及:

  • 1)proof_inputs模块:
type t = {public_inputs: Field.Vector.t; auxiliary_inputs: Field.Vector.t}
  • 2)Verification_key模块:有vesta和pallas 2种backend定义:
module Verification_key = struct (* pallas backend中的Verification_key定义 *)
  type t =
    ( Kimchi.Foundations.Fq.t
    , Kimchi.Protocol.SRS.Fq.t
    , Kimchi.Foundations.Fp.t Kimchi.Foundations.or_infinity
      Kimchi.Protocol.poly_comm )
    Kimchi.Protocol.VerifierIndex.verifier_index

module Verification_key = struct (* vesta backend中的Verification_key定义 *)
  type t =
    ( Kimchi.Foundations.Fp.t
    , Kimchi.Protocol.SRS.Fp.t
    , Kimchi.Foundations.Fq.t Kimchi.Foundations.or_infinity
      Kimchi.Protocol.poly_comm )
    Kimchi.Protocol.VerifierIndex.verifier_index
    
type verification_key = t [@@deriving bin_io]

    module With_r1cs_hash = struct
      type t = Md5.t * verification_key [@@deriving bin_io]
    end

其中verifier_index 结构为:

	decl_type!(w, env, CamlPlonkDomain<T1> => "domain");
    decl_type!(w, env, CamlPlonkVerificationEvals<T1> => "verification_evals");
    decl_type!(w, env, CamlPlonkVerifierIndex<T1, T2, T3> => "verifier_index");
            
#[derive(ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)]
pub struct CamlPlonkVerifierIndex<Fr, SRS, PolyComm> {
    pub domain: CamlPlonkDomain<Fr>,
    pub max_poly_size: ocaml::Int,
    pub max_quot_size: ocaml::Int,
    pub srs: SRS,
    pub evals: CamlPlonkVerificationEvals<PolyComm>,
    pub shifts: Vec<Fr>,
    pub linearization: CamlLinearization<CamlPolishToken<Fr>>,
}

#[derive(ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)]
pub struct CamlPlonkDomain<Fr> {
    pub log_size_of_group: ocaml::Int,
    pub group_gen: Fr,
}

#[derive(ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)]
pub struct CamlPlonkVerificationEvals<PolyComm> {
    pub sigma_comm: Vec<PolyComm>,
    pub coefficients_comm: Vec<PolyComm>,
    pub generic_comm: PolyComm,
    pub psm_comm: PolyComm,
    pub complete_add_comm: PolyComm,
    pub mul_comm: PolyComm,
    pub emul_comm: PolyComm,
    pub endomul_scalar_comm: PolyComm,
    pub chacha_comm: Option<Vec<PolyComm>>,
}
  • 3)Proving_key模块:有vesta和pallas 2种backend定义:
  module Rounds = Rounds (* pallas 对应的模块定义:*)
  module Urs = Kimchi.Protocol.SRS.Fq
  module Index = Kimchi.Protocol.Index.Fq
  module Curve = Curve
  module Poly_comm = Fq_poly_comm
  module Scalar_field = Field
  module Verifier_index = Kimchi.Protocol.VerifierIndex.Fq
  module Gate_vector = Kimchi.Protocol.Gates.Vector.Fq
  module Constraint_system = R1CS_constraint_system

  module Rounds = Rounds (* vesta 对应的模块定义:*)
  module Urs = Kimchi.Protocol.SRS.Fp
  module Index = Kimchi.Protocol.Index.Fp
  module Curve = Curve
  module Poly_comm = Fp_poly_comm
  module Scalar_field = Field
  module Verifier_index = Kimchi.Protocol.VerifierIndex.Fp
  module Gate_vector = Kimchi.Protocol.Gates.Vector.Fp
  module Constraint_system = R1CS_constraint_system

type t =
    { index : Inputs.Index.t
    ; cs :
        (Inputs.Gate_vector.t, Inputs.Scalar_field.t) Plonk_constraint_system.t
    }

type proving_key = t [@@deriving bin_io]

    module With_r1cs_hash = struct
      type t = Md5.t * proving_key [@@deriving bin_io]
    end
  • 4)Keypair模块:包含create、generate函数。
type t = {pk: Proving_key.t; vk: Verification_key.t} [@@deriving bin_io]
  • 5)Var(Var)模块、Field0(Field)模块
  • 6)Cvar(Cvar)模块:包含to_constant_and_terms、eval、add、scale、linear_combination等函数。
module Cvar : sig
    type t = Field.t Cvar.t
   
 type 'f t =
  | Constant of 'f
  | Var of int
  | Add of 'f t * 'f t
  | Scale of 'f * 'f t
  • 7)Constraint模块:
module Constraint : sig
    type t = (Cvar.t, Field.t) Constraint.t

type ('v, 'f) t = ('v, 'f) basic_with_annotation list
type ('v, 'f) basic_with_annotation =
  {basic: ('v, 'f) basic; annotation: string option}
  • 8)Typ_monads模块:分为Store、Read、Alloc子模块。
  • 9)Handler模块:
type t = Request.request -> Request.response

module Response = struct
  type 'a t = Provide of 'a | Delegate of 'a req | Unhandled
end

type request =
  | With : {request: 'a t; respond: 'a Response.t -> response} -> request
  • 10)Typ模块:
  • 11)As_prover模块:
type ('a, 'prover_state) as_prover = ('a, 'prover_state) t
  • 12)Handle模块:
type ('var, 'value) t = {var: 'var; mutable value: 'value option}

  • 13)Checked模块:包含perform、constraint_system、auxiliary_input、run_and_check’、run_unchecked、run_and_check、check、equal_constraints、equal_vars、equal、mul、square、inv、div、unsafe_read_cvars、two_to_the、choose_preimage_unchecked、packing_sum、choose_preimage、choose_preimage_flagged等函数,以及let%snarkydef_ if_ 、let%snarkydef_ assert_non_zero等约束函数,以及Boolean、Control、List、Array等子模块。
  • 14)Data_spec(Typ.Data_spec)模块
  • 15)Run模块,包含:alloc_var、store_field_elt、collect_input_constraints递归、r1cs_h、constraint_system、generate_keypair、generate_public_input、conv、conv_never_use、generate_auxiliary_input、generate_witness_conv、generate_witness函数,以及Proof_system模块。
    • 15.1)Proof_system子模块:allocate_inputs递归、create、run_proof_system、constraint_system、digest、generate_keypair、run_with_input、run_unchecked、run_checked’、run_checked、check、generate_witness等函数。
    type ('checked, 'inputs, 's) proof_system =
        { compute: 'checked
        ; reduced_compute: 'checked Lazy.t
        ; check_inputs: (unit, 's) Checked.t
        ; provide_inputs:
            Field.Vector.t -> (unit, 'inputs) H_list.t -> Field.Vector.t
        ; num_inputs: int
        ; handler: Request.Handler.t
        ; mutable proving_key: Proving_key.t option
        ; mutable verification_key: Verification_key.t option
        ; mutable r1cs_digest: Md5.t option
        ; proving_key_path: string option
        ; verification_key_path: string option
        ; keys_have_hashes: bool }
    
  • 16)CVar1模块
  • 17)Field模块:gen、gen_incl、gen_uniform、gen_uniform_incl等函数 以及 Checked子模块。
    • 17.1)Checked子模块:包含equal、mul、square、div、inv、sqrt、quadratic_nonresidue、sqrt_check、is_square、choose_preimage_var、if_、compare、lt_bitstring_value、field_size_bits、unpack_full、parity等函数,以及Assert子模块(包含lt、lte、gt、gte、non_zero、equal、not_equal函数)。
  • 18)Bitstring_checked模块:包含chunk_for_equality、equal、equal_expect_true等函数。
type t = Checked.Boolean.var list
  • 19)let%snarkydef_ if_z约束函数、generate_keypair、conv、conv_never_use、generate_auxiliary_input、generate_public_input、generate_witness等函数(均是调用“15)Run模块”和“13)Checked模块”内相应的函数)。
  • 20)Proof_system模块:对应“15)Run模块”的Proof_system子模块以及相应函数。
  • 21)Perform模块:调用“15)Run模块”中相应函数。
type ('a, 's, 't) t =
      't -> 's Checked.run_state -> 's Checked.run_state * 'a
  • 22)R1CS_constraint_system模块:pallas和vesta 2种backend:
module R1CS_constraint_system = (* 对应pallas backend *)
  Plonk_constraint_system.Make (Field) (Kimchi.Protocol.Gates.Vector.Fq)
    (struct
      let params =
        Sponge.Params.(
          map pasta_q_3 ~f:(fun x ->
              Field.of_bigint (Bigint256.of_decimal_string x)))
    end)

module R1CS_constraint_system = (* 对应vesta backend *)
  Plonk_constraint_system.Make (Field) (Kimchi.Protocol.Gates.Vector.Fp)
    (struct
      let params =
        Sponge.Params.(
          map pasta_p_3 ~f:(fun x ->
              Field.of_bigint (Bigint256.of_decimal_string x)))
    end)

2.3 Make模块

Make模块中包含:As_prover0、Basic等子模块。

2.4 Run模块

Run模块中包含:is_active_functor_id、active_functor_id等函数,以及 Make_basic、Make子模块。

2.4.1 Make_basic子模块

Make_basic子模块为核心模块,其中包含了:run等函数,以及Boolean、Field、Bitstring_checked、As_prover、Handle、Proof_system等子模块。

let state =
      ref
        { system= None
        ; input= field_vec ()
        ; aux= field_vec ()
        ; eval_constraints= false
        ; num_inputs= 0
        ; next_auxiliary= ref 1
        ; prover_state= None
        ; stack= []
        ; handler= Request.Handler.fail
        ; is_running= false
        ; as_prover= ref false
        ; log_constraint= None }

2.4.2 Make子模块

module Make
      (Backend : Backend_intf.S) (Prover_state : sig
          type t
      end) =
  struct
    module Basic = Make_basic (Backend) (Prover_state)
    include Basic
    module Number = Number.Run.Make (Basic)
    module Enumerable = Enumerable.Run.Make (Basic)
  end

3. transaction_snark

前序博客见:

分为out-of-SNARK transaction和in-SNARK transaction:

  • 对于out-of-SNARK transaction见:Transaction_logic.apply_user_command_unchecked。具体调用路径为:staged_ledger.apply_transaction->apply_transaction->apply_user_command_unchecked
  • 对于in-SNARK transaction见:Transaction_snark.apply_tagged_transaction。具体调用路径为:transaction_snark的Base.rule和Merge.rule->main->apply_tagged_transaction

代码见src/lib/transaction_snark/transaction_snark.ml,该文件基本结构为:

  • 1)Proof_type:分为Base和Merge两种类型。
  • 2)Pending_coinbase_stack_state:
    type t = Pending_coinbase.Stack_versioned.Stable.V1.t Poly.Stable.V1.t
    
    type 'pending_coinbase t =
              { source : 'pending_coinbase; target : 'pending_coinbase }
    
  • 3)Statement:包含module With_sok。
    type t =
            ( Frozen_ledger_hash.Stable.V1.t
            , Currency.Amount.Stable.V1.t
            , Pending_coinbase_stack_state.Stable.V1.t
            , Fee_excess.Stable.V1.t
            , Token_id.Stable.V1.t
            , unit )
            Poly.Stable.V1.t
    (* Poly.Stable.V1.t结构为: *)
    		type ( 'ledger_hash
                 , 'amount
                 , 'pending_coinbase
                 , 'fee_excess
                 , 'token_id
                 , 'sok_digest )
                 t =
              { source : 'ledger_hash
              ; target : 'ledger_hash
              ; supply_increase : 'amount
              ; pending_coinbase_stack_state : 'pending_coinbase
              ; fee_excess : 'fee_excess
              ; next_available_token_before : 'token_id
              ; next_available_token_after : 'token_id
              ; sok_digest : 'sok_digest
              }
    
    • 3.1)With_sok:同时还包含Checked module的to_input和to_field_elements函数。
    type t =
          ( Frozen_ledger_hash.Stable.V1.t
          , Currency.Amount.Stable.V1.t
          , Pending_coinbase_stack_state.Stable.V1.t
          , Fee_excess.Stable.V1.t
          , Token_id.Stable.V1.t
          , Sok_message.Digest.Stable.V1.t )
          Poly.Stable.V1.t
    
    	type ( 'ledger_hash
             , 'amount
             , 'pending_coinbase
             , 'fee_excess
             , 'token_id
             , 'sok_digest )
             t =
          { source : 'ledger_hash
          ; target : 'ledger_hash
          ; supply_increase : 'amount
          ; pending_coinbase_stack_state : 'pending_coinbase
          ; fee_excess : 'fee_excess
          ; next_available_token_before : 'token_id
          ; next_available_token_after : 'token_id
          ; sok_digest : 'sok_digest
          }
    
  • 4)Proof:
    type t = Pickles.Proof.Branching_2.Stable.V2.t
    
  • 5)Transaction_snark自身定义:
    type t =
      { statement : Statement.With_sok.Stable.V1.t; proof : Proof.Stable.V2.t }
    
  • 6)Base:包含module有:User_command_failure、Snapp_command,以及let%snarkydef check_signature、let%snarkydef apply_tagged_transaction、let%snarkydef main 约束函数,check_timing、side_loaded、rule、transaction_union_handler、dummy_constraints函数。
    (* Request类型有:Transaction、State_body和Init_stack *)
    type _ Snarky_backendless.Request.t +=
    | Transaction : Transaction_union.t Snarky_backendless.Request.t
    | State_body :
        Mina_state.Protocol_state.Body.Value.t Snarky_backendless.Request.t
    | Init_stack : Pending_coinbase.Stack.t Snarky_backendless.Request.t
    
    
    • 6.1)User_command_failure:包含了user_command失败的方式,以及compute_unchecked函数 和 let%snarkydef compute_as_prover 约束函数。
    • 6.2)Snapp_command:包含了_handler、check_fee、snapp1_tag、snapp1_tag、unhash_snapp_account、apply_body、assert_account_present、signature_verifies、pay_fee、shouldn’t_update_nonce_and_rch、update_nonce_and_rch、modify、compute_fee_excess、determine_fee_payer、create_checker等函数,以及module有:Check_predicate(包含snapp_self、snapp_other和signed_self函数)、Two_proved(包含main和_rule函数)、One_proved(包含main和_rule函数)、Zero_proved(包含main和_rule函数)。
    type _ t +=
        | State_body : Mina_state.Protocol_state.Body.Value.t t
        | Snapp_account : [ `One | `Two ] -> Snapp_account.t t
        | Fee_payer_signature : Signature.t t
        | Account_signature : [ `One | `Two ] -> Signature.t t
        | Zero_complement : Snapp_command.Payload.Zero_proved.t t
        | One_complement : Snapp_statement.Complement.One_proved.t t
        | Two_complement : Snapp_statement.Complement.Two_proved.t t
    
  • 7)Transition_data:
    type t =
    { proof : Proof_type.t
    ; supply_increase : Amount.t
    ; fee_excess : Fee_excess.t
    ; sok_digest : Sok_message.Digest.t
    ; pending_coinbase_stack_state : Pending_coinbase_stack_state.t
    }
    
  • 8)Merge:包含let%snarkydef main约束函数和rule函数。
  • 9)tag:以及time、system、check_transaction_union、check_transaction、check_user_command、generate_transaction_union_witness、generate_transaction_witness、verify和constraint_system_digests函数。
    type tag =
    ( Statement.With_sok.Checked.t
    , Statement.With_sok.t
    , Nat.N2.n
    , Nat.N2.n )
    Pickles.Tag.t
    
  • 10)Make:调用system->Pickles.compile,构建Proof module,以及verify_against_digest、verify、of_transaction_union、of_transaction、of_user_command、of_fee_transfer、merge和constraint_system_digests函数。

Mina中transaction交易类型主要有4大类:

  • Command (Signed_command x)
  • Fee transfer x
  • Coinbase x
  • Command (Parities x)

transaction_snark交易证明类型主要有2种:

  • Base
  • Merge

transaction_snark由statement和proof表示:

type t =
      { statement : Statement.With_sok.Stable.V1.t; proof : Proof.Stable.V2.t }

3.0 transaction_union表示

transaction_union表示为:【选用Tick曲线】

type ('payload, 'pk, 'signature) t_ =
  { payload : 'payload; signer : 'pk; signature : 'signature }

type t = (Payload.t, Public_key.t, Signature.t) t_

type var = (Payload.var, Public_key.var, Signature.var) t_

其中:

  • 1)Mina中的签名方案采用Schnorr signature,详细可参看 Mina中的Schnorr signature,表示为 ( r x ∈ F q , s ∈ F r ) (r_x\in\mathbb{F}_q,s\in\mathbb{F}_r) (rxFq,sFr)
    type t = Field.t * Inner_curve.Scalar.t
    
  • 2)公钥为Tick曲线上的点 ( x ∈ F q , y ∈ F q ) (x\in\mathbb{F}_q,y\in\mathbb{F}_q) (xFq,yFq),表示为:
    type t = Field.t * Field.t 
    
  • 3)payload表示为:
    type t = (Signed_command_payload.Common.t, Body.t) Signed_command_payload.Poly.t
    type ('common, 'body) t = { common : 'common; body : 'body }
    
    其中:
    • 3.1)Signed_command_payload.Common结构为:
    (* Signed_command_payload.Common结构为: *)
    type t =
        ( Currency.Fee.Stable.V1.t
        , Public_key.Compressed.Stable.V1.t
        , Token_id.Stable.V1.t
        , Mina_numbers.Account_nonce.Stable.V1.t
        , Mina_numbers.Global_slot.Stable.V1.t
        , Signed_command_memo.t )
        Poly.Stable.V1.t
    type ('fee, 'public_key, 'token_id, 'nonce, 'global_slot, 'memo) t =
          { fee : 'fee
          ; fee_token : 'token_id
          ; fee_payer_pk : 'public_key
          ; nonce : 'nonce
          ; valid_until : 'global_slot
          ; memo : 'memo
          }
    
    • 3.2)Body结构为
    (* Body结构为: *)
    type t =
    (Tag.t, Public_key.Compressed.t, Token_id.t, Currency.Amount.t, bool) t_
    type ('tag, 'public_key, 'token_id, 'amount, 'bool) t_ =
    { tag : 'tag
    ; source_pk : 'public_key
    ; receiver_pk : 'public_key
    ; token_id : 'token_id
    ; amount : 'amount
    ; token_locked : 'bool
    }
    
    其中的Tag结构为:【交易类型:payment、委托质押、创建账号、mint token、fee transfer、coinbase。其中前4种对应为user_command交易,对应is_user_command=true;fee transfer和coinbase交易不是user_command交易,is_user_command=false。】
    type t =
    | Payment
    | Stake_delegation
    | Create_account
    | Mint_tokens
    | Fee_transfer
    | Coinbase
    

3.1 transaction_snark对应的statement表示

transaction_snark对应的statement为:

	type t =
          ( Frozen_ledger_hash.Stable.V1.t
          , Currency.Amount.Stable.V1.t
          , Pending_coinbase_stack_state.Stable.V1.t
          , Fee_excess.Stable.V1.t
          , Token_id.Stable.V1.t
          , Sok_message.Digest.Stable.V1.t )
          Poly.Stable.V1.t
                  
(* Poly.Stable.V1.t结构为: *)
		type ( 'ledger_hash
             , 'amount
             , 'pending_coinbase
             , 'fee_excess
             , 'token_id
             , 'sok_digest )
             t =
          { source : 'ledger_hash
          ; target : 'ledger_hash
          ; supply_increase : 'amount
          ; pending_coinbase_stack_state : 'pending_coinbase
          ; fee_excess : 'fee_excess
          ; next_available_token_before : 'token_id
          ; next_available_token_after : 'token_id
          ; sok_digest : 'sok_digest
          }

3.2 transaction_snark对应的proof表示

transaction_snark对应的proof为:

type t = Pickles.Proof.Branching_2.Stable.V2.t

3.3 transaction_snark中的Base proof

Base rule对应的inductive_rule表示为:

let rule ~constraint_constants : _ Pickles.Inductive_rule.t =
    { identifier = "transaction"
    ; prevs = []
    ; main =
        (fun [] x ->
          Run.run_checked (main ~constraint_constants x) ;
          [])
    ; main_value = (fun [] _ -> [])
    }

3.4 transaction_snark中的Merge proof

Merge rule对应的inductive_rule表示为:【对应Mina主网,prev_should_verify=true。】

let rule ~proof_level self : _ Pickles.Inductive_rule.t =
    let prev_should_verify =
      match proof_level with
      | Genesis_constants.Proof_level.Full ->
          true
      | _ ->
          false
    in
    let b = Boolean.var_of_value prev_should_verify in
    { identifier = "merge"
    ; prevs = [ self; self ]
    ; main =
        (fun ps x ->
          Run.run_checked (main ps x) ;
          [ b; b ])
    ; main_value = (fun _ _ -> [ prev_should_verify; prev_should_verify ])
    }

3.5 transaction_snark中的Verification

4. snark_worker模块

snark_worker模块主要提供了2个异步RPC接口:

  • get_work
  • submit_work

5. Mina signer签名模块

Mina的签名机制见:【使用的是Tock曲线】

proof_systems/signer模块内,提供了2种Mina签名接口:

  • 1)[create_legacy]:为与Mina主网和测试网交易签名兼容的legacy signer接口。
  • 2)[create_kimchi]:为一种实验性的kimchi签名接口。

对相同的交易采用相同的私钥签名,结果是不同的,因为主网和测试网在签名时hash的networkid不同。

5.1 Mina中的用户签名交易

Mina中的用户签名交易结构为:【分为普通支付交易和委托交易】

pub struct Transaction {
    // Common
    pub fee: u64,
    pub fee_token: u64,
    pub fee_payer_pk: CompressedPubKey,
    pub nonce: u32,
    pub valid_until: u32,
    pub memo: [u8; MEMO_BYTES],
    // Body
    pub tag: [bool; TAG_BITS],
    pub source_pk: CompressedPubKey,
    pub receiver_pk: CompressedPubKey,
    pub token_id: u64,
    pub amount: u64,
    pub token_locked: bool,
}

const MEMO_BYTES: usize = 34;
const TAG_BITS: usize = 3;
const PAYMENT_TX_TAG: [bool; TAG_BITS] = [false, false, false];
const DELEGATION_TX_TAG: [bool; TAG_BITS] = [false, false, true];
  • 普通支付交易为:
pub fn new_payment(from: PubKey, to: PubKey, amount: u64, fee: u64, nonce: u32) -> Self {
        Transaction {
            fee: fee,
            fee_token: 1,
            fee_payer_pk: from.into_compressed(),
            nonce: nonce,
            valid_until: u32::MAX,
            memo: array_init::array_init(|i| (i == 0) as u8),
            tag: PAYMENT_TX_TAG,
            source_pk: from.into_compressed(),
            receiver_pk: to.into_compressed(),
            token_id: 1,
            amount: amount,
            token_locked: false,
        }
    }
  • 委托交易为:【amount为0,且tag不同】
pub fn new_delegation(from: PubKey, to: PubKey, fee: u64, nonce: u32) -> Self {
        Transaction {
            fee: fee,
            fee_token: 1,
            fee_payer_pk: from.into_compressed(),
            nonce: nonce,
            valid_until: u32::MAX,
            memo: array_init::array_init(|i| (i == 0) as u8),
            tag: DELEGATION_TX_TAG,
            source_pk: from.into_compressed(),
            receiver_pk: to.into_compressed(),
            token_id: 1,
            amount: 0,
            token_locked: false,
        }
    }

5.2 proof of knowledge of signature

基本调用逻辑为:【使用的是Tock曲线】
transaction_snark.ml中:Base模块的rule->main->apply_tagged_transaction->check_signature

let%bind t =
      with_label __LOC__
        (exists Transaction_union.typ ~request:(As_prover.return Transaction))
(* 其中返回的t结构为: *)
({ signer; signature; payload } as txn : Transaction_union.var)

let%bind () =
      [%with_label "Check transaction signature"]
        (check_signature shifted ~payload ~is_user_command ~signer ~signature)

let%snarkydef check_signature shifted ~payload ~is_user_command ~signer
      ~signature =
    let%bind input = Transaction_union_payload.Checked.to_input payload in
    let%bind verifies =
      Schnorr.Checked.verifies shifted signature signer input
    in
    Boolean.Assert.any [ Boolean.not is_user_command; verifies ]

相应的测试用例见:

let%test_unit "schnorr checked + unchecked" =
  Quickcheck.test ~trials:5 gen ~f:(fun (pk, msg) ->
      let s = S.sign pk msg in
      let pubkey = Tick.Inner_curve.(scale one pk) in
      assert (S.verify s pubkey msg) ;
      (Tick.Test.test_equal ~sexp_of_t:[%sexp_of: bool] ~equal:Bool.equal
         Tick.Typ.(tuple3 Tick.Inner_curve.typ (message_typ ()) S.Signature.typ)
         Tick.Boolean.typ
         (fun (public_key, msg, s) ->
           let open Tick.Checked in
           let%bind (module Shifted) =
             Tick.Inner_curve.Checked.Shifted.create ()
           in
           S.Checked.verifies (module Shifted) s public_key msg)
         (fun _ -> true))
        (pubkey, msg, s))

相应的verifies流程为:

let verifies s =
      verifier ~equal:Field.Checked.equal ~final_check:Boolean.( && ) s

let%snarkydef verifier (type s) ~equal ~final_check
        ((module Shifted) as shifted :
          (module Curve.Checked.Shifted.S with type t = s))
        ((r, s) : Signature.var) (public_key : Public_key.var) (m : Message.var)
        =
      let%bind e = Message.hash_checked m ~public_key ~r in
      (* s * g - e * public_key *)
      let%bind e_pk =
        Curve.Checked.scale shifted
          (Curve.Checked.negate public_key)
          (Curve.Scalar.Checked.to_bits e)
          ~init:Shifted.zero
      in
      let%bind s_g_e_pk =
        Curve.Checked.scale_known shifted Curve.one
          (Curve.Scalar.Checked.to_bits s)
          ~init:e_pk
      in
      let%bind rx, ry = Shifted.unshift_nonzero s_g_e_pk in
      let%bind y_even = is_even ry in
      let%bind r_correct = equal r rx in
      final_check r_correct y_even

相应的交易证明见snark_worker/prod.ml中的perform_single函数:

Work.Single.Spec.Transition
                  (input, t, (w : Transaction_witness.t)) ->
                  process (fun () ->
                      let%bind t =
                        Deferred.return
                        @@
                        (* Validate the received transaction *)
                        match t with
                        | Command (Signed_command cmd) -> (
                            match Signed_command.check cmd with
                            | Some cmd ->
                                ( Ok (Command (Signed_command cmd))
                                  : Transaction.Valid.t Or_error.t )
                            | None ->
                                Or_error.errorf
                                  "Command has an invalid signature" )
                        | Command (Parties _) ->
                            failwith "TODO"
                        | Fee_transfer ft ->
                            Ok (Fee_transfer ft)
                        | Coinbase cb ->
                            Ok (Coinbase cb)
                      in
                      Deferred.Or_error.try_with ~here:[%here] (fun () ->
                          M.of_transaction ~sok_digest ~snapp_account1:None
                            ~snapp_account2:None
                            ~source:input.Transaction_snark.Statement.source
                            ~target:input.target
                            { Transaction_protocol_state.Poly.transaction = t
                            ; block_data = w.protocol_state_body
                            }
                            ~init_stack:w.init_stack
                            ~next_available_token_before:
                              input.next_available_token_before
                            ~next_available_token_after:
                              input.next_available_token_after
                            ~pending_coinbase_stack_state:
                              input
                                .Transaction_snark.Statement
                                 .pending_coinbase_stack_state
                            (unstage (Mina_base.Sparse_ledger.handler w.ledger))))

其中的of_transaction函数对应在transaction_snark/transaction_snark.ml的Make模块内:

let of_transaction ~sok_digest ~source ~target ~init_stack
      ~pending_coinbase_stack_state ~next_available_token_before
      ~next_available_token_after ~snapp_account1:_ ~snapp_account2:_
      transaction_in_block handler =
    let transaction : Transaction.t =
      Transaction.forget
        (Transaction_protocol_state.transaction transaction_in_block)
    in
    let state_body =
      Transaction_protocol_state.block_data transaction_in_block
    in
    match to_preunion transaction with
    | `Parties _ ->
        failwith "TODO"
    | `Transaction t ->
        of_transaction_union sok_digest source target ~init_stack
          ~pending_coinbase_stack_state ~next_available_token_before
          ~next_available_token_after
          (Transaction_union.of_transaction t)
          state_body handler

let of_transaction_union sok_digest source target ~init_stack
      ~pending_coinbase_stack_state ~next_available_token_before
      ~next_available_token_after transaction state_body handler =
    let s =
      { Statement.source
      ; target
      ; sok_digest
      ; next_available_token_before
      ; next_available_token_after
      ; fee_excess = Transaction_union.fee_excess transaction
      ; supply_increase = Transaction_union.supply_increase transaction
      ; pending_coinbase_stack_state
      }
    in
    let%map.Async.Deferred proof =
      base []
        ~handler:
          (Base.transaction_union_handler handler transaction state_body
             init_stack)
        s
    in
    { statement = s; proof }

其中of_transaction_union调用transaction_snark prover的base函数来生成proof。【具体的base函数 对应第一个Base.rule规则,具体的merge函数 对应第二个Merge.rule规则。
对于proof of knowledge,相应的证明见pickles/wrap.ml中的wrap函数:

let%map.Deferred next_proof =
    let (T (input, conv)) = Impls.Wrap.input () in
    Common.time "wrap proof" (fun () ->
        Impls.Wrap.generate_witness_conv
          ~f:(fun { Impls.Wrap.Proof_inputs.auxiliary_inputs; public_inputs } ->
            Backend.Tock.Proof.create_async ~primary:public_inputs
              ~auxiliary:auxiliary_inputs pk
              ~message:
                ( Vector.map2
                    (Vector.extend_exn prev_statement.proof_state.me_only.sg
                       max_branching
                       (Lazy.force Dummy.Ipa.Wrap.sg))
                    me_only_prepared.old_bulletproof_challenges
                    ~f:(fun sg chals ->
                      { Tock.Proof.Challenge_polynomial.commitment = sg
                      ; challenges = Vector.to_array chals
                      })
                |> Vector.to_list ))
          [ input ]
          (fun x () : unit ->
            Impls.Wrap.handle (fun () : unit -> wrap_main (conv x)) handler)
          ()
          { pass_through = prev_statement_with_hashes.proof_state.me_only
          ; proof_state =
              { next_statement.proof_state with
                me_only =
                  Common.hash_dlog_me_only max_branching me_only_prepared
              }
          })

其中的Backend.Tock.Proof.create_async对应为crypto/kimchi_backend/common/plonk_dlog_proof.ml中:

let create_async ?message pk ~primary ~auxiliary =
    let chal_polys =
      match (message : message option) with Some s -> s | None -> []
    in
    let challenges =
      List.map chal_polys ~f:(fun { Challenge_polynomial.challenges; _ } ->
          challenges)
      |> Array.concat
    in
    let commitments =
      Array.of_list_map chal_polys
        ~f:(fun { Challenge_polynomial.commitment; _ } ->
          G.Affine.to_backend (Finite commitment))
    in
    let%map.Deferred res =
      Backend.create_async pk primary auxiliary challenges commitments
    in
    of_backend res

Tock(Pallas)曲线对应Backend.create_async为pallas_based_plonk.ml中:

let create_async (pk : Keypair.t) primary auxiliary prev_chals prev_comms =
      create_aux pk primary auxiliary prev_chals prev_comms
        ~f:(fun pk auxiliary_input prev_challenges prev_sgs ->
          Run_in_thread.run_in_thread (fun () ->
              create pk auxiliary_input prev_challenges prev_sgs))

let create_aux ~f:create (pk : Keypair.t) primary auxiliary prev_chals
        prev_comms =
      (* external values contains [1, primary..., auxiliary ] *)
      let external_values i =
        let open Field.Vector in
        if i = 0 then Field.one
        else if i - 1 < length primary then get primary (i - 1)
        else get auxiliary (i - 1 - length primary)
      in

      (* compute witness *)
      let computed_witness =
        R1CS_constraint_system.compute_witness pk.cs external_values
      in
      let num_rows = Array.length computed_witness.(0) in

      (* convert to Rust vector *)
      let witness_cols =
        Array.init Kimchi_backend_common.Constants.columns ~f:(fun col ->
            let witness = Field.Vector.create () in
            for row = 0 to num_rows - 1 do
              Field.Vector.emplace_back witness computed_witness.(col).(row)
            done ;
            witness)
      in
      create pk.index witness_cols prev_chals prev_comms

let create (pk : Keypair.t) primary auxiliary prev_chals prev_comms = 
      create_aux pk primary auxiliary prev_chals prev_comms ~f:create 

具体生成证明的逻辑~f:create见proof_system/kimchi/src/prover.rs中ProverProof.create函数:

impl<G: CommitmentCurve> ProverProof<G>
where
    G::BaseField: PrimeField,
{
    /// This function constructs prover's zk-proof from the witness & the ProverIndex against SRS instance
    pub fn create<
        EFqSponge: Clone + FqSponge<BaseField<G>, G, ScalarField<G>>,
        EFrSponge: FrSponge<ScalarField<G>>,
    >(
        groupmap: &G::Map,
        witness: [Vec<ScalarField<G>>; COLUMNS],
        index: &ProverIndex<G>,
    ) -> Result<Self> {
        Self::create_recursive::<EFqSponge, EFrSponge>(groupmap, witness, index, Vec::new())
    }
........
}

create_async返回的应为Kimchi.Protocol.prover_proof结构(在proof_system/kimchi/src/prover.rs中同时定义了rust和OCaml结构,便于跨语言调用):

module Backend : sig
    type t =
      (Curve.Affine.Backend.t, Scalar_field.t) Kimchi.Protocol.prover_proof
      
    val create_async :
         Index.t
      -> Scalar_field.Vector.t
      -> Scalar_field.Vector.t
      -> Scalar_field.t array
      -> Curve.Affine.Backend.t array
      -> t Deferred.t

对应Kimchi.Protocol.prover_proof OCaml结构表示为:

decl_type!(w, env, CamlProverProof<T1, T2> => "prover_proof");

pub struct CamlProverProof<CamlG, CamlF> {
        pub commitments: CamlProverCommitments<CamlG>,
        pub proof: CamlOpeningProof<CamlG, CamlF>,
        // OCaml doesn't have sized arrays, so we have to convert to a tuple..
        pub evals: (CamlProofEvaluations<CamlF>, CamlProofEvaluations<CamlF>),
        pub ft_eval1: CamlF,
        pub public: Vec<CamlF>,
        pub prev_challenges: Vec<(Vec<CamlF>, CamlPolyComm<CamlG>)>,
    }

对应Kimchi.Protocol.prover_proof Rust结构表示为:

/// The proof that the prover creates from a [ProverIndex] and a `witness`.
#[derive(Clone)]
pub struct ProverProof<G: AffineCurve> {
    /// All the polynomial commitments required in the proof
    pub commitments: ProverCommitments<G>,

    /// batched commitment opening proof
    pub proof: OpeningProof<G>,

    /// Two evaluations over a number of committed polynomials
    // TODO(mimoo): that really should be a type Evals { z: PE, zw: PE }
    pub evals: [ProofEvaluations<Vec<ScalarField<G>>>; 2],

    /// Required evaluation for [Maller's optimization](https://o1-labs.github.io/mina-book/crypto/plonk/maller_15.html#the-evaluation-of-l)
    pub ft_eval1: ScalarField<G>,

    /// The public input
    pub public: Vec<ScalarField<G>>,

    /// The challenges underlying the optional polynomials folded into the proof
    pub prev_challenges: Vec<(Vec<ScalarField<G>>, PolyComm<G>)>,
}

6. Mina hasher模块

前序博客有:

实际有2个接口:

  • 1)[create_legacy]:create a legacy hasher
  • 2)[create_kimchi]:create an experimental kimchi hasher

7. Mina kimchi circuit

前序博客有:

Mina Kimchi proof system主要由3大算法组成:

  • Setup算法:输入为circuit,输出为Prover index和Verifier index。
  • Proof creation证明生成算法:输入为Prover index 和 该circuit的execution trace,输出为a proof。
  • Proof verification证明验证算法:输入为Verifier index和proof,验证通过输出为true,否则为false。

Mina Kimchi proof system的circuit中包含的门类型有:

pub enum GateType {
    /// Zero gate
    Zero = 0,
    /// Generic arithmetic gate
    Generic = 1,
    /// Poseidon permutation gate
    Poseidon = 2,
    /// Complete EC addition in Affine form
    CompleteAdd = 3,
    /// EC variable base scalar multiplication
    VarBaseMul = 4,
    /// EC variable base scalar multiplication with group endomorphim optimization
    EndoMul = 5,
    /// Gate for computing the scalar corresponding to an endoscaling
    EndoMulScalar = 6,
    /// ChaCha
    ChaCha0 = 7,
    ChaCha1 = 8,
    ChaCha2 = 9,
    ChaChaFinal = 10,
}

8. Prover模块

8.1 prover/prover.ml代码结构

src/lib/prover/prover.ml的代码结构为:

  • 0)create、initialized、prove_from_input_sexp、extend_blockchain、prove和create_genesis_block函数实现。
  • 1)Extend_blockchain_input模块
  • 2)Consensus_mechanism(Consensus)模块:等价为consensus/proof_of_stake.ml。
  • 3)Blockchain(Blockchain)模块:等价为blockchain_snark/blockchain.ml。
  • 4)Worker_state模块
  • 5)Functions模块
  • 6)Worker模块

prove.ml的结构体定义为:

type t =
  { connection : Worker.Connection.t; process : Process.t; logger : Logger.t }

8.1.1 Extend_blockchain_input模块

Extend_blockchain_input结构为:

module Extend_blockchain_input = struct
      type t =
        { chain : Blockchain.Stable.V2.t
        ; next_state : Protocol_state.Value.Stable.V1.t
        ; block : Snark_transition.Value.Stable.V1.t
        ; ledger_proof : Ledger_proof.Stable.V2.t option
        ; prover_state : Consensus.Data.Prover_state.Stable.V2.t
        ; pending_coinbase : Pending_coinbase_witness.Stable.V1.t
        }

其中:

  • 1)chain字段:Blockchain.Stable.V2.t结构为:
    type t =
            { state : Protocol_state.Value.Stable.V1.t; proof : Proof.Stable.V2.t }
    
  • 2)next_state字段:Protocol_state.Value.Stable.V1.t结构为:详细见Mina概览 中“5.1 protocol state”。
    	type t = (State_hash.Stable.V1.t, Body.Value.Stable.V1.t) 
    
    	Poly.Stable.V1.t
    	type ('state_hash, 'body) t =
    	        { previous_state_hash : 'state_hash; body : 'body }
    
  • 3)block字段:Snark_transition.Value.Stable.V1.t结构为:详细见Mina中的genesis_proof中“2. Snark transition”。
    type t =
        ( Blockchain_state.Value.Stable.V1.t
        , Consensus.Data.Consensus_transition.Value.Stable.V1.t
        , Pending_coinbase.Update.Stable.V1.t )
        Poly.Stable.V1.t
        
    type ( 'blockchain_state
           , 'consensus_transition
           , 'pending_coinbase_update )
           t =
        { blockchain_state : 'blockchain_state
        ; consensus_transition : 'consensus_transition
        ; pending_coinbase_update : 'pending_coinbase_update
        }
    
  • 4)ledger_proof字段:Ledger_proof.Stable.V2.t option结构为:【等价为Transaction_snark.t】。详细见Mina中的genesis_proof中“3.2 Ledger_proof结构”。
    module Prod : S with type t = Transaction_snark.t
    
    include S with type t = Prod.t
    
    module Prod : Ledger_proof_intf.S with type t = Transaction_snark.t = struct
    [%%versioned
    module Stable = struct
    module V2 = struct
      type t = Transaction_snark.Stable.V2.t
    
  • 5)prover_state字段:Consensus.Data.Prover_state.Stable.V2.t结构为:【等价为stake_proof】
    type t =
      { delegator : Account.Index.Stable.V1.t
      ; delegator_pk : Public_key.Compressed.Stable.V1.t
      ; coinbase_receiver_pk : Public_key.Compressed.Stable.V1.t
      ; ledger : Sparse_ledger.Stable.V2.t
      ; producer_private_key : Private_key.Stable.V1.t
      ; producer_public_key : Public_key.Stable.V1.t
      }	
    
  • 6)pending_coinbase字段:Pending_coinbase_witness.Stable.V1.t结构为:
    type t =
      { pending_coinbases : Pending_coinbase.Stable.V1.t; is_new_stack : bool }
    
    其中Pending_coinbase.Stable.V1.t结构为:
    type t =
      ( Merkle_tree_versioned.Stable.V1.t
      , Stack_id.Stable.V1.t ) (* 为int类型 *)
      Poly_versioned.Stable.V1.t
    
    type ('tree, 'stack_id) t = ('tree, 'stack_id) T.Poly.t =
        { tree : 'tree; pos_list : 'stack_id list; new_pos : 'stack_id }
    
    Merkle_tree_versioned.Stable.V1.t结构为:
    type t =
        ( Hash_versioned.Stable.V1.t (* 实际为Ticke曲线的Field.t *)
        , Stack_id.Stable.V1.t (* 为int类型 *)
        , Stack_versioned.Stable.V1.t
        , unit )
        Sparse_ledger_lib.Sparse_ledger.T.Stable.V1.t
    
    Stack_versioned.Stable.V1.t结构为:
    type t =
        (Coinbase_stack.Stable.V1.t, (* 实际为Ticke曲线的Field.t *)
        State_stack.Stable.V1.t) 
        Poly.Stable.V1.t
    
    type ('data_stack, 'state_stack) t =
          { data : 'data_stack; state : 'state_stack }
    
    State_stack.Stable.V1.t结构为:
    type t = Stack_hash.Stable.V1.t (* 实际为Ticke曲线的Field.t *)
    		Poly.Stable.V1.t
    
    type 'stack_hash t = { init : 'stack_hash; curr : 'stack_hash }
    

8.1.2 Worker_state模块

Worker_state模块中包含了:

  • extend_blockchain和verify函数定义。【在create函数中,做了extend_blockchain和verify相应的函数实现
  • ledger_proof_opt和create函数实现。

8.1.3 Functions模块

Functions模块中的结构体定义为:

type ('i, 'o) t =
    'i Bin_prot.Type_class.t
    * 'o Bin_prot.Type_class.t
    * (Worker_state.t -> 'i -> 'o Deferred.t)

Functions模块包含有:

  • create、initialized、 extend_blockchain、verify_blockchain函数实现。

8.1.4 Worker模块

Worker模块包含:

  • Rpc_parallel.Function、Worker_state、Connection_state、Functions子模块

其中Functions子模块中包含了:

  • init_worker_state和init_connection_state的函数实现。

8.2 create_genesis_block流程

genesis_breadcrumb= block=
	Prover.create_genesis_block prover
                  (Genesis_proof.to_inputs precomputed_values)

create_genesis_block函数中的关键在于调用extend_blockchain函数:

let%map chain =
    extend_blockchain t
      (Blockchain.create ~proof:blockchain_dummy ~state:prev_state)
      genesis_inputs.protocol_state_with_hashes.data snark_transition None
      prover_state pending_coinbase

在create时创建的module中做了extend_blockchain函数实现,此时:

  • t(Ledger_proof.t option)参数为None;
  • chain为:[~proof:blockchain_dummy ~state:prev_state]
  • next_state为:genesis_inputs.protocol_state_with_hashes.data
let extend_blockchain (chain : Blockchain.t)
                   (next_state : Protocol_state.Value.t)
                   (block : Snark_transition.value) (t : Ledger_proof.t option)
                   state_for_handler pending_coinbase =
                 let%map.Async.Deferred res =
                   Deferred.Or_error.try_with ~here:[%here] (fun () ->
                       let t = ledger_proof_opt chain next_state t in
                       let%map.Async.Deferred proof =
                         B.step
                           ~handler:
                             (Consensus.Data.Prover_state.handler
                                ~constraint_constants state_for_handler
                                ~pending_coinbase)
                           { transition = block
                           ; prev_state =
                               Blockchain_snark.Blockchain.state chain
                           }
                           [ ( Blockchain_snark.Blockchain.state chain
                             , Blockchain_snark.Blockchain.proof chain )
                           ; t
                           ]
                           next_state
                       in
                       Blockchain_snark.Blockchain.create ~state:next_state
                         ~proof)
                 in
                 Or_error.iter_error res ~f:(fun e ->
                     [%log error]
                       ~metadata:[ ("error", Error_json.error_to_yojson e) ]
                       "Prover threw an error while extending block: $error") ;
                 res

此时:【此时的t参数为None】

let ledger_proof_opt (chain : Blockchain.t) next_state = function
    | Some t ->
        Ledger_proof.
          ({ (statement t) with sok_digest = sok_digest t }, underlying_proof t)
    | None ->
        let bs = Protocol_state.blockchain_state in
        let lh x = Blockchain_state.snarked_ledger_hash (bs x) in
        let tok x = Blockchain_state.snarked_next_available_token (bs x) in
        let chain_state = Blockchain_snark.Blockchain.state chain in
        ( { source = lh chain_state
          ; target = lh next_state
          ; supply_increase = Currency.Amount.zero
          ; fee_excess = Fee_excess.zero
          ; sok_digest = Sok_message.Digest.default
          ; next_available_token_before = tok chain_state
          ; next_available_token_after = tok next_state
          ; pending_coinbase_stack_state =
              { source = Pending_coinbase.Stack.empty
              ; target = Pending_coinbase.Stack.empty
              }
          }
        , Proof.transaction_dummy )

blockchain_state为:

let negative_one
    ~(constraint_constants : Genesis_constants.Constraint_constants.t)
    ~(consensus_constants : Consensus.Constants.t) ~genesis_ledger_hash
    ~snarked_next_available_token : Value.t =
  let genesis_ledger_hash =
    Frozen_ledger_hash.of_ledger_hash genesis_ledger_hash
  in
  { staged_ledger_hash =
      Staged_ledger_hash.genesis ~constraint_constants ~genesis_ledger_hash
  ; snarked_ledger_hash = genesis_ledger_hash
  ; genesis_ledger_hash
  ; snarked_next_available_token
  ; timestamp = consensus_constants.genesis_state_timestamp
  }

相应的step证明见Pickles.ml中的Step proof system,具体为:

let step handler prevs next_state =
          let wrap_vk = Lazy.force wrap_vk in
          S.f ?handler branch_data next_state ~prevs_length:prev_vars_length
            ~self ~step_domains ~self_dlog_plonk_index:wrap_vk.commitments
            (Impls.Step.Keypair.pk (fst (Lazy.force step_pk)))
            wrap_vk.index prevs

详细的证明逻辑见pickles/step.ml中:

let f
      (type max_local_max_branchings self_branches prev_vars prev_values
      local_widths local_heights prevs_length) ?handler
      (T branch_data :
        ( A.t
        , A_value.t
        , Max_branching.n
        , self_branches
        , prev_vars
        , prev_values
        , local_widths
        , local_heights )
        Step_branch_data.t) (next_state : A_value.t)
      ~maxes:
        (module Maxes : Pickles_types.Hlist.Maxes.S
          with type length = Max_branching.n
           and type ns = max_local_max_branchings)
      ~(prevs_length : (prev_vars, prevs_length) Length.t) ~self ~step_domains
      ~self_dlog_plonk_index pk self_dlog_vk
      (prev_with_proofs :
        (prev_values, local_widths, local_heights) H3.T(P.With_data).t) :
      ( A_value.t
      , (_, Max_branching.n) Vector.t
      , (_, prevs_length) Vector.t
      , (_, prevs_length) Vector.t
      , _
      , (_, Max_branching.n) Vector.t )
      P.Base.Pairing_based.t
      Deferred.t =
    let _, prev_vars_length = branch_data.branching in
    let T = Length.contr prev_vars_length prevs_length in
    let (module Req) = branch_data.requests in
    let T = Hlist.Length.contr (snd branch_data.branching) prev_vars_length in
    let prev_values_length =
      let module L12 = H4.Length_1_to_2 (Tag) in
      L12.f branch_data.rule.prevs prev_vars_length
    in
    let lte = branch_data.lte in
    let inners_must_verify =
      let prevs =
        let module M =
          H3.Map1_to_H1 (P.With_data) (Id)
            (struct
              let f : type a. (a, _, _) P.With_data.t -> a =
               fun (T t) -> t.statement.pass_through.app_state
            end)
        in
        M.f prev_with_proofs
      in
      branch_data.rule.main_value prevs next_state
    in
    let module X_hat = struct
      type t = Tock.Field.t Double.t
    end in
    let module Statement_with_hashes = struct
      type t =
        ( Challenge.Constant.t
        , Challenge.Constant.t Scalar_challenge.t
        , Tick.Field.t Shifted_value.Type1.t
        , Tock.Field.t
        , Digest.Constant.t
        , Digest.Constant.t
        , Digest.Constant.t
        , Challenge.Constant.t Scalar_challenge.t Bulletproof_challenge.t
          Step_bp_vec.t
        , Index.t )
        Dlog_based.Statement.In_circuit.t
    end in
    let b_poly = Tock.Field.(Dlog_main.b_poly ~add ~mul ~one) in
    let sgs, unfinalized_proofs, statements_with_hashes, x_hats, witnesses =
      let f :
          type var value max local_max_branching m.
             max Nat.t
          -> Impls.Wrap.Verification_key.t
          -> 'a
          -> (value, local_max_branching, m) P.With_data.t
          -> (var, value, local_max_branching, m) Tag.t
          -> must_verify:bool
          -> [ `Sg of Tock.Curve.Affine.t ]
             * Unfinalized.Constant.t
             * Statement_with_hashes.t
             * X_hat.t
             * (value, local_max_branching, m) Per_proof_witness.Constant.t =
       fun max dlog_vk dlog_index (T t) tag ~must_verify ->
        let plonk0 = t.statement.proof_state.deferred_values.plonk in
        let plonk =
          let domain =
            (Vector.to_array (Types_map.lookup_step_domains tag)).(Index.to_int
                                                                     t.statement
                                                                       .proof_state
                                                                       .deferred_values
                                                                       .which_branch)
          in
          let to_field =
            SC.to_field_constant
              (module Tick.Field)
              ~endo:Endo.Wrap_inner_curve.scalar
          in
          let alpha = to_field plonk0.alpha in
          let zeta = to_field plonk0.zeta in
          let zetaw =
            Tick.Field.(
              zeta * domain_generator ~log2_size:(Domain.log2_size domain))
          in
          let combined_evals =
            Plonk_checks.evals_of_split_evals
              (module Tick.Field)
              (Double.map t.prev_evals.evals ~f:(fun e -> e.evals))
              ~rounds:(Nat.to_int Tick.Rounds.n) ~zeta ~zetaw
          in
          let plonk_minimal =
            { Composition_types.Dlog_based.Proof_state.Deferred_values.Plonk
              .Minimal
              .zeta
            ; alpha
            ; beta = Challenge.Constant.to_tick_field plonk0.beta
            ; gamma = Challenge.Constant.to_tick_field plonk0.gamma
            }
          in
          let env =
            Plonk_checks.scalars_env
              (module Tick.Field)
              ~srs_length_log2:Common.Max_degree.step_log2
              ~endo:Endo.Step_inner_curve.base ~mds:Tick_field_sponge.params.mds
              ~field_of_hex:(fun s ->
                Kimchi_pasta.Pasta.Bigint256.of_hex_string s
                |> Kimchi_pasta.Pasta.Fp.of_bigint)
              ~domain:
                (Plonk_checks.domain
                   (module Tick.Field)
                   domain ~shifts:Common.tick_shifts
                   ~domain_generator:Backend.Tick.Field.domain_generator)
              plonk_minimal combined_evals
          in
          time "plonk_checks" (fun () ->
              Plonk_checks.Type1.derive_plonk
                (module Tick.Field)
                ~env ~shift:Shifts.tick1 plonk_minimal combined_evals)
        in
        let data = Types_map.lookup_basic tag in
        let (module Local_max_branching) = data.max_branching in
        let T = Local_max_branching.eq in
        let statement = t.statement in
        let prev_challenges =
          (* TODO: This is redone in the call to Dlog_based_reduced_me_only.prepare *)
          Vector.map ~f:Ipa.Wrap.compute_challenges
            statement.proof_state.me_only.old_bulletproof_challenges
        in
        let prev_statement_with_hashes :
            ( _
            , _
            , _ Shifted_value.Type1.t
            , _
            , _
            , _
            , _
            , _
            , _ )
            Dlog_based.Statement.In_circuit.t =
          { pass_through =
              Common.hash_pairing_me_only
                (Reduced_me_only.Pairing_based.prepare
                   ~dlog_plonk_index:dlog_index statement.pass_through)
                ~app_state:data.value_to_field_elements
          ; proof_state =
              { statement.proof_state with
                deferred_values =
                  { statement.proof_state.deferred_values with
                    plonk =
                      { plonk with
                        zeta = plonk0.zeta
                      ; alpha = plonk0.alpha
                      ; beta = plonk0.beta
                      ; gamma = plonk0.gamma
                      }
                  }
              ; me_only =
                  Common.hash_dlog_me_only Max_branching.n
                    { old_bulletproof_challenges =
                        (* TODO: Get rid of this padding *)
                        Vector.extend_exn prev_challenges Max_branching.n
                          Dummy.Ipa.Wrap.challenges_computed
                    ; sg = statement.proof_state.me_only.sg
                    }
              }
          }
        in
        let module O = Tock.Oracles in
        let o =
          let public_input =
            tock_public_input_of_statement prev_statement_with_hashes
          in
          O.create dlog_vk
            Vector.(
              map2
                (Vector.extend_exn statement.pass_through.sg
                   Local_max_branching.n
                   (Lazy.force Dummy.Ipa.Wrap.sg))
                (* This should indeed have length max_branching... No! It should have type max_branching_a. That is, the max_branching specific to a proof of this type...*)
                prev_challenges
                ~f:(fun commitment chals ->
                  { Tock.Proof.Challenge_polynomial.commitment
                  ; challenges = Vector.to_array chals
                  })
              |> to_list)
            public_input t.proof
        in
        let ((x_hat_1, x_hat_2) as x_hat) = O.(p_eval_1 o, p_eval_2 o) in
        let scalar_chal f =
          Scalar_challenge.map ~f:Challenge.Constant.of_tock_field (f o)
        in
        let plonk0 =
          { Types.Dlog_based.Proof_state.Deferred_values.Plonk.Minimal.alpha =
              scalar_chal O.alpha
          ; beta = O.beta o
          ; gamma = O.gamma o
          ; zeta = scalar_chal O.zeta
          }
        in
        let xi = scalar_chal O.v in
        let r = scalar_chal O.u in
        let sponge_digest_before_evaluations = O.digest_before_evaluations o in
        let to_field =
          SC.to_field_constant
            (module Tock.Field)
            ~endo:Endo.Step_inner_curve.scalar
        in
        let module As_field = struct
          let r = to_field r

          let xi = to_field xi

          let zeta = to_field plonk0.zeta

          let alpha = to_field plonk0.alpha
        end in
        let w =
          Tock.Field.domain_generator
            ~log2_size:(Domain.log2_size data.wrap_domains.h)
        in
        let zetaw = Tock.Field.mul As_field.zeta w in
        let new_bulletproof_challenges, b =
          let prechals =
            Array.map (O.opening_prechallenges o) ~f:(fun x ->
                Scalar_challenge.map ~f:Challenge.Constant.of_tock_field x)
          in
          let chals =
            Array.map prechals ~f:(fun x -> Ipa.Wrap.compute_challenge x)
          in
          let b_poly = unstage (b_poly chals) in
          let open As_field in
          let b =
            let open Tock.Field in
            b_poly zeta + (r * b_poly zetaw)
          in
          let prechals =
            Vector.of_list_and_length_exn
              ( Array.map prechals ~f:(fun x ->
                    { Bulletproof_challenge.prechallenge = x })
              |> Array.to_list )
              Tock.Rounds.n
          in
          (prechals, b)
        in
        let sg =
          if not must_verify then Ipa.Wrap.compute_sg new_bulletproof_challenges
          else t.proof.openings.proof.sg
        in
        let witness : _ Per_proof_witness.Constant.t =
          ( t.P.Base.Dlog_based.statement.pass_through.app_state
          , { prev_statement_with_hashes.proof_state with me_only = () }
          , t.prev_evals
          , Vector.extend_exn t.statement.pass_through.sg Local_max_branching.n
              (Lazy.force Dummy.Ipa.Wrap.sg)
            (* TODO: This computation is also redone elsewhere. *)
          , Vector.extend_exn
              (Vector.map t.statement.pass_through.old_bulletproof_challenges
                 ~f:Ipa.Step.compute_challenges)
              Local_max_branching.n Dummy.Ipa.Step.challenges_computed
          , ({ t.proof.openings.proof with sg }, t.proof.messages) )
        in
        let tock_domain =
          Plonk_checks.domain
            (module Tock.Field)
            data.wrap_domains.h ~shifts:Common.tock_shifts
            ~domain_generator:Backend.Tock.Field.domain_generator
        in
        let tock_combined_evals =
          Plonk_checks.evals_of_split_evals
            (module Tock.Field)
            t.proof.openings.evals ~rounds:(Nat.to_int Tock.Rounds.n)
            ~zeta:As_field.zeta ~zetaw
        in
        let tock_plonk_minimal =
          { plonk0 with zeta = As_field.zeta; alpha = As_field.alpha }
        in
        let tock_env =
          Plonk_checks.scalars_env
            (module Tock.Field)
            ~domain:tock_domain ~srs_length_log2:Common.Max_degree.wrap_log2
            ~field_of_hex:(fun s ->
              Kimchi_pasta.Pasta.Bigint256.of_hex_string s
              |> Kimchi_pasta.Pasta.Fq.of_bigint)
            ~endo:Endo.Wrap_inner_curve.base ~mds:Tock_field_sponge.params.mds
            tock_plonk_minimal tock_combined_evals
        in
        let combined_inner_product =
          let e1, e2 = t.proof.openings.evals in
          let b_polys =
            Vector.map
              ~f:(fun chals -> unstage (b_poly (Vector.to_array chals)))
              prev_challenges
          in
          let open As_field in
          let combine ~ft_eval (x_hat : Tock.Field.t) pt e =
            let a, b = Dlog_plonk_types.Evals.(to_vectors (e : _ array t)) in
            let v : (Tock.Field.t array, _) Vector.t =
              Vector.append
                (Vector.map b_polys ~f:(fun f -> [| f pt |]))
                ([| x_hat |] :: [| ft_eval |] :: a)
                (snd (Local_max_branching.add Nat.N26.n))
            in
            let open Tock.Field in
            Pcs_batch.combine_split_evaluations
              (Common.dlog_pcs_batch (Local_max_branching.add Nat.N26.n))
              ~xi ~init:Fn.id ~mul ~last:Array.last
              ~mul_and_add:(fun ~acc ~xi fx -> fx + (xi * acc))
              ~evaluation_point:pt
              ~shifted_pow:(fun deg x ->
                Pcs_batch.pow ~one ~mul x
                  Int.(Max_degree.wrap - (deg mod Max_degree.wrap)))
              v b
          in
          let ft_eval0 =
            Plonk_checks.Type2.ft_eval0
              (module Tock.Field)
              ~domain:tock_domain ~env:tock_env tock_plonk_minimal
              tock_combined_evals x_hat_1
          in
          let open Tock.Field in
          combine ~ft_eval:ft_eval0 x_hat_1 As_field.zeta e1
          + (r * combine ~ft_eval:t.proof.openings.ft_eval1 x_hat_2 zetaw e2)
        in
        let chal = Challenge.Constant.of_tock_field in
        let plonk =
          Plonk_checks.Type2.derive_plonk
            (module Tock.Field)
            ~env:tock_env ~shift:Shifts.tock2 tock_plonk_minimal
            tock_combined_evals
        in
        let shifted_value =
          Shifted_value.Type2.of_field (module Tock.Field) ~shift:Shifts.tock2
        in
        ( `Sg sg
        , { Types.Pairing_based.Proof_state.Per_proof.deferred_values =
              { plonk =
                  { plonk with
                    zeta = plonk0.zeta
                  ; alpha = plonk0.alpha
                  ; beta = chal plonk0.beta
                  ; gamma = chal plonk0.gamma
                  }
              ; combined_inner_product = shifted_value combined_inner_product
              ; xi
              ; bulletproof_challenges = new_bulletproof_challenges
              ; b = shifted_value b
              }
          ; should_finalize = must_verify
          ; sponge_digest_before_evaluations =
              Digest.Constant.of_tock_field sponge_digest_before_evaluations
          }
        , prev_statement_with_hashes
        , x_hat
        , witness )
      in
      let rec go :
          type vars values ns ms maxes k.
             (values, ns, ms) H3.T(P.With_data).t
          -> maxes H1.T(Nat).t
          -> (vars, values, ns, ms) H4.T(Tag).t
          -> vars H1.T(E01(Bool)).t
          -> (vars, k) Length.t
          -> (Tock.Curve.Affine.t, k) Vector.t
             * (Unfinalized.Constant.t, k) Vector.t
             * (Statement_with_hashes.t, k) Vector.t
             * (X_hat.t, k) Vector.t
             * (values, ns, ms) H3.T(Per_proof_witness.Constant).t =
       fun ps maxes ts must_verifys l ->
        match (ps, maxes, ts, must_verifys, l) with
        | [], _, [], [], Z ->
            ([], [], [], [], [])
        | p :: ps, max :: maxes, t :: ts, must_verify :: must_verifys, S l ->
            let dlog_vk, dlog_index =
              if Type_equal.Id.same self.Tag.id t.id then
                (self_dlog_vk, self_dlog_plonk_index)
              else
                let d = Types_map.lookup_basic t in
                (d.wrap_vk, d.wrap_key)
            in
            let `Sg sg, u, s, x, w = f max dlog_vk dlog_index p t ~must_verify
            and sgs, us, ss, xs, ws = go ps maxes ts must_verifys l in
            (sg :: sgs, u :: us, s :: ss, x :: xs, w :: ws)
        | _ :: _, [], _, _, _ ->
            assert false
      in
      go prev_with_proofs Maxes.maxes branch_data.rule.prevs inners_must_verify
        prev_vars_length
    in
    let next_statement : _ Types.Pairing_based.Statement.t =
      let unfinalized_proofs_extended =
        Vector.extend unfinalized_proofs lte Max_branching.n
          Unfinalized.Constant.dummy
      in
      let pass_through =
        let module M =
          H3.Map2_to_H1 (P.With_data) (P.Base.Me_only.Dlog_based)
            (struct
              let f :
                  type a b c.
                  (a, b, c) P.With_data.t -> b P.Base.Me_only.Dlog_based.t =
               fun (T t) -> t.statement.proof_state.me_only
            end)
        in
        M.f prev_with_proofs
      in
      let old_bulletproof_challenges =
        let module VV = struct
          type t =
            Challenge.Constant.t Scalar_challenge.t Bulletproof_challenge.t
            Step_bp_vec.t
        end in
        let module M =
          H3.Map
            (P.With_data)
            (E03 (VV))
            (struct
              let f (T t : _ P.With_data.t) : VV.t =
                t.statement.proof_state.deferred_values.bulletproof_challenges
            end)
        in
        let module V = H3.To_vector (VV) in
        V.f prev_values_length (M.f prev_with_proofs)
      in
      let me_only : _ Reduced_me_only.Pairing_based.t =
        (* Have the sg be available in the opening proof and verify it. *)
        { app_state = next_state; sg = sgs; old_bulletproof_challenges }
      in
      { proof_state =
          { unfinalized_proofs = unfinalized_proofs_extended; me_only }
      ; pass_through
      }
    in
    let next_me_only_prepared =
      Reduced_me_only.Pairing_based.prepare
        ~dlog_plonk_index:self_dlog_plonk_index
        next_statement.proof_state.me_only
    in
    let handler (Snarky_backendless.Request.With { request; respond } as r) =
      let k x = respond (Provide x) in
      match request with
      | Req.Proof_with_datas ->
          k witnesses
      | Req.Wrap_index ->
          k self_dlog_plonk_index
      | Req.App_state ->
          k next_me_only_prepared.app_state
      | _ -> (
          match handler with
          | Some f ->
              f r
          | None ->
              Snarky_backendless.Request.unhandled )
    in
    let next_statement_hashed : _ Types.Pairing_based.Statement.t =
      let rec pad :
          type n k maxes pvals lws lhs.
             (Digest.Constant.t, k) Vector.t
          -> maxes H1.T(Nat).t
          -> (maxes, n) Hlist.Length.t
          -> (Digest.Constant.t, n) Vector.t =
       fun xs maxes l ->
        match (xs, maxes, l) with
        | [], [], Z ->
            []
        | x :: xs, [], Z ->
            assert false
        | x :: xs, _ :: ms, S n ->
            x :: pad xs ms n
        | [], m :: ms, S n ->
            let t : _ Types.Dlog_based.Proof_state.Me_only.t =
              { sg = Lazy.force Dummy.Ipa.Step.sg
              ; old_bulletproof_challenges =
                  Vector.init Max_branching.n ~f:(fun _ ->
                      Dummy.Ipa.Wrap.challenges_computed)
              }
            in
            Common.hash_dlog_me_only Max_branching.n t :: pad [] ms n
      in
      { proof_state =
          { next_statement.proof_state with
            me_only =
              Common.hash_pairing_me_only ~app_state:A_value.to_field_elements
                next_me_only_prepared
          }
      ; pass_through =
          (* TODO: Use the same pad_pass_through function as in wrap *)
          pad
            (Vector.map statements_with_hashes ~f:(fun s ->
                 s.proof_state.me_only))
            Maxes.maxes Maxes.length
      }
    in
    let prev_polynomials =
      let to_fold_in =
        let module M =
          H3.Map
            (P.With_data)
            (E03 (Tick.Curve.Affine))
            (struct
              let f (T t : _ P.With_data.t) = t.statement.proof_state.me_only.sg
            end)
        in
        let module V = H3.To_vector (Tick.Curve.Affine) in
        V.f prev_values_length (M.f prev_with_proofs)
      in
      (* emphatically NOT padded with dummies *)
      Vector.(
        map2 to_fold_in next_me_only_prepared.old_bulletproof_challenges
          ~f:(fun commitment chals ->
            { Tick.Proof.Challenge_polynomial.commitment
            ; challenges = Vector.to_array chals
            })
        |> to_list)
    in
    let%map.Async_kernel.Deferred (next_proof : Tick.Proof.t) =
      let (T (input, conv)) =
        Impls.Step.input ~branching:Max_branching.n ~wrap_rounds:Tock.Rounds.n
      in
      let { Domains.h; x } =
        List.nth_exn
          (Vector.to_list step_domains)
          (Index.to_int branch_data.index)
      in
      ksprintf Common.time "step-prover %d (%d, %d)"
        (Index.to_int branch_data.index) (Domain.size h) (Domain.size x)
        (fun () ->
          Impls.Step.generate_witness_conv
            ~f:
              (fun { Impls.Step.Proof_inputs.auxiliary_inputs; public_inputs } ->
              Backend.Tick.Proof.create_async ~primary:public_inputs
                ~auxiliary:auxiliary_inputs ~message:prev_polynomials pk)
            [ input ]
            (fun x () : unit ->
              Impls.Step.handle
                (fun () : unit -> branch_data.main ~step_domains (conv x))
                handler)
            () next_statement_hashed)
    in
    let prev_evals =
      let module M =
        H3.Map
          (P.With_data)
          (E03 (E))
          (struct
            let f (T t : _ P.With_data.t) =
              (t.proof.openings.evals, t.proof.openings.ft_eval1)
          end)
      in
      let module V = H3.To_vector (E) in
      V.f prev_values_length (M.f prev_with_proofs)
    in
    { P.Base.Pairing_based.proof = next_proof
    ; statement = next_statement
    ; index = branch_data.index
    ; prev_evals =
        Vector.extend
          (Vector.map2 prev_evals x_hats ~f:(fun (es, ft_eval1) x_hat ->
               Dlog_plonk_types.All_evals.
                 { ft_eval1
                 ; evals =
                     Double.map2 es x_hat ~f:(fun es x_hat ->
                         { With_public_input.evals = es; public_input = x_hat })
                 }))
          lte Max_branching.n Dummy.evals
    }

8.3 生成区块证明——protocol_state_proof流程

genesis_breadcrumb= block=
	Prover.create_genesis_block prover
                  (Genesis_proof.to_inputs precomputed_values)
previous_protocol_state_proof = Blockchain_snark.Blockchain.proof block

let previous_protocol_state =
              External_transition.protocol_state
                (With_hash.data previous_transition)
protocol_state_proof = 
		Prover.prove prover
              ~prev_state:previous_protocol_state
              ~prev_state_proof:previous_protocol_state_proof
              ~next_state:protocol_state internal_transition
              pending_coinbase_witness)

其中的protocol_state和internal_transition来源于:

let%bind next_state_opt =
              generate_next_state ~constraint_constants ~scheduled_time
                ~block_data ~previous_protocol_state ~time_controller
                ~staged_ledger:(Breadcrumb.staged_ledger crumb)
                ~transactions ~get_completed_work ~logger ~log_block_creation
                ~winner_pk ~block_reward_threshold
 match next_state_opt with
            | Some
                (protocol_state, internal_transition, pending_coinbase_witness)
              -> ......
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值