-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathStateMap.lean
More file actions
463 lines (378 loc) · 15.9 KB
/
Copy pathStateMap.lean
File metadata and controls
463 lines (378 loc) · 15.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
import EvmYul.EVM.Semantics
import EvmEquivalence.KEVM2Lean.Sorts
import EvmEquivalence.KEVM2Lean.Inj
import EvmEquivalence.KEVM2Lean.Func
import EvmEquivalence.KEVM2Lean.Rewrite
import EvmEquivalence.Interfaces.EvmYulInterface
import EvmEquivalence.Interfaces.Axioms
import EvmEquivalence.Utils.IntUtils
/-! # State Map
Mapping KEVM to EvmYul states.
-/
open EvmYul
open EVM
set_option linter.deprecated false
/-! ## `SortGeneratedTopCell` Getters
Getters for accessing cells from the Generated Top Cell.
-/
namespace SortGeneratedTopCell
variable (tc : SortGeneratedTopCell)
@[simp]
def evm :SortEvmCell := tc.kevm.ethereum.evm
@[simp]
def callState : SortCallStateCell := tc.kevm.ethereum.evm.callState
@[simp]
def wordStackCell : SortWordStackCell := tc.kevm.ethereum.evm.callState.wordStack
@[simp]
def pc : SortPcCell := tc.kevm.ethereum.evm.callState.pc
@[simp]
def gas : SortGasCell := tc.kevm.ethereum.evm.callState.gas
@[simp]
def program : SortProgramCell := tc.kevm.ethereum.evm.callState.program
@[simp]
def output : SortOutputCell := tc.kevm.ethereum.evm.output
@[simp]
def accessedStorage : SortAccessedStorageCell := tc.kevm.ethereum.evm.substate.accessedStorage
@[simp]
def refund : SortRefundCell := tc.kevm.ethereum.evm.substate.refund
@[simp]
def accounts : SortAccountsCell := tc.kevm.ethereum.network.accounts
@[simp]
def Iₐ : SortIdCell := tc.kevm.ethereum.evm.callState.id
@[simp]
def isStatic : SortStaticCell := tc.kevm.ethereum.evm.callState.static
@[simp]
def memoryUsed : SortMemoryUsedCell := tc.kevm.ethereum.evm.callState.memoryUsed
@[simp]
def memory : SortLocalMemCell := tc.kevm.ethereum.evm.callState.localMem
@[simp]
def origin : SortOriginCell := tc.kevm.ethereum.evm.origin
@[simp]
def caller : SortCallerCell := tc.kevm.ethereum.evm.callState.caller
@[simp]
def gasPrice : SortGasPriceCell := tc.kevm.ethereum.evm.gasPrice
@[simp]
def coinbase : SortCoinbaseCell := tc.kevm.ethereum.evm.block.coinbase
@[simp]
def timestamp : SortTimestampCell := tc.kevm.ethereum.evm.block.timestamp
@[simp]
def mixhash : SortMixHashCell := tc.kevm.ethereum.evm.block.mixHash
@[simp]
def number : SortNumberCell := tc.kevm.ethereum.evm.block.number
@[simp]
def gaslimit : SortGasLimitCell := tc.kevm.ethereum.evm.block.gasLimit
@[simp]
def chainid : SortChainIDCell := tc.kevm.ethereum.network.chainID
end SortGeneratedTopCell
namespace SortKItem
/-- KItem projections to subsorts -/
@[simp]
def toAccountSort (k : SortKItem) : Option SortAccount :=
match k with
| .inj_SortAccount acc => some acc
| _ => none
/-- Subsort projections to KItem -/
@[simp]
def ofAccountSort(acc : SortAccount) : SortKItem :=
SortKItem.inj_SortAccount acc
end SortKItem
open SortKItem
namespace StateMap
/-! ## Type Mapping
Maps from K types to EvmYul types.
-/
abbrev intMap (n : SortInt) : UInt256 := UInt256.toSigned n
@[simp]
def wordStackMap (ws : SortWordStack) : Stack UInt256 :=
match ws with
| .«.WordStack_EVM-TYPES_WordStack» => []
| .«_:__EVM-TYPES_WordStack_Int_WordStack» w ws => intMap w :: (wordStackMap ws)
@[simp]
def wordStackCellMap (wsc : SortWordStackCell) : Stack UInt256 :=
wordStackMap wsc.val
@[simp]
def pcCellMap (pcc : SortPcCell) : UInt256 :=
intMap pcc.val
@[simp]
def gasMap : SortGas → UInt256
| .inj_SortInt g => intMap g
@[simp]
def gasCellMap (gc : SortGasCell) : UInt256 :=
gasMap gc.val
@[simp]
def accountAddressMap : SortAccount → AccountAddress
| .«.Account_EVM-TYPES_Account» => 0
| .inj_SortInt n => AccountAddress.ofNat (Int.toNat n)
@[simp]
def idMap (idc : SortIdCell) : AccountAddress :=
accountAddressMap idc.val
@[simp]
noncomputable def storageMap (stor : SortStorageCell) : Storage :=
Axioms.SortStorageCellMap stor
@[simp]
noncomputable def transStorageMap (tstor : SortTransientStorageCell) : Storage :=
Axioms.SortTransientStorageCellMap tstor
@[simp]
def accCodeMap : SortAccountCode → ByteArray
| .inj_SortBytes code => code
/- Note that Origin Storage Cell (`origStorage`) is not needed from `SortAccountCell` -/
@[simp]
noncomputable def accountMap (acc : SortAccountCell) : Account where
nonce := intMap acc.nonce.val
balance := intMap acc.balance.val
storage := storageMap acc.storage
code := accCodeMap acc.code.val
tstorage := transStorageMap acc.transientStorage
@[simp]
noncomputable def substate_map (sc : SortSubstateCell) (s : Substate) : Substate :=
match sc with
| .mk
_ --selfDestruct
_ --log
refund
_ --accessedAccounts
accessedStorage
_ --createdAccounts
=> {s with
accessedStorageKeys := Axioms.SortAccessedStorageCellMap accessedStorage
refundBalance := intMap refund.val}
@[simp]
def memory_map : SortLocalMemCell → ByteArray | .mk b => b
/- Maps from parts of the Generated Top Cell to EvmYul structures -/
@[simp]
def blockHeader_map (tc : SortGeneratedTopCell) (s : EVM.State) : BlockHeader :=
{s.executionEnv.header with
beneficiary := .ofNat <| Int.toNat tc.coinbase.val
timestamp := Int.toNat tc.timestamp.val
number := Int.toNat tc.number.val
prevRandao := intMap tc.mixhash.val
gasLimit := Int.toNat tc.gaslimit.val
}
@[simp]
def executionEnv_map (tc : SortGeneratedTopCell) (s : EVM.State) : ExecutionEnv :=
{s.executionEnv with
codeOwner := idMap tc.Iₐ
source := accountAddressMap tc.caller.val
sender := accountAddressMap tc.origin.val
code := tc.program.val,
gasPrice := Int.toNat tc.gasPrice.val
header := blockHeader_map tc s
perm := !tc.isStatic.val}
/-! ## State Map
The function mapping KEVM states to EvmYul states.
-/
/--
**State Mapping**: Mapping KEVM states to EvmYul states
We temporarely require the `symState` argument since we don't map the entire KEVM state yet
The following data structures are axiomatically mapped:
1. `Substate.accessedStorageKeys`:
The `EvmYul` data representation for this is an `RBSet`, which is hard to reason about.
The mapping will remain an axiom until a better reasoning interface is provided or we have time to implement it
2. `State.accountMap`: Similar reasons as above
-/
noncomputable def stateMap (symState : EVM.State) (tc : SortGeneratedTopCell) : EVM.State :=
{symState with
stack := wordStackCellMap tc.wordStackCell
pc := pcCellMap tc.pc
gasAvailable := gasCellMap tc.gas
executionEnv := executionEnv_map tc symState
accountMap := Axioms.SortAccountsCellMap tc.accounts
substate := {symState.substate with
accessedStorageKeys := Axioms.SortAccessedStorageCellMap tc.accessedStorage
refundBalance := intMap tc.refund.val
}
returnData := tc.output.val
activeWords := intMap tc.memoryUsed.val
memory := memory_map tc.memory
}
/-! ## State Mapping Results
Theorems to make life easier.
-/
theorem intMap_sub_dist {n m : SortInt} (le_m_n : m <= n) (pos : 0 <= m) (size : n < UInt256.size) :
intMap (n - m) = intMap n - intMap m := by
unfold intMap UInt256.toSigned; split <;> rename_i a b h
. cases cn : n with
| ofNat p => cases m with
| ofNat q =>
simp_all
rw [←Int.ofNat_sub, Int.ofNat_inj] at h <;> try assumption
simp only [←h, HSub.hSub, Sub.sub, UInt256.sub, Fin.sub]
aesop (add simp [UInt256.ofNat_eq, UInt256.size, Fin.ofNat])
(add safe (by omega))
| negSucc q => aesop
| negSucc p =>
have _ : 0 ≤ n := by apply (Int.le_trans pos le_m_n)
aesop
. rw [←sub_nonneg, h] at le_m_n; contradiction
theorem intMap_add_dist {n m : SortInt} (nh : 0 ≤ n) (mh : 0 ≤ m) :
intMap ((n + m) % ↑UInt256.size) = intMap n + intMap m := by
unfold intMap UInt256.toSigned
split; rename_i h p mod_eq
. split <;> split <;> rename_i h' q j l <;> try contradiction
. simp_all only [Int.ofNat_eq_coe, Int.ofNat_add_ofNat]
rw [Int.mod_cast, Int.toNat_ofNat, Int.ofNat_inj] at * <;> try simp
. aesop (add simp [UInt256.ofNat, UInt256.size, Id.run, dbgTrace, Fin.ofNat])
(add safe (by congr 1))
. aesop (add safe (by omega))
. have mod_nonneg: 0 ≤ (n + m) % ↑UInt256.size := by
rw [Int.mod_def']; apply Int.emod_nonneg; simp [UInt256.size]
simp_all
theorem intMap_toNat {n : SortInt} (nh : 0 ≤ n) (size : n < UInt256.size) :
(intMap n).toNat = n.toNat := by
aesop (add simp [intMap, Int.toNat, UInt256.toSigned, Int.toNat_ofNat, UInt256.ofNat_toNat])
end StateMap
open StateMap
/-! ## State Map Axioms
Axioms that have to do with the axiomatic state mapping.
-/
namespace Axioms
/--
This axiom states that if an account is in an `AccountCellMap`, then
`Batteries.RBMap.find?` finds it in the image of the axiomatized mapping
The second element of `AccountCellMapItem` is provided embedded in `accCellMap_def` for
ease of use when proving theorems
-/
axiom findAccountInAccountCellMap
{ID_CELL : SortInt}
{balance : SortBalanceCell}
{code : SortCodeCell}
{STORAGE_CELL ORIG_STORAGE_CELL : SortMap}
{tstorage : SortTransientStorageCell}
{nonce : SortNonceCell}
{accCellMap dotVar accCellMap2 : SortAccountCellMap}
(accCellMap_def : AccountCellMapItem { val := ID_CELL } {
acctID := { val := ID_CELL },
balance := balance,
code := code,
storage := { val := STORAGE_CELL },
origStorage := { val := ORIG_STORAGE_CELL },
transientStorage := tstorage,
nonce := nonce } = some accCellMap)
(accCellMap2_def : _AccountCellMap_ accCellMap dotVar = some accCellMap2) :
Batteries.RBMap.find? (Axioms.SortAccountsCellMap { val := accCellMap2 }) (AccountAddress.ofNat (Int.toNat ID_CELL)) = some (StateMap.accountMap {
acctID := { val := ID_CELL },
balance := balance,
code := code,
storage := { val := STORAGE_CELL },
origStorage := { val := ORIG_STORAGE_CELL },
transientStorage := tstorage,
nonce := nonce })
/--
Expected behavior of `SortAccountsCellMap` w.r.t. `Batteries.RBMap.find?`
This axiom states that
- Given an `accountsCell` (`accCellMap2`) containing an account identifiable by `ID_CELL` (`acc`)
- The (axiomatic) mapping of `accCellMap2` contains the mapping of `acc`
- And, in particular, `RBMap.find?` correctly finds the mapped `acc` if provided with the mapped `ID_CELL`
-/
axiom accountsCell_map_find?
{ID_CELL : SortInt}
{balance : SortBalanceCell}
{code : SortCodeCell}
{STORAGE_CELL ORIG_STORAGE_CELL : SortMap}
{tstorage : SortTransientStorageCell}
{nonce : SortNonceCell}
{accCellMap dotVar accCellMap2 : SortAccountCellMap}
(acc : SortAccountCell)
(acc_def : acc = {
acctID := { val := ID_CELL },
balance := balance,
code := code,
storage := { val := STORAGE_CELL },
origStorage := { val := ORIG_STORAGE_CELL },
transientStorage := tstorage,
nonce := nonce })
(accCellMap_def : AccountCellMapItem { val := ID_CELL } acc = some accCellMap)
(accCellMap2_def : _AccountCellMap_ accCellMap dotVar = some accCellMap2) :
Batteries.RBMap.find? (Axioms.SortAccountsCellMap { val := accCellMap2 }) (AccountAddress.ofNat (Int.toNat ID_CELL)) = some (StateMap.accountMap acc)
/--
Expected behavior of `SortAccountsCellMap` w.r.t. `Batteries.RBMap.insert`
This axiom states that
- Given an `accountsCell` (`initCellMap`) containing an account identifiable by `ID_CELL` (`initAccount`) with symbolic storage `STORAGE_CELL`
- Given an updated `accountsCell` (`updatedCellMap`) consisting of `initAccount` with an updated `STORAGE_CELL` which contains the symbolic (`key`, `value`) pair (`stor_update`)
- `RBMap.insert`ing the mapped (`key`, `value`) pair into the (axiomatically) mapped `initCellMap` equals to the (axiomatic) mapping of `updatedCellMap`
-/
axiom accountsCell_map_insert
{ID_CELL key value : SortInt}
{balance : SortBalanceCell}
{code : SortCodeCell}
{tstorage : SortTransientStorageCell}
{nonce : SortNonceCell}
{ACCESSEDSTORAGE_CELL ORIG_STORAGE_CELL STORAGE_CELL stor_update : SortMap}
{emptySet kitemToSet keySet fullSet : SortSet}
{kitemLookup : SortKItem}
{dotvar initAccount initCellMap updatedAccount updatedCellMap : SortAccountCellMap}
(defn_Val34 : «.Set» = some emptySet)
(defn_Val35 : «Map:lookupOrDefault» ACCESSEDSTORAGE_CELL ((@inj SortInt SortKItem) ID_CELL) ((@inj SortSet SortKItem) emptySet) = some kitemLookup)
(defn_Val36 : «project:Set» (SortK.kseq kitemLookup SortK.dotk) = some kitemToSet)
(defn_Val37 : SetItem ((@inj SortInt SortKItem) key) = some keySet)
(defn_Val38 : «_|Set__SET_Set_Set_Set» kitemToSet keySet = some fullSet)
(defn_Val40 : «Map:update» STORAGE_CELL ((@inj SortInt SortKItem) key) ((@inj SortInt SortKItem) value) = some stor_update)
(defn_Val41 : AccountCellMapItem { val := ID_CELL } {
acctID := { val := ID_CELL },
balance := balance,
code := code,
storage := { val := stor_update },
origStorage := { val := ORIG_STORAGE_CELL },
transientStorage := tstorage,
nonce := nonce } = some updatedAccount)
(defn_Val42 : _AccountCellMap_ updatedAccount dotvar = some updatedCellMap)
(defn_Val19 : AccountCellMapItem { val := ID_CELL } {
acctID := { val := ID_CELL },
balance := balance,
code := code,
storage := { val := STORAGE_CELL },
origStorage := { val := ORIG_STORAGE_CELL },
transientStorage := tstorage,
nonce := nonce } = some initAccount)
(defn_Val20 : _AccountCellMap_ initAccount dotvar = some initCellMap)
:
Batteries.RBMap.insert (Axioms.SortAccountsCellMap { val := initCellMap }) (accountAddressMap (inj ID_CELL))
((accountMap {
acctID := { val := ID_CELL },
balance := balance,
code := code,
storage := { val := STORAGE_CELL },
origStorage := { val := ORIG_STORAGE_CELL },
transientStorage := tstorage,
nonce := nonce }).updateStorage (intMap key) (intMap value)) =
Axioms.SortAccountsCellMap { val := updatedCellMap }
/--
Expected behavior of `SortAccessedStorageCellMap` w.r.t. `Batteries.RBSet.insert`
This axiom states that
- Given a symbolic map of accessed storage keys `ACCESSEDSTORAGE_CELL`
- Given an update of `ACCESSEDSTORAGE_CELL` containing the account `ID_CELL` and the key `key` (`stor_update`)
- `RBMap.insert`ing the mapped pair (`ID_CELL`, `key`) into the (axiomatically) mapped `ACCESSEDSTORAGE_CELL` equals to the (axiomatic) mapping of `stor_update`
-/
axiom accessedStorageCell_map_insert
{ID_CELL key : SortInt}
{ACCESSEDSTORAGE_CELL stor_update : SortMap}
{emptySet kitemToSet keySet fullSet : SortSet}
{kitemLookup : SortKItem}
(defn_Val34 : «.Set» = some emptySet)
(defn_Val35 : «Map:lookupOrDefault» ACCESSEDSTORAGE_CELL ((@inj SortInt SortKItem) ID_CELL) ((@inj SortSet SortKItem) emptySet) = some kitemLookup)
(defn_Val36 : «project:Set» (SortK.kseq kitemLookup SortK.dotk) = some kitemToSet)
(defn_Val37 : SetItem ((@inj SortInt SortKItem) key) = some keySet)
(defn_Val38 : «_|Set__SET_Set_Set_Set» kitemToSet keySet = some fullSet)
(defn_Val39 : «Map:update» ACCESSEDSTORAGE_CELL ((@inj SortInt SortKItem) ID_CELL) ((@inj SortSet SortKItem) fullSet) = some stor_update) :
(Axioms.SortAccessedStorageCellMap { val := ACCESSEDSTORAGE_CELL }).insert
(AccountAddress.ofNat (Int.toNat ID_CELL), intMap key) =
Axioms.SortAccessedStorageCellMap { val := stor_update }
/--
Mapping a `SortStorageCell` through `Axioms.SortStorageCellMap` results
in an equivalence of behavior between K's `lookup` function and EvmYul's `findD`.
Provided that `lookup` results in `some result`.
-/
axiom lookup_mapped_storage (storage : SortMap) (key result : SortInt) (_ : lookup storage key = some result):
Batteries.RBMap.findD (Axioms.SortStorageCellMap { val := storage }) (intMap key) { val := 0 } = intMap result
/--
Mapping a `SortAccessedStorageCell` through `Axioms.SortAccessedStorageCellMap` results
in an equivalence of behavior between K's `«#inStorage»` function and EvmYul's `RBSet.contains`.
-/
axiom contains_accessedStorage_map
{contained : Bool}
{stor : SortMap}
{acc key : SortInt}
(_ : «#inStorage» stor (SortAccount.inj_SortInt acc) key = some contained):
(Axioms.SortAccessedStorageCellMap { val := stor }).contains
(AccountAddress.ofNat (Int.toNat acc), intMap key) = contained
end Axioms