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

Check verification key hash in apply #12498

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 5 additions & 2 deletions src/app/cli/src/init/transaction_snark_profiler.ml
Original file line number Diff line number Diff line change
Expand Up @@ -609,8 +609,11 @@ let profile_zkapps ~verifier ledger zkapp_commands =
let v_start_time = Time.now () in
let%bind res =
Verifier.verify_commands verifier
[ User_command.to_verifiable ~find_vk:(Zkapp_command.Verifiable.find_vk_via_ledger ~ledger ~get:Mina_ledger.Ledger.get
~location_of_account:Mina_ledger.Ledger.location_of_account)
[ User_command.to_verifiable
~find_vk:
(Zkapp_command.Verifiable.find_vk_via_ledger ~ledger
~get:Mina_ledger.Ledger.get
~location_of_account:Mina_ledger.Ledger.location_of_account )
(Zkapp_command zkapp_command)
|> Or_error.ok_exn
]
Expand Down
11 changes: 10 additions & 1 deletion src/lib/mina_base/transaction_status.ml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ module Failure = struct
| Account_proved_state_precondition_unsatisfied
| Account_is_new_precondition_unsatisfied
| Protocol_state_precondition_unsatisfied
| Unexpected_verification_key_hash
| Incorrect_nonce
| Invalid_fee_excess
| Cancelled
Expand Down Expand Up @@ -127,7 +128,8 @@ module Failure = struct
List.init 8 ~f:var.constructor @ acc )
~account_proved_state_precondition_unsatisfied:add
~account_is_new_precondition_unsatisfied:add
~protocol_state_precondition_unsatisfied:add ~incorrect_nonce:add
~protocol_state_precondition_unsatisfied:add
~unexpected_verification_key_hash:add ~incorrect_nonce:add
~invalid_fee_excess:add ~cancelled:add

