-
Notifications
You must be signed in to change notification settings - Fork 542
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fast zkapp proofs with max_proofs_verified=0 #11053
Changes from all commits
8cb7303
93323ef
71bf1ae
d952a58
eb1f178
01c368a
cb41a41
4304cc5
40259f6
19644b7
418157e
a1529d0
a379027
f1ccdf5
7f1f44c
460c394
d935d0f
07d8e9f
8e6eba7
abb4bdf
c6f22ef
c9c313a
3b8fec1
e50044e
a36456f
017807b
c3f0511
2830249
065d068
c25a427
f71d634
e1490b0
692932e
b7b41c5
6f2f67b
d548186
502c31f
8bf6160
6bb6197
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -51,30 +51,56 @@ module As_field = struct | |
|
||
let of_field_obj (x : field_class Js.t) : t = Obj.magic x | ||
|
||
let of_number_exn (value : t) : Impl.Field.t = | ||
let number : Js.number Js.t = Obj.magic value in | ||
let float = Js.float_of_number number in | ||
if Float.is_integer float then | ||
if float >= 0. then | ||
Impl.Field.( | ||
constant @@ Constant.of_string @@ Js.to_string @@ number##toString) | ||
else | ||
let number : Js.number Js.t = Obj.magic (-.float) in | ||
Impl.Field.negate | ||
Impl.Field.( | ||
constant @@ Constant.of_string @@ Js.to_string @@ number##toString) | ||
else raise_error "Cannot convert a float to a field element" | ||
|
||
let of_boolean (value : t) : Impl.Field.t = | ||
let value = Js.to_bool (Obj.magic value) in | ||
if value then Impl.Field.one else Impl.Field.zero | ||
|
||
let of_string_exn (value : t) : Impl.Field.t = | ||
let value : Js.js_string Js.t = Obj.magic value in | ||
let s = Js.to_string value in | ||
try | ||
Impl.Field.constant | ||
( if | ||
String.length s >= 2 | ||
&& Char.equal s.[0] '0' | ||
&& Char.equal (Char.lowercase_ascii s.[1]) 'x' | ||
then Kimchi_pasta.Pasta.Fp.(of_bigint (Bigint.of_hex_string s)) | ||
else if String.length s >= 1 && Char.equal s.[0] '-' then | ||
String.sub s 1 (String.length s - 1) | ||
|> Impl.Field.Constant.of_string |> Impl.Field.Constant.negate | ||
else Impl.Field.Constant.of_string s ) | ||
with Failure e -> raise_error e | ||
|
||
let of_bigint_exn (value : t) : Impl.Field.t = | ||
let bigint : < toString : Js.js_string Js.t Js.meth > Js.t = | ||
Obj.magic value | ||
in | ||
bigint##toString |> Obj.magic |> of_string_exn | ||
|
||
let value (value : t) : Impl.Field.t = | ||
match Js.to_string (Js.typeof (Obj.magic value)) with | ||
| "number" -> | ||
let value = Js.float_of_number (Obj.magic value) in | ||
if Float.is_integer value then | ||
let value = Float.to_int value in | ||
if value >= 0 then Impl.Field.of_int value | ||
else Impl.Field.negate (Impl.Field.of_int (-value)) | ||
else raise_error "Cannot convert a float to a field element" | ||
of_number_exn value | ||
| "boolean" -> | ||
let value = Js.to_bool (Obj.magic value) in | ||
if value then Impl.Field.one else Impl.Field.zero | ||
| "string" -> ( | ||
let value : Js.js_string Js.t = Obj.magic value in | ||
let s = Js.to_string value in | ||
try | ||
Impl.Field.constant | ||
( if | ||
String.length s >= 2 | ||
&& Char.equal s.[0] '0' | ||
&& Char.equal (Char.lowercase_ascii s.[1]) 'x' | ||
then Kimchi_pasta.Pasta.Fp.(of_bigint (Bigint.of_hex_string s)) | ||
else Impl.Field.Constant.of_string s ) | ||
with Failure e -> raise_error e ) | ||
of_boolean value | ||
| "string" -> | ||
of_string_exn value | ||
| "bigint" -> | ||
of_bigint_exn value | ||
| "object" -> | ||
let is_array = Js.to_bool (Js.Unsafe.global ##. Array##isArray value) in | ||
if is_array then | ||
|
@@ -228,6 +254,11 @@ let optdef_arg_method (type a) class_ (name : string) | |
in | ||
Js.Unsafe.set prototype (Js.string name) meth | ||
|
||
let to_js_bigint = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unrelated |
||
let bigint_constr = Js.Unsafe.eval_string {js|BigInt|js} in | ||
fun (s : Js.js_string Js.t) -> | ||
Js.Unsafe.fun_call bigint_constr [| Js.Unsafe.inject s |] | ||
|
||
let to_js_field x : field_class Js.t = new%js field_constr (As_field.of_field x) | ||
|
||
let of_js_field (x : field_class Js.t) : Field.t = x##.value | ||
|
@@ -278,6 +309,7 @@ let () = | |
method_ "sizeInFields" (fun _this : int -> 1) ; | ||
method_ "toFields" (fun this : field_class Js.t Js.js_array Js.t -> | ||
singleton_array this ) ; | ||
method_ "toBigInt" (fun this -> to_string this##.value |> to_js_bigint) ; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unrelated |
||
((* TODO: Make this work with arbitrary bit length *) | ||
let bit_length = Field.size_in_bits - 2 in | ||
let cmp_method (name, f) = | ||
|
@@ -358,6 +390,10 @@ let () = | |
in | ||
field_class##.one := mk Field.one ; | ||
field_class##.zero := mk Field.zero ; | ||
field_class##.minusOne := mk @@ Field.negate Field.one ; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unrelated |
||
Js.Unsafe.set field_class (Js.string "ORDER") | ||
( to_js_bigint @@ Js.string @@ Pasta_bindings.BigInt256.to_string | ||
@@ Pasta_bindings.Fp.size () ) ; | ||
field_class##.random := | ||
Js.wrap_callback (fun () : field_class Js.t -> | ||
mk (Field.constant (Field.Constant.random ())) ) ; | ||
|
@@ -494,7 +530,11 @@ let () = | |
else Field.Constant.of_string s ) ) | ||
with Failure _ -> Js.Opt.empty ) | ||
| _ -> | ||
Js.Opt.empty ) | ||
Js.Opt.empty ) ; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unrelated |
||
let from f x = new%js field_constr (As_field.of_field (f x)) in | ||
static_method "fromNumber" (from As_field.of_number_exn) ; | ||
static_method "fromString" (from As_field.of_string_exn) ; | ||
static_method "fromBigInt" (from As_field.of_bigint_exn) | ||
|
||
let () = | ||
let handle_constants2 f f_constant (x : Boolean.var) (y : Boolean.var) = | ||
|
@@ -517,13 +557,18 @@ let () = | |
method_ name (fun this (y : As_bool.t) : bool_class Js.t -> | ||
mk (f this##.value (As_bool.value y)) ) | ||
in | ||
Js.Unsafe.set bool_class (Js.string "true") (mk Boolean.true_) ; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unrelated |
||
Js.Unsafe.set bool_class (Js.string "false") (mk Boolean.false_) ; | ||
method_ "toField" (fun this : field_class Js.t -> | ||
new%js field_constr (As_field.of_field (this##.value :> Field.t)) ) ; | ||
add_op1 "not" Boolean.not ; | ||
add_op2 "and" Boolean.( &&& ) ; | ||
add_op2 "or" Boolean.( ||| ) ; | ||
method_ "assertEquals" (fun this (y : As_bool.t) : unit -> | ||
Boolean.Assert.( = ) this##.value (As_bool.value y) ) ; | ||
method_ "assertTrue" (fun this : unit -> Boolean.Assert.is_true this##.value) ; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unrelated |
||
method_ "assertFalse" (fun this : unit -> | ||
Boolean.Assert.( = ) this##.value Boolean.false_ ) ; | ||
add_op2 "equals" equal ; | ||
method_ "toBoolean" (fun this : bool Js.t -> | ||
match (this##.value :> Field.t) with | ||
|
@@ -1570,7 +1615,7 @@ module Zkapp_statement = struct | |
val atParty = to_js_field at_party | ||
end | ||
|
||
let of_js (statement : zkapp_statement_js) = | ||
let of_js (statement : zkapp_statement_js) : t = | ||
{ transaction = of_js_field statement##.transaction | ||
; at_party = of_js_field statement##.atParty | ||
} | ||
|
@@ -1585,6 +1630,11 @@ module Zkapp_statement = struct | |
{ transaction = Field.constant transaction | ||
; at_party = Field.constant at_party | ||
} | ||
|
||
let of_js (statement : zkapp_statement_js) : t = | ||
{ transaction = of_js_field statement##.transaction |> to_unchecked | ||
; at_party = of_js_field statement##.atParty |> to_unchecked | ||
} | ||
end | ||
end | ||
|
||
|
@@ -1642,26 +1692,11 @@ let create_pickles_rule ((identifier, main) : pickles_rule_js) = | |
; main_value = (fun _ _ -> []) | ||
} | ||
|
||
let dummy_rule self = | ||
{ identifier = "dummy" | ||
; prevs = [ self; self ] | ||
; main_value = (fun _ _ -> [ true; true ]) | ||
; main = | ||
(fun _ _ -> | ||
dummy_constraints () ; | ||
(* unsatisfiable *) | ||
let x = | ||
Impl.exists Field.typ ~compute:(fun () -> Field.Constant.zero) | ||
in | ||
Field.(Assert.equal x (x + one)) ; | ||
Boolean.[ true_; true_ ] ) | ||
} | ||
|
||
let other_verification_key_constr : | ||
(Other_impl.Verification_key.t -> verification_key_class Js.t) Js.constr = | ||
Obj.magic verification_key_class | ||
|
||
type proof = (Pickles_types.Nat.N2.n, Pickles_types.Nat.N2.n) Pickles.Proof.t | ||
type proof = (Pickles_types.Nat.N0.n, Pickles_types.Nat.N0.n) Pickles.Proof.t | ||
|
||
module Statement_with_proof = | ||
Pickles_types.Hlist.H3.T (Pickles.Statement_with_proof) | ||
|
@@ -1696,10 +1731,8 @@ let nat_module (i : int) : (module Pickles_types.Nat.Intf) = | |
|
||
let pickles_compile (choices : pickles_rule_js Js.js_array Js.t) = | ||
let choices = choices |> Js.to_array |> Array.to_list in | ||
let branches = List.length choices + 1 in | ||
let choices ~self = | ||
List.map choices ~f:create_pickles_rule @ [ dummy_rule self ] | ||
in | ||
let branches = List.length choices in | ||
let choices ~self:_ = List.map choices ~f:create_pickles_rule in | ||
let (module Branches) = nat_module branches in | ||
(* TODO get rid of Obj.magic for choices *) | ||
let tag, _cache, p, provers = | ||
|
@@ -1708,7 +1741,7 @@ let pickles_compile (choices : pickles_rule_js Js.js_array Js.t) = | |
(module Zkapp_statement.Constant) | ||
~typ:zkapp_statement_typ | ||
~branches:(module Branches) | ||
~max_proofs_verified:(module Pickles_types.Nat.N2) | ||
~max_proofs_verified:(module Pickles_types.Nat.N0) | ||
(* ^ TODO make max_branching configurable -- needs refactor in party types *) | ||
~name:"smart-contract" | ||
~constraint_constants: | ||
|
@@ -1731,15 +1764,18 @@ let pickles_compile (choices : pickles_rule_js Js.js_array Js.t) = | |
(* TODO: get rid of Obj.magic, this should be an empty "H3.T" *) | ||
let prevs = Obj.magic [] in | ||
let statement = Zkapp_statement.(statement_js |> of_js |> to_constant) in | ||
prover ?handler:None prevs statement |> Promise_js_helpers.to_js | ||
prover ?handler:None prevs statement | ||
|> Promise.map ~f:Pickles.Side_loaded.Proof.of_proof | ||
|> Promise_js_helpers.to_js | ||
in | ||
prove | ||
in | ||
let rec to_js_provers : | ||
type a b c. | ||
(a, b, c, Zkapp_statement.Constant.t, proof Promise.t) Pickles.Provers.t | ||
-> (zkapp_statement_js -> proof Promise_js_helpers.js_promise) list = | ||
function | ||
-> ( zkapp_statement_js | ||
-> Pickles.Side_loaded.Proof.t Promise_js_helpers.js_promise ) | ||
list = function | ||
| [] -> | ||
[] | ||
| p :: ps -> | ||
|
@@ -2198,6 +2234,21 @@ module Ledger = struct | |
| Proof _ | None_given -> | ||
() ) | ||
|
||
let verify_party_proof (statement : zkapp_statement_js) | ||
(proof : Js.js_string Js.t) (vk : Js.js_string Js.t) = | ||
let statement = Zkapp_statement.Constant.of_js statement in | ||
let proof = | ||
Result.ok_or_failwith | ||
(Pickles.Side_loaded.Proof.of_base64 (Js.to_string proof)) | ||
in | ||
let vk = | ||
Pickles.Side_loaded.Verification_key.of_base58_check_exn (Js.to_string vk) | ||
in | ||
Pickles.Side_loaded.verify_promise | ||
[ (vk, statement, proof) ] | ||
~value_to_field_elements:Zkapp_statement.Constant.to_field_elements | ||
|> Promise.map ~f:Js.bool |> Promise_js_helpers.to_js | ||
|
||
let public_key_to_string (pk : public_key) : Js.js_string Js.t = | ||
pk |> public_key |> Signature_lib.Public_key.Compressed.to_base58_check | ||
|> Js.string | ||
|
@@ -2336,6 +2387,8 @@ module Ledger = struct | |
static_method "signFieldElement" sign_field_element ; | ||
static_method "signFeePayer" sign_fee_payer ; | ||
static_method "signOtherParty" sign_other_party ; | ||
static_method "verifyPartyProof" verify_party_proof ; | ||
|
||
static_method "publicKeyToString" public_key_to_string ; | ||
static_method "publicKeyOfString" public_key_of_string ; | ||
static_method "privateKeyToString" private_key_to_string ; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,8 +5,8 @@ let () = | |
let js_layout = | ||
`Assoc | ||
[ ("Parties", layout Parties.deriver) | ||
; ("BalanceChange", layout Fields_derivers_zkapps.Derivers.balance_change) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unrelated |
||
; ("Party", layout Party.Graphql_repr.deriver) | ||
] | ||
in | ||
|
||
print_endline (js_layout |> Yojson.Safe.pretty_to_string) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ import { | |
Mina, | ||
signFeePayer, | ||
Permissions, | ||
Ledger, | ||
} from "snarkyjs"; | ||
import { tic, toc } from "./tictoc.js"; | ||
|
||
|
@@ -90,6 +91,16 @@ partiesJsonInitialize = signFeePayer(partiesJsonInitialize, senderKey, { | |
}); | ||
toc(); | ||
|
||
// verify the proof | ||
tic("verify transaction proof"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: |
||
let parties = JSON.parse(partiesJsonInitialize); | ||
let proof = parties.otherParties[0].authorization.proof; | ||
let statement = Ledger.transactionStatement(partiesJsonInitialize, 0); | ||
let ok = await Ledger.verifyPartyProof(statement, proof, verificationKey.data); | ||
toc(); | ||
console.log("did proof verify?", ok); | ||
if (!ok) throw Error("proof didn't verify"); | ||
|
||
tic("apply initialize transaction"); | ||
Local.applyJsonTransaction(partiesJsonInitialize); | ||
toc(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes are unrelated. Please open a separate PR for them in future.