1. 引言
Mina系列博客有:
- Mina概览
- Mina的支付流程
- Mina的zkApp
- Mina中的Pasta(Pallas和Vesta)曲线
- Mina中的Schnorr signature
- Mina中的Pickles SNARK
- Mina中的Kimchi SNARK
- Mina Kimchi SNARK 代码解析
- Mina Berkeley QANet测试网zkApp初体验
- Mina中的Poseidon hash
- Mina中的多项式承诺方案
- Recursive SNARKs总览
- 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)
(rx∈Fq,s∈Fr):
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)
(x∈Fq,y∈Fq),表示为:
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结构为
其中的Tag结构为:【交易类型:payment、委托质押、创建账号、mint token、fee transfer、coinbase。其中前4种对应为user_command交易,对应is_user_command=true;fee transfer和coinbase交易不是user_command交易,is_user_command=false。】(* 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 }
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结构为:
其中Pending_coinbase.Stable.V1.t结构为:type t = { pending_coinbases : Pending_coinbase.Stable.V1.t; is_new_stack : bool }
Merkle_tree_versioned.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 }
Stack_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
State_stack.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 }
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)
-> ......