let gen = Quickcheck.Generator.of_list all
Expand Down Expand Up @@ -211,6 +213,8 @@ module Failure = struct
"Account_is_new_precondition_unsatisfied"
| Protocol_state_precondition_unsatisfied ->
"Protocol_state_precondition_unsatisfied"
| Unexpected_verification_key_hash ->
"Unexpected_verification_key_hash"
| Incorrect_nonce ->
"Incorrect_nonce"
| Invalid_fee_excess ->
Expand Down Expand Up @@ -295,6 +299,8 @@ module Failure = struct
Ok Account_is_new_precondition_unsatisfied
| "Protocol_state_precondition_unsatisfied" ->
Ok Protocol_state_precondition_unsatisfied
| "Unexpected_verification_key_hash" ->
Ok Unexpected_verification_key_hash
| "Incorrect_nonce" ->
Ok Incorrect_nonce
| "Invalid_fee_excess" ->
Expand Down Expand Up @@ -436,6 +442,9 @@ module Failure = struct
"The account update's account is-new state precondition was unsatisfied"
| Protocol_state_precondition_unsatisfied ->
"The account update's protocol state precondition unsatisfied"
| Unexpected_verification_key_hash ->
"The account update's verification key hash does not match the \
verification key in the ledger account"
| Incorrect_nonce ->
"Incorrect nonce"
| Invalid_fee_excess ->
Expand Down
1 change: 1 addition & 0 deletions src/lib/mina_ledger/dune
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@
quickcheck_lib
snarky.backendless
unsigned_extended
with_hash
ppx_version.runtime
))
57 changes: 41 additions & 16 deletions src/lib/mina_ledger/ledger.ml
Original file line number Diff line number Diff line change
Expand Up @@ -479,19 +479,21 @@ let%test_unit "tokens test" =
in
let main (ledger : t) =
let execute_zkapp_command_transaction
(zkapp_command :
(account_updates :
(Account_update.Body.Simple.t, unit, unit) Zkapp_command.Call_forest.t
) : unit =
let _, ({ nonce; _ } : Account.t), _ =
Ledger_inner.get_or_create ledger
(Account_id.create pk Token_id.default)
|> Or_error.ok_exn
in
let zkapp_command =
mk_zkapp_command ~fee:7 ~fee_payer_pk:pk ~fee_payer_nonce:nonce
account_updates
in
match
apply_zkapp_command_unchecked ~constraint_constants ~state_view:view
ledger
(mk_zkapp_command ~fee:7 ~fee_payer_pk:pk ~fee_payer_nonce:nonce
zkapp_command )
ledger zkapp_command
with
| Ok ({ command = { status; _ }; _ }, _) -> (
match status with
Expand All @@ -515,32 +517,58 @@ let%test_unit "tokens test" =
()
in
let token_funder, _ = keypair_and_amounts.(1) in
let token_funder_pk = token_funder.public_key |> Public_key.compress in
let token_owner = Keypair.create () in
let token_owner_pk = token_owner.public_key |> Public_key.compress in
let token_account1 = Keypair.create () in
let token_account2 = Keypair.create () in
(* patch ledger so that token funder account has Proof send permission and a
zkapp acount dummy verification key

allows use of Proof authorization in `create_token` zkApp, below
*)
iteri ledger ~f:(fun _n acct ->
if Public_key.Compressed.equal acct.public_key token_funder_pk then
let acct_id = Account_id.create token_funder_pk Token_id.default in
let loc = Option.value_exn @@ location_of_account ledger acct_id in
let acct_with_zkapp =
{ acct with
permissions =
{ acct.permissions with send = Permissions.Auth_required.Proof }
; zkapp =
Some
{ Zkapp_account.default with
verification_key =
Some
With_hash.
{ data = Side_loaded_verification_key.dummy
; hash = Zkapp_account.dummy_vk_hash ()
}
}
}
in
set ledger loc acct_with_zkapp ) ;
let account_creation_fee =
Currency.Fee.to_nanomina_int constraint_constants.account_creation_fee
in
let create_token :
(Account_update.Body.Simple.t, unit, unit) Zkapp_command.Call_forest.t =
mk_forest
[ mk_node
(mk_account_update_body Signature Call token_funder Token_id.default
(mk_account_update_body
(Proof (Zkapp_account.dummy_vk_hash ()))
Call token_funder Token_id.default
(-(4 * account_creation_fee)) )
[]
; mk_node
(mk_account_update_body
(Proof (Zkapp_account.dummy_vk_hash ()))
Call token_owner Token_id.default (3 * account_creation_fee) )
(mk_account_update_body Signature Call token_owner Token_id.default
Copy link
Member

Choose a reason for hiding this comment

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

can we use a test zkapp here instead of changing the authorization? or write another similar test with Proof auth?

Copy link
Member Author

Choose a reason for hiding this comment

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

There's a bug in this test, if we use Proof, because the corresponding ledger account has None for the zkapp field, hence no vk hash, so the new vk hash check fails.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm able to patch the ledger so the token funder has a zkapp with the dummy verification key, allowing Proof for this sub-test. (It would require a bit more change to do the same for the token owner.)

(3 * account_creation_fee) )
[]
]
in
let custom_token_id =
Account_id.derive_token_id
~owner:
(Account_id.create
(Public_key.compress token_owner.public_key)
Token_id.default )
~owner:(Account_id.create token_owner_pk Token_id.default)
in
let token_minting =
mk_forest
Expand Down Expand Up @@ -596,10 +624,7 @@ let%test_unit "tokens test" =
in
execute_zkapp_command_transaction create_token ;
(* Check that token_owner exists *)
ledger_get_exn ledger
(Public_key.compress token_owner.public_key)
Token_id.default
|> ignore ;
ledger_get_exn ledger token_owner_pk Token_id.default |> ignore ;
execute_zkapp_command_transaction token_minting ;
check_token_balance token_account1 100 ;
execute_zkapp_command_transaction token_transfers ;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ module Failure = struct
| Account_proved_state_precondition_unsatisfied
| Account_is_new_precondition_unsatisfied
| Protocol_state_precondition_unsatisfied
| Unexpected_verification_key_hash
| Incorrect_nonce
| Invalid_fee_excess
| Cancelled
Expand Down
22 changes: 22 additions & 0 deletions src/lib/transaction_logic/mina_transaction_logic.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,8 @@ module Make (L : Ledger_intf.S) : S with type ledger := L.t = struct
type t = Snark_params.Tick.Field.t

let if_ = value_if

let equal = Snark_params.Tick.Field.equal
end

module Bool = struct
Expand Down Expand Up @@ -1214,6 +1216,12 @@ module Make (L : Ledger_intf.S) : S with type ledger := L.t = struct
let if_ = value_if
end

module Verification_key_hash = struct
type t = Field.t option

let equal vk1 vk2 = Option.equal Field.equal vk1 vk2
end

module Actions = struct
type t = Zkapp_account.Actions.t

Expand Down Expand Up @@ -1349,6 +1357,13 @@ module Make (L : Ledger_intf.S) : S with type ledger := L.t = struct
let set_verification_key verification_key (a : t) =
set_zkapp a ~f:(fun zkapp -> { zkapp with verification_key })

let verification_key_hash (a : t) =
match a.zkapp with
| None ->
None
| Some zkapp ->
Option.map zkapp.verification_key ~f:With_hash.hash

let last_sequence_slot (a : t) = (get_zkapp a).last_sequence_slot

let set_last_sequence_slot last_sequence_slot (a : t) =
Expand Down Expand Up @@ -1494,6 +1509,13 @@ module Make (L : Ledger_intf.S) : S with type ledger := L.t = struct
| Proof _ | None_given ->
false

let verification_key_hash (p : t) =
match p.body.authorization_kind with
| Proof vk_hash ->
Some vk_hash
| _ ->
None

module Update = struct
open Zkapp_basic

Expand Down
45 changes: 38 additions & 7 deletions src/lib/transaction_logic/zkapp_command_logic.ml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,14 @@ module type Global_slot_intf = sig
val equal : t -> t -> bool
end

module type Verification_key_hash_intf = sig
type t

type bool

val equal : t -> t -> bool
end

module type Timing_intf = sig
include Iffable

Expand Down Expand Up @@ -304,6 +312,8 @@ module type Account_update_intf = sig

type nonce

type verification_key_hash

type _ or_ignore

val balance_change : t -> signed_amount
Expand Down Expand Up @@ -332,6 +342,8 @@ module type Account_update_intf = sig

val is_proved : t -> bool

val verification_key_hash : t -> verification_key_hash

module Update : sig
type _ set_or_keep

Expand Down Expand Up @@ -543,10 +555,10 @@ module type Account_intf = sig

val set_receipt_chain_hash : t -> receipt_chain_hash -> t

(** Fill the snapp field of the account if it's currently [None] *)
(** Fill the zkapp field of the account if it's currently [None] *)
val make_zkapp : t -> t

(** If the current account has no snapp fields set, reset its snapp field to
(** If the current account has no zkApp fields set, reset its zkapp field to
[None].
*)
val unmake_zkapp : t -> t
Expand All @@ -569,6 +581,10 @@ module type Account_intf = sig

val set_verification_key : verification_key -> t -> t

type verification_key_hash

val verification_key_hash : t -> verification_key_hash

val last_sequence_slot : t -> global_slot

val set_last_sequence_slot : global_slot -> t -> t
Expand Down Expand Up @@ -690,8 +706,6 @@ module type Inputs_intf = sig
module Timing :
Timing_intf with type bool := Bool.t and type global_slot := Global_slot.t

module Verification_key : Iffable with type bool := Bool.t

module Zkapp_uri : Iffable with type bool := Bool.t

module Token_symbol : Iffable with type bool := Bool.t
Expand All @@ -704,6 +718,10 @@ module type Inputs_intf = sig
and type transaction_commitment := Transaction_commitment.t
and type index := Index.t)

and Verification_key : (Iffable with type bool := Bool.t)
and Verification_key_hash :
(Verification_key_hash_intf with type bool := Bool.t)

and Account :
(Account_intf
with type Permissions.controller := Controller.t
Expand All @@ -714,6 +732,7 @@ module type Inputs_intf = sig
and type global_slot := Global_slot.t
and type field := Field.t
and type verification_key := Verification_key.t
and type verification_key_hash := Verification_key_hash.t
and type zkapp_uri := Zkapp_uri.t
and type token_symbol := Token_symbol.t
and type public_key := Public_key.t
Expand All @@ -735,6 +754,7 @@ module type Inputs_intf = sig
and type public_key := Public_key.t
and type nonce := Nonce.t
and type account_id := Account_id.t
and type verification_key_hash := Verification_key_hash.t
and type Update.timing := Timing.t
and type 'a Update.set_or_keep := 'a Set_or_keep.t
and type Update.field := Field.t
Expand Down Expand Up @@ -884,7 +904,7 @@ module Make (Inputs : Inputs_intf) = struct
}

let get_next_account_update (current_forest : Stack_frame.t)
(* The stack for the most recent snapp *)
(* The stack for the most recent zkApp *)
(call_stack : Call_stack.t) (* The partially-completed parent stacks *)
: get_next_account_update_result =
(* If the current stack is complete, 'return' to the previous
Expand Down Expand Up @@ -1142,6 +1162,17 @@ module Make (Inputs : Inputs_intf) = struct
(Account_update.token_id account_update)
(a, inclusion_proof)
in
let matching_verification_key_hashes =
Inputs.Bool.(
(not (Account_update.is_proved account_update))
||| Verification_key_hash.equal
(Account.verification_key_hash a)
(Account_update.verification_key_hash account_update))
in
let local_state =
Local_state.add_check local_state Unexpected_verification_key_hash
matching_verification_key_hashes
in
let local_state =
h.perform
(Check_account_precondition
Expand Down Expand Up @@ -1334,11 +1365,11 @@ module Make (Inputs : Inputs_intf) = struct
(* The [proved_state] tracks whether the app state has been entirely
determined by proofs ([true] if so), to allow zkApp authors to be
confident that their initialization logic has been run, rather than
some malicious deployer instantiating the snapp in an account with
some malicious deployer instantiating the zkApp in an account with
some fake non-initial state.
The logic here is:
* if the state is unchanged, keep the previous value;
* if the state has been entriely replaced, and the authentication
* if the state has been entirely replaced, and the authentication
was a proof, the state has been 'proved' and [proved_state] is set
to [true];
* if the state has been partially updated by a proof, the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,8 +366,7 @@ let%test_module "multisig_account" =
}
; use_full_commitment = false
; caller = Call
; authorization_kind =
Proof (Mina_base.Zkapp_account.dummy_vk_hash ())
; authorization_kind = Proof (With_hash.hash vk)
}
; authorization = Proof Mina_base.Proof.transaction_dummy
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,10 @@ let%test_module "Sequence events test" =
end

let test_zkapp_command ?expected_failure ?state_body ?(fee_payer_nonce = 0)
~ledger zkapp_command =
~ledger zkapp_command0 =
let zkapp_command =
Zkapps_examples.patch_verification_key_hashes ~ledger zkapp_command0
in
let memo = Signed_command_memo.empty in
let transaction_commitment : Zkapp_command.Transaction_commitment.t =
let account_updates_hash =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ let%test_module "Add events test" =
~handler:(Zkapps_add_events.update_events_handler events) )
end

let test_zkapp_command ?expected_failure zkapp_command =
let test_zkapp_command ?expected_failure zkapp_command0 =
let zkapp_command =
Zkapps_examples.patch_verification_key_hashes zkapp_command0
in
let memo = Signed_command_memo.empty in
let transaction_commitment : Zkapp_command.Transaction_commitment.t =
let account_updates_hash =
Expand Down
Loading