Skip to content
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

Merged
merged 39 commits into from
Jun 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
8cb7303
[snarkyjs] do not export balance change type
mitschabaude May 23, 2022
93323ef
bump snarkyjs
mitschabaude May 23, 2022
71bf1ae
[snarkyjs] fix Field(large number)
mitschabaude May 23, 2022
d952a58
bump snarkyjs
mitschabaude May 23, 2022
eb1f178
[snarkyjs] switch to max_proofs_verified:N0
mitschabaude May 23, 2022
01c368a
Merge branch 'simplify-per-branch-data' into feature/faster-zkapp-proofs
mitschabaude May 24, 2022
cb41a41
Merge branch 'develop' into tmp
mitschabaude May 24, 2022
4304cc5
[snarkyjs] Field(bigint), Field('-1'), Field.fromX
mitschabaude May 24, 2022
40259f6
[snarkyjs] Field.toBigint, minusOne, ORDER
mitschabaude May 25, 2022
19644b7
bump snarkyjs
mitschabaude May 25, 2022
418157e
bump snarkyjs
mitschabaude May 26, 2022
a1529d0
Merge branch 'develop' into feature/snarkyjs-0.3.4
mitschabaude May 26, 2022
a379027
bump snarkyjs
mitschabaude May 26, 2022
f1ccdf5
Merge branch 'feature/consolidated-preconditions-parties' into featur…
mitschabaude May 26, 2022
7f1f44c
Merge branch 'pickles-wrap-hack' into feature/faster-zkapp-proofs
mitschabaude May 26, 2022
460c394
[snarkyjs] convert pickles proof to tx proof type
mitschabaude May 26, 2022
d935d0f
[snarkyjs] enable verification of tx proofs in JS
mitschabaude May 26, 2022
07d8e9f
bump snarkyjs
mitschabaude May 26, 2022
8e6eba7
also verify intg test proof in JS
mitschabaude May 26, 2022
abb4bdf
revert later: add debugging in verifier.common
mitschabaude May 26, 2022
c6f22ef
bump snarkyjs
mitschabaude May 27, 2022
c9c313a
Merge branch 'pickles-wrap-hack' into feature/faster-zkapp-proofs
mitschabaude May 27, 2022
3b8fec1
bump snarkyjs
mitschabaude Jun 1, 2022
e50044e
Merge branch 'develop' into feature/snarkyjs-0.3.4
mitschabaude Jun 1, 2022
a36456f
Merge branch 'fix/re-add-cargo-build-caching' into feature/snarkyjs-0…
mitschabaude Jun 1, 2022
017807b
[snarkyjs] add methods to Bool
mitschabaude Jun 3, 2022
c3f0511
bump snarkyjs
mitschabaude Jun 3, 2022
2830249
Merge branch 'develop' into feature/snarkyjs-0.3.4
mitschabaude Jun 3, 2022
065d068
bump snarkyjs
mitschabaude Jun 3, 2022
c25a427
bump snarkyjs
mitschabaude Jun 3, 2022
f71d634
Merge branch 'develop' into feature/faster-zkapp-proofs
mitschabaude Jun 3, 2022
e1490b0
Merge branch 'feature/snarkyjs-0.3.4' into feature/faster-zkapp-proofs
mitschabaude Jun 3, 2022
692932e
Merge branch 'dynamic-lagrange-commitment-selection' into feature/fas…
mitschabaude Jun 4, 2022
b7b41c5
Revert "revert later: add debugging in verifier.common"
mitschabaude Jun 5, 2022
6f2f67b
Merge branch 'develop' into feature/faster-zkapp-proofs
mitschabaude Jun 7, 2022
d548186
bump snarkyjs
mitschabaude Jun 7, 2022
502c31f
bump snarkyjs
mitschabaude Jun 7, 2022
8bf6160
adress PR feedback
mitschabaude Jun 7, 2022
6bb6197
Merge branch 'develop' into feature/faster-zkapp-proofs
mitschabaude Jun 7, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 99 additions & 46 deletions src/lib/snarky_js_bindings/lib/snarky_js_bindings_lib.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Copy link
Member

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.

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
Expand Down Expand Up @@ -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 =
Copy link
Member

Choose a reason for hiding this comment

The 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
Expand Down Expand Up @@ -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) ;
Copy link
Member

Choose a reason for hiding this comment

The 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) =
Expand Down Expand Up @@ -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 ;
Copy link
Member

Choose a reason for hiding this comment

The 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 ())) ) ;
Expand Down Expand Up @@ -494,7 +530,11 @@ let () =
else Field.Constant.of_string s ) )
with Failure _ -> Js.Opt.empty )
| _ ->
Js.Opt.empty )
Js.Opt.empty ) ;
Copy link
Member

Choose a reason for hiding this comment

The 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) =
Expand All @@ -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_) ;
Copy link
Member

Choose a reason for hiding this comment

The 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) ;
Copy link
Member

Choose a reason for hiding this comment

The 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
Expand Down Expand Up @@ -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
}
Expand All @@ -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

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 =
Expand All @@ -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:
Expand All @@ -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 ->
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 ;
Expand Down
2 changes: 1 addition & 1 deletion src/lib/snarky_js_bindings/snarky_js_types.ml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ let () =
let js_layout =
`Assoc
[ ("Parties", layout Parties.deriver)
; ("BalanceChange", layout Fields_derivers_zkapps.Derivers.balance_change)
Copy link
Member

Choose a reason for hiding this comment

The 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)
2 changes: 1 addition & 1 deletion src/lib/snarky_js_bindings/snarkyjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
Mina,
signFeePayer,
Permissions,
Ledger,
} from "snarkyjs";
import { tic, toc } from "./tictoc.js";

Expand Down Expand Up @@ -90,6 +91,16 @@ partiesJsonInitialize = signFeePayer(partiesJsonInitialize, senderKey, {
});
toc();

// verify the proof
tic("verify transaction proof");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: tic and tock would be better served by self-documenting names. Consider e.g. startTiming and endTiming.
(Not to change in this PR, it's already a grab-bag, lets not make it worse.)

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();
Expand Down
13 changes: 12 additions & 1 deletion src/lib/snarky_js_bindings/test_module/simple-zkapp.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
shutdown,
addCachedAccount,
Mina,
Ledger,
} from "snarkyjs";

await isReady;
Expand Down Expand Up @@ -91,7 +92,7 @@ if (command === "update") {
publicKey: zkappAddress,
zkapp: { appState: [initialState, 0, 0, 0, 0, 0, 0, 0] },
});
await SimpleZkapp.compile(zkappAddress);
let { verificationKey } = await SimpleZkapp.compile(zkappAddress);
let transaction = await Mina.transaction(() => {
new SimpleZkapp(zkappAddress).update(Field(2));
});
Expand All @@ -110,6 +111,16 @@ if (command === "update") {
{ parties, feePayer },
feePayerKeyBase58
);
parties = JSON.parse(data.parties);
let proof = parties.otherParties[0].authorization.proof;
let statement = Ledger.transactionStatement(data.parties, 0);
let ok = await Ledger.verifyPartyProof(
statement,
proof,
verificationKey.data
);
if (!ok) throw Error("verification failed");

console.log(data.parties);
}

Expand Down