From e377573f35d797dacf83e1f1ad069ff54ab147d6 Mon Sep 17 00:00:00 2001 From: Jake Massimo Date: Wed, 26 Aug 2026 03:32:56 +0000 Subject: [PATCH] Add constant-time (f_events) proofs for rej_uniform_eta2 and rej_uniform_eta4 Signed-off-by: Jake Massimo --- README.md | 9 +- SOUNDNESS.md | 26 +- proofs/hol_light/README.md | 57 +- .../mldsa_rej_uniform_eta2_aarch64_asm.ml | 1192 ++++- .../mldsa_rej_uniform_eta4_aarch64_asm.ml | 1348 +++++- .../proofs/mldsa_rej_uniform_eta2_avx2_asm.ml | 3307 +++++++++++++- .../proofs/mldsa_rej_uniform_eta4_avx2_asm.ml | 3823 ++++++++++++++++- 7 files changed, 9693 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 47892ce0bc..5a2cb84e95 100644 --- a/README.md +++ b/README.md @@ -60,10 +60,11 @@ We use the [C Bounded Model Checker (CBMC)](https://github.com/diffblue/cbmc) to All AArch64 and x86_64 assembly is proved functionally correct and memory-safe at the object-code level, using [HOL-Light](https://hol-light.github.io/) and the [s2n-bignum](https://github.com/awslabs/s2n-bignum) verification -infrastructure. All routines are additionally proved to have secret-independent timing, with two exceptions. The -matrix sampler `rej_uniform` operates on public data only, and is deliberately variable-time. The secret-vector -samplers `rej_uniform_eta{2,4}` _do_ have secret-independent timing, but this property is not yet backed by proof. -See [proofs/hol_light](proofs/hol_light) for details. +infrastructure. All routines are additionally proved to have secret-independent timing, with the rejection samplers +as special cases. The matrix sampler `rej_uniform` operates on public data only, and is deliberately variable-time. +The secret-vector samplers `rej_uniform_eta{2,4}` are proved to have secret-independent timing up to their (public) +reject pattern -- their event trace depends on which coefficients are accepted or rejected, but not on the accepted +values. See [proofs/hol_light](proofs/hol_light) for details. Finally, [proofs/isabelle](proofs/isabelle/compress) contains proofs in [Isabelle/HOL](https://isabelle.in.tum.de/) of the correctness of different approaches for computing the scalar decomposition routines used in ML-DSA. Those are still experimental and do not yet operate diff --git a/SOUNDNESS.md b/SOUNDNESS.md index da63267721..32ab708ba2 100644 --- a/SOUNDNESS.md +++ b/SOUNDNESS.md @@ -30,26 +30,24 @@ same TCB, and therefore the same shared mitigations and residual risks. ### Rejection sampling -Both the AArch64 and x86_64 backends are fully covered by HOL Light proofs; the full list of -functions is maintained in [proofs/hol_light/README.md](proofs/hol_light/README.md). - -The rejection samplers are the only routines that do not carry all three target properties, for -two different reasons. +Both the AArch64 and x86_64 backends are fully covered by HOL Light proofs of functional correctness +and memory safety; the full list of functions is maintained in +[proofs/hol_light/README.md](proofs/hol_light/README.md). The two rejection samplers are handled +specially with respect to secret-independent timing, for two different reasons. The matrix sampler `rej_uniform` expands the public matrix A from the public seed rho. Since it operates on public data only, secret-independent timing is not a requirement, and admitting variable-time execution enables a faster implementation. It is proven functionally correct and memory-safe on both backends, and is deliberately not proven constant-time. -The secret-vector samplers `rej_uniform_eta{2,4}` do operate on secret data. On both backends -these are proven functionally correct and memory-safe, but their secret-independent timing is -not yet formally proved (see -[#1160](https://github.com/pq-code-package/mldsa-native/issues/1160)). Their memory access -pattern depends on which coefficients fall inside vs. outside the acceptance interval, but no -other information about the secret coefficients is leaked, and the indices of in-bound vs. -out-of-bound coefficients are statistically independent of the secret key; see Section 5.5 of -the Dilithium Round 3 specification[^Round3_Spec]. This property is validated empirically through the `valgrind`-based -constant-time tests, but not formally proved. +The secret-vector samplers `rej_uniform_eta{2,4}` do operate on secret data, so their timing must not +depend on the secret coefficient values. Their memory-access pattern and trip count do depend on which +candidate coefficients fall inside vs. outside the acceptance interval, but that reject pattern is +public: it is a statistically-independent function of the public XOF stream (Section 5.5 of the +Dilithium Round 3 specification[^Round3_Spec]) and reveals nothing about the accepted values. On +both AArch64 and x86_64 this is now formally proved -- the microarchitectural event trace is proven to +be a function of the public pointers and the per-nibble accept/reject bitmap only ("constant-time up to +the reject pattern"). [^Round3_Spec]: Bai, Ducas, Kiltz, Lepoint, Lyubashevsky, Schwabe, Seiler, Stehlé: CRYSTALS-Dilithium Algorithm Specifications and Supporting Documentation (Version 3.1), [https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf](https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf) diff --git a/proofs/hol_light/README.md b/proofs/hol_light/README.md index 2483a96b2c..11034ae974 100644 --- a/proofs/hol_light/README.md +++ b/proofs/hol_light/README.md @@ -23,13 +23,56 @@ Unless documented otherwise, for each assembly routine listed below, we prove th secret-independent timing is not a requirement, and admitting variable-time execution enables a faster implementation. We therefore prove properties 1 and 2 for it, but deliberately not property 3. -### Known gap: rejection sampling for the secret vector (`rej_uniform_eta{2,4}`) +### Constant-time rejection sampling for the secret vector (`rej_uniform_eta{2,4}`) + +The `rej_uniform_eta{2,4}` kernels (on both AArch64 and x86_64) sample the secret vectors `s1`/`s2` by +rejection, so their +control flow and memory-access pattern legitimately depend on *which* candidate coefficients are accepted +vs. rejected. They are therefore **not** data-oblivious, and the standard one-line safety tactic (which +asserts full obliviousness) does not apply. + +Instead we prove **constant-time up to the reject pattern**: the microarchitectural event trace is a +function of the public pointers and the *reject bitmap* — one accept/reject bit per candidate nibble — and +of nothing else about the input. In particular it does not depend on the accepted coefficient *values* (the +secret). The reject bitmap is itself public: whether a coefficient falls in the acceptance interval is a +statistically-independent function of the public XOF output (Section 5.5 of @[Round3_Spec]). + +Concretely, the constant-time safety theorems for `rej_uniform_eta2` and `rej_uniform_eta4` state +that some event-generating function `f_events`, depending only on public data, reproduces the +entire trace (shown here for eta2; the eta4 statement is identical with `REJ_MASK_ETA4` and `val x < 9`): + +```ocaml +`?f_events. + !res buf buflen table (inlist:byte list) pc e stackpointer returnaddress. + (* same alignment / non-overlap preconditions as _MEMSAFE *) + ... + ==> ensures arm + (\s. (* same precondition as _MEMSAFE: code at pc, C arguments + [res;buf;buflen;table], input bytes at buf, table at table, + event log = e *) + ... /\ read events s = e) + (\s. read PC s = returnaddress /\ + ?e2. read events s = APPEND e2 e /\ + (* the events of this call are EXACTLY f_events applied to the + public arguments and the reject bitmap -- and not the + accepted coefficient values *) + e2 = f_events res buf buflen table pc stackpointer + returnaddress (REJ_MASK_ETA2 inlist) /\ + memaccess_inbounds e2 (read set) (write set)) + (* same footprint as _MEMSAFE *)` +``` + +where `REJ_MASK_ETA2 l = MAP (\x. val x < 15) (NIBBLES_OF_BYTES l)` is the public reject bitmap — one +accept/reject bit per nibble, accepted values discarded. (Contrast `REJ_NIBBLES_ETA2`, which *keeps* the +accepted values and is secret.) Because the whole trace factors through this bitmap, two inputs with the +same accept/reject pattern are indistinguishable to a timing/cache adversary regardless of their +coefficient values. + +The x86_64 AVX2 kernels prove the identical property (with `ensures x86`). Because the x86_64 +`rej_uniform_eta{2,4}` assembly processes a fixed-length input buffer (136 bytes for eta2, 272 for eta4) +rather than taking a runtime `buflen` argument, its `f_events` and preconditions specialise `buflen` to +that constant; the reject-bitmap factoring is otherwise identical. -The AArch64 and AVX2 kernels `rej_uniform_eta{2,4}` have secret-independent timing, but we do not yet prove it (see -[#1160](https://github.com/pq-code-package/mldsa-native/issues/1160)): Their memory access pattern depends on which -coefficients fall inside vs. outside the acceptance interval, but no other information about the secret coefficients is -leaked. The indices of in bound vs. out of bounds coefficients are statistically independent of the secret key; see -Section 5.5 of the Dilithium Round 3 specification[^Round3_Spec]. ## Primer @@ -133,7 +176,7 @@ echo '1+1;;' | nc -w 5 127.0.0.1 2012 ## Routines covered -All routines listed below have been proven correct, memory-safe, and secret-independent in their timing, except for the rejection samplers. `rej_uniform` is proven correct and memory-safe, and is variable-time by design (see [By design](#by-design-rejection-sampling-for-the-public-matrix-rej_uniform)). `rej_uniform_eta{2,4}` are proven correct and memory-safe, with only their timing property outstanding (see [Known gap](#known-gap-rejection-sampling-for-the-secret-vector-rej_uniform_eta24)). +All routines listed below have been proven correct, memory-safe, and secret-independent in their timing, except for the rejection samplers. `rej_uniform` is proven correct and memory-safe, and is variable-time by design (see [By design](#by-design-rejection-sampling-for-the-public-matrix-rej_uniform)). `rej_uniform_eta{2,4}` are proven correct and memory-safe, and secret-independent in timing up to the reject pattern (see [Constant-time rejection sampling](#constant-time-rejection-sampling-for-the-secret-vector-rej_uniform_eta24)). ### AArch64 - ML-DSA Arithmetic: diff --git a/proofs/hol_light/aarch64/proofs/mldsa_rej_uniform_eta2_aarch64_asm.ml b/proofs/hol_light/aarch64/proofs/mldsa_rej_uniform_eta2_aarch64_asm.ml index a559e52f04..5986a90f91 100644 --- a/proofs/hol_light/aarch64/proofs/mldsa_rej_uniform_eta2_aarch64_asm.ml +++ b/proofs/hol_light/aarch64/proofs/mldsa_rej_uniform_eta2_aarch64_asm.ml @@ -2278,24 +2278,17 @@ let MLDSA_REJ_UNIFORM_ETA2_SUBROUTINE_CORRECT = prove (* ========================================================================= *) (* Memory Safety Proof *) (* *) -(* We prove memory-safety, but not yet secret-independent timing. *) -(* *) (* The safety specification below differs in shape from the ones used in *) -(* most other HOL-Light proofs, which consolidate safety and *) -(* secret-independent timing into a single theorem. *) -(* *) -(* Here, we show that the assembly kernel emits _some_ list of *) -(* microarchitectural events the memory-accesses in which fall *) -(* within the expected bounds. *) -(* *) -(* In a joint safety + secret-independent timing specification, in turn, *) -(* we would _additionally_ seek to express the list of microarchitectural *) -(* events as a _function_ of public data. *) +(* most other HOL-Light proofs, which consolidate memory safety and *) +(* secret-independent timing into a single theorem. Here we prove memory *) +(* safety on its own: the kernel emits _some_ list of microarchitectural *) +(* events whose memory accesses fall within the expected bounds. *) (* *) -(* TODO (#1160): In the context of rejection sampling, the event-generating *) -(* function should take the set of in-bound indices as an argument, but *) -(* not the entire input data. This corresponds to declassifying _which_ *) -(* coefficients are in bounds vs. out of bounds, but not their values. *) +(* Secret-independent timing is proven separately below (see "Constant-time *) +(* rejection sampling"): rather than assert full data-obliviousness, the *) +(* event-generating function there takes the reject bitmap -- one accept/ *) +(* reject bit per candidate nibble -- as its data argument, declassifying *) +(* which coefficients are in bounds vs. out of bounds, but not their values. *) (* ========================================================================= *) needs "s2n_bignum/arm/proofs/consttime.ml";; @@ -3201,3 +3194,1170 @@ let MLDSA_REJ_UNIFORM_ETA2_SUBROUTINE_MEMSAFE = time prove (CONV_RULE LENGTH_SIMPLIFY_CONV MLDSA_REJ_UNIFORM_ETA2_MEMSAFE)) `[]:int64 list` 576 THEN DISCHARGE_MEMSAFE_TAC);; + +(* Constant-time (secret-independent timing) proof for rej_uniform_eta2. + See proofs/hol_light/README.md for the security property and the statement of + MLDSA_REJ_UNIFORM_ETA2_SUBROUTINE_SAFE. + + This is a rejection sampler, so it is NOT data-oblivious and the standard + PROVE_SAFETY_SPEC_TAC does not apply. We prove constant-time up to the reject + pattern: the event trace is a function of the public pointers and the reject + bitmap REJ_MASK_ETA2 (one accept/reject bit per nibble, "accept" = + val < 15), never the accepted values. gen_mk_safety_spec cannot express this + (its f_events takes only pointers/pc/sp/ra), so the spec is hand-written with + the reject mask as an extra public argument. + + Secret-dependent behaviour lives only in the loop8 sampler: + - table reads ldr q,[x3, mask*16] address = 8-bit accept mask + - scratch stores st1 [x7]; x7 += 2*popcount offset = accepted count + - loop trip count = f(accept masks, buflen) + All three are functions of the accept masks and the public buflen; the + prologue zero-init and the final Barrett-reduce copy have fixed trip counts. *) + +(* The public reject-mask projection: one accept/reject bit per nibble, with *) +(* the accepted values DISCARDED. Mirrors REJ_NIBBLES_ETA2 (which FILTERs the *) +(* same predicate to keep the accepted values = the SECRET); here we MAP the *) +(* predicate to keep only the decisions. From this bool list one recovers the *) +(* per-group 8-bit masks (pack 8 bits), the accepted counts (popcounts), and *) +(* hence every secret-dependent address/branch above — but not the values. *) +(* *) +(* NOTE: REJ_NIBBLES_ETA2 l = FILTER (\x. val x < 15) (NIBBLES_OF_BYTES l) *) +(* so LENGTH(REJ_NIBBLES_ETA2 l) = number of `true` in REJ_MASK_ETA2 l. *) +(* REJ_NIBBLES_ETA2 is NOT recoverable from REJ_MASK_ETA2 alone (the *) +(* accepted values are gone) — that is the whole point. *) + +let REJ_MASK_ETA2 = define + `REJ_MASK_ETA2 (l:byte list) : bool list = + MAP (\x:int16. val x < 15) (NIBBLES_OF_BYTES l)`;; + +(* Store-advance / trip-count half of the mask bridge (pure list facts): they *) +(* express the SECRET accepted-count as a function of the PUBLIC reject mask *) +(* only; the accepted values never appear. *) + +(* Abstract core: #elements passing P = #`true`s in the boolean image. *) +let LENGTH_FILTER_EQ_LENGTH_FILTER_MAP = prove + (`!(P:A->bool) xs. + LENGTH(FILTER (\b:bool. b) (MAP P xs)) = LENGTH(FILTER P xs)`, + GEN_TAC THEN LIST_INDUCT_TAC THEN + REWRITE_TAC[MAP; FILTER; LENGTH] THEN + COND_CASES_TAC THEN ASM_REWRITE_TAC[LENGTH]);; + +(* THE store-advance / trip-count bridge: the number of ACCEPTED nibbles + (= niblen, driving all sp+2*niblen store offsets and the WOP trip count N) + equals the number of `true`s in the PUBLIC reject mask. Value-free: the RHS + mentions only REJ_MASK_ETA2 (public), never the accepted values. *) +let LENGTH_REJ_NIBBLES_ETA2_EQ_MASK = prove + (`!l:byte list. + LENGTH(REJ_NIBBLES_ETA2 l) = LENGTH(FILTER (\b:bool. b) (REJ_MASK_ETA2 l))`, + REWRITE_TAC[REJ_NIBBLES_ETA2; REJ_MASK_ETA2; + LENGTH_FILTER_EQ_LENGTH_FILTER_MAP]);; + +(* A clean public "accepted count" over a mask, additive over APPEND — the + form the f_events per-iteration store-offset witness will use. *) +let NUM_ACCEPTED = define + `NUM_ACCEPTED (m:bool list) = LENGTH(FILTER (\b:bool. b) m)`;; + +let NUM_ACCEPTED_APPEND = prove + (`!m1 m2. NUM_ACCEPTED(APPEND m1 m2) = NUM_ACCEPTED m1 + NUM_ACCEPTED m2`, + REWRITE_TAC[NUM_ACCEPTED; FILTER_APPEND; LENGTH_APPEND]);; + +(* Public table-index witness: the 8-bit LSB-first packing of an accept-mask + group. The compaction table (mldsa_rej_uniform_eta_table) is indexed by this + 0..255 value, so the loop's data-dependent table read decodes to + EventLoad (table + 16 * PACK_MASK8 ) — a function of the PUBLIC + mask only. Explicit 8-EL form (not nsum) to match the eventual hardware + value-bridge, whose shape mirrors UADDLV_COUNT_LEMMA (8 explicit bits). *) +let PACK_MASK8 = define + `PACK_MASK8 (bs:bool list) = + bitval(EL 0 bs) + 2 * bitval(EL 1 bs) + + 4 * bitval(EL 2 bs) + 8 * bitval(EL 3 bs) + + 16 * bitval(EL 4 bs) + 32 * bitval(EL 5 bs) + + 64 * bitval(EL 6 bs) + 128 * bitval(EL 7 bs)`;; + +let PACK_MASK8_BOUND = prove + (`!bs:bool list. PACK_MASK8 bs < 256`, + GEN_TAC THEN REWRITE_TAC[PACK_MASK8] THEN + MAP_EVERY (fun t -> MP_TAC(SPEC t BITVAL_BOUND)) + [`EL 0 (bs:bool list)`; `EL 1 (bs:bool list)`; `EL 2 (bs:bool list)`; + `EL 3 (bs:bool list)`; `EL 4 (bs:bool list)`; `EL 5 (bs:bool list)`; + `EL 6 (bs:bool list)`; `EL 7 (bs:bool list)`] THEN + ARITH_TAC);; + +(* idx0 = weighted 8-bit pack of the per-nibble accept mask; drives the *) +(* data-dependent table read LDR Q24,[X3,X12,LSL#4] = *) +(* EventLoad(table+16*idx0). In nibble order these bits are REJ_MASK_ETA2 of *) +(* the group, so val idx0 = PACK_MASK8(mask): the table address is a function *) +(* of the PUBLIC mask only. *) + +let UADDLV_PACK_LEMMA = prove + (`!b0 b1 b2 b3 b4 b5 b6 b7. + (val (word_zx (word_subword ((word_add (word_subword ((word_and (word 664619068533544770747334646890102785:(128)word)) (word_join (word_join (word_join (word_neg (word (bitval b0):(16)word)) (word_neg (word (bitval b1):(16)word)):(32)word) (word_join (word_neg (word (bitval b2):(16)word)) (word_neg (word (bitval b3):(16)word)):(32)word):(64)word) (word_join (word_join (word_neg (word (bitval b4):(16)word)) (word_neg (word (bitval b5):(16)word)):(32)word) (word_join (word_neg (word (bitval b6):(16)word)) (word_neg (word (bitval b7):(16)word)):(32)word):(64)word):(128)word)) (0,16):(128)word)) ((word_add (word_subword ((word_and (word 664619068533544770747334646890102785:(128)word)) (word_join (word_join (word_join (word_neg (word (bitval b0):(16)word)) (word_neg (word (bitval b1):(16)word)):(32)word) (word_join (word_neg (word (bitval b2):(16)word)) (word_neg (word (bitval b3):(16)word)):(32)word):(64)word) (word_join (word_join (word_neg (word (bitval b4):(16)word)) (word_neg (word (bitval b5):(16)word)):(32)word) (word_join (word_neg (word (bitval b6):(16)word)) (word_neg (word (bitval b7):(16)word)):(32)word):(64)word):(128)word)) (16,16):(128)word)) ((word_add (word_subword ((word_and (word 664619068533544770747334646890102785:(128)word)) (word_join (word_join (word_join (word_neg (word (bitval b0):(16)word)) (word_neg (word (bitval b1):(16)word)):(32)word) (word_join (word_neg (word (bitval b2):(16)word)) (word_neg (word (bitval b3):(16)word)):(32)word):(64)word) (word_join (word_join (word_neg (word (bitval b4):(16)word)) (word_neg (word (bitval b5):(16)word)):(32)word) (word_join (word_neg (word (bitval b6):(16)word)) (word_neg (word (bitval b7):(16)word)):(32)word):(64)word):(128)word)) (32,16):(128)word)) ((word_add (word_subword ((word_and (word 664619068533544770747334646890102785:(128)word)) (word_join (word_join (word_join (word_neg (word (bitval b0):(16)word)) (word_neg (word (bitval b1):(16)word)):(32)word) (word_join (word_neg (word (bitval b2):(16)word)) (word_neg (word (bitval b3):(16)word)):(32)word):(64)word) (word_join (word_join (word_neg (word (bitval b4):(16)word)) (word_neg (word (bitval b5):(16)word)):(32)word) (word_join (word_neg (word (bitval b6):(16)word)) (word_neg (word (bitval b7):(16)word)):(32)word):(64)word):(128)word)) (48,16):(128)word)) ((word_add (word_subword ((word_and (word 664619068533544770747334646890102785:(128)word)) (word_join (word_join (word_join (word_neg (word (bitval b0):(16)word)) (word_neg (word (bitval b1):(16)word)):(32)word) (word_join (word_neg (word (bitval b2):(16)word)) (word_neg (word (bitval b3):(16)word)):(32)word):(64)word) (word_join (word_join (word_neg (word (bitval b4):(16)word)) (word_neg (word (bitval b5):(16)word)):(32)word) (word_join (word_neg (word (bitval b6):(16)word)) (word_neg (word (bitval b7):(16)word)):(32)word):(64)word):(128)word)) (64,16):(128)word)) ((word_add (word_subword ((word_and (word 664619068533544770747334646890102785:(128)word)) (word_join (word_join (word_join (word_neg (word (bitval b0):(16)word)) (word_neg (word (bitval b1):(16)word)):(32)word) (word_join (word_neg (word (bitval b2):(16)word)) (word_neg (word (bitval b3):(16)word)):(32)word):(64)word) (word_join (word_join (word_neg (word (bitval b4):(16)word)) (word_neg (word (bitval b5):(16)word)):(32)word) (word_join (word_neg (word (bitval b6):(16)word)) (word_neg (word (bitval b7):(16)word)):(32)word):(64)word):(128)word)) (80,16):(128)word)) ((word_add (word_subword ((word_and (word 664619068533544770747334646890102785:(128)word)) (word_join (word_join (word_join (word_neg (word (bitval b0):(16)word)) (word_neg (word (bitval b1):(16)word)):(32)word) (word_join (word_neg (word (bitval b2):(16)word)) (word_neg (word (bitval b3):(16)word)):(32)word):(64)word) (word_join (word_join (word_neg (word (bitval b4):(16)word)) (word_neg (word (bitval b5):(16)word)):(32)word) (word_join (word_neg (word (bitval b6):(16)word)) (word_neg (word (bitval b7):(16)word)):(32)word):(64)word):(128)word)) (96,16):(128)word)) (word_subword ((word_and (word 664619068533544770747334646890102785:(128)word)) (word_join (word_join (word_join (word_neg (word (bitval b0):(16)word)) (word_neg (word (bitval b1):(16)word)):(32)word) (word_join (word_neg (word (bitval b2):(16)word)) (word_neg (word (bitval b3):(16)word)):(32)word):(64)word) (word_join (word_join (word_neg (word (bitval b4):(16)word)) (word_neg (word (bitval b5):(16)word)):(32)word) (word_join (word_neg (word (bitval b6):(16)word)) (word_neg (word (bitval b7):(16)word)):(32)word):(64)word):(128)word)) (112,16):(128)word)))))))) (0,32):(32)word):(64)word)) = + 128 * bitval b0 + 64 * bitval b1 + 32 * bitval b2 + 16 * bitval b3 + + 8 * bitval b4 + 4 * bitval b5 + 2 * bitval b6 + bitval b7`, + REPEAT GEN_TAC THEN + MAP_EVERY BOOL_CASES_TAC [`b0:bool`;`b1:bool`;`b2:bool`;`b3:bool`; + `b4:bool`;`b5:bool`;`b6:bool`;`b7:bool`] THEN + REWRITE_TAC[BITVAL_CLAUSES] THEN + CONV_TAC(DEPTH_CONV WORD_NUM_RED_CONV) THEN CONV_TAC NUM_REDUCE_CONV);; + +(* The value bridge's weighted sum IS PACK_MASK8 of the accept-mask in NIBBLE *) +(* order. UADDLV_PACK_LEMMA's b0..b7 are in LANE order (b0 = highest lane = *) +(* byte3's high nibble = weight 128 ... b7 = lowest lane = byte0's low nibble *) +(* = weight 1). NIBBLES_OF_BYTES [byte0;byte1;byte2;byte3] lists nibbles *) +(* low-first per byte: [byte0-lo; byte0-hi; byte1-lo; ...; byte3-hi] = *) +(* [b7;b6;b5;b4;b3;b2; b1;b0]. Hence val(idx0) = PACK_MASK8 (REJ_MASK_ETA2 *) +(* ) once the abstract booleans are instantiated to (val *) +(* nibble_k < 15) — the core _SAFE proof does that instantiation using the *) +(* eta2 nibble machinery. *) +let PACK_CONNECT = prove + (`!b0 b1 b2 b3 b4 b5 b6 b7:bool. + 128 * bitval b0 + 64 * bitval b1 + 32 * bitval b2 + 16 * bitval b3 + + 8 * bitval b4 + 4 * bitval b5 + 2 * bitval b6 + bitval b7 = + PACK_MASK8 [b7;b6;b5;b4;b3;b2;b1;b0]`, + REWRITE_TAC[PACK_MASK8] THEN + CONV_TAC(ONCE_DEPTH_CONV EL_CONV) THEN ARITH_TAC);; + +(* Atomic-mask discipline: the event LHS must carry the mask as a single var *) +(* `mask` (= REJ_MASK_ETA2 inlist), not the compound term, or CONCRETIZE's *) +(* unification fails. The lemmas below rewrite hardware inlist-SUB_LISTs into *) +(* SUB_LISTs of the atomic mask (idx0/idx1/curlen), keeping inlist out of the *) +(* trace. *) + +(* byte-index SUB_LIST maps to a nibble-index SUB_LIST at 2x offset/length. *) +let NIBBLES_OF_BYTES_SUB_LIST = prove + (`!l a b. NIBBLES_OF_BYTES(SUB_LIST(a,b) l) = + SUB_LIST(2*a,2*b)(NIBBLES_OF_BYTES l)`, + LIST_INDUCT_TAC THEN REPEAT GEN_TAC THEN + MAP_EVERY (fun v -> STRUCT_CASES_TAC(SPEC v num_CASES)) [`a:num`;`b:num`] THEN + ASM_REWRITE_TAC[NIBBLES_OF_BYTES; NIBBLE_PAIR; SUB_LIST_CLAUSES; APPEND; + MULT_CLAUSES; ADD_CLAUSES; ARITH_RULE `2 * SUC n = SUC(SUC(2*n))`] THEN + ASM_REWRITE_TAC[SUB_LIST_CLAUSES; APPEND]);; + +(* General-offset MAP/SUB_LIST commutation (aarch64_utils' SUB_LIST_MAP is *) +(* prefix-only, (0,n)). *) +let SUB_LIST_MAP_GEN = prove + (`!(f:A->B) l a b. SUB_LIST(a,b)(MAP f l) = MAP f (SUB_LIST(a,b) l)`, + GEN_TAC THEN LIST_INDUCT_TAC THEN REPEAT GEN_TAC THEN + MAP_EVERY (fun v -> STRUCT_CASES_TAC(SPEC v num_CASES)) [`a:num`;`b:num`] THEN + ASM_REWRITE_TAC[MAP; SUB_LIST_CLAUSES]);; + +(* THE mask-level length-doubling commutation: converts a hardware *) +(* REJ_MASK_ETA2(SUB_LIST(a,b) inlist) into a SUB_LIST of the ATOMIC mask — *) +let REJ_MASK_ETA2_SUB_LIST = prove + (`!l a b. REJ_MASK_ETA2(SUB_LIST(a,b) l) = SUB_LIST(2*a,2*b)(REJ_MASK_ETA2 l)`, + REWRITE_TAC[REJ_MASK_ETA2; NIBBLES_OF_BYTES_SUB_LIST; SUB_LIST_MAP_GEN]);; + +(* The loop8 trip count is data-dependent but PUBLIC: the least n at which *) +(* the input is exhausted (val buflen < 8*(n+1)) OR the output is full (256 *) +(* <= NUM_ACCEPTED of the first 16n mask bits). Function of buflen and the *) +(* PUBLIC mask only -- never the accepted values. *) + +let MLDSA_ETA2_LOOP8_TRIP = define + `MLDSA_ETA2_LOOP8_TRIP (buflen:int64) (mask:bool list) : num = + minimal n. val buflen < 8 * (n + 1) \/ + 256 <= NUM_ACCEPTED (SUB_LIST(0,16 * n) mask)`;; + +(* Analytical crux of loop8's dual-exit closure, from minimality of the trip *) +(* count: (1) at the trip point either input is exhausted or output is full *) +(* (which branch fired); (2) below the trip point neither holds (we execute *) +(* iteration i). Pure arithmetic on `minimal`; no SIMD. *) + +let MLDSA_ETA2_LOOP8_TRIP_MINIMAL = prove + (`!(buflen:int64) (mask:(bool)list). + (val buflen < 8 * (MLDSA_ETA2_LOOP8_TRIP buflen mask + 1) \/ + 256 <= NUM_ACCEPTED(SUB_LIST(0,16 * MLDSA_ETA2_LOOP8_TRIP buflen mask) mask)) /\ + (!i. i < MLDSA_ETA2_LOOP8_TRIP buflen mask + ==> ~(val buflen < 8 * (i + 1)) /\ + ~(256 <= NUM_ACCEPTED(SUB_LIST(0,16 * i) mask)))`, + REPEAT GEN_TAC THEN REWRITE_TAC[MLDSA_ETA2_LOOP8_TRIP] THEN + SUBGOAL_THEN + `?n. val(buflen:int64) < 8 * (n + 1) \/ 256 <= NUM_ACCEPTED(SUB_LIST(0,16 * n) mask)` + ASSUME_TAC THENL + [EXISTS_TAC `val(buflen:int64)` THEN DISJ1_TAC THEN ARITH_TAC; ALL_TAC] THEN + FIRST_X_ASSUM(STRIP_ASSUME_TAC o REWRITE_RULE[MINIMAL]) THEN + ASM_REWRITE_TAC[] THEN + X_GEN_TAC `i:num` THEN DISCH_TAC THEN + REWRITE_TAC[GSYM DE_MORGAN_THM] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN + ASM_REWRITE_TAC[]);; + +(* Event vocabulary: EventLoad/EventStore/EventJump accumulate via CONS. *) +(* Every conditional branch (arm_Bcond) emits EventJump(pc, if cond then *) +(* target else pc+4). Per loop8 iteration: buf load + 2 table loads + 2 *) +(* stores + branch jumps. *) + +(* The zero-init loop is oblivious but its back-edge is a signed cmp/b.lt *) +(* whose flag condition the stepper leaves in raw `ival` form. ZINIT_BRANCH *) +(* proves that raw condition equals the loop bound i+1<8; IVAL_WORD_SMALL is *) +(* the standard ival(word m)=&m for m below 2^63. *) + +let IVAL_WORD_SMALL = prove + (`!m. m < 2 EXP 63 ==> ival(word m:int64) = &m`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN `val(word m:int64) = m` ASSUME_TAC THENL + [REWRITE_TAC[VAL_WORD; DIMINDEX_64] THEN MATCH_MP_TAC MOD_LT THEN + ASM_ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `~bit 63 (word m:int64)` ASSUME_TAC THENL + [REWRITE_TAC[BIT_WORD; DIMINDEX_64] THEN + SUBGOAL_THEN `m DIV 2 EXP 63 = 0` SUBST1_TAC THENL + [MATCH_MP_TAC DIV_LT THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + ASM_REWRITE_TAC[IVAL_VAL; DIMINDEX_64; ARITH_RULE `64 - 1 = 63`; + BITVAL_CLAUSES] THEN + INT_ARITH_TAC);; + +(* The signed b.lt back-edge condition for the zero-init counter: given i<8 *) +(* (loop bound), the raw stepper flag condition on 32*(i+1) is equivalent to *) +(* the loop-continuation predicate i+1<8. This is what the loop-body PC leaf *) +let ZINIT_BRANCH = prove + (`!i. i < 8 ==> + (~(ival (word_add (word (32 * i)) (word 18446744073709551392):int64) < &0 <=> + ~(ival (word_add (word (32 * i)) (word 32):int64) - &256 = + ival (word_add (word (32 * i)) (word 18446744073709551392):int64))) + <=> i + 1 < 8)`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN + `ival (word_add (word (32 * i)) (word 32):int64) = &(32 * i) + &32` + SUBST1_TAC THENL + [SUBGOAL_THEN `word_add (word (32*i)) (word 32):int64 = word(32*i+32)` + SUBST1_TAC THENL [CONV_TAC WORD_RULE; ALL_TAC] THEN + SUBGOAL_THEN `ival(word(32*i+32):int64) = &(32*i+32)` + (fun th -> REWRITE_TAC[th; GSYM INT_OF_NUM_ADD]) THEN + MATCH_MP_TAC IVAL_WORD_SMALL THEN ASM_ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN + `ival (word_add (word (32 * i)) (word 18446744073709551392):int64) = + &(32 * i) - &224` + SUBST1_TAC THENL + [SUBGOAL_THEN + `word_add (word (32*i)) (word 18446744073709551392):int64 = + iword(&(32*i) - &224)` SUBST1_TAC THENL + [REWRITE_TAC[IWORD_INT_SUB; GSYM WORD_IWORD] THEN + REWRITE_TAC[WORD_RULE `word_sub a (b:int64) = word_add a (word_neg b)`] THEN + AP_TERM_TAC THEN CONV_TAC WORD_REDUCE_CONV; ALL_TAC] THEN + MATCH_MP_TAC IVAL_IWORD THEN REWRITE_TAC[DIMINDEX_64] THEN + ASM_SIMP_TAC[GSYM INT_OF_NUM_MUL; GSYM INT_OF_NUM_LT] THEN + ASM_ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `(&(32 * i) + &32) - &256 = &(32 * i) - &224:int` SUBST1_TAC THENL + [INT_ARITH_TAC; ALL_TAC] THEN + REWRITE_TAC[] THEN + REWRITE_TAC[INT_ARITH `(x:int) - &224 < &0 <=> x < &224`; + GSYM INT_OF_NUM_MUL; GSYM INT_OF_NUM_LT] THEN + ARITH_TAC);; + +(* The signed b.lt back-edge condition for the FINAL-COPY (fcopy) counter: *) +(* given i<16 (loop bound), the raw stepper flag condition on the *) +(* post-increment counter 16*(i+1) is equivalent to the loop-continuation *) +(* predicate i+1<16. This is FCOPY's analogue of ZINIT_BRANCH (32*(i+1) vs *) +(* 8): 16*(i+1) vs 256, -240 = word 18446744073709551376 (= 16 - 256 in two's *) +(* complement). *) +let FCOPY_BRANCH = prove + (`!i. i < 16 ==> + (~(ival (word_add (word (16 * i)) (word 18446744073709551376):int64) < &0 <=> + ~(ival (word_add (word (16 * i)) (word 16):int64) - &256 = + ival (word_add (word (16 * i)) (word 18446744073709551376):int64))) + <=> i + 1 < 16)`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN + `ival (word_add (word (16 * i)) (word 16):int64) = &(16 * i) + &16` + SUBST1_TAC THENL + [SUBGOAL_THEN `word_add (word (16*i)) (word 16):int64 = word(16*i+16)` + SUBST1_TAC THENL [CONV_TAC WORD_RULE; ALL_TAC] THEN + SUBGOAL_THEN `ival(word(16*i+16):int64) = &(16*i+16)` + (fun th -> REWRITE_TAC[th; GSYM INT_OF_NUM_ADD]) THEN + MATCH_MP_TAC IVAL_WORD_SMALL THEN ASM_ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN + `ival (word_add (word (16 * i)) (word 18446744073709551376):int64) = + &(16 * i) - &240` + SUBST1_TAC THENL + [SUBGOAL_THEN + `word_add (word (16*i)) (word 18446744073709551376):int64 = + iword(&(16*i) - &240)` SUBST1_TAC THENL + [REWRITE_TAC[IWORD_INT_SUB; GSYM WORD_IWORD] THEN + REWRITE_TAC[WORD_RULE `word_sub a (b:int64) = word_add a (word_neg b)`] THEN + AP_TERM_TAC THEN CONV_TAC WORD_REDUCE_CONV; ALL_TAC] THEN + MATCH_MP_TAC IVAL_IWORD THEN REWRITE_TAC[DIMINDEX_64] THEN + ASM_SIMP_TAC[GSYM INT_OF_NUM_MUL; GSYM INT_OF_NUM_LT] THEN + ASM_ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `(&(16 * i) + &16) - &256 = &(16 * i) - &240:int` SUBST1_TAC THENL + [INT_ARITH_TAC; ALL_TAC] THEN + REWRITE_TAC[] THEN + REWRITE_TAC[INT_ARITH `(x:int) - &240 < &0 <=> x < &240`; + GSYM INT_OF_NUM_MUL; GSYM INT_OF_NUM_LT] THEN + ARITH_TAC);; + +(* The two word-arith bridges that discharge loop8's dual exit: BOT turns the *) +(* bottom hw cond (8 <= val(word_sub buflen (word 8*(i+1)))) into ~(val *) +(* buflen < 8*(i+2)) (input-exhaust); TOP turns 256 <= val(word n) into 256 *) +(* <= n (output-full), given n < 2^64. *) + +let LOOP8_TOP_VAL_BRIDGE = prove + (`!n. n < 2 EXP 64 ==> (256 <= val(word n:int64) <=> 256 <= n)`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN `val(word n:int64) = n` SUBST1_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN ASM_REWRITE_TAC[DIMINDEX_64]; ALL_TAC] THEN + REWRITE_TAC[]);; + +let LOOP8_BOT_VAL_BRIDGE = prove + (`!(buflen:int64) i. 8*(i+1) <= val buflen + ==> (8 <= val(word_sub buflen (word(8*(i+1))):int64) <=> ~(val buflen < 8*(i+2)))`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN `val(word(8*(i+1)):int64) = 8*(i+1)` ASSUME_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN + MP_TAC(ISPEC `buflen:int64` VAL_BOUND) THEN REWRITE_TAC[DIMINDEX_64] THEN + ASM_ARITH_TAC; ALL_TAC] THEN + ASM_SIMP_TAC[VAL_WORD_SUB_CASES] THEN ASM_ARITH_TAC);; + +(* -------------------------------------------------------------------------- *) +(* *) +(* This is the analytical core of the loop8 tail-close PC obligation. It *) +(* connects the TOP branch's hardware condition (256 <= curlen', where *) +(* curlen' = NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask) is the accepted count *) +(* after iteration i) to the loop-exit predicate ~(i+1 < TRIP), GIVEN the *) +(* BOTTOM branch fell through to the top check (input not exhausted at i+1, *) +(* i.e. ~(val buflen < 8*(i+2))). Both directions follow from *) +(* MLDSA_ETA2_LOOP8_TRIP_MINIMAL: *) +(* (<=) ~(i+1 i+1 = TRIP (with i) 256 <= curlen' with i+1 (256 <= NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask) <=> + ~(i + 1 < MLDSA_ETA2_LOOP8_TRIP buflen mask))`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + MP_TAC(SPECL[`buflen:int64`;`mask:(bool)list`] MLDSA_ETA2_LOOP8_TRIP_MINIMAL) THEN + DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "PT2")) THEN + ASM_CASES_TAC `i + 1 < MLDSA_ETA2_LOOP8_TRIP buflen mask` THENL + [ASM_REWRITE_TAC[] THEN + USE_THEN "PT2" (MP_TAC o SPEC `i + 1`) THEN ANTS_TAC THENL + [ASM_REWRITE_TAC[]; DISCH_THEN(fun th -> REWRITE_TAC[CONJUNCT2 th])]; + SUBGOAL_THEN `i + 1 = MLDSA_ETA2_LOOP8_TRIP buflen mask` ASSUME_TAC THENL + [MAP_EVERY UNDISCH_TAC + [`i < MLDSA_ETA2_LOOP8_TRIP buflen mask`; + `~(i + 1 < MLDSA_ETA2_LOOP8_TRIP buflen mask)`] THEN ARITH_TAC; + ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN + FIRST_ASSUM(DISJ_CASES_TAC o check (is_disj o concl)) THEN ASM_ARITH_TAC]);; + +(* TAIL_CLOSE: reusable dual-exit tail leaf. Steps the bottom (input-exhaust) *) +(* and top (output-full) branches and lands at pc + (if i+1 ensures arm + (\s. aligned_bytes_loaded s (word pc) mldsa_rej_uniform_eta2_mc /\ + read PC s = word (pc + 0xf4) /\ + read SP s = word_sub stackpointer (word 576) /\ + read X30 s = returnaddress /\ + read X0 s = res /\ + read X1 s = word_add buf (word(8*(i+1))) /\ + read X2 s = word_sub buflen (word(8*(i+1))) /\ + read X3 s = table /\ + read X4 s = word 256 /\ + read X7 s = word_add (word_sub stackpointer (word 576)) + (word(2 * NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask))) /\ + read X8 s = word_sub stackpointer (word 576) /\ + read X9 s = word (NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask)) /\ + read Q30 s = word 77885641318594292392624080437575695 /\ + read Q31 s = word 664619068533544770747334646890102785 /\ + read (memory :> bytes(table,4096)) s = tabval /\ + read (memory :> bytes(buf, val buflen)) s = bufval /\ + read events s = e) + (\s. read PC s = + word (pc + (if i + 1 < MLDSA_ETA2_LOOP8_TRIP buflen mask then 0x70 else 0xfc)) /\ + read SP s = word_sub stackpointer (word 576) /\ + read X30 s = returnaddress /\ + read X0 s = res /\ + read X1 s = word_add buf (word(8*(i+1))) /\ + read X2 s = word_sub buflen (word(8*(i+1))) /\ + read X3 s = table /\ + read X4 s = word 256 /\ + read X7 s = word_add (word_sub stackpointer (word 576)) + (word(2 * NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask))) /\ + read X8 s = word_sub stackpointer (word 576) /\ + read X9 s = word (NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask)) /\ + read Q30 s = word 77885641318594292392624080437575695 /\ + read Q31 s = word 664619068533544770747334646890102785 /\ + read (memory :> bytes(table,4096)) s = tabval /\ + read (memory :> bytes(buf, val buflen)) s = bufval /\ + read events s = + APPEND + (if 8 <= val(word_sub buflen (word(8*(i+1))):int64) + then [EventJump(word(pc+108), + (if 256 <= val(word(NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask)):int64) + then word(pc+252) else word(pc+112))); + EventJump(word(pc+248), word(pc+104))] + else [EventJump(word(pc+248), word(pc+252))]) e) + (\s s'. T)`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN `8 * (i + 1) <= val(buflen:int64)` ASSUME_TAC THENL + [MP_TAC(SPECL[`buflen:int64`;`mask:(bool)list`] MLDSA_ETA2_LOOP8_TRIP_MINIMAL) THEN + DISCH_THEN(MP_TAC o SPEC `i:num` o CONJUNCT2) THEN + ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o CONJUNCT1) THEN ARITH_TAC; + ALL_TAC] THEN + ENSURES_INIT_TAC "s0" THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC (1--2) THEN + ASM_CASES_TAC `8 <= val(word_sub buflen (word(8*(i+1))):int64)` THENL + [UNDISCH_TAC `8 <= val(word_sub buflen (word(8*(i+1))):int64)` THEN + DISCH_THEN(fun th -> RULE_ASSUM_TAC(REWRITE_RULE[th]) THEN ASSUME_TAC th) THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC (3--4) THEN + SUBGOAL_THEN + `256 <= val(word(NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask)):int64) <=> + ~(i + 1 < MLDSA_ETA2_LOOP8_TRIP buflen mask)` ASSUME_TAC THENL + [ASM_SIMP_TAC[LOOP8_TOP_VAL_BRIDGE] THEN + MATCH_MP_TAC LOOP8_OUTPUT_FULL_IFF THEN + ASM_MESON_TAC[LOOP8_BOT_VAL_BRIDGE]; + ALL_TAC] THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN + REWRITE_TAC[APPEND] THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[]; + SUBGOAL_THEN `val (buflen:int64) < 8 * (i + 2)` ASSUME_TAC THENL + [UNDISCH_TAC `~(8 <= val(word_sub buflen (word(8*(i+1))):int64))` THEN + ASM_SIMP_TAC[LOOP8_BOT_VAL_BRIDGE]; ALL_TAC] THEN + SUBGOAL_THEN `~(i + 1 < MLDSA_ETA2_LOOP8_TRIP buflen mask)` ASSUME_TAC THENL + [DISCH_TAC THEN + MP_TAC(SPECL[`buflen:int64`;`mask:(bool)list`] MLDSA_ETA2_LOOP8_TRIP_MINIMAL) THEN + DISCH_THEN(MP_TAC o SPEC `i + 1` o CONJUNCT2) THEN + ASM_REWRITE_TAC[ARITH_RULE `8 * ((i + 1) + 1) = 8 * (i + 2)`]; ALL_TAC] THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[APPEND]]);; + +(* Count-bridge for the loop8 per-iteration accepted count (final X9 value *) +(* and the 2nd stack-store address): the accepted-count after i+1 groups = *) +(* the count after i groups + the two 4-byte-half counts of group i. Pure *) +(* list *) +let NUM_ACCEPTED_SUB_LIST_STEP = prove + (`!(mask:bool list) i. + NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask) = + NUM_ACCEPTED(SUB_LIST(0,16*i) mask) + + NUM_ACCEPTED(SUB_LIST(16*i,8) mask) + + NUM_ACCEPTED(SUB_LIST(16*i+8,8) mask)`, + REPEAT GEN_TAC THEN + ASSUME_TAC(REWRITE_RULE[ADD_CLAUSES; ARITH_RULE `8+8=16`] + (ISPECL[`mask:bool list`;`8`;`8`;`16*i:num`] SUB_LIST_SPLIT)) THEN + ASSUME_TAC(REWRITE_RULE[ADD_CLAUSES] + (ISPECL[`mask:bool list`;`16*i:num`;`16`;`0`] SUB_LIST_SPLIT)) THEN + ASM_REWRITE_TAC[ARITH_RULE `16*(i+1) = 16*i+16`; NUM_ACCEPTED_APPEND] THEN + ARITH_TAC);; + +(* Each 4-byte loop8 half-group accepts at most 8 nibbles (LENGTH bound). *) +(* Used to bound the per-iteration store advance so the 2nd stack store's *) +(* address stays *) +let NUM_ACCEPTED_LE_8 = prove + (`!(m:bool list) a. NUM_ACCEPTED(SUB_LIST(a,8) m) <= 8`, + REPEAT GEN_TAC THEN REWRITE_TAC[NUM_ACCEPTED] THEN + MATCH_MP_TAC LE_TRANS THEN + EXISTS_TAC `LENGTH(SUB_LIST(a,8) (m:bool list))` THEN + REWRITE_TAC[LENGTH_FILTER; LENGTH_SUB_LIST] THEN ARITH_TAC);; + +(* Cancel a prefix of known length off an APPEND equality. *) +let APPEND_EQ_LEN = prove + (`!l1 m1 l2 m2:A list. LENGTH l1 = LENGTH m1 + ==> (APPEND l1 l2 = APPEND m1 m2 <=> l1 = m1 /\ l2 = m2)`, + LIST_INDUCT_TAC THEN LIST_INDUCT_TAC THEN + REWRITE_TAC[LENGTH; NOT_SUC; SUC_INJ; APPEND; CONS_11] THEN + REPEAT STRIP_TAC THEN ASM_MESON_TAC[]);; + +(* Split a known 8-element SUB_LIST into its two 4-element halves (the loop8 *) +(* group is 8 bytes = two 4-byte lanes feeding idx0 and idx1 respectively). *) +let SUB_LIST_4_FROM_8 = prove + (`!(l:A list) a x0 x1 x2 x3 x4 x5 x6 x7. + SUB_LIST(a,8) l = [x0;x1;x2;x3;x4;x5;x6;x7] + ==> SUB_LIST(a,4) l = [x0;x1;x2;x3] /\ SUB_LIST(a+4,4) l = [x4;x5;x6;x7]`, + REPEAT GEN_TAC THEN DISCH_TAC THEN + SUBGOAL_THEN `8 <= LENGTH(l:A list) - a` ASSUME_TAC THENL + [FIRST_ASSUM(MP_TAC o AP_TERM `LENGTH:A list->num`) THEN + REWRITE_TAC[LENGTH_SUB_LIST; LENGTH] THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `APPEND (SUB_LIST(a,4)(l:A list)) (SUB_LIST(a+4,4) l) = + [x0;x1;x2;x3;x4;x5;x6;x7]` MP_TAC THENL + [FIRST_X_ASSUM(fun th -> REWRITE_TAC[SYM th]) THEN + MP_TAC(ISPECL[`l:A list`;`4`;`4`;`a:num`] SUB_LIST_SPLIT) THEN + REWRITE_TAC[ARITH_RULE `4+4=8`] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN REFL_TAC; + ALL_TAC] THEN + MP_TAC(ISPECL[`SUB_LIST(a,4)(l:A list)`;`[x0;x1;x2;x3]:A list`; + `SUB_LIST(a+4,4)(l:A list)`;`[x4;x5;x6;x7]:A list`] APPEND_EQ_LEN) THEN + ANTS_TAC THENL + [REWRITE_TAC[LENGTH_SUB_LIST; LENGTH] THEN CONV_TAC NUM_REDUCE_CONV THEN + ASM_ARITH_TAC; ALL_TAC] THEN + REWRITE_TAC[APPEND] THEN DISCH_THEN(fun th -> ONCE_REWRITE_TAC[GSYM th]) THEN + DISCH_THEN ACCEPT_TAC);; + +(* Expand the reject mask of an explicit 4-byte group into the 8 per-nibble *) +(* accept predicates (low then high nibble of each byte, matching the SIMD *) +(* lane order after the AND/USHR/ZIP/UXTL chain). *) +let MASK_SLICE_4 = prove + (`!(l:byte list) a b0 b1 b2 b3. + SUB_LIST(a,4) l = [b0;b1;b2;b3] + ==> REJ_MASK_ETA2(SUB_LIST(a,4) l) = + [val b0 MOD 16 < 15; val b0 DIV 16 < 15; val b1 MOD 16 < 15; val b1 DIV 16 < 15; + val b2 MOD 16 < 15; val b2 DIV 16 < 15; val b3 MOD 16 < 15; val b3 DIV 16 < 15]`, + REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[REJ_MASK_ETA2; NIBBLES_OF_BYTES_4; MAP] THEN + REWRITE_TAC[VAL_WORD_NIBBLE_LT]);; + +(* COMPUTE materialises all 5 loop8 events (buf load, 2 table loads, 2 *) +(* stores) as addresses that are functions of the PUBLIC *) +(* (buf,table,sp,i,mask) only -- never the accepted values. Its postcond = *) +(* TAIL_CLOSE's precond at i+1 plus those 5 events *) +(* (leakage-up-to-the-reject-mask). *) + +(* --- self-contained helper tactics for the COMPUTE proof --- *) +let bitblast8_compute = List.map (fun k -> BITBLAST_RULE (vsubst[mk_small_numeral k,`k:num`] + `bit k (word_subword (word_neg (word (bitval b):16 word)) (0,8):8 word) <=> b`)) (0--7);; + +(* rewrite the goal with (mk th) for every assumption where mk succeeds *) +let COLLECT_COMPUTE (mk:thm->thm) : tactic = fun (asl,w) -> + REWRITE_TAC(List.filter_map (fun (_,th) -> try Some(mk th) with _ -> None) asl) (asl,w);; + +let is_nibvar_compute v = (try let n = fst(dest_var v) in n="nibbles0"||n="nibbles1b" with _ -> false);; +let NIBGSYM_COMPUTE : tactic = COLLECT_COMPUTE (fun th -> + match lhs(concl th) with + | Comb(Comb(Const("word_subword",_),v),_) when is_nibvar_compute v -> GSYM th + | _ -> failwith "no");; +(* MASK_SLICE_4 applied to each SUB_LIST(_,4) assumption *) +let MASKSLICE_COMPUTE : tactic = COLLECT_COMPUTE (fun th -> MATCH_MP MASK_SLICE_4 th);; +let is_sub4_compute c = is_eq c && (try let (f,a)=strip_comb(lhs c) in + fst(dest_const f)="SUB_LIST" && dest_small_numeral(snd(dest_pair(hd a)))=4 with _ -> false);; +let SUB4GSYM_COMPUTE : tactic = COLLECT_COMPUTE (fun th -> if is_sub4_compute(concl th) then GSYM th else failwith "no");; + +(* find first assumption whose conclusion satisfies p, apply f to it *) +let W_ASM_COMPUTE p (f:thm->tactic) : tactic = fun (asl,w) -> + f (snd(List.find (fun (_,th) -> try p(concl th) with _ -> false) asl)) (asl,w);; + +(* the 16 per-nibble facts word_subword nibbles0/1b (16k,16) = *) +(* word_zx(word_and/ushr..) *) +let PROVE_HW_ALL_COMPUTE : tactic = + let prove_hw name pos byte_pos op = + let rhs_inner = if op = "and" + then Printf.sprintf + "(word_and (word_subword (loaded_d:int64) (%d,8):byte) (word 15):byte)" byte_pos + else Printf.sprintf + "(word_ushr (word_subword (loaded_d:int64) (%d,8):byte) 4:byte)" byte_pos in + let goal_str = Printf.sprintf + "(word_subword (%s:int128) (%d,16)):int16 = word_zx %s :int16" name pos rhs_inner in + SUBGOAL_THEN (parse_term goal_str) ASSUME_TAC THENL + [FIRST_X_ASSUM(MP_TAC o SYM o check + (fun th -> let c = concl th in is_eq c && + (try fst(dest_var(rhs c)) = name with _ -> false) && + (match lhs c with Comb(Comb(Const("read",_),_),_)->false|_->true))) THEN + DISCH_THEN(fun th -> SUBST1_TAC th THEN ASSUME_TAC(SYM th)) THEN + CONV_TAC WORD_BLAST; + ALL_TAC] in + prove_hw "nibbles0" 0 0 "and" THEN prove_hw "nibbles0" 16 0 "ushr" THEN + prove_hw "nibbles0" 32 8 "and" THEN prove_hw "nibbles0" 48 8 "ushr" THEN + prove_hw "nibbles0" 64 16 "and" THEN prove_hw "nibbles0" 80 16 "ushr" THEN + prove_hw "nibbles0" 96 24 "and" THEN prove_hw "nibbles0" 112 24 "ushr" THEN + prove_hw "nibbles1b" 0 32 "and" THEN prove_hw "nibbles1b" 16 32 "ushr" THEN + prove_hw "nibbles1b" 32 40 "and" THEN prove_hw "nibbles1b" 48 40 "ushr" THEN + prove_hw "nibbles1b" 64 48 "and" THEN prove_hw "nibbles1b" 80 48 "ushr" THEN + prove_hw "nibbles1b" 96 56 "and" THEN prove_hw "nibbles1b" 112 56 "ushr";; + +(* the postcondition fold: normalise driven state + target to a common form *) +let POSTCOND_FOLD_COMPUTE : tactic = fun (asl,w) -> + let find p = snd(List.find (fun (_,th) -> try p(concl th) with _ -> false) asl) in + let maskeq = find (fun c -> c = `mask:(bool)list = REJ_MASK_ETA2 inlist`) in + let curleneq= find (fun c -> c = `NUM_ACCEPTED (SUB_LIST (0,16 * i) mask) = curlen`) in + let len0na = find (fun c -> c = `val(len0:int64) = NUM_ACCEPTED (SUB_LIST (16 * i,8) mask)`) in + let len1na = find (fun c -> c = `val(len1:int64) = NUM_ACCEPTED (SUB_LIST (16 * i + 8,8) mask)`) in + let is_lenlen v c = is_eq c && lhs c = v && + (try fst(dest_const(fst(strip_comb(rhs c))))="LENGTH" with _->false) in + let len0len = find (is_lenlen `val(len0:int64)`) in + let len1len = find (is_lenlen `val(len1:int64)`) in + (REWRITE_TAC[GSYM maskeq] THEN REWRITE_TAC[NUM_ACCEPTED_SUB_LIST_STEP] THEN + REWRITE_TAC[GSYM len0len; GSYM len1len] THEN REWRITE_TAC[curleneq] THEN + REWRITE_TAC[GSYM len0na; GSYM len1na] THEN + REWRITE_TAC[ARITH_RULE `8*(i+1) = 8*i+8`; APPEND] THEN + REPEAT CONJ_TAC THEN TRY(CONV_TAC WORD_RULE) THEN TRY REFL_TAC) (asl,w);; + +let MLDSA_ETA2_LOOP8_COMPUTE = prove + (`!res (buf:int64) (buflen:int64) (table:int64) (inlist:byte list) (mask:(bool)list) + (pc:num) (i:num) (e:(uarch_event)list) (stackpointer:int64) (tabval:num) + (returnaddress:int64). + mask = REJ_MASK_ETA2 inlist /\ + LENGTH inlist = val buflen /\ + 8 * (i + 1) <= val buflen /\ + NUM_ACCEPTED(SUB_LIST(0,16 * i) mask) < 256 /\ + ALL (nonoverlapping (word_sub stackpointer (word 576),576)) + [(word pc,372); (buf,val buflen); (table,4096)] + ==> ensures arm + (\s. aligned_bytes_loaded s (word pc) mldsa_rej_uniform_eta2_mc /\ + read PC s = word (pc + 0x70) /\ + read SP s = word_sub stackpointer (word 576) /\ + read X30 s = returnaddress /\ + read X0 s = res /\ + read X1 s = word_add buf (word(8 * i)) /\ + read X2 s = word_sub buflen (word(8 * i)) /\ + read X3 s = table /\ + read X4 s = word 256 /\ + read X7 s = word_add (word_sub stackpointer (word 576)) + (word(2 * NUM_ACCEPTED(SUB_LIST(0,16 * i) mask))) /\ + read X8 s = word_sub stackpointer (word 576) /\ + read X9 s = word (NUM_ACCEPTED(SUB_LIST(0,16 * i) mask)) /\ + read Q30 s = word 77885641318594292392624080437575695 /\ + read Q31 s = word 664619068533544770747334646890102785 /\ + read (memory :> bytes(table,4096)) s = tabval /\ + read (memory :> bytes(buf,val buflen)) s = num_of_wordlist inlist /\ + read events s = e) + (\s. aligned_bytes_loaded s (word pc) mldsa_rej_uniform_eta2_mc /\ + read PC s = word (pc + 0xf4) /\ + read SP s = word_sub stackpointer (word 576) /\ + read X30 s = returnaddress /\ + read X0 s = res /\ + read X1 s = word_add buf (word(8 * (i + 1))) /\ + read X2 s = word_sub buflen (word(8 * (i + 1))) /\ + read X3 s = table /\ + read X4 s = word 256 /\ + read X7 s = word_add (word_sub stackpointer (word 576)) + (word(2 * NUM_ACCEPTED(SUB_LIST(0,16 * (i + 1)) mask))) /\ + read X8 s = word_sub stackpointer (word 576) /\ + read X9 s = word (NUM_ACCEPTED(SUB_LIST(0,16 * (i + 1)) mask)) /\ + read Q30 s = word 77885641318594292392624080437575695 /\ + read Q31 s = word 664619068533544770747334646890102785 /\ + read (memory :> bytes(table,4096)) s = tabval /\ + read (memory :> bytes(buf,val buflen)) s = num_of_wordlist inlist /\ + read events s = + APPEND + [EventStore (word_add (word_sub stackpointer (word 576)) + (word(2 * (NUM_ACCEPTED(SUB_LIST(0,16 * i) mask) + + NUM_ACCEPTED(SUB_LIST(16 * i,8) mask)))), 16); + EventStore (word_add (word_sub stackpointer (word 576)) + (word(2 * NUM_ACCEPTED(SUB_LIST(0,16 * i) mask))), 16); + EventLoad (word_add table + (word(16 * PACK_MASK8(SUB_LIST(16 * i + 8,8) mask))), 16); + EventLoad (word_add table + (word(16 * PACK_MASK8(SUB_LIST(16 * i,8) mask))), 16); + EventLoad (word_add buf (word(8 * i)), 8)] + e) + (\s s'. T)`, + REPEAT GEN_TAC THEN DISCH_THEN(MAP_EVERY ASSUME_TAC o CONJUNCTS) THEN + ABBREV_TAC `curlen = NUM_ACCEPTED(SUB_LIST(0,16 * i) mask)` THEN + GHOST_INTRO_TAC `nibbles1:int128` `read Q17` THEN + ENSURES_INIT_TAC "s0" THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC [1] THEN + ABBREV_TAC `loaded_d:int64 = read (memory :> bytes64 (word_add buf (word (8 * i)))) s1` THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC [2] THEN + ARM_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC (3--9) THEN + REABBREV_TAC `nibbles0:int128 = read Q16 s9` THEN + REABBREV_TAC `nibbles1b:int128 = read Q17 s9` THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC (10--17) THEN + RULE_ASSUM_TAC(CONV_RULE(TOP_DEPTH_CONV WORD_SIMPLE_SUBWORD_CONV)) THEN + RULE_ASSUM_TAC(CONV_RULE WORD_REDUCE_CONV) THEN + RULE_ASSUM_TAC(REWRITE_RULE[word_ugt; relational2; GT; WORD_AND_MASK]) THEN + RULE_ASSUM_TAC(ONCE_REWRITE_RULE[COND_RAND]) THEN + RULE_ASSUM_TAC(CONV_RULE WORD_REDUCE_CONV) THEN + PROVE_HW_ALL_COMPUTE THEN + SUBGOAL_THEN + `SUB_LIST(8 * i,8) inlist = + [word_subword (loaded_d:int64) (0,8):byte; word_subword loaded_d (8,8); + word_subword loaded_d (16,8); word_subword loaded_d (24,8); + word_subword loaded_d (32,8); word_subword loaded_d (40,8); + word_subword loaded_d (48,8); word_subword loaded_d (56,8)]` + ASSUME_TAC THENL + [MP_TAC(SPECL[`buf:int64`;`val(buflen:int64)`;`inlist:byte list`;`i:num`;`s17:armstate`] + SUB_LIST_8_BYTES_FROM_INT64) THEN + ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + FIRST_ASSUM(fun th -> STRIP_ASSUME_TAC(MATCH_MP SUB_LIST_4_FROM_8 th)) THEN + SUBGOAL_THEN `val(read X12 s17:int64) = PACK_MASK8(SUB_LIST(16 * i,8) mask)` ASSUME_TAC THENL + [W_ASM_COMPUTE (fun c -> is_eq c && lhs c = `read X12 s17:int64`) + (fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [th]) THEN + REWRITE_TAC[UADDLV_PACK_LEMMA; PACK_CONNECT] THEN AP_TERM_TAC THEN + SUBGOAL_THEN `SUB_LIST(16 * i,8) mask = REJ_MASK_ETA2(SUB_LIST(8 * i,4) inlist)` + SUBST1_TAC THENL + [REWRITE_TAC[REJ_MASK_ETA2_SUB_LIST] THEN + ASM_REWRITE_TAC[ARITH_RULE`2*(8*i)=16*i`; ARITH_RULE`2*4=8`]; ALL_TAC] THEN + MASKSLICE_COMPUTE THEN + ASM_REWRITE_TAC[VAL_WORD_ZX_BYTE16; BYTE_AND_15_MOD; BYTE_USHR4_DIV]; ALL_TAC] THEN + SUBGOAL_THEN `val(read X13 s17:int64) = PACK_MASK8(SUB_LIST(16 * i + 8,8) mask)` ASSUME_TAC THENL + [W_ASM_COMPUTE (fun c -> is_eq c && lhs c = `read X13 s17:int64`) + (fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [th]) THEN + REWRITE_TAC[UADDLV_PACK_LEMMA; PACK_CONNECT] THEN AP_TERM_TAC THEN + SUBGOAL_THEN `SUB_LIST(16 * i + 8,8) mask = REJ_MASK_ETA2(SUB_LIST(8 * i + 4,4) inlist)` + SUBST1_TAC THENL + [REWRITE_TAC[REJ_MASK_ETA2_SUB_LIST] THEN + ASM_REWRITE_TAC[ARITH_RULE`2*(8*i+4)=16*i+8`; ARITH_RULE`2*4=8`]; ALL_TAC] THEN + MASKSLICE_COMPUTE THEN + ASM_REWRITE_TAC[VAL_WORD_ZX_BYTE16; BYTE_AND_15_MOD; BYTE_USHR4_DIV]; ALL_TAC] THEN + MAP_EVERY REABBREV_TAC [`idx0:int64 = read X12 s17`; `idx1:int64 = read X13 s17`] THEN + MAP_EVERY ABBREV_TAC + [`tab0:int128 = read(memory :> bytes128(word_add table (word(16 * val(idx0:int64))))) s17`; + `tab1:int128 = read(memory :> bytes128(word_add table (word(16 * val(idx1:int64))))) s17`] THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC (18--25) THEN + RULE_ASSUM_TAC(REWRITE_RULE[WORD_SUBWORD_AND]) THEN + RULE_ASSUM_TAC(CONV_RULE(TOP_DEPTH_CONV WORD_SIMPLE_SUBWORD_CONV)) THEN + RULE_ASSUM_TAC(CONV_RULE WORD_REDUCE_CONV) THEN + RULE_ASSUM_TAC(REWRITE_RULE[word_ugt; relational2; GT; WORD_AND_MASK]) THEN + RULE_ASSUM_TAC(ONCE_REWRITE_RULE[COND_RAND]) THEN + RULE_ASSUM_TAC(CONV_RULE WORD_REDUCE_CONV) THEN + SUBGOAL_THEN `val(read X12 s25:int64) = + LENGTH(REJ_NIBBLES_ETA2 [word_subword (loaded_d:int64) (0,8):byte; + word_subword loaded_d (8,8); word_subword loaded_d (16,8); + word_subword loaded_d (24,8)])` ASSUME_TAC THENL + [W_ASM_COMPUTE (fun c -> is_eq c && lhs c = `read X12 s25:int64`) + (fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [th]) THEN + REWRITE_TAC[WORD_AND_0; WORD_POPCOUNT_0; ADD_CLAUSES] THEN + REWRITE_TAC[POPCOUNT_AND_POWERS] THEN REWRITE_TAC[UADDLV_COUNT_LEMMA] THEN + REWRITE_TAC bitblast8_compute THEN NIBGSYM_COMPUTE THEN + MP_TAC(SPECL[`nibbles0:int128`; `word_subword (loaded_d:int64) (0,8):byte`; + `word_subword (loaded_d:int64) (8,8):byte`; `word_subword (loaded_d:int64) (16,8):byte`; + `word_subword (loaded_d:int64) (24,8):byte`] COUNT_BRIDGE_ABSTRACT_4) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN DISCH_THEN SUBST1_TAC THEN REFL_TAC; + ALL_TAC] THEN + SUBGOAL_THEN `val(read X12 s25:int64) = NUM_ACCEPTED(SUB_LIST(16 * i,8) mask)` ASSUME_TAC THENL + [ASM_REWRITE_TAC[] THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA2_EQ_MASK; GSYM NUM_ACCEPTED] THEN AP_TERM_TAC THEN + SUB4GSYM_COMPUTE THEN REWRITE_TAC[REJ_MASK_ETA2_SUB_LIST] THEN + ASM_REWRITE_TAC[ARITH_RULE`2*(8*i)=16*i`; ARITH_RULE`2*4=8`]; ALL_TAC] THEN + SUBGOAL_THEN `val(read X13 s25:int64) = + LENGTH(REJ_NIBBLES_ETA2 [word_subword (loaded_d:int64) (32,8):byte; + word_subword loaded_d (40,8); word_subword loaded_d (48,8); + word_subword loaded_d (56,8)])` ASSUME_TAC THENL + [W_ASM_COMPUTE (fun c -> is_eq c && lhs c = `read X13 s25:int64`) + (fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [th]) THEN + REWRITE_TAC[WORD_AND_0; WORD_POPCOUNT_0; ADD_CLAUSES] THEN + REWRITE_TAC[POPCOUNT_AND_POWERS] THEN REWRITE_TAC[UADDLV_COUNT_LEMMA] THEN + REWRITE_TAC bitblast8_compute THEN NIBGSYM_COMPUTE THEN + MP_TAC(SPECL[`nibbles1b:int128`; `word_subword (loaded_d:int64) (32,8):byte`; + `word_subword (loaded_d:int64) (40,8):byte`; `word_subword (loaded_d:int64) (48,8):byte`; + `word_subword (loaded_d:int64) (56,8):byte`] COUNT_BRIDGE_ABSTRACT_4) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN DISCH_THEN SUBST1_TAC THEN REFL_TAC; + ALL_TAC] THEN + SUBGOAL_THEN `val(read X13 s25:int64) = NUM_ACCEPTED(SUB_LIST(16 * i + 8,8) mask)` ASSUME_TAC THENL + [ASM_REWRITE_TAC[] THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA2_EQ_MASK; GSYM NUM_ACCEPTED] THEN AP_TERM_TAC THEN + SUB4GSYM_COMPUTE THEN REWRITE_TAC[REJ_MASK_ETA2_SUB_LIST] THEN + ASM_REWRITE_TAC[ARITH_RULE`2*(8*i+4)=16*i+8`; ARITH_RULE`2*4=8`]; ALL_TAC] THEN + ABBREV_TAC `sp0:int64 = word_sub stackpointer (word 576)` THEN + MAP_EVERY REABBREV_TAC [`len0:int64 = read X12 s25`; `len1:int64 = read X13 s25`] THEN + FIRST_X_ASSUM(STRIP_ASSUME_TAC o REWRITE_RULE[ALL] o check + (fun th -> match concl th with Comb(Comb(Const("ALL",_),_),_) -> true | _ -> false)) THEN + SUBGOAL_THEN `val(len0:int64) <= 8` ASSUME_TAC THENL + [ASM_REWRITE_TAC[NUM_ACCEPTED_LE_8; REJ_NIBBLES_ETA2_LENGTH_4]; ALL_TAC] THEN + SUBGOAL_THEN `val(len1:int64) <= 8` ASSUME_TAC THENL + [ASM_REWRITE_TAC[NUM_ACCEPTED_LE_8; REJ_NIBBLES_ETA2_LENGTH_4]; ALL_TAC] THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC (26--28) THEN + ARM_VERBOSE_STEP_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC "s29" THEN + FIRST_X_ASSUM(fun th -> if is_eq(concl th) && lhs(concl th) = `read X7 s29:int64` + then ASSUME_TAC(GEN_REWRITE_RULE RAND_CONV [WORD_ADD_SHL1] th) else failwith "no") THEN + SUBGOAL_THEN + `nonoverlapping (word_add sp0 (word(2*(curlen + val(len0:int64)))):int64,16) (word pc:int64,372)` + ASSUME_TAC THENL [NONOVERLAPPING_TAC; ALL_TAC] THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC [30] THEN + ARM_VERBOSE_STEP_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC "s31" THEN + FIRST_X_ASSUM(fun th -> if is_eq(concl th) && lhs(concl th) = `read X7 s31:int64` + then ASSUME_TAC(GEN_REWRITE_RULE RAND_CONV [WORD_ADD_SHL1] th) else failwith "no") THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC (32--33) THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN POSTCOND_FOLD_COMPUTE);; + +let TAIL_CLOSE_AL = + let th = SPEC_ALL MLDSA_ETA2_LOOP8_TAIL_CLOSE in + let hyps = lhand (concl th) in + let ens = rand (concl th) in + let args = snd(strip_comb ens) in + let p = el 1 args and q = el 2 args and c = el 3 args in + let sv,qb = dest_abs q in + let aligned = subst [sv,`s:armstate`] + `aligned_bytes_loaded s (word pc) mldsa_rej_uniform_eta2_mc` in + let q' = mk_abs(sv, mk_conj(aligned, qb)) in + let goal = mk_imp(hyps, list_mk_icomb "ensures" [`arm`;p;q';c]) in + GEN_ALL (prove(goal, + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN `8 * (i + 1) <= val(buflen:int64)` ASSUME_TAC THENL + [MP_TAC(SPECL[`buflen:int64`;`mask:(bool)list`] MLDSA_ETA2_LOOP8_TRIP_MINIMAL) THEN + DISCH_THEN(MP_TAC o SPEC `i:num` o CONJUNCT2) THEN + ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o CONJUNCT1) THEN ARITH_TAC; + ALL_TAC] THEN + ENSURES_INIT_TAC "s0" THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC (1--2) THEN + ASM_CASES_TAC `8 <= val(word_sub buflen (word(8*(i+1))):int64)` THENL + [UNDISCH_TAC `8 <= val(word_sub buflen (word(8*(i+1))):int64)` THEN + DISCH_THEN(fun th -> RULE_ASSUM_TAC(REWRITE_RULE[th]) THEN ASSUME_TAC th) THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC (3--4) THEN + SUBGOAL_THEN + `256 <= val(word(NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask)):int64) <=> + ~(i + 1 < MLDSA_ETA2_LOOP8_TRIP buflen mask)` ASSUME_TAC THENL + [ASM_SIMP_TAC[LOOP8_TOP_VAL_BRIDGE] THEN + MATCH_MP_TAC LOOP8_OUTPUT_FULL_IFF THEN + ASM_MESON_TAC[LOOP8_BOT_VAL_BRIDGE]; + ALL_TAC] THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN + REWRITE_TAC[APPEND] THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[]; + SUBGOAL_THEN `val (buflen:int64) < 8 * (i + 2)` ASSUME_TAC THENL + [UNDISCH_TAC `~(8 <= val(word_sub buflen (word(8*(i+1))):int64))` THEN + ASM_SIMP_TAC[LOOP8_BOT_VAL_BRIDGE]; ALL_TAC] THEN + SUBGOAL_THEN `~(i + 1 < MLDSA_ETA2_LOOP8_TRIP buflen mask)` ASSUME_TAC THENL + [DISCH_TAC THEN + MP_TAC(SPECL[`buflen:int64`;`mask:(bool)list`] MLDSA_ETA2_LOOP8_TRIP_MINIMAL) THEN + DISCH_THEN(MP_TAC o SPEC `i + 1` o CONJUNCT2) THEN + ASM_REWRITE_TAC[ARITH_RULE `8 * ((i + 1) + 1) = 8 * (i + 2)`]; ALL_TAC] THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[APPEND]]));; + +let BODY_AL = + let strip_PQR th = + let b = concl (SPEC_ALL th) in + let body = if is_imp b then rand b else b in + let (_,args) = strip_comb body in (el 1 args, el 2 args, el 3 args) in + let (cP,cQ,cR) = strip_PQR MLDSA_ETA2_LOOP8_COMPUTE in + let (tP,tQ,tR) = strip_PQR TAIL_CLOSE_AL in + let _,cQbody = dest_abs cQ in + let ev_compute = + rhs (find (fun c -> is_eq c && lhs c = `read events (s:armstate)`) + (conjuncts cQbody)) in + let subl = [`num_of_wordlist(inlist:byte list)`,`bufval:num`; + ev_compute,`e:(uarch_event)list`] in + let tQ_inst = subst subl tQ in + let c_hyps = conjuncts (lhand (concl (SPEC_ALL MLDSA_ETA2_LOOP8_COMPUTE))) in + let bl_hyps = list_mk_conj + [el 0 c_hyps; el 1 c_hyps; `i < MLDSA_ETA2_LOOP8_TRIP buflen mask`; last c_hyps] in + let ef,eargs = strip_comb (rand (concl (SPEC_ALL MLDSA_ETA2_LOOP8_COMPUTE))) in + let bl_ensures = list_mk_comb(ef, [el 0 eargs; el 1 eargs; tQ_inst; el 3 eargs]) in + let midstate = let sv,body = dest_abs cQ in + mk_abs(sv, list_mk_conj (tl (tl (conjuncts body)))) in + GEN_ALL(prove(mk_imp(bl_hyps, bl_ensures), + STRIP_TAC THEN + SUBGOAL_THEN + `~(val (buflen:int64) < 8 * (i + 1)) /\ + ~(256 <= NUM_ACCEPTED(SUB_LIST(0,16 * i) mask))` + STRIP_ASSUME_TAC THENL + [MATCH_MP_TAC(CONJUNCT2(SPECL[`buflen:int64`;`mask:(bool)list`] + MLDSA_ETA2_LOOP8_TRIP_MINIMAL)) THEN FIRST_ASSUM ACCEPT_TAC; + ALL_TAC] THEN + ENSURES_SEQUENCE_TAC `pc + 0xf4` midstate THEN + CONJ_TAC THENL + [ MATCH_MP_TAC MLDSA_ETA2_LOOP8_COMPUTE THEN + REPEAT CONJ_TAC THENL + [ FIRST_ASSUM ACCEPT_TAC; FIRST_ASSUM ACCEPT_TAC; + ASM_ARITH_TAC; ASM_ARITH_TAC; FIRST_ASSUM ACCEPT_TAC ]; + MATCH_MP_TAC TAIL_CLOSE_AL THEN + CONJ_TAC THENL + [ FIRST_ASSUM ACCEPT_TAC; + REWRITE_TAC[NUM_ACCEPTED_SUB_LIST_STEP] THEN + MP_TAC(SPECL[`mask:(bool)list`;`16 * i`] NUM_ACCEPTED_LE_8) THEN + MP_TAC(SPECL[`mask:(bool)list`;`16 * i + 8`] NUM_ACCEPTED_LE_8) THEN + CONV_TAC(ONCE_DEPTH_CONV NUM_REDUCE_CONV) THEN ASM_ARITH_TAC ] ]));; + +let MLDSA_ETA2_LOOP8_BODY_ADAPTED = + let appty = `APPEND:(uarch_event)list->(uarch_event)list->(uarch_event)list` in + let body = SPEC_ALL BODY_AL in + let bargs = snd(strip_comb (rand (concl body))) in + let bP = el 1 bargs and bQ = el 2 bargs in +(* loop8_inv = BODY_AL-pre minus aligned/PC (front 2) and events (last) *) + let sv, bpbody = dest_abs bP in + let loop8_inv = mk_abs(`i:num`, mk_abs(sv, list_mk_conj (butlast (tl (tl (conjuncts bpbody)))))) in +(* e_loop = \i. APPEND jumps five (per-iter delta from BODY_AL-post events) *) + let _, bqbody = dest_abs bQ in + let ev_rhs = rhs (last (conjuncts bqbody)) in + let jumps, rest = dest_binary "APPEND" ev_rhs in + let five, _ = dest_binary "APPEND" rest in + let e_loop = mk_abs(`i:num`, mk_binop appty jumps five) in + let rr = `[(buf:int64),val(buflen:int64); (table:int64),4096; + word_sub (stackpointer:int64) (word 576),576]` in + let wr = `[word_sub (stackpointer:int64) (word 576),576; (res:int64),1024]` in + let mkinb e2v = list_mk_icomb "memaccess_inbounds" [e2v; rr; wr] in + let e_front = `f_ev_loop8_prol:(uarch_event)list` in + let acc = `f_ev_acc:(uarch_event)list` in + let enum_i = list_mk_comb(`ENUMERATEL:num->(num->(uarch_event)list)->(uarch_event)list`,[`i:num`; e_loop]) in + let e2_pre = mk_binop appty enum_i (mk_binop appty e_front acc) in + let eB = mk_binop appty e2_pre `e:(uarch_event)list` in + let bP_inst = subst [eB,`e:(uarch_event)list`] bP in + let bQ_inst = subst [eB,`e:(uarch_event)list`] bQ in + let mi = mkinb e2_pre in + let trip = `MLDSA_ETA2_LOOP8_TRIP buflen mask` in + let pc1 = `pc + 112` and pc2 = `pc + 252` in + let pre = + let e2 = `e2:(uarch_event)list` in + mk_abs(`s:armstate`, + list_mk_conj + [`aligned_bytes_loaded s (word pc) mldsa_rej_uniform_eta2_mc`; + `read PC s = word (pc+112)`; + list_mk_comb(loop8_inv,[`0`;`s:armstate`]); + mk_exists(e2, list_mk_conj [`read events s = APPEND e2 e`; mk_eq(e2,e_front); mkinb e2])]) in + let enum_trip = list_mk_comb(`ENUMERATEL:num->(num->(uarch_event)list)->(uarch_event)list`,[trip; e_loop]) in + let post_e2val = + mk_binop appty (mk_binop appty `f_ev_epil:(uarch_event)list` + (mk_binop appty enum_trip e_front)) acc in + let post = + let e2 = `e2:(uarch_event)list` in + mk_abs(`s:armstate`, + list_mk_conj + [`read PC s = returnaddress`; + mk_exists(e2, list_mk_conj [`read events s = APPEND e2 e`; mk_eq(e2,post_e2val); mkinb e2])]) in + let syn_goal = list_mk_icomb "ensures" [`arm`; pre; post; `\(s:armstate) (s':armstate). T`] in + let conj2 = + let (_,gls,_) = ENSURES_EVENTS_WHILE_UP2_TAC trip pc1 pc2 loop8_inv ([],syn_goal) in + el 2 (conjuncts (snd (hd gls))) in + let enum_i1 = list_mk_comb(`ENUMERATEL:num->(num->(uarch_event)list)->(uarch_event)list`,[`i+1`; e_loop]) in + let e2_post = mk_binop appty enum_i1 (mk_binop appty e_front acc) in + let ambient = list_mk_conj + [`mask = REJ_MASK_ETA2 inlist`; + `LENGTH (inlist:byte list) = val (buflen:int64)`; + `ALL (nonoverlapping (word_sub stackpointer (word 576),576)) + [(word pc,372); (buf:int64,val (buflen:int64)); (table:int64,4096)]`] in + prove(mk_imp(ambient, conj2), + REPEAT STRIP_TAC THEN + ASM_CASES_TAC mi THENL + [ MATCH_MP_TAC ENSURES_PREPOSTCONDITION_THM THEN + MAP_EVERY EXISTS_TAC [bP_inst; bQ_inst] THEN + REPEAT CONJ_TAC THENL + [ GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN + UNDISCH_THEN `mask = REJ_MASK_ETA2 inlist` (K ALL_TAC) THEN + ASM_REWRITE_TAC[] THEN + CONJ_TAC THENL + [ AP_TERM_TAC THEN COND_CASES_TAC THEN ARITH_TAC; + EXISTS_TAC e2_post THEN REPEAT CONJ_TAC THENL + [ ASM_REWRITE_TAC[ENUMERATEL_ADD1] THEN REWRITE_TAC[APPEND; APPEND_ASSOC]; + REFL_TAC; + REWRITE_TAC[ENUMERATEL_ADD1] THEN REWRITE_TAC[APPEND; APPEND_ASSOC] THEN + REWRITE_TAC[MEMACCESS_INBOUNDS_APPEND] THEN + RULE_ASSUM_TAC(REWRITE_RULE[APPEND; APPEND_ASSOC; MEMACCESS_INBOUNDS_APPEND]) THEN + ASM_REWRITE_TAC[] THEN + SUBGOAL_THEN `8 * (i + 1) <= val(buflen:int64) /\ + NUM_ACCEPTED(SUB_LIST(0,16*i) mask) < 256` + STRIP_ASSUME_TAC THENL + [MP_TAC(SPEC `i:num` (CONJUNCT2(SPECL[`buflen:int64`;`mask:(bool)list`] + MLDSA_ETA2_LOOP8_TRIP_MINIMAL))) THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; + ALL_TAC] THEN + ASSUME_TAC(SPECL[`mask:(bool)list`;`16*i`] NUM_ACCEPTED_LE_8) THEN + ASSUME_TAC(SPEC `SUB_LIST(16*i,8) (mask:(bool)list)` PACK_MASK8_BOUND) THEN + ASSUME_TAC(SPEC `SUB_LIST(16*i+8,8) (mask:(bool)list)` PACK_MASK8_BOUND) THEN + CONJ_TAC THENL + [ COND_CASES_TAC THEN DISCHARGE_MEMACCESS_INBOUNDS_TAC; + DISCHARGE_CONCRETE_MEMACCESS_INBOUNDS_TAC THEN + DISJ1_TAC THEN + GEN_REWRITE_TAC I [GSYM CONTAINED_MODULO_MOD2] THEN + GEN_REWRITE_TAC (BINOP_CONV o LAND_CONV o LAND_CONV o TOP_DEPTH_CONV) + [VAL_WORD_ADD; VAL_WORD; DIMINDEX_64] THEN + CONV_TAC(BINOP_CONV(LAND_CONV MOD_DOWN_CONV)) THEN + GEN_REWRITE_TAC I [CONTAINED_MODULO_MOD2] THEN + (MATCH_MP_TAC CONTAINED_MODULO_OFFSET_SIMPLE ORELSE + MATCH_MP_TAC CONTAINED_MODULO_SIMPLE) THEN + UNDISCH_TAC `8 * (i + 1) <= val(buflen:int64)` THEN ARITH_TAC ] ] ]; + MATCH_MP_TAC BODY_AL THEN ASM_REWRITE_TAC[] ]; + MATCH_MP_TAC ENSURES_PRECONDITION_THM THEN EXISTS_TAC `\s:armstate. F` THEN + CONJ_TAC THENL + [ GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN ASM_MESON_TAC[]; + REWRITE_TAC[ensures] THEN MESON_TAC[] ] ]);; + +(* Restore the recursive `STRIP_EXISTS_ASSUM_TAC` from s2n-bignum *) +(* common/misc.ml, which the constant-time proof below was developed against. *) +(* The MEMSAFE section (near line 2363) locally redefines *) +(* STRIP_EXISTS_ASSUM_TAC to a *shallow* variant that only splits the *) +(* outermost conjunction of the chosen existential. The event-loop leaves *) +(* below feed `~preprocess_tac:(TRY STRIP_EXISTS_ASSUM_TAC)` an invariant of *) +(* the form `?e2. read events s = ... /\ e2 = ... /\ memaccess_inbounds e2 *) +(* ...`; the shallow variant leaves `e2 = ... /\ memaccess_inbounds e2 ...` *) +(* conjoined, so DISCHARGE_MEMACCESS_INBOUNDS_USING_ASM_TAC (which filters *) +(* assumptions by head symbol) cannot see the `memaccess_inbounds e2` fact *) +(* and the discharge fails. The recursive STRIP_ASSUME_TAC form splits it *) +(* into a standalone assumption. *) +let STRIP_EXISTS_ASSUM_TAC = + FIRST_X_ASSUM (STRIP_ASSUME_TAC o (check (is_exists o concl)));; + +(* Proof machinery for MLDSA_REJ_UNIFORM_ETA2_SUBROUTINE_SAFE: derive the concretized f_events lambda and + the loop8/fcopy invariants from BODY_AL (see the theorem below). *) +let ETA2_SAFE_MACHINERY = + let appty = `APPEND:(uarch_event)list->(uarch_event)list->(uarch_event)list` in + let bodyth = SPEC_ALL BODY_AL in + let bargs = snd(strip_comb (rand (concl bodyth))) in + let bP = el 1 bargs and bQ = el 2 bargs in + let sv,bpbody = dest_abs bP in + let loop8_inv = + mk_abs(`i:num`, mk_abs(sv, list_mk_conj (butlast (tl (tl (conjuncts bpbody)))))) in + let _,bqbody = dest_abs bQ in + let ev_rhs = rhs (last (conjuncts bqbody)) in + let jumps,rest = dest_binary "APPEND" ev_rhs in + let five,_ = dest_binary "APPEND" rest in + let loop8_inv_real = + subst [`num_of_wordlist mldsa_rej_uniform_eta_table`,`tabval:num`] loop8_inv in + let orig_lam = + `\(res:int64)(buf:int64)(buflen:int64)(table:int64)(pc:num)(sp:int64) + (ra:int64)(mask:(bool)list). + APPEND + (APPEND + (APPEND + (APPEND + (f_ev_epi res buf buflen table pc sp ra mask) + (APPEND (ENUMERATEL 16 (\j. f_ev_fcopy res buf buflen table pc sp ra mask j)) + (f_ev_fcopy_prol res buf buflen table pc sp ra mask))) + (APPEND (ENUMERATEL (MLDSA_ETA2_LOOP8_TRIP buflen mask) + (\i. f_ev_loop8 res buf buflen table pc sp ra mask i)) + (f_ev_loop8_prol res buf buflen table pc sp ra mask))) + (APPEND (ENUMERATEL 8 (\k. f_ev_zinit res buf buflen table pc sp ra mask k)) + (f_ev_zinit_prol res buf buflen table pc sp ra mask))) + (f_ev_begin res buf buflen table pc sp ra mask) :(uarch_event)list` in + let lamvars,obody = strip_abs orig_lam in + let is_l8 t = is_abs t && + (let _,b = dest_abs t in is_comb b && + (let h = fst(strip_comb b) in is_var h && fst(dest_var h) = "f_ev_loop8")) in + let l8_old = find_term is_l8 obody in + let e_loop_lam = mk_abs(`i:num`, + subst [`sp:int64`,`stackpointer:int64`; `ra:int64`,`returnaddress:int64`] + (mk_binop appty jumps five)) in + let modified_lam = list_mk_abs(lamvars, subst [e_loop_lam,l8_old] obody) in + let REASSOC_LOOP8 = METIS[APPEND_ASSOC] + `(exists e2. P e2 /\ + e2 = APPEND (APPEND (APPEND epil (APPEND loop prol)) tail) tail2 /\ Q e2) + <=> + (exists e2. P e2 /\ + e2 = APPEND (APPEND epil (APPEND loop prol)) (APPEND tail tail2) /\ Q e2)` in + let REASSOC_FCOPY = METIS[APPEND_ASSOC] + `(exists e2. P e2 /\ + e2 = APPEND (APPEND fe (APPEND l8e l8p)) zb /\ Q e2) + <=> + (exists e2. P e2 /\ + e2 = APPEND fe (APPEND l8e (APPEND l8p zb)) /\ Q e2)` in +(* MINIMAL fcopy invariant (postcond doesn't constrain regs; omit *) +(* X9/v-consts). *) + let fcopy_inv = + `\(i:num) s. read SP s = word_sub stackpointer (word 576) /\ + read X30 s = returnaddress /\ + read X0 s = word_add res (word(64 * i)) /\ + read X7 s = word_add (word_sub stackpointer (word 576)) (word(32 * i)) /\ + read X8 s = word_sub stackpointer (word 576) /\ + read X11 s = word(16 * i)` in + (modified_lam, loop8_inv_real, REASSOC_LOOP8, fcopy_inv, REASSOC_FCOPY);; + +let MLDSA_REJ_UNIFORM_ETA2_SUBROUTINE_SAFE = time prove + (`?f_events:int64->int64->int64->int64->num->int64->int64-> + (bool list)->(uarch_event)list. + !res buf buflen table (inlist:byte list) pc e stackpointer returnaddress. + 8 divides val buflen /\ + 8 <= val buflen /\ + LENGTH inlist = val buflen /\ + ALL (nonoverlapping (word_sub stackpointer (word 576),576)) + [(word pc,LENGTH mldsa_rej_uniform_eta2_mc); + (buf,val buflen); (table,4096)] /\ + ALL (nonoverlapping (res,1024)) + [(word pc,LENGTH mldsa_rej_uniform_eta2_mc); + (word_sub stackpointer (word 576),576)] + ==> ensures arm + (\s. aligned_bytes_loaded s (word pc) mldsa_rej_uniform_eta2_mc /\ + read PC s = word pc /\ + read SP s = stackpointer /\ + read X30 s = returnaddress /\ + C_ARGUMENTS [res;buf;buflen;table] s /\ + read(memory :> bytes(table,4096)) s = + num_of_wordlist mldsa_rej_uniform_eta_table /\ + read(memory :> bytes(buf,val buflen)) s = + num_of_wordlist (inlist:byte list) /\ + read events s = e) + (\s. read PC s = returnaddress /\ + (?e2. + read events s = APPEND e2 e /\ + e2 = f_events res buf buflen table pc stackpointer + returnaddress (REJ_MASK_ETA2 inlist) /\ + memaccess_inbounds e2 + [buf,val buflen; table,4096; + word_sub stackpointer (word 576),576] + [word_sub stackpointer (word 576),576; res,1024])) + (\s s'. T)`, + let modified_lam, loop8_inv_real, REASSOC_LOOP8, fcopy_inv, REASSOC_FCOPY = + ETA2_SAFE_MACHINERY in + CONCRETIZE_F_EVENTS_TAC modified_lam THEN + REPEAT META_EXISTS_TAC THEN REPEAT GEN_TAC THEN + REWRITE_TAC[C_ARGUMENTS; NONOVERLAPPING_CLAUSES; ALL; + fst MLDSA_REJ_UNIFORM_ETA2_EXEC] THEN + REPEAT STRIP_TAC THEN + ABBREV_TAC `mask:(bool)list = REJ_MASK_ETA2 inlist` THEN + ENSURES_EVENTS_SEQUENCE_TAC `pc + 0x40` + `\s. read X30 s = returnaddress /\ read X0 s = res /\ read X1 s = buf /\ + read X2 s = buflen /\ read X3 s = table /\ + read SP s = word_sub stackpointer (word 576) /\ + read X7 s = word_sub stackpointer (word 576) /\ + read X8 s = word_sub stackpointer (word 576) /\ + read X11 s = word 0 /\ + read Q30 s = word 77885641318594292392624080437575695 /\ + read Q31 s = word 664619068533544770747334646890102785 /\ + read Q16 s = word 0 /\ + read (memory :> bytes (table,4096)) s = + num_of_wordlist mldsa_rej_uniform_eta_table /\ + read (memory :> bytes (buf,val buflen)) s = num_of_wordlist (inlist:byte list)` THEN + CONJ_TAC THENL [ + GHOST_INTRO_TAC `q31_init:int128` `read Q31` THEN + ENSURES_INIT_TAC "s0" THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC (1--16) THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN + REWRITE_TAC[WORD_INSERT_Q31] THEN + DISCHARGE_SAFETY_PROPERTY_TAC; + ALL_TAC] THEN + ENSURES_EVENTS_WHILE_UP2_TAC `8` `pc + 0x40` `pc + 0x5c` + `\(i:num) s. read SP s = word_sub stackpointer (word 576) /\ + read X30 s = returnaddress /\ read X0 s = res /\ read X1 s = buf /\ + read X2 s = buflen /\ read X3 s = table /\ + read X8 s = word_sub stackpointer (word 576) /\ + read X7 s = word_add (word_sub stackpointer (word 576)) (word (64 * i)) /\ + read X11 s = word (32 * i) /\ + read Q30 s = word 77885641318594292392624080437575695 /\ + read Q31 s = word 664619068533544770747334646890102785 /\ + read Q16 s = word 0 /\ + read (memory :> bytes (table,4096)) s = + num_of_wordlist mldsa_rej_uniform_eta_table /\ + read (memory :> bytes (buf,val buflen)) s = num_of_wordlist (inlist:byte list)` THEN + REPEAT CONJ_TAC THENL [ + ARITH_TAC; + ARM_SIM_TAC ~preprocess_tac:(TRY STRIP_EXISTS_ASSUM_TAC) + ~canonicalize_pc_diff:false MLDSA_REJ_UNIFORM_ETA2_EXEC (1--0) THEN + REWRITE_TAC[MULT_CLAUSES; WORD_ADD_0] THEN DISCHARGE_SAFETY_PROPERTY_TAC; + REPEAT STRIP_TAC THEN + ARM_SIM_TAC ~preprocess_tac:(TRY STRIP_EXISTS_ASSUM_TAC) + ~canonicalize_pc_diff:false MLDSA_REJ_UNIFORM_ETA2_EXEC (1--7) THEN + CONJ_TAC THENL + [ASM_SIMP_TAC[ZINIT_BRANCH] THEN REWRITE_TAC[COND_RAND] THEN + COND_CASES_TAC THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + CONJ_TAC THENL + [REWRITE_TAC[ARITH_RULE `64*(i+1)=64*i+64`] THEN CONV_TAC WORD_RULE; ALL_TAC] THEN + CONJ_TAC THENL + [REWRITE_TAC[ARITH_RULE `32*(i+1)=32*i+32`] THEN CONV_TAC WORD_RULE; ALL_TAC] THEN + DISCHARGE_SAFETY_PROPERTY_TAC; + ONCE_REWRITE_TAC[REASSOC_LOOP8] THEN + ENSURES_EVENTS_WHILE_UP2_TAC `MLDSA_ETA2_LOOP8_TRIP buflen mask` + `pc + 0x70` `pc + 0xfc` loop8_inv_real THEN + REPEAT CONJ_TAC THENL [ + SUBGOAL_THEN `NUM_ACCEPTED(SUB_LIST(0,16 * 0) (mask:(bool)list)) = 0` ASSUME_TAC THENL + [REWRITE_TAC[ARITH_RULE `16 * 0 = 0`; SUB_LIST_CLAUSES; NUM_ACCEPTED; FILTER; LENGTH]; + ALL_TAC] THEN + DISCH_TAC THEN + MP_TAC(CONJUNCT1(SPECL[`buflen:int64`;`mask:(bool)list`] + MLDSA_ETA2_LOOP8_TRIP_MINIMAL)) THEN + ASM_REWRITE_TAC[ARITH_RULE `8 * (0 + 1) = 8`] THEN ASM_ARITH_TAC; + ARM_SIM_TAC ~preprocess_tac:(TRY STRIP_EXISTS_ASSUM_TAC) + ~canonicalize_pc_diff:false MLDSA_REJ_UNIFORM_ETA2_EXEC (1--5) THEN + REWRITE_TAC[MULT_CLAUSES; SUB_LIST_CLAUSES; NUM_ACCEPTED; FILTER; LENGTH] THEN + REPEAT CONJ_TAC THEN TRY(CONV_TAC WORD_RULE) THEN DISCHARGE_SAFETY_PROPERTY_TAC; + MATCH_MP_TAC MLDSA_ETA2_LOOP8_BODY_ADAPTED THEN ASM_REWRITE_TAC[] THEN + REWRITE_TAC[ALL] THEN REPEAT CONJ_TAC THEN NONOVERLAPPING_TAC; + ONCE_REWRITE_TAC[REASSOC_FCOPY] THEN + ENSURES_EVENTS_WHILE_UP2_TAC `16` `pc + 0x11c` `pc + 0x168` fcopy_inv THEN + REPEAT CONJ_TAC THENL [ + ARITH_TAC; + ARM_SIM_TAC ~preprocess_tac:(TRY STRIP_EXISTS_ASSUM_TAC) + ~canonicalize_pc_diff:false MLDSA_REJ_UNIFORM_ETA2_EXEC (1--8) THEN + REWRITE_TAC[MULT_CLAUSES; WORD_ADD_0] THEN + REPEAT CONJ_TAC THEN TRY(CONV_TAC WORD_RULE) THEN DISCHARGE_SAFETY_PROPERTY_TAC; + REPEAT STRIP_TAC THEN + ARM_SIM_TAC ~preprocess_tac:(TRY STRIP_EXISTS_ASSUM_TAC) + ~canonicalize_pc_diff:false MLDSA_REJ_UNIFORM_ETA2_EXEC (1--19) THEN + CONJ_TAC THENL + [ASM_SIMP_TAC[FCOPY_BRANCH] THEN REWRITE_TAC[COND_RAND] THEN + COND_CASES_TAC THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + CONJ_TAC THENL + [REWRITE_TAC[ARITH_RULE `64*(i+1)=64*i+64`; ARITH_RULE `32*(i+1)=32*i+32`; + ARITH_RULE `16*(i+1)=16*i+16`] THEN CONV_TAC WORD_RULE; ALL_TAC] THEN + CONJ_TAC THENL + [REWRITE_TAC[ARITH_RULE `64*(i+1)=64*i+64`; ARITH_RULE `32*(i+1)=32*i+32`; + ARITH_RULE `16*(i+1)=16*i+16`] THEN CONV_TAC WORD_RULE; ALL_TAC] THEN + CONJ_TAC THENL + [REWRITE_TAC[ARITH_RULE `64*(i+1)=64*i+64`; ARITH_RULE `32*(i+1)=32*i+32`; + ARITH_RULE `16*(i+1)=16*i+16`] THEN CONV_TAC WORD_RULE; ALL_TAC] THEN + DISCHARGE_SAFETY_PROPERTY_TAC; + ARM_SIM_TAC ~preprocess_tac:(TRY STRIP_EXISTS_ASSUM_TAC) + ~canonicalize_pc_diff:false MLDSA_REJ_UNIFORM_ETA2_EXEC (1--3) THEN + DISCHARGE_SAFETY_PROPERTY_TAC]]]);; diff --git a/proofs/hol_light/aarch64/proofs/mldsa_rej_uniform_eta4_aarch64_asm.ml b/proofs/hol_light/aarch64/proofs/mldsa_rej_uniform_eta4_aarch64_asm.ml index b60fe7a913..e3790c8728 100644 --- a/proofs/hol_light/aarch64/proofs/mldsa_rej_uniform_eta4_aarch64_asm.ml +++ b/proofs/hol_light/aarch64/proofs/mldsa_rej_uniform_eta4_aarch64_asm.ml @@ -1880,24 +1880,17 @@ let MLDSA_REJ_UNIFORM_ETA4_SUBROUTINE_CORRECT = prove (* ========================================================================= *) (* Memory Safety Proof *) (* *) -(* We prove memory-safety, but not secret-independent timing. *) -(* *) (* The safety specification below differs in shape from the ones used in *) -(* most other HOL-Light proofs, which consolidate safety and *) -(* secret-independent timing into a single theorem. *) -(* *) -(* Here, we show that the assembly kernel emits _some_ list of *) -(* microarchitectural events the memory-accesses in which fall *) -(* within the expected bounds. *) -(* *) -(* In a joint safety + secret-independent timing specification, in turn, *) -(* we would _additionally_ seek to express the list of microarchitectural *) -(* events as a _function_ of public data. *) +(* most other HOL-Light proofs, which consolidate memory safety and *) +(* secret-independent timing into a single theorem. Here we prove memory *) +(* safety on its own: the kernel emits _some_ list of microarchitectural *) +(* events whose memory accesses fall within the expected bounds. *) (* *) -(* TODO (#1160): In the context of rejection sampling, the event-generating *) -(* function should take the set of in-bound indices as an argument, but *) -(* not the entire input data. This corresponds to declassifying _which_ *) -(* coefficients are in bounds vs. out of bounds, but not their values. *) +(* Secret-independent timing is proven separately below (see "Constant-time *) +(* rejection sampling"): rather than assert full data-obliviousness, the *) +(* event-generating function there takes the reject bitmap -- one accept/ *) +(* reject bit per candidate nibble -- as its data argument, declassifying *) +(* which coefficients are in bounds vs. out of bounds, but not their values. *) (* ========================================================================= *) needs "s2n_bignum/arm/proofs/consttime.ml";; @@ -2809,3 +2802,1326 @@ let MLDSA_REJ_UNIFORM_ETA4_SUBROUTINE_MEMSAFE = time prove (CONV_RULE LENGTH_SIMPLIFY_CONV MLDSA_REJ_UNIFORM_ETA4_MEMSAFE)) `[]:int64 list` 576 THEN DISCHARGE_MEMSAFE_TAC);; + +(* Constant-time (secret-independent timing) proof for rej_uniform_eta4. + See proofs/hol_light/README.md for the security property and the statement of + MLDSA_REJ_UNIFORM_ETA4_SUBROUTINE_SAFE. + + This is a rejection sampler, so it is NOT data-oblivious and the standard + PROVE_SAFETY_SPEC_TAC does not apply. We prove constant-time up to the reject + pattern: the event trace is a function of the public pointers and the reject + bitmap REJ_MASK_ETA4 (one accept/reject bit per nibble, "accept" = val < 9), + never the accepted values. gen_mk_safety_spec cannot express this (its + f_events takes only pointers/pc/sp/ra), so the spec is hand-written with the + reject mask as an extra public argument. + + Secret-dependent behaviour lives only in the loop8 sampler: + - table reads ldr q,[x3, mask*16] address = 8-bit accept mask + - scratch stores st1 [x7]; x7 += 2*popcount offset = accepted count + - loop trip count = f(accept masks, buflen) + All three are functions of the accept masks and the public buflen; the + prologue zero-init and the final Barrett-reduce copy have fixed trip counts. *) + +(* The public reject-mask projection: one accept/reject bit per nibble, with *) +(* the accepted values DISCARDED. Mirrors REJ_NIBBLES_ETA4 (which FILTERs the *) +(* same predicate to keep the accepted values = the SECRET); here we MAP the *) +(* predicate to keep only the decisions. From this bool list one recovers the *) +(* per-group 8-bit masks (pack 8 bits), the accepted counts (popcounts), and *) +(* hence every secret-dependent address/branch above — but not the values. *) +(* *) +(* NOTE: REJ_NIBBLES_ETA4 l = FILTER (\x. val x < 9) (NIBBLES_OF_BYTES l) *) +(* so LENGTH(REJ_NIBBLES_ETA4 l) = number of `true` in REJ_MASK_ETA4 l. *) +(* REJ_NIBBLES_ETA4 is NOT recoverable from REJ_MASK_ETA4 alone (the *) +(* accepted values are gone) — that is the whole point. *) + +let REJ_MASK_ETA4 = define + `REJ_MASK_ETA4 (l:byte list) : bool list = + MAP (\x:int16. val x < 9) (NIBBLES_OF_BYTES l)`;; + +(* -------------------------------------------------------------------------- *) +(* *) +(* These are the "store-advance / trip-count" half of the mask bridge (the *) +(* and independently of the assembly (pure list facts). They express the *) +(* SECRET accepted-count (which drives niblen, every stack-store offset *) +(* sp+2*niblen, and the loop trip count) as a function of the PUBLIC reject *) +(* mask only — the accepted VALUES never appear. Migrate together with the *) +(* SUBROUTINE_SAFE theorem when the proof is closed. *) +(* -------------------------------------------------------------------------- *) + +(* Abstract core: #elements passing P = #`true`s in the boolean image. *) +let LENGTH_FILTER_EQ_LENGTH_FILTER_MAP = prove + (`!(P:A->bool) xs. + LENGTH(FILTER (\b:bool. b) (MAP P xs)) = LENGTH(FILTER P xs)`, + GEN_TAC THEN LIST_INDUCT_TAC THEN + REWRITE_TAC[MAP; FILTER; LENGTH] THEN + COND_CASES_TAC THEN ASM_REWRITE_TAC[LENGTH]);; + +(* THE store-advance / trip-count bridge: the number of ACCEPTED nibbles + (= niblen, driving all sp+2*niblen store offsets and the WOP trip count N) + equals the number of `true`s in the PUBLIC reject mask. Value-free: the RHS + mentions only REJ_MASK_ETA4 (public), never the accepted values. *) +let LENGTH_REJ_NIBBLES_ETA4_EQ_MASK = prove + (`!l:byte list. + LENGTH(REJ_NIBBLES_ETA4 l) = LENGTH(FILTER (\b:bool. b) (REJ_MASK_ETA4 l))`, + REWRITE_TAC[REJ_NIBBLES_ETA4; REJ_MASK_ETA4; + LENGTH_FILTER_EQ_LENGTH_FILTER_MAP]);; + +(* A clean public "accepted count" over a mask, additive over APPEND — the + form the f_events per-iteration store-offset witness will use. *) +let NUM_ACCEPTED = define + `NUM_ACCEPTED (m:bool list) = LENGTH(FILTER (\b:bool. b) m)`;; + +let NUM_ACCEPTED_APPEND = prove + (`!m1 m2. NUM_ACCEPTED(APPEND m1 m2) = NUM_ACCEPTED m1 + NUM_ACCEPTED m2`, + REWRITE_TAC[NUM_ACCEPTED; FILTER_APPEND; LENGTH_APPEND]);; + +(* Public table-index witness: the 8-bit LSB-first packing of an accept-mask + group. The compaction table (mldsa_rej_uniform_eta_table) is indexed by this + 0..255 value, so the loop's data-dependent table read decodes to + EventLoad (table + 16 * PACK_MASK8 ) — a function of the PUBLIC + mask only. Explicit 8-EL form (not nsum) to match the eventual hardware + value-bridge, whose shape mirrors UADDLV_COUNT_LEMMA (8 explicit bits). *) +let PACK_MASK8 = define + `PACK_MASK8 (bs:bool list) = + bitval(EL 0 bs) + 2 * bitval(EL 1 bs) + + 4 * bitval(EL 2 bs) + 8 * bitval(EL 3 bs) + + 16 * bitval(EL 4 bs) + 32 * bitval(EL 5 bs) + + 64 * bitval(EL 6 bs) + 128 * bitval(EL 7 bs)`;; + +let PACK_MASK8_BOUND = prove + (`!bs:bool list. PACK_MASK8 bs < 256`, + GEN_TAC THEN REWRITE_TAC[PACK_MASK8] THEN + MAP_EVERY (fun t -> MP_TAC(SPEC t BITVAL_BOUND)) + [`EL 0 (bs:bool list)`; `EL 1 (bs:bool list)`; `EL 2 (bs:bool list)`; + `EL 3 (bs:bool list)`; `EL 4 (bs:bool list)`; `EL 5 (bs:bool list)`; + `EL 6 (bs:bool list)`; `EL 7 (bs:bool list)`] THEN + ARITH_TAC);; + +(* -------------------------------------------------------------------------- *) +(* *) +(* table index; it drives the data-dependent table read *) +(* LDR Q24,[X3,X12,LSL#4] = EventLoad(table + 16 * val(idx0)). *) +(* idx0 = FMOV(UADDLV(AND(CMHI(Q30=15-per-lane, *) +(* nibbles),Q31=[1;2;4;..;128]))) i.e. the WEIGHTED 8-bit pack of the *) +(* per-nibble accept mask (NOT popcount; the eta4.ml:2744 *) +(* "popcount-accumulator" comment is stale — the real bound proof at *) +(* 2754-2774 uses SUM_8_BIT_BOUND_POLY with weights <=128, val<256). with the *) +(* 8 per-nibble accept predicates (val nibble_k < 9) ABSTRACTED to booleans *) +(* b0..b7. Lane layout (from the word_join tree): b0 = highest lane = weight *) +(* 128, ..., b7 = lowest lane = weight 1. *) +(* *) +(* PACK companion to UADDLV_COUNT_LEMMA (aarch64_utils.ml:534, the POPCOUNT *) +(* used for the X9/X7 store advance). Proven UADDLV_COUNT_LEMMA-style: REPEAT *) +(* NUM_REDUCE_CONV (256 concrete cases, ~84s). *) +(* *) +(* SECRET-INDEPENDENCE LINK: in nibble order the accept bits b0..b7 of a *) +(* 4-byte group = REJ_MASK_ETA4 of that group, and 128*b0+64*b1+..+bitval b7 *) +(* = PACK_MASK8 (that group's mask) [PACK_MASK8 above]. So val(idx0) — hence *) +(* the table-read address table+16*val(idx0) — is a function of the PUBLIC *) +(* reject the 2nd 4 bytes; the same lemma applies.) *) +(* -------------------------------------------------------------------------- *) + +let UADDLV_PACK_LEMMA = prove + (`!b0 b1 b2 b3 b4 b5 b6 b7. + (val (word_zx (word_subword ((word_add (word_subword ((word_and (word 664619068533544770747334646890102785:(128)word)) (word_join (word_join (word_join (word_neg (word (bitval b0):(16)word)) (word_neg (word (bitval b1):(16)word)):(32)word) (word_join (word_neg (word (bitval b2):(16)word)) (word_neg (word (bitval b3):(16)word)):(32)word):(64)word) (word_join (word_join (word_neg (word (bitval b4):(16)word)) (word_neg (word (bitval b5):(16)word)):(32)word) (word_join (word_neg (word (bitval b6):(16)word)) (word_neg (word (bitval b7):(16)word)):(32)word):(64)word):(128)word)) (0,16):(128)word)) ((word_add (word_subword ((word_and (word 664619068533544770747334646890102785:(128)word)) (word_join (word_join (word_join (word_neg (word (bitval b0):(16)word)) (word_neg (word (bitval b1):(16)word)):(32)word) (word_join (word_neg (word (bitval b2):(16)word)) (word_neg (word (bitval b3):(16)word)):(32)word):(64)word) (word_join (word_join (word_neg (word (bitval b4):(16)word)) (word_neg (word (bitval b5):(16)word)):(32)word) (word_join (word_neg (word (bitval b6):(16)word)) (word_neg (word (bitval b7):(16)word)):(32)word):(64)word):(128)word)) (16,16):(128)word)) ((word_add (word_subword ((word_and (word 664619068533544770747334646890102785:(128)word)) (word_join (word_join (word_join (word_neg (word (bitval b0):(16)word)) (word_neg (word (bitval b1):(16)word)):(32)word) (word_join (word_neg (word (bitval b2):(16)word)) (word_neg (word (bitval b3):(16)word)):(32)word):(64)word) (word_join (word_join (word_neg (word (bitval b4):(16)word)) (word_neg (word (bitval b5):(16)word)):(32)word) (word_join (word_neg (word (bitval b6):(16)word)) (word_neg (word (bitval b7):(16)word)):(32)word):(64)word):(128)word)) (32,16):(128)word)) ((word_add (word_subword ((word_and (word 664619068533544770747334646890102785:(128)word)) (word_join (word_join (word_join (word_neg (word (bitval b0):(16)word)) (word_neg (word (bitval b1):(16)word)):(32)word) (word_join (word_neg (word (bitval b2):(16)word)) (word_neg (word (bitval b3):(16)word)):(32)word):(64)word) (word_join (word_join (word_neg (word (bitval b4):(16)word)) (word_neg (word (bitval b5):(16)word)):(32)word) (word_join (word_neg (word (bitval b6):(16)word)) (word_neg (word (bitval b7):(16)word)):(32)word):(64)word):(128)word)) (48,16):(128)word)) ((word_add (word_subword ((word_and (word 664619068533544770747334646890102785:(128)word)) (word_join (word_join (word_join (word_neg (word (bitval b0):(16)word)) (word_neg (word (bitval b1):(16)word)):(32)word) (word_join (word_neg (word (bitval b2):(16)word)) (word_neg (word (bitval b3):(16)word)):(32)word):(64)word) (word_join (word_join (word_neg (word (bitval b4):(16)word)) (word_neg (word (bitval b5):(16)word)):(32)word) (word_join (word_neg (word (bitval b6):(16)word)) (word_neg (word (bitval b7):(16)word)):(32)word):(64)word):(128)word)) (64,16):(128)word)) ((word_add (word_subword ((word_and (word 664619068533544770747334646890102785:(128)word)) (word_join (word_join (word_join (word_neg (word (bitval b0):(16)word)) (word_neg (word (bitval b1):(16)word)):(32)word) (word_join (word_neg (word (bitval b2):(16)word)) (word_neg (word (bitval b3):(16)word)):(32)word):(64)word) (word_join (word_join (word_neg (word (bitval b4):(16)word)) (word_neg (word (bitval b5):(16)word)):(32)word) (word_join (word_neg (word (bitval b6):(16)word)) (word_neg (word (bitval b7):(16)word)):(32)word):(64)word):(128)word)) (80,16):(128)word)) ((word_add (word_subword ((word_and (word 664619068533544770747334646890102785:(128)word)) (word_join (word_join (word_join (word_neg (word (bitval b0):(16)word)) (word_neg (word (bitval b1):(16)word)):(32)word) (word_join (word_neg (word (bitval b2):(16)word)) (word_neg (word (bitval b3):(16)word)):(32)word):(64)word) (word_join (word_join (word_neg (word (bitval b4):(16)word)) (word_neg (word (bitval b5):(16)word)):(32)word) (word_join (word_neg (word (bitval b6):(16)word)) (word_neg (word (bitval b7):(16)word)):(32)word):(64)word):(128)word)) (96,16):(128)word)) (word_subword ((word_and (word 664619068533544770747334646890102785:(128)word)) (word_join (word_join (word_join (word_neg (word (bitval b0):(16)word)) (word_neg (word (bitval b1):(16)word)):(32)word) (word_join (word_neg (word (bitval b2):(16)word)) (word_neg (word (bitval b3):(16)word)):(32)word):(64)word) (word_join (word_join (word_neg (word (bitval b4):(16)word)) (word_neg (word (bitval b5):(16)word)):(32)word) (word_join (word_neg (word (bitval b6):(16)word)) (word_neg (word (bitval b7):(16)word)):(32)word):(64)word):(128)word)) (112,16):(128)word)))))))) (0,32):(32)word):(64)word)) = + 128 * bitval b0 + 64 * bitval b1 + 32 * bitval b2 + 16 * bitval b3 + + 8 * bitval b4 + 4 * bitval b5 + 2 * bitval b6 + bitval b7`, + REPEAT GEN_TAC THEN + MAP_EVERY BOOL_CASES_TAC [`b0:bool`;`b1:bool`;`b2:bool`;`b3:bool`; + `b4:bool`;`b5:bool`;`b6:bool`;`b7:bool`] THEN + REWRITE_TAC[BITVAL_CLAUSES] THEN + CONV_TAC(DEPTH_CONV WORD_NUM_RED_CONV) THEN CONV_TAC NUM_REDUCE_CONV);; + +(* The value bridge's weighted sum IS PACK_MASK8 of the accept-mask in NIBBLE *) +(* order. UADDLV_PACK_LEMMA's b0..b7 are in LANE order (b0 = highest lane = *) +(* byte3's high nibble = weight 128 ... b7 = lowest lane = byte0's low nibble *) +(* = weight 1). NIBBLES_OF_BYTES [byte0;byte1;byte2;byte3] lists nibbles *) +(* low-first per byte: [byte0-lo; byte0-hi; byte1-lo; ...; byte3-hi] = *) +(* [b7;b6;b5;b4;b3;b2; b1;b0]. Hence val(idx0) = PACK_MASK8 (REJ_MASK_ETA4 *) +(* ) once the abstract booleans are instantiated to (val *) +(* nibble_k < 9) — the core _SAFE proof does that instantiation using the *) +(* eta4 nibble machinery. *) +let PACK_CONNECT = prove + (`!b0 b1 b2 b3 b4 b5 b6 b7:bool. + 128 * bitval b0 + 64 * bitval b1 + 32 * bitval b2 + 16 * bitval b3 + + 8 * bitval b4 + 4 * bitval b5 + 2 * bitval b6 + bitval b7 = + PACK_MASK8 [b7;b6;b5;b4;b3;b2;b1;b0]`, + REWRITE_TAC[PACK_MASK8] THEN + CONV_TAC(ONCE_DEPTH_CONV EL_CONV) THEN ARITH_TAC);; + +(* -------------------------------------------------------------------------- *) +(* *) +(* misc.ml:2100). Its guard FAILS the unification if the per-iteration event *) +(* LHS contains ANY free variable that is not *syntactically* one of *) +(* f_ev_loop8's applied arguments. The hand-written f_events spec passes the *) +(* WHOLE reject mask (REJ_MASK_ETA4 inlist) as f_ev_loop8's mask argument. If *) +(* that argument stays the COMPOUND term (REJ_MASK_ETA4 inlist), then `frees` *) +(* extracts the atom `inlist`, which is NOT syntactically the compound arg, *) +(* so *) +(* TEST (s124, live): unify `f_ev table mask i = [EventLoad(table+16* *) +(* PACK_MASK8(SUB_LIST(16*i,16) mask),16)]` SUCCEEDS with atomic `mask`, *) +(* but the same with the compound (REJ_MASK_ETA4 inlist) FAILS. *) +(* *) +(* `mask = REJ_MASK_ETA4 inlist` (atomic var). Then the postcondition *) +(* extracts e_loop = \i. f_ev_loop8 .. mask i (atomic). The loop-body mask *) +(* bridge must then rewrite every hardware `inlist`-form into a SUB_LIST of *) +(* the atomic `mask` via REJ_MASK_ETA4_SUB_LIST below: *) +(* idx0 = PACK_MASK8(REJ_MASK_ETA4(SUB_LIST(8*i,4) inlist)) *) +(* = PACK_MASK8(SUB_LIST(16*i,8) mask) *) +(* idx1 = PACK_MASK8(SUB_LIST(16*i+8,8) mask) *) +(* curlen (store advance base) = *) +(* NUM_ACCEPTED(REJ_MASK_ETA4(SUB_LIST(0,8*i) inlist)) *) +(* = NUM_ACCEPTED(SUB_LIST(0,16*i) mask) *) +(* The `inlist`-only parts (curlist = REJ_NIBBLES_ETA4 .., memory contents) *) +(* keep `inlist`; they never enter the event LHS. *) +(* -------------------------------------------------------------------------- *) + +(* byte-index SUB_LIST maps to a nibble-index SUB_LIST at 2x offset/length. *) +let NIBBLES_OF_BYTES_SUB_LIST = prove + (`!l a b. NIBBLES_OF_BYTES(SUB_LIST(a,b) l) = + SUB_LIST(2*a,2*b)(NIBBLES_OF_BYTES l)`, + LIST_INDUCT_TAC THEN REPEAT GEN_TAC THEN + MAP_EVERY (fun v -> STRUCT_CASES_TAC(SPEC v num_CASES)) [`a:num`;`b:num`] THEN + ASM_REWRITE_TAC[NIBBLES_OF_BYTES; NIBBLE_PAIR; SUB_LIST_CLAUSES; APPEND; + MULT_CLAUSES; ADD_CLAUSES; ARITH_RULE `2 * SUC n = SUC(SUC(2*n))`] THEN + ASM_REWRITE_TAC[SUB_LIST_CLAUSES; APPEND]);; + +(* General-offset MAP/SUB_LIST commutation (aarch64_utils' SUB_LIST_MAP is *) +(* prefix-only, (0,n)). *) +let SUB_LIST_MAP_GEN = prove + (`!(f:A->B) l a b. SUB_LIST(a,b)(MAP f l) = MAP f (SUB_LIST(a,b) l)`, + GEN_TAC THEN LIST_INDUCT_TAC THEN REPEAT GEN_TAC THEN + MAP_EVERY (fun v -> STRUCT_CASES_TAC(SPEC v num_CASES)) [`a:num`;`b:num`] THEN + ASM_REWRITE_TAC[MAP; SUB_LIST_CLAUSES]);; + +(* THE mask-level length-doubling commutation: converts a hardware *) +(* REJ_MASK_ETA4(SUB_LIST(a,b) inlist) into a SUB_LIST of the ATOMIC mask — *) +let REJ_MASK_ETA4_SUB_LIST = prove + (`!l a b. REJ_MASK_ETA4(SUB_LIST(a,b) l) = SUB_LIST(2*a,2*b)(REJ_MASK_ETA4 l)`, + REWRITE_TAC[REJ_MASK_ETA4; NIBBLES_OF_BYTES_SUB_LIST; SUB_LIST_MAP_GEN]);; + +(* -------------------------------------------------------------------------- *) +(* *) +(* The number of loop8 iterations is data-dependent but PUBLIC: a function of *) +(* the public buflen and the public reject mask ONLY (never the accepted *) +(* values). It equals MEMSAFE's WOP-defined N (rej_uniform_eta4_aarch64_asm *) +(* .ml:2442): the least n at which EITHER the input is exhausted (val buflen *) +(* < 8*(n+1)) OR the output is full (256 <= accepted-so-far). Each loop *) +(* iteration consumes 8 bytes = 16 nibbles, and the accepted count after n *) +(* iterations = NUM_ACCEPTED of the first 16n mask bits, because *) +(* LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(0,8n) inlist)) = *) +(* NUM_ACCEPTED(SUB_LIST(0,16n)(REJ_MASK_ETA4 inlist)) [s117 count bridge]. *) +(* So this is exactly MEMSAFE's N whenever mask = REJ_MASK_ETA4 inlist, and *) +(* it is expressed WITHOUT reference to inlist (secret-independent). *) +(* -------------------------------------------------------------------------- *) + +let MLDSA_ETA4_LOOP8_TRIP = define + `MLDSA_ETA4_LOOP8_TRIP (buflen:int64) (mask:bool list) : num = + minimal n. val buflen < 8 * (n + 1) \/ + 256 <= NUM_ACCEPTED (SUB_LIST(0,16 * n) mask)`;; + +(* -------------------------------------------------------------------------- *) +(* *) +(* This is the analytical crux of loop8's DUAL-EXIT closure. loop8 exits when *) +(* EITHER the input is exhausted (remaining < 8, i.e. val buflen < 8*(i+1)) *) +(* OR the output is full (256 <= accepted so far). In the prove PC = (if i+1 *) +(* < TRIP then pc1 else pc2), which requires connecting the two HARDWARE *) +(* branch conditions (X2<8 at the bottom b.hs 0xf8; X9>=256 at the top b.hs *) +(* 0x6c) to the arithmetic predicate i+1 < TRIP. This lemma is exactly that *) +(* connector, derived from the minimality of TRIP: *) +(* - part 1 (the exit disjunction AT the trip point) tells the exit tail *) +(* WHICH branch fired (input-exhaust vs output-full = which EventJump *) +(* list the last iteration emits); *) +(* - part 2 (neither condition holds strictly BELOW the trip point) is the *) +(* "we execute iteration i" fact — it kills the top b.hs (curlen<256, so *) +(* 0x6c falls through to 0x70) and guarantees the bottom b.hs is taken *) +(* back to 0x68 for every non-final iteration, exactly MEMSAFE's *) +(* invariant conjuncts `curlen < 256` (eta4.ml:2504) and `8*(i+1) <= *) +(* buflen` (eta4.ml:2508), but stated over the PUBLIC atomic mask via the *) +(* s117 count bridge (LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(0,8i) inlist)) = *) +(* NUM_ACCEPTED(SUB_LIST(0,16i)(REJ_MASK_ETA4 inlist))) rather than the *) +(* secret niblen. Pure arithmetic on `minimal` (MINIMAL); no SIMD. *) +(* -------------------------------------------------------------------------- *) + +let MLDSA_ETA4_LOOP8_TRIP_MINIMAL = prove + (`!(buflen:int64) (mask:(bool)list). + (val buflen < 8 * (MLDSA_ETA4_LOOP8_TRIP buflen mask + 1) \/ + 256 <= NUM_ACCEPTED(SUB_LIST(0,16 * MLDSA_ETA4_LOOP8_TRIP buflen mask) mask)) /\ + (!i. i < MLDSA_ETA4_LOOP8_TRIP buflen mask + ==> ~(val buflen < 8 * (i + 1)) /\ + ~(256 <= NUM_ACCEPTED(SUB_LIST(0,16 * i) mask)))`, + REPEAT GEN_TAC THEN REWRITE_TAC[MLDSA_ETA4_LOOP8_TRIP] THEN + SUBGOAL_THEN + `?n. val(buflen:int64) < 8 * (n + 1) \/ 256 <= NUM_ACCEPTED(SUB_LIST(0,16 * n) mask)` + ASSUME_TAC THENL + [EXISTS_TAC `val(buflen:int64)` THEN DISJ1_TAC THEN ARITH_TAC; ALL_TAC] THEN + FIRST_X_ASSUM(STRIP_ASSUME_TAC o REWRITE_RULE[MINIMAL]) THEN + ASM_REWRITE_TAC[] THEN + X_GEN_TAC `i:num` THEN DISCH_TAC THEN + REWRITE_TAC[GSYM DE_MORGAN_THM] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN + ASM_REWRITE_TAC[]);; + +(* -------------------------------------------------------------------------- *) +(* MATERIALIZED + mask-bridge demonstrated end-to-end (not just asserted). *) +(* *) +(* EVENT VOCABULARY (confirmed from arm/proofs/instruction.ml + live steps): *) +(* EventLoad (addr:int64, size:num) EventStore (addr:int64, size:num) *) +(* EventJump (pc:int64, pc_next:int64) -- all accumulate via CONS. *) +(* arm_Bcond (instruction.ml:997): EVERY conditional branch (taken OR not- *) +(* taken) emits CONS(EventJump(pc, pc_next)) where pc_next is the symbolic *) +(* `if then else `. A symbolic-condition branch steps *) +(* to a CLEAN `if`-term for BOTH read PC and the EventJump target. *) +(* *) +(* read events s = CONS (EventStore (sp + 2*curlen, 16)) [st1 0xdc]*) +(* (CONS (EventLoad (table + 16*val idx1, 16)) [ldr 0xb8]*) +(* (CONS (EventLoad (table + 16*val idx0, 16)) [ldr 0xb4]*) +(* (CONS (EventLoad (buf + 8*i, 8)) e0))) [ld1 0x74]*) +(* Second store (0xe4) is EventStore(sp + 2*(curlen + val len0), 16), after *) +(* `add x7,x7,x12,lsl#1`. So the full per-iteration f_ev_loop8 = the 3 loads*) +(* + 2 stores + the trailing branch EventJump(s), all as CONS on e0. *) +(* *) +(* MASK BRIDGE demonstrated LIVE (the s124 "integration asserted not *) +(* demonstrated" gap is now CLOSED at the compute half): after the MEMSAFE *) +(* simp chain (eta4.ml:2564-2569), the live idx0 = read X12 collapses to *) +(* EXACTLY UADDLV_PACK_LEMMA's LHS shape *) +(* val(word_zx(word_subword(word_add(...word_and Q31 *) +(* (word_join.. word_neg(word(bitval(val(word_subword nibbles0 (k,16))<15)))))))) *) +(* machinery + REJ_MASK_ETA4_SUB_LIST + `REJ_MASK_ETA4 inlist = mask` give *) +(* val idx0 = PACK_MASK8(SUB_LIST(16*i,8) mask) *) +(* val idx1 = PACK_MASK8(SUB_LIST(16*i+8,8) mask) *) +(* curlen = NUM_ACCEPTED(SUB_LIST(0,16*i) mask) *) +(* val len0 = NUM_ACCEPTED(SUB_LIST(16*i,8) mask) *) +(* mask), so f_ev_loop8 (a CONCRETIZE meta-var) auto-instantiates via *) +(* REJECT-MASK, demonstrated. (Accepted VALUES never enter the trace.) *) +(* *) +(* add x7; add x12; add x9; cmp x2,#8]. *) +(* BEFORE `add x7`. (b) stores need `nonoverlapping (word pc,344) *) +(* (stackpointer,576)` in context (from the theorem's ALL clause) AND the 2nd *) +(* store additionally needs val len0<=8 (UADDLV_BOUND_LEMMA) + the MEMSAFE *) +(* WORD_ADD_SHL1 rewrite (eta4.ml:2971) on the word_shl'd X7 offset, else *) +(* "could not prove updates will not modify the program code". *) +(* *) +(* `8 <= val(read X2 )`: *) +(* * remaining>=8 (input not exhausted): step 0x68 (cmp x9,x4), 0x6c (b.cs, *) +(* if val buflen < 8*(i+2) then else =8 list> *) +(* the theorem's loop8 leaf; connect 256<=val(curlen') and remaining bounds *) +(* to `i+1 ival(word m:int64) = &m`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN `val(word m:int64) = m` ASSUME_TAC THENL + [REWRITE_TAC[VAL_WORD; DIMINDEX_64] THEN MATCH_MP_TAC MOD_LT THEN + ASM_ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `~bit 63 (word m:int64)` ASSUME_TAC THENL + [REWRITE_TAC[BIT_WORD; DIMINDEX_64] THEN + SUBGOAL_THEN `m DIV 2 EXP 63 = 0` SUBST1_TAC THENL + [MATCH_MP_TAC DIV_LT THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + ASM_REWRITE_TAC[IVAL_VAL; DIMINDEX_64; ARITH_RULE `64 - 1 = 63`; + BITVAL_CLAUSES] THEN + INT_ARITH_TAC);; + +(* The signed b.lt back-edge condition for the zero-init counter: given i<8 *) +(* (loop bound), the raw stepper flag condition on 32*(i+1) is equivalent to *) +(* the loop-continuation predicate i+1<8. This is what the loop-body PC leaf *) +let ZINIT_BRANCH = prove + (`!i. i < 8 ==> + (~(ival (word_add (word (32 * i)) (word 18446744073709551392):int64) < &0 <=> + ~(ival (word_add (word (32 * i)) (word 32):int64) - &256 = + ival (word_add (word (32 * i)) (word 18446744073709551392):int64))) + <=> i + 1 < 8)`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN + `ival (word_add (word (32 * i)) (word 32):int64) = &(32 * i) + &32` + SUBST1_TAC THENL + [SUBGOAL_THEN `word_add (word (32*i)) (word 32):int64 = word(32*i+32)` + SUBST1_TAC THENL [CONV_TAC WORD_RULE; ALL_TAC] THEN + SUBGOAL_THEN `ival(word(32*i+32):int64) = &(32*i+32)` + (fun th -> REWRITE_TAC[th; GSYM INT_OF_NUM_ADD]) THEN + MATCH_MP_TAC IVAL_WORD_SMALL THEN ASM_ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN + `ival (word_add (word (32 * i)) (word 18446744073709551392):int64) = + &(32 * i) - &224` + SUBST1_TAC THENL + [SUBGOAL_THEN + `word_add (word (32*i)) (word 18446744073709551392):int64 = + iword(&(32*i) - &224)` SUBST1_TAC THENL + [REWRITE_TAC[IWORD_INT_SUB; GSYM WORD_IWORD] THEN + REWRITE_TAC[WORD_RULE `word_sub a (b:int64) = word_add a (word_neg b)`] THEN + AP_TERM_TAC THEN CONV_TAC WORD_REDUCE_CONV; ALL_TAC] THEN + MATCH_MP_TAC IVAL_IWORD THEN REWRITE_TAC[DIMINDEX_64] THEN + ASM_SIMP_TAC[GSYM INT_OF_NUM_MUL; GSYM INT_OF_NUM_LT] THEN + ASM_ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `(&(32 * i) + &32) - &256 = &(32 * i) - &224:int` SUBST1_TAC THENL + [INT_ARITH_TAC; ALL_TAC] THEN + REWRITE_TAC[] THEN + REWRITE_TAC[INT_ARITH `(x:int) - &224 < &0 <=> x < &224`; + GSYM INT_OF_NUM_MUL; GSYM INT_OF_NUM_LT] THEN + ARITH_TAC);; + +(* The signed b.lt back-edge condition for the FINAL-COPY (fcopy) counter: *) +(* given i<16 (loop bound), the raw stepper flag condition on the *) +(* post-increment counter 16*(i+1) is equivalent to the loop-continuation *) +(* predicate i+1<16. This is FCOPY's analogue of ZINIT_BRANCH (32*(i+1) vs *) +(* 8): 16*(i+1) vs 256, -240 = word 18446744073709551376 (= 16 - 256 in two's *) +(* complement). *) +let FCOPY_BRANCH = prove + (`!i. i < 16 ==> + (~(ival (word_add (word (16 * i)) (word 18446744073709551376):int64) < &0 <=> + ~(ival (word_add (word (16 * i)) (word 16):int64) - &256 = + ival (word_add (word (16 * i)) (word 18446744073709551376):int64))) + <=> i + 1 < 16)`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN + `ival (word_add (word (16 * i)) (word 16):int64) = &(16 * i) + &16` + SUBST1_TAC THENL + [SUBGOAL_THEN `word_add (word (16*i)) (word 16):int64 = word(16*i+16)` + SUBST1_TAC THENL [CONV_TAC WORD_RULE; ALL_TAC] THEN + SUBGOAL_THEN `ival(word(16*i+16):int64) = &(16*i+16)` + (fun th -> REWRITE_TAC[th; GSYM INT_OF_NUM_ADD]) THEN + MATCH_MP_TAC IVAL_WORD_SMALL THEN ASM_ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN + `ival (word_add (word (16 * i)) (word 18446744073709551376):int64) = + &(16 * i) - &240` + SUBST1_TAC THENL + [SUBGOAL_THEN + `word_add (word (16*i)) (word 18446744073709551376):int64 = + iword(&(16*i) - &240)` SUBST1_TAC THENL + [REWRITE_TAC[IWORD_INT_SUB; GSYM WORD_IWORD] THEN + REWRITE_TAC[WORD_RULE `word_sub a (b:int64) = word_add a (word_neg b)`] THEN + AP_TERM_TAC THEN CONV_TAC WORD_REDUCE_CONV; ALL_TAC] THEN + MATCH_MP_TAC IVAL_IWORD THEN REWRITE_TAC[DIMINDEX_64] THEN + ASM_SIMP_TAC[GSYM INT_OF_NUM_MUL; GSYM INT_OF_NUM_LT] THEN + ASM_ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `(&(16 * i) + &16) - &256 = &(16 * i) - &240:int` SUBST1_TAC THENL + [INT_ARITH_TAC; ALL_TAC] THEN + REWRITE_TAC[] THEN + REWRITE_TAC[INT_ARITH `(x:int) - &240 < &0 <=> x < &240`; + GSYM INT_OF_NUM_MUL; GSYM INT_OF_NUM_LT] THEN + ARITH_TAC);; + +(* -------------------------------------------------------------------------- *) +(* *) +(* These two word-arith lemmas are the ONLY analytical pieces (beyond the *) +(* already-landed MLDSA_ETA4_LOOP8_TRIP_MINIMAL) needed to discharge loop8's *) +(* *) +(* BOTTOM branch (0xf4 cmp x2,#8 ; 0xf8 b.cs 0x68), x2 = buflen-8*(i+1): *) +(* live form: read PC = if 8 <= val(word_sub buflen (word(8*(i+1)))) *) +(* then word(pc+108)[=0x68] else word(pc+256)[=0xfc] *) +(* LOOP8_BOT_VAL_BRIDGE turns the hw cond into ~(val buflen < 8*(i+2)) *) +(* (input-exhaust), given the invariant fact 8*(i+1) <= val buflen *) +(* (= MINIMAL part 2 at j=i, i.e. ~(val buflen < 8*(i+1))). *) +(* *) +(* TOP branch (0x68 cmp x9,x4=256 ; 0x6c b.cs 0xfc), x9 = curlen' = *) +(* word(NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask)): *) +(* live form: read PC = if 256 <= val(word(NUM_ACCEPTED(...))) *) +(* then word(pc+256)[=0xfc] else word(pc+116)[=0x70] *) +(* LOOP8_TOP_VAL_BRIDGE turns the hw cond into 256 <= NUM_ACCEPTED(...) *) +(* (output-full), given NUM_ACCEPTED(...) < 2^64 (from the loop invariant *) +(* conjunct curlen' < 256+8 that mirrors MEMSAFE's niblen<256, eta4.ml *) +(* :2504 — MUST be added to the loop8 UP2 invariant). *) +(* -------------------------------------------------------------------------- *) + +let LOOP8_TOP_VAL_BRIDGE = prove + (`!n. n < 2 EXP 64 ==> (256 <= val(word n:int64) <=> 256 <= n)`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN `val(word n:int64) = n` SUBST1_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN ASM_REWRITE_TAC[DIMINDEX_64]; ALL_TAC] THEN + REWRITE_TAC[]);; + +let LOOP8_BOT_VAL_BRIDGE = prove + (`!(buflen:int64) i. 8*(i+1) <= val buflen + ==> (8 <= val(word_sub buflen (word(8*(i+1))):int64) <=> ~(val buflen < 8*(i+2)))`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN `val(word(8*(i+1)):int64) = 8*(i+1)` ASSUME_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN + MP_TAC(ISPEC `buflen:int64` VAL_BOUND) THEN REWRITE_TAC[DIMINDEX_64] THEN + ASM_ARITH_TAC; ALL_TAC] THEN + ASM_SIMP_TAC[VAL_WORD_SUB_CASES] THEN ASM_ARITH_TAC);; + +(* -------------------------------------------------------------------------- *) +(* *) +(* This is the analytical core of the loop8 tail-close PC obligation. It *) +(* connects the TOP branch's hardware condition (256 <= curlen', where *) +(* curlen' = NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask) is the accepted count *) +(* after iteration i) to the loop-exit predicate ~(i+1 < TRIP), GIVEN the *) +(* BOTTOM branch fell through to the top check (input not exhausted at i+1, *) +(* i.e. ~(val buflen < 8*(i+2))). Both directions follow from *) +(* MLDSA_ETA4_LOOP8_TRIP_MINIMAL: *) +(* (<=) ~(i+1 i+1 = TRIP (with i) 256 <= curlen' with i+1 (256 <= NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask) <=> + ~(i + 1 < MLDSA_ETA4_LOOP8_TRIP buflen mask))`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + MP_TAC(SPECL[`buflen:int64`;`mask:(bool)list`] MLDSA_ETA4_LOOP8_TRIP_MINIMAL) THEN + DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (LABEL_TAC "PT2")) THEN + ASM_CASES_TAC `i + 1 < MLDSA_ETA4_LOOP8_TRIP buflen mask` THENL + [ASM_REWRITE_TAC[] THEN + USE_THEN "PT2" (MP_TAC o SPEC `i + 1`) THEN ANTS_TAC THENL + [ASM_REWRITE_TAC[]; DISCH_THEN(fun th -> REWRITE_TAC[CONJUNCT2 th])]; + SUBGOAL_THEN `i + 1 = MLDSA_ETA4_LOOP8_TRIP buflen mask` ASSUME_TAC THENL + [MAP_EVERY UNDISCH_TAC + [`i < MLDSA_ETA4_LOOP8_TRIP buflen mask`; + `~(i + 1 < MLDSA_ETA4_LOOP8_TRIP buflen mask)`] THEN ARITH_TAC; + ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN + FIRST_ASSUM(DISJ_CASES_TAC o check (is_disj o concl)) THEN ASM_ARITH_TAC]);; + +let MLDSA_ETA4_LOOP8_TAIL_CLOSE = prove + (`!res (buf:int64) (buflen:int64) table mask pc i (e:(uarch_event)list) stackpointer + (tabval:num) (bufval:num) (returnaddress:int64). + i < MLDSA_ETA4_LOOP8_TRIP buflen mask /\ + NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask) < 2 EXP 64 + ==> ensures arm + (\s. aligned_bytes_loaded s (word pc) mldsa_rej_uniform_eta4_mc /\ + read PC s = word (pc + 0xf8) /\ + read SP s = word_sub stackpointer (word 576) /\ + read X30 s = returnaddress /\ + read X0 s = res /\ + read X1 s = word_add buf (word(8*(i+1))) /\ + read X2 s = word_sub buflen (word(8*(i+1))) /\ + read X3 s = table /\ + read X4 s = word 256 /\ + read X7 s = word_add (word_sub stackpointer (word 576)) + (word(2 * NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask))) /\ + read X8 s = word_sub stackpointer (word 576) /\ + read X9 s = word (NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask)) /\ + read Q30 s = word 46731384791156575435574448262545417 /\ + read Q31 s = word 664619068533544770747334646890102785 /\ + read (memory :> bytes(table,4096)) s = tabval /\ + read (memory :> bytes(buf, val buflen)) s = bufval /\ + read events s = e) + (\s. read PC s = + word (pc + (if i + 1 < MLDSA_ETA4_LOOP8_TRIP buflen mask then 0x74 else 0x100)) /\ + read SP s = word_sub stackpointer (word 576) /\ + read X30 s = returnaddress /\ + read X0 s = res /\ + read X1 s = word_add buf (word(8*(i+1))) /\ + read X2 s = word_sub buflen (word(8*(i+1))) /\ + read X3 s = table /\ + read X4 s = word 256 /\ + read X7 s = word_add (word_sub stackpointer (word 576)) + (word(2 * NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask))) /\ + read X8 s = word_sub stackpointer (word 576) /\ + read X9 s = word (NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask)) /\ + read Q30 s = word 46731384791156575435574448262545417 /\ + read Q31 s = word 664619068533544770747334646890102785 /\ + read (memory :> bytes(table,4096)) s = tabval /\ + read (memory :> bytes(buf, val buflen)) s = bufval /\ + read events s = + APPEND + (if 8 <= val(word_sub buflen (word(8*(i+1))):int64) + then [EventJump(word(pc+112), + (if 256 <= val(word(NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask)):int64) + then word(pc+256) else word(pc+116))); + EventJump(word(pc+252), word(pc+108))] + else [EventJump(word(pc+252), word(pc+256))]) e) + (\s s'. T)`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN `8 * (i + 1) <= val(buflen:int64)` ASSUME_TAC THENL + [MP_TAC(SPECL[`buflen:int64`;`mask:(bool)list`] MLDSA_ETA4_LOOP8_TRIP_MINIMAL) THEN + DISCH_THEN(MP_TAC o SPEC `i:num` o CONJUNCT2) THEN + ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o CONJUNCT1) THEN ARITH_TAC; + ALL_TAC] THEN + ENSURES_INIT_TAC "s0" THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (1--2) THEN + ASM_CASES_TAC `8 <= val(word_sub buflen (word(8*(i+1))):int64)` THENL + [UNDISCH_TAC `8 <= val(word_sub buflen (word(8*(i+1))):int64)` THEN + DISCH_THEN(fun th -> RULE_ASSUM_TAC(REWRITE_RULE[th]) THEN ASSUME_TAC th) THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (3--4) THEN + SUBGOAL_THEN + `256 <= val(word(NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask)):int64) <=> + ~(i + 1 < MLDSA_ETA4_LOOP8_TRIP buflen mask)` ASSUME_TAC THENL + [ASM_SIMP_TAC[LOOP8_TOP_VAL_BRIDGE] THEN + MATCH_MP_TAC LOOP8_OUTPUT_FULL_IFF THEN + ASM_MESON_TAC[LOOP8_BOT_VAL_BRIDGE]; + ALL_TAC] THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN + REWRITE_TAC[APPEND] THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[]; + SUBGOAL_THEN `val (buflen:int64) < 8 * (i + 2)` ASSUME_TAC THENL + [UNDISCH_TAC `~(8 <= val(word_sub buflen (word(8*(i+1))):int64))` THEN + ASM_SIMP_TAC[LOOP8_BOT_VAL_BRIDGE]; ALL_TAC] THEN + SUBGOAL_THEN `~(i + 1 < MLDSA_ETA4_LOOP8_TRIP buflen mask)` ASSUME_TAC THENL + [DISCH_TAC THEN + MP_TAC(SPECL[`buflen:int64`;`mask:(bool)list`] MLDSA_ETA4_LOOP8_TRIP_MINIMAL) THEN + DISCH_THEN(MP_TAC o SPEC `i + 1` o CONJUNCT2) THEN + ASM_REWRITE_TAC[ARITH_RULE `8 * ((i + 1) + 1) = 8 * (i + 2)`]; ALL_TAC] THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[APPEND]]);; + +(* Count-bridge for the loop8 per-iteration accepted count (final X9 value *) +(* and the 2nd stack-store address): the accepted-count after i+1 groups = *) +(* the count after i groups + the two 4-byte-half counts of group i. Pure *) +(* list *) +let NUM_ACCEPTED_SUB_LIST_STEP = prove + (`!(mask:bool list) i. + NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask) = + NUM_ACCEPTED(SUB_LIST(0,16*i) mask) + + NUM_ACCEPTED(SUB_LIST(16*i,8) mask) + + NUM_ACCEPTED(SUB_LIST(16*i+8,8) mask)`, + REPEAT GEN_TAC THEN + ASSUME_TAC(REWRITE_RULE[ADD_CLAUSES; ARITH_RULE `8+8=16`] + (ISPECL[`mask:bool list`;`8`;`8`;`16*i:num`] SUB_LIST_SPLIT)) THEN + ASSUME_TAC(REWRITE_RULE[ADD_CLAUSES] + (ISPECL[`mask:bool list`;`16*i:num`;`16`;`0`] SUB_LIST_SPLIT)) THEN + ASM_REWRITE_TAC[ARITH_RULE `16*(i+1) = 16*i+16`; NUM_ACCEPTED_APPEND] THEN + ARITH_TAC);; + +(* Each 4-byte loop8 half-group accepts at most 8 nibbles (LENGTH bound). *) +(* Used to bound the per-iteration store advance so the 2nd stack store's *) +(* address stays *) +let NUM_ACCEPTED_LE_8 = prove + (`!(m:bool list) a. NUM_ACCEPTED(SUB_LIST(a,8) m) <= 8`, + REPEAT GEN_TAC THEN REWRITE_TAC[NUM_ACCEPTED] THEN + MATCH_MP_TAC LE_TRANS THEN + EXISTS_TAC `LENGTH(SUB_LIST(a,8) (m:bool list))` THEN + REWRITE_TAC[LENGTH_FILTER; LENGTH_SUB_LIST] THEN ARITH_TAC);; + +(* Cancel a prefix of known length off an APPEND equality. *) +let APPEND_EQ_LEN = prove + (`!l1 m1 l2 m2:A list. LENGTH l1 = LENGTH m1 + ==> (APPEND l1 l2 = APPEND m1 m2 <=> l1 = m1 /\ l2 = m2)`, + LIST_INDUCT_TAC THEN LIST_INDUCT_TAC THEN + REWRITE_TAC[LENGTH; NOT_SUC; SUC_INJ; APPEND; CONS_11] THEN + REPEAT STRIP_TAC THEN ASM_MESON_TAC[]);; + +(* Split a known 8-element SUB_LIST into its two 4-element halves (the loop8 *) +(* group is 8 bytes = two 4-byte lanes feeding idx0 and idx1 respectively). *) +let SUB_LIST_4_FROM_8 = prove + (`!(l:A list) a x0 x1 x2 x3 x4 x5 x6 x7. + SUB_LIST(a,8) l = [x0;x1;x2;x3;x4;x5;x6;x7] + ==> SUB_LIST(a,4) l = [x0;x1;x2;x3] /\ SUB_LIST(a+4,4) l = [x4;x5;x6;x7]`, + REPEAT GEN_TAC THEN DISCH_TAC THEN + SUBGOAL_THEN `8 <= LENGTH(l:A list) - a` ASSUME_TAC THENL + [FIRST_ASSUM(MP_TAC o AP_TERM `LENGTH:A list->num`) THEN + REWRITE_TAC[LENGTH_SUB_LIST; LENGTH] THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `APPEND (SUB_LIST(a,4)(l:A list)) (SUB_LIST(a+4,4) l) = + [x0;x1;x2;x3;x4;x5;x6;x7]` MP_TAC THENL + [FIRST_X_ASSUM(fun th -> REWRITE_TAC[SYM th]) THEN + MP_TAC(ISPECL[`l:A list`;`4`;`4`;`a:num`] SUB_LIST_SPLIT) THEN + REWRITE_TAC[ARITH_RULE `4+4=8`] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN REFL_TAC; + ALL_TAC] THEN + MP_TAC(ISPECL[`SUB_LIST(a,4)(l:A list)`;`[x0;x1;x2;x3]:A list`; + `SUB_LIST(a+4,4)(l:A list)`;`[x4;x5;x6;x7]:A list`] APPEND_EQ_LEN) THEN + ANTS_TAC THENL + [REWRITE_TAC[LENGTH_SUB_LIST; LENGTH] THEN CONV_TAC NUM_REDUCE_CONV THEN + ASM_ARITH_TAC; ALL_TAC] THEN + REWRITE_TAC[APPEND] THEN DISCH_THEN(fun th -> ONCE_REWRITE_TAC[GSYM th]) THEN + DISCH_THEN ACCEPT_TAC);; + +(* Expand the reject mask of an explicit 4-byte group into the 8 per-nibble *) +(* accept predicates (low then high nibble of each byte, matching the SIMD *) +(* lane order after the AND/USHR/ZIP/UXTL chain). *) +let MASK_SLICE_4 = prove + (`!(l:byte list) a b0 b1 b2 b3. + SUB_LIST(a,4) l = [b0;b1;b2;b3] + ==> REJ_MASK_ETA4(SUB_LIST(a,4) l) = + [val b0 MOD 16 < 9; val b0 DIV 16 < 9; val b1 MOD 16 < 9; val b1 DIV 16 < 9; + val b2 MOD 16 < 9; val b2 DIV 16 < 9; val b3 MOD 16 < 9; val b3 DIV 16 < 9]`, + REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[REJ_MASK_ETA4; NIBBLES_OF_BYTES_4; MAP] THEN + REWRITE_TAC[VAL_WORD_NIBBLE_LT]);; + +(* --- self-contained helper tactics for the COMPUTE proof --- *) +let bitblast8_compute = List.map (fun k -> BITBLAST_RULE (vsubst[mk_small_numeral k,`k:num`] + `bit k (word_subword (word_neg (word (bitval b):16 word)) (0,8):8 word) <=> b`)) (0--7);; + +(* rewrite the goal with (mk th) for every assumption where mk succeeds *) +let COLLECT_COMPUTE (mk:thm->thm) : tactic = fun (asl,w) -> + REWRITE_TAC(List.filter_map (fun (_,th) -> try Some(mk th) with _ -> None) asl) (asl,w);; + +let is_nibvar_compute v = (try let n = fst(dest_var v) in n="nibbles0"||n="nibbles1b" with _ -> false);; +let NIBGSYM_COMPUTE : tactic = COLLECT_COMPUTE (fun th -> + match lhs(concl th) with + | Comb(Comb(Const("word_subword",_),v),_) when is_nibvar_compute v -> GSYM th + | _ -> failwith "no");; +(* MASK_SLICE_4 applied to each SUB_LIST(_,4) assumption *) +let MASKSLICE_COMPUTE : tactic = COLLECT_COMPUTE (fun th -> MATCH_MP MASK_SLICE_4 th);; +let is_sub4_compute c = is_eq c && (try let (f,a)=strip_comb(lhs c) in + fst(dest_const f)="SUB_LIST" && dest_small_numeral(snd(dest_pair(hd a)))=4 with _ -> false);; +let SUB4GSYM_COMPUTE : tactic = COLLECT_COMPUTE (fun th -> if is_sub4_compute(concl th) then GSYM th else failwith "no");; + +(* find first assumption whose conclusion satisfies p, apply f to it *) +let W_ASM_COMPUTE p (f:thm->tactic) : tactic = fun (asl,w) -> + f (snd(List.find (fun (_,th) -> try p(concl th) with _ -> false) asl)) (asl,w);; + +(* the 16 per-nibble facts word_subword nibbles0/1b (16k,16) = *) +(* word_zx(word_and/ushr..) *) +let PROVE_HW_ALL_COMPUTE : tactic = + let prove_hw name pos byte_pos op = + let rhs_inner = if op = "and" + then Printf.sprintf + "(word_and (word_subword (loaded_d:int64) (%d,8):byte) (word 15):byte)" byte_pos + else Printf.sprintf + "(word_ushr (word_subword (loaded_d:int64) (%d,8):byte) 4:byte)" byte_pos in + let goal_str = Printf.sprintf + "(word_subword (%s:int128) (%d,16)):int16 = word_zx %s :int16" name pos rhs_inner in + SUBGOAL_THEN (parse_term goal_str) ASSUME_TAC THENL + [FIRST_X_ASSUM(MP_TAC o SYM o check + (fun th -> let c = concl th in is_eq c && + (try fst(dest_var(rhs c)) = name with _ -> false) && + (match lhs c with Comb(Comb(Const("read",_),_),_)->false|_->true))) THEN + DISCH_THEN(fun th -> SUBST1_TAC th THEN ASSUME_TAC(SYM th)) THEN + CONV_TAC WORD_BLAST; + ALL_TAC] in + prove_hw "nibbles0" 0 0 "and" THEN prove_hw "nibbles0" 16 0 "ushr" THEN + prove_hw "nibbles0" 32 8 "and" THEN prove_hw "nibbles0" 48 8 "ushr" THEN + prove_hw "nibbles0" 64 16 "and" THEN prove_hw "nibbles0" 80 16 "ushr" THEN + prove_hw "nibbles0" 96 24 "and" THEN prove_hw "nibbles0" 112 24 "ushr" THEN + prove_hw "nibbles1b" 0 32 "and" THEN prove_hw "nibbles1b" 16 32 "ushr" THEN + prove_hw "nibbles1b" 32 40 "and" THEN prove_hw "nibbles1b" 48 40 "ushr" THEN + prove_hw "nibbles1b" 64 48 "and" THEN prove_hw "nibbles1b" 80 48 "ushr" THEN + prove_hw "nibbles1b" 96 56 "and" THEN prove_hw "nibbles1b" 112 56 "ushr";; + +(* the postcondition fold: normalise driven state + target to a common form *) +let POSTCOND_FOLD_COMPUTE : tactic = fun (asl,w) -> + let find p = snd(List.find (fun (_,th) -> try p(concl th) with _ -> false) asl) in + let maskeq = find (fun c -> c = `mask:(bool)list = REJ_MASK_ETA4 inlist`) in + let curleneq= find (fun c -> c = `NUM_ACCEPTED (SUB_LIST (0,16 * i) mask) = curlen`) in + let len0na = find (fun c -> c = `val(len0:int64) = NUM_ACCEPTED (SUB_LIST (16 * i,8) mask)`) in + let len1na = find (fun c -> c = `val(len1:int64) = NUM_ACCEPTED (SUB_LIST (16 * i + 8,8) mask)`) in + let is_lenlen v c = is_eq c && lhs c = v && + (try fst(dest_const(fst(strip_comb(rhs c))))="LENGTH" with _->false) in + let len0len = find (is_lenlen `val(len0:int64)`) in + let len1len = find (is_lenlen `val(len1:int64)`) in + (REWRITE_TAC[GSYM maskeq] THEN REWRITE_TAC[NUM_ACCEPTED_SUB_LIST_STEP] THEN + REWRITE_TAC[GSYM len0len; GSYM len1len] THEN REWRITE_TAC[curleneq] THEN + REWRITE_TAC[GSYM len0na; GSYM len1na] THEN + REWRITE_TAC[ARITH_RULE `8*(i+1) = 8*i+8`; APPEND] THEN + REPEAT CONJ_TAC THEN TRY(CONV_TAC WORD_RULE) THEN TRY REFL_TAC) (asl,w);; + +let MLDSA_ETA4_LOOP8_COMPUTE = prove + (`!res (buf:int64) (buflen:int64) (table:int64) (inlist:byte list) (mask:(bool)list) + (pc:num) (i:num) (e:(uarch_event)list) (stackpointer:int64) (tabval:num) + (returnaddress:int64). + mask = REJ_MASK_ETA4 inlist /\ + LENGTH inlist = val buflen /\ + 8 * (i + 1) <= val buflen /\ + NUM_ACCEPTED(SUB_LIST(0,16 * i) mask) < 256 /\ + ALL (nonoverlapping (word_sub stackpointer (word 576),576)) + [(word pc,344); (buf,val buflen); (table,4096)] + ==> ensures arm + (\s. aligned_bytes_loaded s (word pc) mldsa_rej_uniform_eta4_mc /\ + read PC s = word (pc + 0x74) /\ + read SP s = word_sub stackpointer (word 576) /\ + read X30 s = returnaddress /\ + read X0 s = res /\ + read X1 s = word_add buf (word(8 * i)) /\ + read X2 s = word_sub buflen (word(8 * i)) /\ + read X3 s = table /\ + read X4 s = word 256 /\ + read X7 s = word_add (word_sub stackpointer (word 576)) + (word(2 * NUM_ACCEPTED(SUB_LIST(0,16 * i) mask))) /\ + read X8 s = word_sub stackpointer (word 576) /\ + read X9 s = word (NUM_ACCEPTED(SUB_LIST(0,16 * i) mask)) /\ + read Q30 s = word 46731384791156575435574448262545417 /\ + read Q31 s = word 664619068533544770747334646890102785 /\ + read (memory :> bytes(table,4096)) s = tabval /\ + read (memory :> bytes(buf,val buflen)) s = num_of_wordlist inlist /\ + read events s = e) + (\s. aligned_bytes_loaded s (word pc) mldsa_rej_uniform_eta4_mc /\ + read PC s = word (pc + 0xf8) /\ + read SP s = word_sub stackpointer (word 576) /\ + read X30 s = returnaddress /\ + read X0 s = res /\ + read X1 s = word_add buf (word(8 * (i + 1))) /\ + read X2 s = word_sub buflen (word(8 * (i + 1))) /\ + read X3 s = table /\ + read X4 s = word 256 /\ + read X7 s = word_add (word_sub stackpointer (word 576)) + (word(2 * NUM_ACCEPTED(SUB_LIST(0,16 * (i + 1)) mask))) /\ + read X8 s = word_sub stackpointer (word 576) /\ + read X9 s = word (NUM_ACCEPTED(SUB_LIST(0,16 * (i + 1)) mask)) /\ + read Q30 s = word 46731384791156575435574448262545417 /\ + read Q31 s = word 664619068533544770747334646890102785 /\ + read (memory :> bytes(table,4096)) s = tabval /\ + read (memory :> bytes(buf,val buflen)) s = num_of_wordlist inlist /\ + read events s = + APPEND + [EventStore (word_add (word_sub stackpointer (word 576)) + (word(2 * (NUM_ACCEPTED(SUB_LIST(0,16 * i) mask) + + NUM_ACCEPTED(SUB_LIST(16 * i,8) mask)))), 16); + EventStore (word_add (word_sub stackpointer (word 576)) + (word(2 * NUM_ACCEPTED(SUB_LIST(0,16 * i) mask))), 16); + EventLoad (word_add table + (word(16 * PACK_MASK8(SUB_LIST(16 * i + 8,8) mask))), 16); + EventLoad (word_add table + (word(16 * PACK_MASK8(SUB_LIST(16 * i,8) mask))), 16); + EventLoad (word_add buf (word(8 * i)), 8)] + e) + (\s s'. T)`, + REPEAT GEN_TAC THEN DISCH_THEN(MAP_EVERY ASSUME_TAC o CONJUNCTS) THEN + ABBREV_TAC `curlen = NUM_ACCEPTED(SUB_LIST(0,16 * i) mask)` THEN + GHOST_INTRO_TAC `nibbles1:int128` `read Q17` THEN + ENSURES_INIT_TAC "s0" THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC [1] THEN + ABBREV_TAC `loaded_d:int64 = read (memory :> bytes64 (word_add buf (word (8 * i)))) s1` THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC [2] THEN + ARM_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (3--9) THEN + REABBREV_TAC `nibbles0:int128 = read Q16 s9` THEN + REABBREV_TAC `nibbles1b:int128 = read Q17 s9` THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (10--17) THEN + RULE_ASSUM_TAC(CONV_RULE(TOP_DEPTH_CONV WORD_SIMPLE_SUBWORD_CONV)) THEN + RULE_ASSUM_TAC(CONV_RULE WORD_REDUCE_CONV) THEN + RULE_ASSUM_TAC(REWRITE_RULE[word_ugt; relational2; GT; WORD_AND_MASK]) THEN + RULE_ASSUM_TAC(ONCE_REWRITE_RULE[COND_RAND]) THEN + RULE_ASSUM_TAC(CONV_RULE WORD_REDUCE_CONV) THEN + PROVE_HW_ALL_COMPUTE THEN + SUBGOAL_THEN + `SUB_LIST(8 * i,8) inlist = + [word_subword (loaded_d:int64) (0,8):byte; word_subword loaded_d (8,8); + word_subword loaded_d (16,8); word_subword loaded_d (24,8); + word_subword loaded_d (32,8); word_subword loaded_d (40,8); + word_subword loaded_d (48,8); word_subword loaded_d (56,8)]` + ASSUME_TAC THENL + [MP_TAC(SPECL[`buf:int64`;`val(buflen:int64)`;`inlist:byte list`;`i:num`;`s17:armstate`] + SUB_LIST_8_BYTES_FROM_INT64) THEN + ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + FIRST_ASSUM(fun th -> STRIP_ASSUME_TAC(MATCH_MP SUB_LIST_4_FROM_8 th)) THEN + SUBGOAL_THEN `val(read X12 s17:int64) = PACK_MASK8(SUB_LIST(16 * i,8) mask)` ASSUME_TAC THENL + [W_ASM_COMPUTE (fun c -> is_eq c && lhs c = `read X12 s17:int64`) + (fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [th]) THEN + REWRITE_TAC[UADDLV_PACK_LEMMA; PACK_CONNECT] THEN AP_TERM_TAC THEN + SUBGOAL_THEN `SUB_LIST(16 * i,8) mask = REJ_MASK_ETA4(SUB_LIST(8 * i,4) inlist)` + SUBST1_TAC THENL + [REWRITE_TAC[REJ_MASK_ETA4_SUB_LIST] THEN + ASM_REWRITE_TAC[ARITH_RULE`2*(8*i)=16*i`; ARITH_RULE`2*4=8`]; ALL_TAC] THEN + MASKSLICE_COMPUTE THEN + ASM_REWRITE_TAC[VAL_WORD_ZX_BYTE16; BYTE_AND_15_MOD; BYTE_USHR4_DIV]; ALL_TAC] THEN + SUBGOAL_THEN `val(read X13 s17:int64) = PACK_MASK8(SUB_LIST(16 * i + 8,8) mask)` ASSUME_TAC THENL + [W_ASM_COMPUTE (fun c -> is_eq c && lhs c = `read X13 s17:int64`) + (fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [th]) THEN + REWRITE_TAC[UADDLV_PACK_LEMMA; PACK_CONNECT] THEN AP_TERM_TAC THEN + SUBGOAL_THEN `SUB_LIST(16 * i + 8,8) mask = REJ_MASK_ETA4(SUB_LIST(8 * i + 4,4) inlist)` + SUBST1_TAC THENL + [REWRITE_TAC[REJ_MASK_ETA4_SUB_LIST] THEN + ASM_REWRITE_TAC[ARITH_RULE`2*(8*i+4)=16*i+8`; ARITH_RULE`2*4=8`]; ALL_TAC] THEN + MASKSLICE_COMPUTE THEN + ASM_REWRITE_TAC[VAL_WORD_ZX_BYTE16; BYTE_AND_15_MOD; BYTE_USHR4_DIV]; ALL_TAC] THEN + MAP_EVERY REABBREV_TAC [`idx0:int64 = read X12 s17`; `idx1:int64 = read X13 s17`] THEN + MAP_EVERY ABBREV_TAC + [`tab0:int128 = read(memory :> bytes128(word_add table (word(16 * val(idx0:int64))))) s17`; + `tab1:int128 = read(memory :> bytes128(word_add table (word(16 * val(idx1:int64))))) s17`] THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (18--25) THEN + RULE_ASSUM_TAC(REWRITE_RULE[WORD_SUBWORD_AND]) THEN + RULE_ASSUM_TAC(CONV_RULE(TOP_DEPTH_CONV WORD_SIMPLE_SUBWORD_CONV)) THEN + RULE_ASSUM_TAC(CONV_RULE WORD_REDUCE_CONV) THEN + RULE_ASSUM_TAC(REWRITE_RULE[word_ugt; relational2; GT; WORD_AND_MASK]) THEN + RULE_ASSUM_TAC(ONCE_REWRITE_RULE[COND_RAND]) THEN + RULE_ASSUM_TAC(CONV_RULE WORD_REDUCE_CONV) THEN + SUBGOAL_THEN `val(read X12 s25:int64) = + LENGTH(REJ_NIBBLES_ETA4 [word_subword (loaded_d:int64) (0,8):byte; + word_subword loaded_d (8,8); word_subword loaded_d (16,8); + word_subword loaded_d (24,8)])` ASSUME_TAC THENL + [W_ASM_COMPUTE (fun c -> is_eq c && lhs c = `read X12 s25:int64`) + (fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [th]) THEN + REWRITE_TAC[WORD_AND_0; WORD_POPCOUNT_0; ADD_CLAUSES] THEN + REWRITE_TAC[POPCOUNT_AND_POWERS] THEN REWRITE_TAC[UADDLV_COUNT_LEMMA] THEN + REWRITE_TAC bitblast8_compute THEN NIBGSYM_COMPUTE THEN + MP_TAC(SPECL[`nibbles0:int128`; `word_subword (loaded_d:int64) (0,8):byte`; + `word_subword (loaded_d:int64) (8,8):byte`; `word_subword (loaded_d:int64) (16,8):byte`; + `word_subword (loaded_d:int64) (24,8):byte`] COUNT_BRIDGE_ABSTRACT_4) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN DISCH_THEN SUBST1_TAC THEN REFL_TAC; + ALL_TAC] THEN + SUBGOAL_THEN `val(read X12 s25:int64) = NUM_ACCEPTED(SUB_LIST(16 * i,8) mask)` ASSUME_TAC THENL + [ASM_REWRITE_TAC[] THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA4_EQ_MASK; GSYM NUM_ACCEPTED] THEN AP_TERM_TAC THEN + SUB4GSYM_COMPUTE THEN REWRITE_TAC[REJ_MASK_ETA4_SUB_LIST] THEN + ASM_REWRITE_TAC[ARITH_RULE`2*(8*i)=16*i`; ARITH_RULE`2*4=8`]; ALL_TAC] THEN + SUBGOAL_THEN `val(read X13 s25:int64) = + LENGTH(REJ_NIBBLES_ETA4 [word_subword (loaded_d:int64) (32,8):byte; + word_subword loaded_d (40,8); word_subword loaded_d (48,8); + word_subword loaded_d (56,8)])` ASSUME_TAC THENL + [W_ASM_COMPUTE (fun c -> is_eq c && lhs c = `read X13 s25:int64`) + (fun th -> GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [th]) THEN + REWRITE_TAC[WORD_AND_0; WORD_POPCOUNT_0; ADD_CLAUSES] THEN + REWRITE_TAC[POPCOUNT_AND_POWERS] THEN REWRITE_TAC[UADDLV_COUNT_LEMMA] THEN + REWRITE_TAC bitblast8_compute THEN NIBGSYM_COMPUTE THEN + MP_TAC(SPECL[`nibbles1b:int128`; `word_subword (loaded_d:int64) (32,8):byte`; + `word_subword (loaded_d:int64) (40,8):byte`; `word_subword (loaded_d:int64) (48,8):byte`; + `word_subword (loaded_d:int64) (56,8):byte`] COUNT_BRIDGE_ABSTRACT_4) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN DISCH_THEN SUBST1_TAC THEN REFL_TAC; + ALL_TAC] THEN + SUBGOAL_THEN `val(read X13 s25:int64) = NUM_ACCEPTED(SUB_LIST(16 * i + 8,8) mask)` ASSUME_TAC THENL + [ASM_REWRITE_TAC[] THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA4_EQ_MASK; GSYM NUM_ACCEPTED] THEN AP_TERM_TAC THEN + SUB4GSYM_COMPUTE THEN REWRITE_TAC[REJ_MASK_ETA4_SUB_LIST] THEN + ASM_REWRITE_TAC[ARITH_RULE`2*(8*i+4)=16*i+8`; ARITH_RULE`2*4=8`]; ALL_TAC] THEN + ABBREV_TAC `sp0:int64 = word_sub stackpointer (word 576)` THEN + MAP_EVERY REABBREV_TAC [`len0:int64 = read X12 s25`; `len1:int64 = read X13 s25`] THEN + FIRST_X_ASSUM(STRIP_ASSUME_TAC o REWRITE_RULE[ALL] o check + (fun th -> match concl th with Comb(Comb(Const("ALL",_),_),_) -> true | _ -> false)) THEN + SUBGOAL_THEN `val(len0:int64) <= 8` ASSUME_TAC THENL + [ASM_REWRITE_TAC[NUM_ACCEPTED_LE_8; REJ_NIBBLES_ETA4_LENGTH_4]; ALL_TAC] THEN + SUBGOAL_THEN `val(len1:int64) <= 8` ASSUME_TAC THENL + [ASM_REWRITE_TAC[NUM_ACCEPTED_LE_8; REJ_NIBBLES_ETA4_LENGTH_4]; ALL_TAC] THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (26--28) THEN + ARM_VERBOSE_STEP_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC "s29" THEN + FIRST_X_ASSUM(fun th -> if is_eq(concl th) && lhs(concl th) = `read X7 s29:int64` + then ASSUME_TAC(GEN_REWRITE_RULE RAND_CONV [WORD_ADD_SHL1] th) else failwith "no") THEN + SUBGOAL_THEN + `nonoverlapping (word_add sp0 (word(2*(curlen + val(len0:int64)))):int64,16) (word pc:int64,344)` + ASSUME_TAC THENL [NONOVERLAPPING_TAC; ALL_TAC] THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC [30] THEN + ARM_VERBOSE_STEP_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC "s31" THEN + FIRST_X_ASSUM(fun th -> if is_eq(concl th) && lhs(concl th) = `read X7 s31:int64` + then ASSUME_TAC(GEN_REWRITE_RULE RAND_CONV [WORD_ADD_SHL1] th) else failwith "no") THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (32--33) THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN POSTCOND_FOLD_COMPUTE);; + +(* -------------------------------------------------------------------------- *) +(* *) +(* are `\s. program_decodes s /\ read PC s = word pc1 /\ (GROUPED loopinv) /\ *) +(* (APPEND e_front acc) /\ memaccess_inbounds e2 ...)}` (relational.ml:1974 *) +(* pth) — which does NOT flat-match MLDSA_ETA4_LOOP8_BODY's precond. *) +(* *) +(* BOTH pre AND post, but BODY's postcond (=TAIL_CLOSE's) DROPS aligned. *) +(* => augment TAIL_CLOSE/BODY with `aligned_bytes_loaded s (word pc) mc` *) +(* aligned so it re-proves for free, exactly like s135's SP/X30 augment).*) +(* pre, covar post, SAME `(\s s'.T)` frame — all of COMPUTE/TAIL_CLOSE/ *) +(* BODY use `(\s s'.T)`), instantiating P/Q to BODY_AL's pre/post with *) +(* acc)) e. Pre-strengthen: grouped=>flat + pick the events witness. *) +(* Post-weaken: PC bridge (word(pc+if..)=word(if..then pc+116..) via *) +(* with e_loop i = the per-iter delta), memaccess (see (3)). Body conjunct *) +(* (3) memaccess of the NEW e2 splits (MEMACCESS_INBOUNDS_APPEND) into the *) +(* per-iter delta memaccess (proven concretely) AND the pre's accumulated*) +(* memaccess. The latter is state-independent, so it is threaded via *) +(* => MI available in-context for the post; ~MI => the pre's `?e2 ... /\ *) +(* memaccess e2_pre` is unsatisfiable so the ensures is vacuous *) +(* (4) The per-iter delta memaccess: jumps (EventJumps) close via *) +(* the buf load needs `8*i+8<=val buflen` which MENTIONS `val` so *) +(* *) +(* MLDSA_ETA4_LOOP8_BODY_ADAPTED is stated with e_front/acc as FREE vars its *) +(* 3 ambient hyps (mask=REJ_MASK_ETA4 inlist, LENGTH inlist=val buflen, ALL *) +(* nonoverlapping) discharge from the main-proof context. conj2 is built (no *) +(* SIMD), guaranteeing the statement is exactly the shape the front emits. *) +(* -------------------------------------------------------------------------- *) + +let TAIL_CLOSE_AL = + let th = SPEC_ALL MLDSA_ETA4_LOOP8_TAIL_CLOSE in + let hyps = lhand (concl th) in + let ens = rand (concl th) in + let args = snd(strip_comb ens) in + let p = el 1 args and q = el 2 args and c = el 3 args in + let sv,qb = dest_abs q in + let aligned = subst [sv,`s:armstate`] + `aligned_bytes_loaded s (word pc) mldsa_rej_uniform_eta4_mc` in + let q' = mk_abs(sv, mk_conj(aligned, qb)) in + let goal = mk_imp(hyps, list_mk_icomb "ensures" [`arm`;p;q';c]) in + GEN_ALL (prove(goal, + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN `8 * (i + 1) <= val(buflen:int64)` ASSUME_TAC THENL + [MP_TAC(SPECL[`buflen:int64`;`mask:(bool)list`] MLDSA_ETA4_LOOP8_TRIP_MINIMAL) THEN + DISCH_THEN(MP_TAC o SPEC `i:num` o CONJUNCT2) THEN + ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o CONJUNCT1) THEN ARITH_TAC; + ALL_TAC] THEN + ENSURES_INIT_TAC "s0" THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (1--2) THEN + ASM_CASES_TAC `8 <= val(word_sub buflen (word(8*(i+1))):int64)` THENL + [UNDISCH_TAC `8 <= val(word_sub buflen (word(8*(i+1))):int64)` THEN + DISCH_THEN(fun th -> RULE_ASSUM_TAC(REWRITE_RULE[th]) THEN ASSUME_TAC th) THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (3--4) THEN + SUBGOAL_THEN + `256 <= val(word(NUM_ACCEPTED(SUB_LIST(0,16*(i+1)) mask)):int64) <=> + ~(i + 1 < MLDSA_ETA4_LOOP8_TRIP buflen mask)` ASSUME_TAC THENL + [ASM_SIMP_TAC[LOOP8_TOP_VAL_BRIDGE] THEN + MATCH_MP_TAC LOOP8_OUTPUT_FULL_IFF THEN + ASM_MESON_TAC[LOOP8_BOT_VAL_BRIDGE]; + ALL_TAC] THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN + REWRITE_TAC[APPEND] THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[]; + SUBGOAL_THEN `val (buflen:int64) < 8 * (i + 2)` ASSUME_TAC THENL + [UNDISCH_TAC `~(8 <= val(word_sub buflen (word(8*(i+1))):int64))` THEN + ASM_SIMP_TAC[LOOP8_BOT_VAL_BRIDGE]; ALL_TAC] THEN + SUBGOAL_THEN `~(i + 1 < MLDSA_ETA4_LOOP8_TRIP buflen mask)` ASSUME_TAC THENL + [DISCH_TAC THEN + MP_TAC(SPECL[`buflen:int64`;`mask:(bool)list`] MLDSA_ETA4_LOOP8_TRIP_MINIMAL) THEN + DISCH_THEN(MP_TAC o SPEC `i + 1` o CONJUNCT2) THEN + ASM_REWRITE_TAC[ARITH_RULE `8 * ((i + 1) + 1) = 8 * (i + 2)`]; ALL_TAC] THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[APPEND]]));; + +let BODY_AL = + let strip_PQR th = + let b = concl (SPEC_ALL th) in + let body = if is_imp b then rand b else b in + let (_,args) = strip_comb body in (el 1 args, el 2 args, el 3 args) in + let (cP,cQ,cR) = strip_PQR MLDSA_ETA4_LOOP8_COMPUTE in + let (tP,tQ,tR) = strip_PQR TAIL_CLOSE_AL in + let _,cQbody = dest_abs cQ in + let ev_compute = + rhs (find (fun c -> is_eq c && lhs c = `read events (s:armstate)`) + (conjuncts cQbody)) in + let subl = [`num_of_wordlist(inlist:byte list)`,`bufval:num`; + ev_compute,`e:(uarch_event)list`] in + let tQ_inst = subst subl tQ in + let c_hyps = conjuncts (lhand (concl (SPEC_ALL MLDSA_ETA4_LOOP8_COMPUTE))) in + let bl_hyps = list_mk_conj + [el 0 c_hyps; el 1 c_hyps; `i < MLDSA_ETA4_LOOP8_TRIP buflen mask`; last c_hyps] in + let ef,eargs = strip_comb (rand (concl (SPEC_ALL MLDSA_ETA4_LOOP8_COMPUTE))) in + let bl_ensures = list_mk_comb(ef, [el 0 eargs; el 1 eargs; tQ_inst; el 3 eargs]) in + let midstate = let sv,body = dest_abs cQ in + mk_abs(sv, list_mk_conj (tl (tl (conjuncts body)))) in + GEN_ALL(prove(mk_imp(bl_hyps, bl_ensures), + STRIP_TAC THEN + SUBGOAL_THEN + `~(val (buflen:int64) < 8 * (i + 1)) /\ + ~(256 <= NUM_ACCEPTED(SUB_LIST(0,16 * i) mask))` + STRIP_ASSUME_TAC THENL + [MATCH_MP_TAC(CONJUNCT2(SPECL[`buflen:int64`;`mask:(bool)list`] + MLDSA_ETA4_LOOP8_TRIP_MINIMAL)) THEN FIRST_ASSUM ACCEPT_TAC; + ALL_TAC] THEN + ENSURES_SEQUENCE_TAC `pc + 0xf8` midstate THEN + CONJ_TAC THENL + [ MATCH_MP_TAC MLDSA_ETA4_LOOP8_COMPUTE THEN + REPEAT CONJ_TAC THENL + [ FIRST_ASSUM ACCEPT_TAC; FIRST_ASSUM ACCEPT_TAC; + ASM_ARITH_TAC; ASM_ARITH_TAC; FIRST_ASSUM ACCEPT_TAC ]; + MATCH_MP_TAC TAIL_CLOSE_AL THEN + CONJ_TAC THENL + [ FIRST_ASSUM ACCEPT_TAC; + REWRITE_TAC[NUM_ACCEPTED_SUB_LIST_STEP] THEN + MP_TAC(SPECL[`mask:(bool)list`;`16 * i`] NUM_ACCEPTED_LE_8) THEN + MP_TAC(SPECL[`mask:(bool)list`;`16 * i + 8`] NUM_ACCEPTED_LE_8) THEN + CONV_TAC(ONCE_DEPTH_CONV NUM_REDUCE_CONV) THEN ASM_ARITH_TAC ] ]));; + +let MLDSA_ETA4_LOOP8_BODY_ADAPTED = + let appty = `APPEND:(uarch_event)list->(uarch_event)list->(uarch_event)list` in + let body = SPEC_ALL BODY_AL in + let bargs = snd(strip_comb (rand (concl body))) in + let bP = el 1 bargs and bQ = el 2 bargs in +(* loop8_inv = BODY_AL-pre minus aligned/PC (front 2) and events (last) *) + let sv, bpbody = dest_abs bP in + let loop8_inv = mk_abs(`i:num`, mk_abs(sv, list_mk_conj (butlast (tl (tl (conjuncts bpbody)))))) in +(* e_loop = \i. APPEND jumps five (per-iter delta from BODY_AL-post events) *) + let _, bqbody = dest_abs bQ in + let ev_rhs = rhs (last (conjuncts bqbody)) in + let jumps, rest = dest_binary "APPEND" ev_rhs in + let five, _ = dest_binary "APPEND" rest in + let e_loop = mk_abs(`i:num`, mk_binop appty jumps five) in + let rr = `[(buf:int64),val(buflen:int64); (table:int64),4096; + word_sub (stackpointer:int64) (word 576),576]` in + let wr = `[word_sub (stackpointer:int64) (word 576),576; (res:int64),1024]` in + let mkinb e2v = list_mk_icomb "memaccess_inbounds" [e2v; rr; wr] in + let e_front = `f_ev_loop8_prol:(uarch_event)list` in + let acc = `f_ev_acc:(uarch_event)list` in + let enum_i = list_mk_comb(`ENUMERATEL:num->(num->(uarch_event)list)->(uarch_event)list`,[`i:num`; e_loop]) in + let e2_pre = mk_binop appty enum_i (mk_binop appty e_front acc) in + let eB = mk_binop appty e2_pre `e:(uarch_event)list` in + let bP_inst = subst [eB,`e:(uarch_event)list`] bP in + let bQ_inst = subst [eB,`e:(uarch_event)list`] bQ in + let mi = mkinb e2_pre in + let trip = `MLDSA_ETA4_LOOP8_TRIP buflen mask` in + let pc1 = `pc + 116` and pc2 = `pc + 256` in + let pre = + let e2 = `e2:(uarch_event)list` in + mk_abs(`s:armstate`, + list_mk_conj + [`aligned_bytes_loaded s (word pc) mldsa_rej_uniform_eta4_mc`; + `read PC s = word (pc+116)`; + list_mk_comb(loop8_inv,[`0`;`s:armstate`]); + mk_exists(e2, list_mk_conj [`read events s = APPEND e2 e`; mk_eq(e2,e_front); mkinb e2])]) in + let enum_trip = list_mk_comb(`ENUMERATEL:num->(num->(uarch_event)list)->(uarch_event)list`,[trip; e_loop]) in + let post_e2val = + mk_binop appty (mk_binop appty `f_ev_epil:(uarch_event)list` + (mk_binop appty enum_trip e_front)) acc in + let post = + let e2 = `e2:(uarch_event)list` in + mk_abs(`s:armstate`, + list_mk_conj + [`read PC s = returnaddress`; + mk_exists(e2, list_mk_conj [`read events s = APPEND e2 e`; mk_eq(e2,post_e2val); mkinb e2])]) in + let syn_goal = list_mk_icomb "ensures" [`arm`; pre; post; `\(s:armstate) (s':armstate). T`] in + let conj2 = + let (_,gls,_) = ENSURES_EVENTS_WHILE_UP2_TAC trip pc1 pc2 loop8_inv ([],syn_goal) in + el 2 (conjuncts (snd (hd gls))) in + let enum_i1 = list_mk_comb(`ENUMERATEL:num->(num->(uarch_event)list)->(uarch_event)list`,[`i+1`; e_loop]) in + let e2_post = mk_binop appty enum_i1 (mk_binop appty e_front acc) in + let ambient = list_mk_conj + [`mask = REJ_MASK_ETA4 inlist`; + `LENGTH (inlist:byte list) = val (buflen:int64)`; + `ALL (nonoverlapping (word_sub stackpointer (word 576),576)) + [(word pc,344); (buf:int64,val (buflen:int64)); (table:int64,4096)]`] in + prove(mk_imp(ambient, conj2), + REPEAT STRIP_TAC THEN + ASM_CASES_TAC mi THENL + [ MATCH_MP_TAC ENSURES_PREPOSTCONDITION_THM THEN + MAP_EVERY EXISTS_TAC [bP_inst; bQ_inst] THEN + REPEAT CONJ_TAC THENL + [ GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN + UNDISCH_THEN `mask = REJ_MASK_ETA4 inlist` (K ALL_TAC) THEN + ASM_REWRITE_TAC[] THEN + CONJ_TAC THENL + [ AP_TERM_TAC THEN COND_CASES_TAC THEN ARITH_TAC; + EXISTS_TAC e2_post THEN REPEAT CONJ_TAC THENL + [ ASM_REWRITE_TAC[ENUMERATEL_ADD1] THEN REWRITE_TAC[APPEND; APPEND_ASSOC]; + REFL_TAC; + REWRITE_TAC[ENUMERATEL_ADD1] THEN REWRITE_TAC[APPEND; APPEND_ASSOC] THEN + REWRITE_TAC[MEMACCESS_INBOUNDS_APPEND] THEN + RULE_ASSUM_TAC(REWRITE_RULE[APPEND; APPEND_ASSOC; MEMACCESS_INBOUNDS_APPEND]) THEN + ASM_REWRITE_TAC[] THEN + SUBGOAL_THEN `8 * (i + 1) <= val(buflen:int64) /\ + NUM_ACCEPTED(SUB_LIST(0,16*i) mask) < 256` + STRIP_ASSUME_TAC THENL + [MP_TAC(SPEC `i:num` (CONJUNCT2(SPECL[`buflen:int64`;`mask:(bool)list`] + MLDSA_ETA4_LOOP8_TRIP_MINIMAL))) THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; + ALL_TAC] THEN + ASSUME_TAC(SPECL[`mask:(bool)list`;`16*i`] NUM_ACCEPTED_LE_8) THEN + ASSUME_TAC(SPEC `SUB_LIST(16*i,8) (mask:(bool)list)` PACK_MASK8_BOUND) THEN + ASSUME_TAC(SPEC `SUB_LIST(16*i+8,8) (mask:(bool)list)` PACK_MASK8_BOUND) THEN + CONJ_TAC THENL + [ COND_CASES_TAC THEN DISCHARGE_MEMACCESS_INBOUNDS_TAC; + DISCHARGE_CONCRETE_MEMACCESS_INBOUNDS_TAC THEN + DISJ1_TAC THEN + GEN_REWRITE_TAC I [GSYM CONTAINED_MODULO_MOD2] THEN + GEN_REWRITE_TAC (BINOP_CONV o LAND_CONV o LAND_CONV o TOP_DEPTH_CONV) + [VAL_WORD_ADD; VAL_WORD; DIMINDEX_64] THEN + CONV_TAC(BINOP_CONV(LAND_CONV MOD_DOWN_CONV)) THEN + GEN_REWRITE_TAC I [CONTAINED_MODULO_MOD2] THEN + (MATCH_MP_TAC CONTAINED_MODULO_OFFSET_SIMPLE ORELSE + MATCH_MP_TAC CONTAINED_MODULO_SIMPLE) THEN + UNDISCH_TAC `8 * (i + 1) <= val(buflen:int64)` THEN ARITH_TAC ] ] ]; + MATCH_MP_TAC BODY_AL THEN ASM_REWRITE_TAC[] ]; + MATCH_MP_TAC ENSURES_PRECONDITION_THM THEN EXISTS_TAC `\s:armstate. F` THEN + CONJ_TAC THENL + [ GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN ASM_MESON_TAC[]; + REWRITE_TAC[ensures] THEN MESON_TAC[] ] ]);; + +(* Restore the recursive `STRIP_EXISTS_ASSUM_TAC` from s2n-bignum *) +(* common/misc.ml, which the constant-time proof below was developed against. *) +(* The MEMSAFE section (near line 2363) locally redefines *) +(* STRIP_EXISTS_ASSUM_TAC to a *shallow* variant that only splits the *) +(* outermost conjunction of the chosen existential. The event-loop leaves *) +(* below feed `~preprocess_tac:(TRY STRIP_EXISTS_ASSUM_TAC)` an invariant of *) +(* the form `?e2. read events s = ... /\ e2 = ... /\ memaccess_inbounds e2 *) +(* ...`; the shallow variant leaves `e2 = ... /\ memaccess_inbounds e2 ...` *) +(* conjoined, so DISCHARGE_MEMACCESS_INBOUNDS_USING_ASM_TAC (which filters *) +(* assumptions by head symbol) cannot see the `memaccess_inbounds e2` fact *) +(* and the discharge fails. The recursive STRIP_ASSUME_TAC form splits it *) +(* into a standalone assumption. *) +let STRIP_EXISTS_ASSUM_TAC = + FIRST_X_ASSUM (STRIP_ASSUME_TAC o (check (is_exists o concl)));; + +(* Proof machinery for MLDSA_REJ_UNIFORM_ETA4_SUBROUTINE_SAFE: derive the concretized f_events lambda and + the loop8/fcopy invariants from BODY_AL (see the theorem below). *) +let ETA4_SAFE_MACHINERY = + let appty = `APPEND:(uarch_event)list->(uarch_event)list->(uarch_event)list` in + let bodyth = SPEC_ALL BODY_AL in + let bargs = snd(strip_comb (rand (concl bodyth))) in + let bP = el 1 bargs and bQ = el 2 bargs in + let sv,bpbody = dest_abs bP in + let loop8_inv = + mk_abs(`i:num`, mk_abs(sv, list_mk_conj (butlast (tl (tl (conjuncts bpbody)))))) in + let _,bqbody = dest_abs bQ in + let ev_rhs = rhs (last (conjuncts bqbody)) in + let jumps,rest = dest_binary "APPEND" ev_rhs in + let five,_ = dest_binary "APPEND" rest in + let loop8_inv_real = + subst [`num_of_wordlist mldsa_rej_uniform_eta_table`,`tabval:num`] loop8_inv in + let orig_lam = + `\(res:int64)(buf:int64)(buflen:int64)(table:int64)(pc:num)(sp:int64) + (ra:int64)(mask:(bool)list). + APPEND + (APPEND + (APPEND + (APPEND + (f_ev_epi res buf buflen table pc sp ra mask) + (APPEND (ENUMERATEL 16 (\j. f_ev_fcopy res buf buflen table pc sp ra mask j)) + (f_ev_fcopy_prol res buf buflen table pc sp ra mask))) + (APPEND (ENUMERATEL (MLDSA_ETA4_LOOP8_TRIP buflen mask) + (\i. f_ev_loop8 res buf buflen table pc sp ra mask i)) + (f_ev_loop8_prol res buf buflen table pc sp ra mask))) + (APPEND (ENUMERATEL 8 (\k. f_ev_zinit res buf buflen table pc sp ra mask k)) + (f_ev_zinit_prol res buf buflen table pc sp ra mask))) + (f_ev_begin res buf buflen table pc sp ra mask) :(uarch_event)list` in + let lamvars,obody = strip_abs orig_lam in + let is_l8 t = is_abs t && + (let _,b = dest_abs t in is_comb b && + (let h = fst(strip_comb b) in is_var h && fst(dest_var h) = "f_ev_loop8")) in + let l8_old = find_term is_l8 obody in + let e_loop_lam = mk_abs(`i:num`, + subst [`sp:int64`,`stackpointer:int64`; `ra:int64`,`returnaddress:int64`] + (mk_binop appty jumps five)) in + let modified_lam = list_mk_abs(lamvars, subst [e_loop_lam,l8_old] obody) in + let REASSOC_LOOP8 = METIS[APPEND_ASSOC] + `(exists e2. P e2 /\ + e2 = APPEND (APPEND (APPEND epil (APPEND loop prol)) tail) tail2 /\ Q e2) + <=> + (exists e2. P e2 /\ + e2 = APPEND (APPEND epil (APPEND loop prol)) (APPEND tail tail2) /\ Q e2)` in + let REASSOC_FCOPY = METIS[APPEND_ASSOC] + `(exists e2. P e2 /\ + e2 = APPEND (APPEND fe (APPEND l8e l8p)) zb /\ Q e2) + <=> + (exists e2. P e2 /\ + e2 = APPEND fe (APPEND l8e (APPEND l8p zb)) /\ Q e2)` in +(* MINIMAL fcopy invariant (postcond doesn't constrain regs; omit *) +(* X9/v-consts). *) + let fcopy_inv = + `\(i:num) s. read SP s = word_sub stackpointer (word 576) /\ + read X30 s = returnaddress /\ + read X0 s = word_add res (word(64 * i)) /\ + read X7 s = word_add (word_sub stackpointer (word 576)) (word(32 * i)) /\ + read X8 s = word_sub stackpointer (word 576) /\ + read X11 s = word(16 * i)` in + (modified_lam, loop8_inv_real, REASSOC_LOOP8, fcopy_inv, REASSOC_FCOPY);; + +let MLDSA_REJ_UNIFORM_ETA4_SUBROUTINE_SAFE = time prove + (`?f_events:int64->int64->int64->int64->num->int64->int64-> + (bool list)->(uarch_event)list. + !res buf buflen table (inlist:byte list) pc e stackpointer returnaddress. + 8 divides val buflen /\ + 8 <= val buflen /\ + LENGTH inlist = val buflen /\ + ALL (nonoverlapping (word_sub stackpointer (word 576),576)) + [(word pc,LENGTH mldsa_rej_uniform_eta4_mc); + (buf,val buflen); (table,4096)] /\ + ALL (nonoverlapping (res,1024)) + [(word pc,LENGTH mldsa_rej_uniform_eta4_mc); + (word_sub stackpointer (word 576),576)] + ==> ensures arm + (\s. aligned_bytes_loaded s (word pc) mldsa_rej_uniform_eta4_mc /\ + read PC s = word pc /\ + read SP s = stackpointer /\ + read X30 s = returnaddress /\ + C_ARGUMENTS [res;buf;buflen;table] s /\ + read(memory :> bytes(table,4096)) s = + num_of_wordlist mldsa_rej_uniform_eta_table /\ + read(memory :> bytes(buf,val buflen)) s = + num_of_wordlist (inlist:byte list) /\ + read events s = e) + (\s. read PC s = returnaddress /\ + (?e2. + read events s = APPEND e2 e /\ + e2 = f_events res buf buflen table pc stackpointer + returnaddress (REJ_MASK_ETA4 inlist) /\ + memaccess_inbounds e2 + [buf,val buflen; table,4096; + word_sub stackpointer (word 576),576] + [word_sub stackpointer (word 576),576; res,1024])) + (\s s'. T)`, +(* -------------------------------------------------------------------------- *) +(* bignum_copy_row_from_table.ml:635-880 (LEFT-leaning lambda association). *) +(* -------------------------------------------------------------------------- *) + let modified_lam, loop8_inv_real, REASSOC_LOOP8, fcopy_inv, REASSOC_FCOPY = + ETA4_SAFE_MACHINERY in + CONCRETIZE_F_EVENTS_TAC modified_lam THEN + REPEAT META_EXISTS_TAC THEN REPEAT GEN_TAC THEN + REWRITE_TAC[C_ARGUMENTS; NONOVERLAPPING_CLAUSES; ALL; + fst MLDSA_REJ_UNIFORM_ETA4_EXEC] THEN + REPEAT STRIP_TAC THEN + ABBREV_TAC `mask:(bool)list = REJ_MASK_ETA4 inlist` THEN + ENSURES_EVENTS_SEQUENCE_TAC `pc + 0x44` + `\s. read X30 s = returnaddress /\ read X0 s = res /\ read X1 s = buf /\ + read X2 s = buflen /\ read X3 s = table /\ + read SP s = word_sub stackpointer (word 576) /\ + read X7 s = word_sub stackpointer (word 576) /\ + read X8 s = word_sub stackpointer (word 576) /\ + read X11 s = word 0 /\ + read Q30 s = word 46731384791156575435574448262545417 /\ + read Q31 s = word 664619068533544770747334646890102785 /\ + read Q16 s = word 0 /\ + read (memory :> bytes (table,4096)) s = + num_of_wordlist mldsa_rej_uniform_eta_table /\ + read (memory :> bytes (buf,val buflen)) s = num_of_wordlist (inlist:byte list)` THEN + CONJ_TAC THENL [ + GHOST_INTRO_TAC `q31_init:int128` `read Q31` THEN + ENSURES_INIT_TAC "s0" THEN + ARM_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (1--17) THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN + REWRITE_TAC[WORD_INSERT_Q31] THEN + DISCHARGE_SAFETY_PROPERTY_TAC; + ALL_TAC] THEN + ENSURES_EVENTS_WHILE_UP2_TAC `8` `pc + 0x44` `pc + 0x60` + `\(i:num) s. read SP s = word_sub stackpointer (word 576) /\ + read X30 s = returnaddress /\ read X0 s = res /\ read X1 s = buf /\ + read X2 s = buflen /\ read X3 s = table /\ + read X8 s = word_sub stackpointer (word 576) /\ + read X7 s = word_add (word_sub stackpointer (word 576)) (word (64 * i)) /\ + read X11 s = word (32 * i) /\ + read Q30 s = word 46731384791156575435574448262545417 /\ + read Q31 s = word 664619068533544770747334646890102785 /\ + read Q16 s = word 0 /\ + read (memory :> bytes (table,4096)) s = + num_of_wordlist mldsa_rej_uniform_eta_table /\ + read (memory :> bytes (buf,val buflen)) s = num_of_wordlist (inlist:byte list)` THEN + REPEAT CONJ_TAC THENL [ + ARITH_TAC; + ARM_SIM_TAC ~preprocess_tac:(TRY STRIP_EXISTS_ASSUM_TAC) + ~canonicalize_pc_diff:false MLDSA_REJ_UNIFORM_ETA4_EXEC (1--0) THEN + REWRITE_TAC[MULT_CLAUSES; WORD_ADD_0] THEN DISCHARGE_SAFETY_PROPERTY_TAC; + REPEAT STRIP_TAC THEN + ARM_SIM_TAC ~preprocess_tac:(TRY STRIP_EXISTS_ASSUM_TAC) + ~canonicalize_pc_diff:false MLDSA_REJ_UNIFORM_ETA4_EXEC (1--7) THEN + CONJ_TAC THENL + [ASM_SIMP_TAC[ZINIT_BRANCH] THEN REWRITE_TAC[COND_RAND] THEN + COND_CASES_TAC THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + CONJ_TAC THENL + [REWRITE_TAC[ARITH_RULE `64*(i+1)=64*i+64`] THEN CONV_TAC WORD_RULE; ALL_TAC] THEN + CONJ_TAC THENL + [REWRITE_TAC[ARITH_RULE `32*(i+1)=32*i+32`] THEN CONV_TAC WORD_RULE; ALL_TAC] THEN + DISCHARGE_SAFETY_PROPERTY_TAC; + ONCE_REWRITE_TAC[REASSOC_LOOP8] THEN + ENSURES_EVENTS_WHILE_UP2_TAC `MLDSA_ETA4_LOOP8_TRIP buflen mask` + `pc + 0x74` `pc + 0x100` loop8_inv_real THEN + REPEAT CONJ_TAC THENL [ + SUBGOAL_THEN `NUM_ACCEPTED(SUB_LIST(0,16 * 0) (mask:(bool)list)) = 0` ASSUME_TAC THENL + [REWRITE_TAC[ARITH_RULE `16 * 0 = 0`; SUB_LIST_CLAUSES; NUM_ACCEPTED; FILTER; LENGTH]; + ALL_TAC] THEN + DISCH_TAC THEN + MP_TAC(CONJUNCT1(SPECL[`buflen:int64`;`mask:(bool)list`] + MLDSA_ETA4_LOOP8_TRIP_MINIMAL)) THEN + ASM_REWRITE_TAC[ARITH_RULE `8 * (0 + 1) = 8`] THEN ASM_ARITH_TAC; + ARM_SIM_TAC ~preprocess_tac:(TRY STRIP_EXISTS_ASSUM_TAC) + ~canonicalize_pc_diff:false MLDSA_REJ_UNIFORM_ETA4_EXEC (1--5) THEN + REWRITE_TAC[MULT_CLAUSES; SUB_LIST_CLAUSES; NUM_ACCEPTED; FILTER; LENGTH] THEN + REPEAT CONJ_TAC THEN TRY(CONV_TAC WORD_RULE) THEN DISCHARGE_SAFETY_PROPERTY_TAC; + MATCH_MP_TAC MLDSA_ETA4_LOOP8_BODY_ADAPTED THEN ASM_REWRITE_TAC[] THEN + REWRITE_TAC[ALL] THEN REPEAT CONJ_TAC THEN NONOVERLAPPING_TAC; + ONCE_REWRITE_TAC[REASSOC_FCOPY] THEN + ENSURES_EVENTS_WHILE_UP2_TAC `16` `pc + 0x110` `pc + 0x14c` fcopy_inv THEN + REPEAT CONJ_TAC THENL [ + ARITH_TAC; + ARM_SIM_TAC ~preprocess_tac:(TRY STRIP_EXISTS_ASSUM_TAC) + ~canonicalize_pc_diff:false MLDSA_REJ_UNIFORM_ETA4_EXEC (1--4) THEN + REWRITE_TAC[MULT_CLAUSES; WORD_ADD_0] THEN + REPEAT CONJ_TAC THEN TRY(CONV_TAC WORD_RULE) THEN DISCHARGE_SAFETY_PROPERTY_TAC; + REPEAT STRIP_TAC THEN + ARM_SIM_TAC ~preprocess_tac:(TRY STRIP_EXISTS_ASSUM_TAC) + ~canonicalize_pc_diff:false MLDSA_REJ_UNIFORM_ETA4_EXEC (1--15) THEN + CONJ_TAC THENL + [ASM_SIMP_TAC[FCOPY_BRANCH] THEN REWRITE_TAC[COND_RAND] THEN + COND_CASES_TAC THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + CONJ_TAC THENL + [REWRITE_TAC[ARITH_RULE `64*(i+1)=64*i+64`; ARITH_RULE `32*(i+1)=32*i+32`; + ARITH_RULE `16*(i+1)=16*i+16`] THEN CONV_TAC WORD_RULE; ALL_TAC] THEN + CONJ_TAC THENL + [REWRITE_TAC[ARITH_RULE `64*(i+1)=64*i+64`; ARITH_RULE `32*(i+1)=32*i+32`; + ARITH_RULE `16*(i+1)=16*i+16`] THEN CONV_TAC WORD_RULE; ALL_TAC] THEN + CONJ_TAC THENL + [REWRITE_TAC[ARITH_RULE `64*(i+1)=64*i+64`; ARITH_RULE `32*(i+1)=32*i+32`; + ARITH_RULE `16*(i+1)=16*i+16`] THEN CONV_TAC WORD_RULE; ALL_TAC] THEN + DISCHARGE_SAFETY_PROPERTY_TAC; + ARM_SIM_TAC ~preprocess_tac:(TRY STRIP_EXISTS_ASSUM_TAC) + ~canonicalize_pc_diff:false MLDSA_REJ_UNIFORM_ETA4_EXEC (1--3) THEN + DISCHARGE_SAFETY_PROPERTY_TAC]]]);; diff --git a/proofs/hol_light/x86_64/proofs/mldsa_rej_uniform_eta2_avx2_asm.ml b/proofs/hol_light/x86_64/proofs/mldsa_rej_uniform_eta2_avx2_asm.ml index 960ba1eac5..9c4f081ac0 100644 --- a/proofs/hol_light/x86_64/proofs/mldsa_rej_uniform_eta2_avx2_asm.ml +++ b/proofs/hol_light/x86_64/proofs/mldsa_rej_uniform_eta2_avx2_asm.ml @@ -855,7 +855,7 @@ let OP8_R8B_READ = prove let MOVZBL_R10_CAPTURE_TAC : tactic = RULE_ASSUM_TAC(CONV_RULE(REWRITE_CONV[OP8_R8B_READ] THENC ONCE_DEPTH_CONV COMPONENT_READ_OVER_WRITE_CONV));; -(* ZZCOLLAPSE / LACC8: reproved inline (the main-file let-names aren't in session scope). *) +(* ZZCOLLAPSE / LACC8: reproved inline (the corresponding names are not in scope here). *) let LACC8 = prove(`!m:byte. LENGTH(ACC_IDX m) <= 8`, GEN_TAC THEN REWRITE_TAC[ACC_IDX] THEN @@ -9378,3 +9378,3308 @@ let MLDSA_REJ_UNIFORM_ETA2_SUBROUTINE_MEMSAFE = (* Trailing subroutine-signature load for the constant-time harness. Loads *) (* AFTER both MEMSAFE theorems. *) needs "mldsa_native/x86_64/proofs/subroutine_signatures.ml";; + +(* ========================================================================= *) +(* Constant-time (secret-independent timing) machinery for rej_uniform_eta2. *) +(* Arch-neutral prelude shared with the aarch64 proof: the public *) +(* reject-mask projection and its list algebra, with one accept/reject bit *) +(* per nibble (accept = val < 15) and the accepted VALUES discarded. From *) +(* this bool list one recovers the per-group 8-bit table index (PACK_MASK8) *) +(* and the accepted counts (NUM_ACCEPTED = store-advance / trip-count *) +(* driver) — every secret-dependent address, but not the accepted values. *) +(* ========================================================================= *) + +let REJ_MASK_ETA2 = define + `REJ_MASK_ETA2 (l:byte list) : bool list = + MAP (\x:int16. val x < 15) (NIBBLES_OF_BYTES l)`;; + +(* Abstract core: #elements passing P = #`true`s in the boolean image. *) +let LENGTH_FILTER_EQ_LENGTH_FILTER_MAP = prove + (`!(P:A->bool) xs. + LENGTH(FILTER (\b:bool. b) (MAP P xs)) = LENGTH(FILTER P xs)`, + GEN_TAC THEN LIST_INDUCT_TAC THEN + REWRITE_TAC[MAP; FILTER; LENGTH] THEN + COND_CASES_TAC THEN ASM_REWRITE_TAC[LENGTH]);; + +(* Store-advance / trip-count bridge: #ACCEPTED nibbles = #`true`s in the *) +(* PUBLIC reject mask. Value-free. *) +let LENGTH_REJ_NIBBLES_ETA2_EQ_MASK = prove + (`!l:byte list. + LENGTH(REJ_NIBBLES_ETA2 l) = LENGTH(FILTER (\b:bool. b) (REJ_MASK_ETA2 l))`, + REWRITE_TAC[REJ_NIBBLES_ETA2; REJ_MASK_ETA2; + LENGTH_FILTER_EQ_LENGTH_FILTER_MAP]);; + +(* Public "accepted count" over a mask, additive over APPEND. *) +let NUM_ACCEPTED = define + `NUM_ACCEPTED (m:bool list) = LENGTH(FILTER (\b:bool. b) m)`;; + +let NUM_ACCEPTED_APPEND = prove + (`!m1 m2. NUM_ACCEPTED(APPEND m1 m2) = NUM_ACCEPTED m1 + NUM_ACCEPTED m2`, + REWRITE_TAC[NUM_ACCEPTED; FILTER_APPEND; LENGTH_APPEND]);; + +(* Public table-index witness: 8-bit LSB-first packing of an accept-mask *) +(* group. The compaction table is indexed by this 0..255 value. *) +let PACK_MASK8 = define + `PACK_MASK8 (bs:bool list) = + bitval(EL 0 bs) + 2 * bitval(EL 1 bs) + + 4 * bitval(EL 2 bs) + 8 * bitval(EL 3 bs) + + 16 * bitval(EL 4 bs) + 32 * bitval(EL 5 bs) + + 64 * bitval(EL 6 bs) + 128 * bitval(EL 7 bs)`;; + +let PACK_MASK8_BOUND = prove + (`!bs:bool list. PACK_MASK8 bs < 256`, + GEN_TAC THEN REWRITE_TAC[PACK_MASK8] THEN + MAP_EVERY (fun t -> MP_TAC(SPEC t BITVAL_BOUND)) + [`EL 0 (bs:bool list)`; `EL 1 (bs:bool list)`; `EL 2 (bs:bool list)`; + `EL 3 (bs:bool list)`; `EL 4 (bs:bool list)`; `EL 5 (bs:bool list)`; + `EL 6 (bs:bool list)`; `EL 7 (bs:bool list)`] THEN + ARITH_TAC);; + +(* weighted-sum <-> PACK_MASK8 of the nibble-ordered accept mask. *) +let PACK_CONNECT = prove + (`!b0 b1 b2 b3 b4 b5 b6 b7:bool. + 128 * bitval b0 + 64 * bitval b1 + 32 * bitval b2 + 16 * bitval b3 + + 8 * bitval b4 + 4 * bitval b5 + 2 * bitval b6 + bitval b7 = + PACK_MASK8 [b7;b6;b5;b4;b3;b2;b1;b0]`, + REWRITE_TAC[PACK_MASK8] THEN + CONV_TAC(ONCE_DEPTH_CONV EL_CONV) THEN ARITH_TAC);; + +(* byte-index SUB_LIST maps to nibble-index SUB_LIST at 2x offset/length. *) +let NIBBLES_OF_BYTES_SUB_LIST = prove + (`!l a b. NIBBLES_OF_BYTES(SUB_LIST(a,b) l) = + SUB_LIST(2*a,2*b)(NIBBLES_OF_BYTES l)`, + LIST_INDUCT_TAC THEN REPEAT GEN_TAC THEN + MAP_EVERY (fun v -> STRUCT_CASES_TAC(SPEC v num_CASES)) [`a:num`;`b:num`] THEN + ASM_REWRITE_TAC[NIBBLES_OF_BYTES; NIBBLE_PAIR; SUB_LIST_CLAUSES; APPEND; + MULT_CLAUSES; ADD_CLAUSES; ARITH_RULE `2 * SUC n = SUC(SUC(2*n))`] THEN + ASM_REWRITE_TAC[SUB_LIST_CLAUSES; APPEND]);; + +(* General-offset MAP/SUB_LIST commutation. *) +let SUB_LIST_MAP_GEN = prove + (`!(f:A->B) l a b. SUB_LIST(a,b)(MAP f l) = MAP f (SUB_LIST(a,b) l)`, + GEN_TAC THEN LIST_INDUCT_TAC THEN REPEAT GEN_TAC THEN + MAP_EVERY (fun v -> STRUCT_CASES_TAC(SPEC v num_CASES)) [`a:num`;`b:num`] THEN + ASM_REWRITE_TAC[MAP; SUB_LIST_CLAUSES]);; + +(* mask-level length-doubling commutation: hardware REJ_MASK_ETA2(SUB_LIST) *) +(* into SUB_LIST of the ATOMIC mask. *) +let REJ_MASK_ETA2_SUB_LIST = prove + (`!l a b. REJ_MASK_ETA2(SUB_LIST(a,b) l) = SUB_LIST(2*a,2*b)(REJ_MASK_ETA2 l)`, + REWRITE_TAC[REJ_MASK_ETA2; NIBBLES_OF_BYTES_SUB_LIST; SUB_LIST_MAP_GEN]);; + + +(* ------------------------------------------------------------------------- *) +(* Trip-count lemmas. *) +(* ------------------------------------------------------------------------- *) + +(* --- niblen(16N,inlist) = NUM_ACCEPTED(SUB_LIST(0,32N) mask): the public *) +(* re-expression of the (inlist-based) exit predicate over the mask. --- *) +let NIBLEN_EQ_NUMACC_ETA2 = prove + (`!(inlist:byte list) (N:num). + LENGTH(REJ_NIBBLES_ETA2(SUB_LIST(0,16 * N) inlist):int16 list) = + NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA2 inlist))`, + REPEAT GEN_TAC THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA2_EQ_MASK; NUM_ACCEPTED; + REJ_MASK_ETA2_SUB_LIST] THEN + REWRITE_TAC[MULT_CLAUSES; ARITH_RULE `2 * (16 * N) = 32 * N`]);; + +(* --- The mask-based trip count (public loop iteration count). --- *) +let N_OF_MASK_ETA2 = define + `N_OF_MASK_ETA2 (mask:bool list) : num = + minimal N. 120 < 16 * N \/ 248 < NUM_ACCEPTED(SUB_LIST(0,32 * N) mask)`;; + +(* --- Trip minimality (dual-exit crux), analogue of *) +(* MLDSA_ETA2_LOOP8_TRIP_MINIMAL. --- *) +let N_OF_MASK_ETA2_MINIMAL = prove + (`!(mask:bool list). + (120 < 16 * N_OF_MASK_ETA2 mask \/ + 248 < NUM_ACCEPTED(SUB_LIST(0,32 * N_OF_MASK_ETA2 mask) mask)) /\ + (!i. i < N_OF_MASK_ETA2 mask + ==> ~(120 < 16 * i) /\ + ~(248 < NUM_ACCEPTED(SUB_LIST(0,32 * i) mask)))`, + GEN_TAC THEN REWRITE_TAC[N_OF_MASK_ETA2] THEN + SUBGOAL_THEN + `?n. 120 < 16 * n \/ 248 < NUM_ACCEPTED(SUB_LIST(0,32 * n)(mask:bool list))` + ASSUME_TAC THENL + [EXISTS_TAC `8` THEN DISJ1_TAC THEN ARITH_TAC; ALL_TAC] THEN + FIRST_X_ASSUM(STRIP_ASSUME_TAC o REWRITE_RULE[MINIMAL]) THEN + ASM_REWRITE_TAC[] THEN + X_GEN_TAC `i:num` THEN DISCH_TAC THEN + REWRITE_TAC[GSYM DE_MORGAN_THM] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN + ASM_REWRITE_TAC[]);; + + +(* ival(word m) = &m for m below 2^63 (branch-condition normalization). *) +let IVAL_WORD_SMALL = prove + (`!m. m < 2 EXP 63 ==> ival(word m:int64) = &m`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN `val(word m:int64) = m` ASSUME_TAC THENL + [REWRITE_TAC[VAL_WORD; DIMINDEX_64] THEN MATCH_MP_TAC MOD_LT THEN + ASM_ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `~bit 63 (word m:int64)` ASSUME_TAC THENL + [REWRITE_TAC[BIT_WORD; DIMINDEX_64] THEN + SUBGOAL_THEN `m DIV 2 EXP 63 = 0` SUBST1_TAC THENL + [MATCH_MP_TAC DIV_LT THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + ASM_REWRITE_TAC[IVAL_VAL; DIMINDEX_64; ARITH_RULE `64 - 1 = 63`; + BITVAL_CLAUSES] THEN + INT_ARITH_TAC);; + +(* ========================================================================= *) +(* Constant-time (SAFE) proof layer. *) +(* *) +(* Scalar-tail cluster: the OFFSET-arm SAFE ingredients — head-guard leg, *) +(* per-byte body, full scalar-tail run, the at-p corollary, and the *) +(* scalar-tail / head-guard memaccess-recovery lemmas. *) +(* ========================================================================= *) + +(* --- Head-guard events + LEG1B_HEADGUARD_SAFE_ETA2 --- *) +(* SAFE leg1b head-guard step lemma (exit block, OFFSET arm): pc+86 @ pos 16N *) +(* -> pc+399, concrete public events. The 4-instruction head-guard segment *) +(* emits exactly two public EventJumps (eax-guard not-taken, ecx-guard taken).*) + +let f_ev_headguard_eta2 = define + `f_ev_headguard_eta2 (pc:num) = + [EventJump (word (pc + 106),word (pc + 399)); + EventJump (word (pc + 97),word (pc + 97))]`;; + +(* q86_safe / q399_safe : the MEMSAFE value predicates with the existential *) +(* events conjunct replaced by CONCRETE events (thread events-equality only; *) +(* memaccess is form-independent, recovered at assembly time). *) +(* OFFSET arm: 16*N=128 (N=8) always, so use concrete 128-form predicates - *) +(* self-consistent for stepping; the assembly bridges 16*N=128 when composing.*) +let q86_safe_eta2 = + let sv,body = dest_abs q86_ms_eta2 in + mk_abs(sv, mk_conj(subst[`128`,`16 * N`] (lhand body), `read events (s:x86state) = ec`));; +let q399_safe_eta2 = + let sv,body = dest_abs q399_ms_eta2 in + mk_abs(sv, mk_conj(subst[`128`,`16 * N`] (lhand body), + `read events (s:x86state) = APPEND (f_ev_headguard_eta2 pc) ec`));; + +let exoff = snd(strip_forall(concl EXIT_OFFSET_MS_ETA2));; +let ens = snd(dest_imp exoff);; +let frame = rand ens;; +let ens_hd = rator(rator(rator ens));; + +let leg1b_headguard_safe_tm = list_mk_forall + ([`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`; + `N:num`;`stackpointer:int64`;`e:(uarch_event)list`;`ec:(uarch_event)list`], + mk_imp(lhand exoff, + mk_comb(mk_comb(mk_comb(ens_hd, q86_safe_eta2), q399_safe_eta2), frame)));; + +let ja_eax_128 = + `~(&(val(word_zx(word(LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,128) inlist):int32 list)):int64):int32)):int - &248 = &(val(word_sub(word_zx(word(LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,128) inlist):int32 list)):int64):int32) (word 248):int32))) \/ val(word_sub(word_zx(word(LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,128) inlist):int32 list)):int64):int32) (word 248):int32) = 0`;; + +let ja_ecx_128 = + `~(~(&(val(word_zx(word(128):int64):int32)):int - &120 = &(val(word_sub(word_zx(word(128):int64):int32) (word 120):int32))) \/ val(word_sub(word_zx(word(128):int64):int32) (word 120):int32) = 0)`;; + +let LEG1B_HEADGUARD_SAFE_ETA2 = prove(leg1b_headguard_safe_tm, + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,128) inlist):int32 list) <= 248` ASSUME_TAC THENL + [REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA2_BYTES] THEN + SUBST1_TAC(SYM(ASSUME `16 * N = 128`)) THEN FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN + ENSURES_INIT_TAC "s0" THEN + SUBGOAL_THEN ja_eax_128 ASSUME_TAC THENL + [MATCH_MP_TAC JA_NOT_TAKEN_LE THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN ja_ecx_128 ASSUME_TAC THENL + [MATCH_MP_TAC JA_TAKEN_GT THEN CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + X86_STEPS_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC (1--4) THEN + ENSURES_FINAL_STATE_TAC THEN + ASM_REWRITE_TAC[f_ev_headguard_eta2; APPEND]);; + + +(* --- f_ev_scalar_body + SCALAR_TAIL_BODY_SAFE_ETA2 --- *) +(* SAFE scalar-tail per-byte BODY (leg2, land-the-body): pc+399 -> pc+399 *) +(* consuming input byte p, with CONCRETE PUBLIC events. f_ev_scalar_body is a *) +(* COND tree over the two PUBLIC nibble conditions (low<15, high<15). Proof = *) +(* SCALAR_TAIL_BODY_MEMSAFE_ETA2 with 2 swaps: *) +(* (a) setup no-strip: SCALAR_BODY_SETUP_ETA2 (not _MS) *) +(* (b) DISCHARGE_MEMSAFE_ASM_TAC -> SAFE_SCALAR_DISCHARGE_TAC (x4). *) + +let f_ev_scalar_body = define + `f_ev_scalar_body (res:int64) (buf:int64) (pc:num) (inlist:byte list) + (p:num) (outlen0:num) = + if val(EL p inlist) MOD 16 < 15 then + (if val(EL p inlist) DIV 16 < 15 then + [EventJump (word (pc + 542),word (pc + 399)); + EventStore (word_add res (word (4 * (outlen0 + 1))),4); + EventJump (word (pc + 501),word (pc + 501)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 481),word (pc + 481)); + EventStore (word_add res (word (4 * val (word outlen0:int64))),4); + EventJump (word (pc + 438),word (pc + 438)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 418),word (pc + 418)); + EventJump (word (pc + 410),word (pc + 410))] + else + [EventJump (word (pc + 501),word (pc + 399)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 481),word (pc + 481)); + EventStore (word_add res (word (4 * val (word outlen0:int64))),4); + EventJump (word (pc + 438),word (pc + 438)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 418),word (pc + 418)); + EventJump (word (pc + 410),word (pc + 410))]) + else + (if val(EL p inlist) DIV 16 < 15 then + [EventJump (word (pc + 542),word (pc + 399)); + EventStore (word_add res (word (4 * outlen0)),4); + EventJump (word (pc + 501),word (pc + 501)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 438),word (pc + 481)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 418),word (pc + 418)); + EventJump (word (pc + 410),word (pc + 410))] + else + [EventJump (word (pc + 501),word (pc + 399)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 438),word (pc + 481)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 418),word (pc + 418)); + EventJump (word (pc + 410),word (pc + 410))])`;; + +(* Concrete-events discharge (replaces DISCHARGE_MEMSAFE_ASM_TAC). Goal at *) +(* each branch end: read events sN = APPEND (f_ev_scalar_body ...) e /\ *) +(* memaccess_inbounds (f_ev_scalar_body ...) [buf,136;table,2048] [res,1024]. *) +(* Unfold the def; the branch conds (in the asl) reduce the COND uniformly; *) +(* events-eq closes by APPEND + the stepped events assumption; memaccess reuses *) +(* the MEMSAFE containment machinery (raw = public here, no bridge). *) +let SAFE_SCALAR_DISCHARGE_TAC = + REWRITE_TAC[f_ev_scalar_body] THEN + CONJ_TAC THENL + [ASM_REWRITE_TAC[APPEND]; + ASM_REWRITE_TAC[] THEN + REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND] THEN + REPEAT CONJ_TAC THEN + TRY(REPEAT ((DISJ1_TAC THEN CONTAINED_ASM_TAC) ORELSE DISJ2_TAC ORELSE + CONTAINED_ASM_TAC) THEN NO_TAC)];; + +(* Build the SAFE goal term: concrete events conjoined onto SCALAR_TAIL_BODY_ETA2's + pre & post (events OUTERMOST), universally over the extra `e`. outlen0 slot + uses the statement var `L`; the setup substitutes L->outlen0. *) +let scalar_body_safe_eta2_tm = + let qvars, body = strip_forall (concl SCALAR_TAIL_BODY_ETA2) in + let hyps_tm, ens = dest_imp body in + let ensc, ppf = strip_comb ens in + let pre = el 1 ppf and post = el 2 ppf and frame = el 3 ppf in + let sv, preb = dest_abs pre in + let sv2, postb = dest_abs post in + let fev = `f_ev_scalar_body res buf pc (inlist:byte list) p L` in + let eq_pre = `read events (s:x86state) = e` in + let eq_post = mk_conj + (mk_eq(`read events (s:x86state)`, mk_comb(mk_comb(`APPEND:(uarch_event)list->(uarch_event)list->(uarch_event)list`, fev), `e:(uarch_event)list`)), + list_mk_comb(`memaccess_inbounds`, + [fev; `[(buf:int64),136; (table:int64),2048]`; `[(res:int64),1024]`])) in + let pre' = mk_abs(sv, mk_conj(preb, vsubst[sv,`s:x86state`] eq_pre)) in + let post' = mk_abs(sv2, mk_conj(postb, vsubst[sv2,`s:x86state`] eq_post)) in + let ens' = list_mk_comb(ensc,[el 0 ppf; pre'; post'; frame]) in + list_mk_forall(qvars @ [`e:(uarch_event)list`], mk_imp(hyps_tm, ens'));; + +let SCALAR_TAIL_BODY_SAFE_ETA2 = prove + (scalar_body_safe_eta2_tm, + SCALAR_BODY_SETUP_ETA2 THEN + ASM_CASES_TAC `val(EL p (inlist:byte list)) MOD 16 < 15` THENL + [(* ============ ACCEPT-LOW (low<15): jae s10 NOT taken ============ *) + SUBGOAL_THEN `~(&(val(word_zx(word(val(EL p (inlist:byte list)) MOD 16):int64):int32)):int - &15 = &(val(word_sub(word_zx(word(val(EL p (inlist:byte list)) MOD 16):int64):int32) (word 15):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT_ETA2 THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + X86_VSTEPS_TAC EXEC_ETA2 (9--19) THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->t=`RAX`))c && can(find_term(fun t->t=`s19:x86state`))c + then ASSUME_TAC(REWRITE_RULE[MATCH_MP RAX_INC_ETA2 (ASSUME `outlen0<256`)] th) else NO_TAC) THEN + SUBGOAL_THEN `outlen0 + 1 < 256` ASSUME_TAC THENL + [REPEAT(FIRST_X_ASSUM(MP_TAC o check(fun th->let c=concl th in c=`outlen0<256`||c=`val(EL p (inlist:byte list)) MOD 16 < 15`||c=`~(outlen0=255/\val(EL p (inlist:byte list)) MOD 16 < 15)`))) THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `~(&(val(word_zx(word(outlen0+1):int64):int32)):int - &256 = &(val(word_sub(word_zx(word(outlen0+1):int64):int32) (word 256):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT_ETA2 THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + X86_VSTEPS_TAC EXEC_ETA2 (20--21) THEN + RELOAD_PREP_ETA2 `s21:x86state` THEN + X86_VSTEPS_TAC EXEC_ETA2 (22--24) THEN + RULE_ASSUM_TAC(REWRITE_RULE[R11_NIBBLE_VAL_ETA2]) THEN DISCARD_OLDSTATE_TAC "s24" THEN + ASM_CASES_TAC `val(EL p (inlist:byte list)) DIV 16 < 15` THENL + [(* ===== ACCEPT-ACCEPT ===== *) + SUBGOAL_THEN `~(&(val(word_zx(word(val(EL p (inlist:byte list)) DIV 16):int64):int32)):int - &15 = &(val(word_sub(word_zx(word(val(EL p (inlist:byte list)) DIV 16):int64):int32) (word 15):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT_ETA2 THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `val(word(outlen0+1):int64) = outlen0+1` ASSUME_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN MP_TAC(ASSUME `outlen0+1<256`) THEN ARITH_TAC; ALL_TAC] THEN + X86_VSTEPS_TAC EXEC_ETA2 (25--35) THEN + X86_VSTEPS_TAC EXEC_ETA2 (36--36) THEN DISCARD_OLDSTATE_TAC "s36" THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->t=`RAX`))c && can(find_term(fun t->t=`s36:x86state`))c + then ASSUME_TAC(REWRITE_RULE[MATCH_MP RAX_INC_ETA2 (ASSUME `outlen0+1<256`)] th) else NO_TAC) THEN + ENSURES_FINAL_STATE_TAC THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p+1) inlist):int32 list) = outlen0 + 2` ASSUME_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] LEN_STEP_BOTH_ETA2) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ASM_ARITH_TAC; ASM_REWRITE_TAC[]]; ALL_TAC] THEN + DISCH_THEN(fun th->REWRITE_TAC[th]) THEN + FIRST_ASSUM(fun th->if concl th=`LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p) inlist):int32 list) = outlen0` then REWRITE_TAC[th] else NO_TAC); ALL_TAC] THEN + ASM_REWRITE_TAC[ARITH_RULE `(outlen0+1)+1 = outlen0+2`] THEN + CONJ_TAC THENL + [TRY(CONJ_TAC THENL [RCX_INC_TAC; ALL_TAC]) THEN + SUBGOAL_THEN `REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p+1) inlist) = + APPEND (REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist)) + [word_sx(word_sub (word 2:int16) (word_umod (word(val(EL p (inlist:byte list)) MOD 16)) (word 5:int16))):int32; + word_sx(word_sub (word 2:int16) (word_umod (word(val(EL p (inlist:byte list)) DIV 16)) (word 5:int16))):int32]` SUBST1_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] REJ_STEP_BOTH_ETA2) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN MATCH_ACCEPT_TAC; ALL_TAC] THEN + SUBGOAL_THEN `4 * (outlen0 + 2) = 4 * outlen0 + 8` SUBST1_TAC THENL [ARITH_TAC; ALL_TAC] THEN + MP_TAC(ISPECL [`memory:(x86state,int64->byte)component`; `res:int64`; `s36:x86state`; + `REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list`; + `[word_sx(word_sub (word 2:int16) (word_umod (word(val(EL p (inlist:byte list)) MOD 16)) (word 5:int16))):int32; + word_sx(word_sub (word 2:int16) (word_umod (word(val(EL p (inlist:byte list)) DIV 16)) (word 5:int16))):int32]`; + `4*outlen0`; `8`] BYTES_EQ_NUM_OF_WORDLIST_APPEND) THEN + ANTS_TAC THENL + [REWRITE_TAC[DIMINDEX_32] THEN + FIRST_ASSUM(fun th->if concl th=`LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p) inlist):int32 list) = outlen0` then REWRITE_TAC[th] else NO_TAC) THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN CONJ_TAC THENL + [FIRST_ASSUM ACCEPT_TAC; + GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [GSYM(REWRITE_CONV[APPEND] `APPEND [a:int32] [b:int32]`)] THEN + SUBGOAL_THEN `(8:num) = 4 + 4` SUBST1_TAC THENL [ARITH_TAC; ALL_TAC] THEN + MP_TAC(ISPECL [`memory:(x86state,int64->byte)component`; `word_add res (word(4*outlen0)):int64`; `s36:x86state`; + `[word_sx(word_sub (word 2:int16) (word_umod (word(val(EL p (inlist:byte list)) MOD 16)) (word 5:int16))):int32]`; + `[word_sx(word_sub (word 2:int16) (word_umod (word(val(EL p (inlist:byte list)) DIV 16)) (word 5:int16))):int32]`; + `4`; `4`] BYTES_EQ_NUM_OF_WORDLIST_APPEND) THEN + ANTS_TAC THENL [REWRITE_TAC[DIMINDEX_32; LENGTH] THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[NUM_OF_WORDLIST_SINGLETON_INT32] THEN + SUBGOAL_THEN `val(word outlen0:int64) = outlen0` ASSUME_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN MP_TAC(ASSUME `outlen0<256`) THEN ARITH_TAC; ALL_TAC] THEN + ETA2_STORE_SPEC_TAC `s36:x86state` `val(EL p (inlist:byte list)) MOD 16` THEN + ETA2_STORE_SPEC_TAC `s36:x86state` `val(EL p (inlist:byte list)) DIV 16` THEN + CONJ_TAC THENL + [FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->try fst(dest_const t)="bytes32" with _->false))c && can(find_term(fun t->t=`val(EL p (inlist:byte list)) MOD 16`))c && not(can(find_term is_cond)c) + then MP_TAC th else NO_TAC) THEN + ASM_REWRITE_TAC[] THEN + STORE4_FROM_SPEC `s36:x86state` `word_add res (word(4 * outlen0)):int64`; + SUBGOAL_THEN `word_add (word_add res (word (4 * outlen0))) (word 4):int64 = word_add res (word (4 * (outlen0+1)))` SUBST1_TAC THENL + [CONV_TAC WORD_RULE; ALL_TAC] THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->try fst(dest_const t)="bytes32" with _->false))c && can(find_term(fun t->t=`val(EL p (inlist:byte list)) DIV 16`))c && not(can(find_term is_cond)c) + then MP_TAC th else NO_TAC) THEN + ASM_REWRITE_TAC[] THEN + STORE4_FROM_SPEC `s36:x86state` `word_add res (word(4 * (outlen0+1))):int64`]]; + SAFE_SCALAR_DISCHARGE_TAC]; + (* ===== LO-only ===== *) + SUBGOAL_THEN `&(val(word_zx(word(val(EL p (inlist:byte list)) DIV 16):int64):int32)):int - &15 = &(val(word_sub(word_zx(word(val(EL p (inlist:byte list)) DIV 16):int64):int32) (word 15):int32))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_TAKEN_GE_ETA2 THEN CONJ_TAC THENL + [MP_TAC(ASSUME `~(val(EL p (inlist:byte list)) DIV 16 < 15)`) THEN ARITH_TAC; + MP_TAC(ISPEC `EL p (inlist:byte list)` VAL_BOUND) THEN REWRITE_TAC[DIMINDEX_8] THEN + MP_TAC(SPECL[`val(EL p (inlist:byte list))`;`16`] DIV_LE) THEN ARITH_TAC]; ALL_TAC] THEN + X86_VSTEPS_TAC EXEC_ETA2 (25--26) THEN DISCARD_OLDSTATE_TAC "s26" THEN + ENSURES_FINAL_STATE_TAC THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p+1) inlist):int32 list) = outlen0 + 1` ASSUME_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] LEN_STEP_LO_ETA2) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ASM_ARITH_TAC; ASM_REWRITE_TAC[]]; ALL_TAC] THEN + DISCH_THEN(fun th->REWRITE_TAC[th]) THEN + FIRST_ASSUM(fun th->if concl th=`LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p) inlist):int32 list) = outlen0` then REWRITE_TAC[th] else NO_TAC); ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN + CONJ_TAC THENL + [TRY(CONJ_TAC THENL [RCX_INC_TAC; ALL_TAC]) THEN + SUBGOAL_THEN `REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p+1) inlist) = + APPEND (REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist)) + [word_sx(word_sub (word 2:int16) (word_umod (word(val(EL p (inlist:byte list)) MOD 16)) (word 5:int16))):int32]` SUBST1_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] REJ_STEP_LO_ETA2) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN MATCH_ACCEPT_TAC; ALL_TAC] THEN + SUBGOAL_THEN `4 * (outlen0 + 1) = 4 * outlen0 + 4` SUBST1_TAC THENL [ARITH_TAC; ALL_TAC] THEN + MP_TAC(ISPECL [`memory:(x86state,int64->byte)component`; `res:int64`; `s26:x86state`; + `REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list`; + `[word_sx(word_sub (word 2:int16) (word_umod (word(val(EL p (inlist:byte list)) MOD 16)) (word 5:int16))):int32]`; + `4*outlen0`; `4`] BYTES_EQ_NUM_OF_WORDLIST_APPEND) THEN + ANTS_TAC THENL + [REWRITE_TAC[DIMINDEX_32] THEN + FIRST_ASSUM(fun th->if concl th=`LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p) inlist):int32 list) = outlen0` then REWRITE_TAC[th] else NO_TAC) THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[NUM_OF_WORDLIST_SINGLETON_INT32] THEN + CONJ_TAC THENL + [FIRST_ASSUM ACCEPT_TAC; + SUBGOAL_THEN `val(word outlen0:int64) = outlen0` ASSUME_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN MP_TAC(ASSUME `outlen0<256`) THEN ARITH_TAC; ALL_TAC] THEN + ETA2_STORE_SPEC_TAC `s26:x86state` `val(EL p (inlist:byte list)) MOD 16` THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->try fst(dest_const t)="bytes32" with _->false))c && can(find_term(fun t->t=`val(EL p (inlist:byte list)) MOD 16`))c && not(can(find_term is_cond)c) + then MP_TAC th else NO_TAC) THEN + ASM_REWRITE_TAC[] THEN + STORE4_FROM_SPEC `s26:x86state` `word_add res (word(4 * outlen0)):int64`]; + SAFE_SCALAR_DISCHARGE_TAC]]; + (* ============ REJECT-LOW (low>=15): jae s10 TAKEN -> movzbl s11 ============ *) + SUBGOAL_THEN `&(val(word_zx(word(val(EL p (inlist:byte list)) MOD 16):int64):int32)):int - &15 = &(val(word_sub(word_zx(word(val(EL p (inlist:byte list)) MOD 16):int64):int32) (word 15):int32))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_TAKEN_GE_ETA2 THEN CONJ_TAC THENL + [MP_TAC(ASSUME `~(val(EL p (inlist:byte list)) MOD 16 < 15)`) THEN ARITH_TAC; + MP_TAC(SPECL[`val(EL p (inlist:byte list))`;`16`] MOD_LT_EQ) THEN ARITH_TAC]; ALL_TAC] THEN + X86_VSTEPS_TAC EXEC_ETA2 (9--10) THEN + RELOAD_PREP_ETA2 `s10:x86state` THEN + X86_VSTEPS_TAC EXEC_ETA2 (11--13) THEN + RULE_ASSUM_TAC(REWRITE_RULE[R11_NIBBLE_VAL_ETA2]) THEN DISCARD_OLDSTATE_TAC "s13" THEN + ASM_CASES_TAC `val(EL p (inlist:byte list)) DIV 16 < 15` THENL + [(* ===== HI-only ===== *) + SUBGOAL_THEN `~(&(val(word_zx(word(val(EL p (inlist:byte list)) DIV 16):int64):int32)):int - &15 = &(val(word_sub(word_zx(word(val(EL p (inlist:byte list)) DIV 16):int64):int32) (word 15):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT_ETA2 THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `val(word outlen0:int64) = outlen0` ASSUME_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN MP_TAC(ASSUME `outlen0<256`) THEN ARITH_TAC; ALL_TAC] THEN + X86_VSTEPS_TAC EXEC_ETA2 (14--23) THEN + X86_VSTEPS_TAC EXEC_ETA2 (24--25) THEN DISCARD_OLDSTATE_TAC "s25" THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->t=`RAX`))c && can(find_term(fun t->t=`s25:x86state`))c + then ASSUME_TAC(REWRITE_RULE[MATCH_MP RAX_INC_ETA2 (ASSUME `outlen0<256`)] th) else NO_TAC) THEN + ENSURES_FINAL_STATE_TAC THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p+1) inlist):int32 list) = outlen0 + 1` ASSUME_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] LEN_STEP_HI_ETA2) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ASM_ARITH_TAC; ASM_REWRITE_TAC[]]; ALL_TAC] THEN + DISCH_THEN(fun th->REWRITE_TAC[th]) THEN + FIRST_ASSUM(fun th->if concl th=`LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p) inlist):int32 list) = outlen0` then REWRITE_TAC[th] else NO_TAC); ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN + CONJ_TAC THENL + [TRY(CONJ_TAC THENL [RCX_INC_TAC; ALL_TAC]) THEN + SUBGOAL_THEN `REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p+1) inlist) = + APPEND (REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist)) + [word_sx(word_sub (word 2:int16) (word_umod (word(val(EL p (inlist:byte list)) DIV 16)) (word 5:int16))):int32]` SUBST1_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] REJ_STEP_HI_ETA2) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN MATCH_ACCEPT_TAC; ALL_TAC] THEN + SUBGOAL_THEN `4 * (outlen0 + 1) = 4 * outlen0 + 4` SUBST1_TAC THENL [ARITH_TAC; ALL_TAC] THEN + MP_TAC(ISPECL [`memory:(x86state,int64->byte)component`; `res:int64`; `s25:x86state`; + `REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list`; + `[word_sx(word_sub (word 2:int16) (word_umod (word(val(EL p (inlist:byte list)) DIV 16)) (word 5:int16))):int32]`; + `4*outlen0`; `4`] BYTES_EQ_NUM_OF_WORDLIST_APPEND) THEN + ANTS_TAC THENL + [REWRITE_TAC[DIMINDEX_32] THEN + FIRST_ASSUM(fun th->if concl th=`LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p) inlist):int32 list) = outlen0` then REWRITE_TAC[th] else NO_TAC) THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[NUM_OF_WORDLIST_SINGLETON_INT32] THEN + CONJ_TAC THENL + [FIRST_ASSUM ACCEPT_TAC; + ETA2_STORE_SPEC_TAC `s25:x86state` `val(EL p (inlist:byte list)) DIV 16` THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->try fst(dest_const t)="bytes32" with _->false))c && can(find_term(fun t->t=`val(EL p (inlist:byte list)) DIV 16`))c && not(can(find_term is_cond)c) + then MP_TAC th else NO_TAC) THEN + ASM_REWRITE_TAC[] THEN + STORE4_FROM_SPEC `s25:x86state` `word_add res (word(4 * outlen0)):int64`]; + SAFE_SCALAR_DISCHARGE_TAC]; + (* ===== NONE (low>=15, high>=15): jae s15 TAKEN -> pc+399, no store ===== *) + SUBGOAL_THEN `&(val(word_zx(word(val(EL p (inlist:byte list)) DIV 16):int64):int32)):int - &15 = &(val(word_sub(word_zx(word(val(EL p (inlist:byte list)) DIV 16):int64):int32) (word 15):int32))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_TAKEN_GE_ETA2 THEN CONJ_TAC THENL + [MP_TAC(ASSUME `~(val(EL p (inlist:byte list)) DIV 16 < 15)`) THEN ARITH_TAC; + MP_TAC(ISPEC `EL p (inlist:byte list)` VAL_BOUND) THEN REWRITE_TAC[DIMINDEX_8] THEN + MP_TAC(SPECL[`val(EL p (inlist:byte list))`;`16`] DIV_LE) THEN ARITH_TAC]; ALL_TAC] THEN + X86_VSTEPS_TAC EXEC_ETA2 (14--15) THEN DISCARD_OLDSTATE_TAC "s15" THEN + ENSURES_FINAL_STATE_TAC THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p+1) inlist):int32 list) = outlen0` ASSUME_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] LEN_STEP_NONE_ETA2) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ASM_ARITH_TAC; ASM_REWRITE_TAC[]]; ALL_TAC] THEN + DISCH_THEN(fun th->REWRITE_TAC[th]) THEN + FIRST_ASSUM(fun th->if concl th=`LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p) inlist):int32 list) = outlen0` then REWRITE_TAC[th] else NO_TAC); ALL_TAC] THEN + SUBGOAL_THEN `REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p+1) inlist):int32 list = REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p) inlist)` ASSUME_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] REJ_STEP_NONE_ETA2) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN MATCH_ACCEPT_TAC; ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN + TRY RCX_INC_TAC THEN SAFE_SCALAR_DISCHARGE_TAC]]);; + + +(* --- f_ev_scalar_tail + FEV_TAIL_* --- *) +(* f_ev_scalar_tail — the public event trace of the eta2 scalar tail *) +(* (byte loop pc+399 .. pc+542), by recursion on the byte budget d. *) +(* Terminals: *) +(* count-exit (outlen>=256): [Jump(410,542)] *) +(* offset-exit (p>=136,<256): [Jump(418,542); Jump(410,410)] *) +(* mid-byte (outlen=255,low<15): [Jump(481,542); Store(res+1020,4); *) +(* Jump(438,438); Load(buf+p,1); Jump(418,418); Jump(410,410)] *) +(* recursive: APPEND (f_ev_scalar_tail d .. (p+1)) (f_ev_scalar_body .. p) *) +(* (events prepend: later segment is the APPEND-left/newer prefix). *) +(* Threads events-EQUALITY only (memaccess recovered separately). *) + +let f_ev_scalar_tail = define + `(f_ev_scalar_tail 0 (res:int64) (buf:int64) (pc:num) (inlist:byte list) (p:num) = + (if 256 <= LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list) + then [EventJump (word (pc + 410),word (pc + 542))] + else [EventJump (word (pc + 418),word (pc + 542)); + EventJump (word (pc + 410),word (pc + 410))])) /\ + (f_ev_scalar_tail (SUC d) (res:int64) (buf:int64) (pc:num) (inlist:byte list) (p:num) = + (if 256 <= LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list) + then [EventJump (word (pc + 410),word (pc + 542))] + else if p = 136 + then [EventJump (word (pc + 418),word (pc + 542)); + EventJump (word (pc + 410),word (pc + 410))] + else if LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list) = 255 /\ + val(EL p inlist) MOD 16 < 15 + then [EventJump (word (pc + 481),word (pc + 542)); + EventStore (word_add res (word 1020),4); + EventJump (word (pc + 438),word (pc + 438)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 418),word (pc + 418)); + EventJump (word (pc + 410),word (pc + 410))] + else APPEND (f_ev_scalar_tail d res buf pc inlist (p+1)) + (f_ev_scalar_body res buf pc inlist p + (LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list)))))`;; + +(* -- Per-terminal reduction lemmas (conditional rewrites, uniform over d). -- *) +let FEV_TAIL_COUNT = prove + (`!d res buf pc (inlist:byte list) p. + 256 <= LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list) + ==> f_ev_scalar_tail d res buf pc inlist p = + [EventJump (word (pc + 410),word (pc + 542))]`, + REPEAT GEN_TAC THEN DISCH_TAC THEN + STRUCT_CASES_TAC (SPEC `d:num` num_CASES) THEN + ASM_REWRITE_TAC[f_ev_scalar_tail]);; + +let FEV_TAIL_OFFSET = prove + (`!d res buf pc (inlist:byte list) p. + ~(256 <= LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list)) /\ + p = 136 + ==> f_ev_scalar_tail d res buf pc inlist p = + [EventJump (word (pc + 418),word (pc + 542)); + EventJump (word (pc + 410),word (pc + 410))]`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + STRUCT_CASES_TAC (SPEC `d:num` num_CASES) THEN + ASM_REWRITE_TAC[f_ev_scalar_tail]);; + +let FEV_TAIL_MIDBYTE = prove + (`!d res buf pc (inlist:byte list) p. + ~(256 <= LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list)) /\ + ~(p = 136) /\ + LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list) = 255 /\ + val(EL p inlist) MOD 16 < 15 + ==> f_ev_scalar_tail (SUC d) res buf pc inlist p = + [EventJump (word (pc + 481),word (pc + 542)); + EventStore (word_add res (word 1020),4); + EventJump (word (pc + 438),word (pc + 438)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 418),word (pc + 418)); + EventJump (word (pc + 410),word (pc + 410))]`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + ASM_REWRITE_TAC[f_ev_scalar_tail]);; + +let FEV_TAIL_REC = prove + (`!d res buf pc (inlist:byte list) p. + ~(256 <= LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list)) /\ + ~(p = 136) /\ + ~(LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list) = 255 /\ + val(EL p inlist) MOD 16 < 15) + ==> f_ev_scalar_tail (SUC d) res buf pc inlist p = + APPEND (f_ev_scalar_tail d res buf pc inlist (p+1)) + (f_ev_scalar_body res buf pc inlist p + (LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list)))`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + ASM_REWRITE_TAC[f_ev_scalar_tail]);; + + +(* --- SCALAR_TAIL_RUN_SAFE_ETA2 --- *) +(* SCALAR_TAIL_RUN_SAFE_ETA2 — the SAFE (constant-time) scalar tail run *) +(* (byte loop pc+399 -> pc+542) with CONCRETE PUBLIC events *) +(* (f_ev_scalar_tail). Mirrors SCALAR_TAIL_RUN_ETA2 (value) with: *) +(* - pre : + read events s = e (concrete anchor; NO strip) *) +(* - post : + read events s = APPEND (f_ev_scalar_tail d res buf pc inlist p) e *) +(* (events-EQUALITY only; memaccess recovered separately). Events *) +(* threaded DEEP-RIGHT (conj_append_right) to keep the canonical *) +(* bytes_loaded /\ RIP=.. /\ REST shape ENSURES_SEQUENCE needs. *) +(* Terminal exits close by reducing f_ev_scalar_tail (FEV_TAIL_COUNT/OFFSET/ *) +(* MIDBYTE) + APPEND. Recursive leg composes SCALAR_TAIL_BODY_SAFE_ETA2 + the *) +(* IH via ENSURES_SEQUENCE, with the IH's `e` set to APPEND(f_ev_body p L)e *) +(* and R pre-rewritten via FEV_TAIL_REC + GSYM APPEND_ASSOC to match IH_post. *) +(* ========================================================================= *) + +let EXEC_ETA2 = MLDSA_REJ_UNIFORM_ETA2_EXEC;; + +let rec conj_append_right t ev = + if is_conj t then + let l,r = dest_conj t in mk_conj(l, conj_append_right r ev) + else mk_conj(t, ev);; + +let scalar_run_safe_eta2_tm = + let qvars, body = strip_forall (concl SCALAR_TAIL_RUN_ETA2) in + let hyps_tm, ens = dest_imp body in + let ensc, ppf = strip_comb ens in + let pre = el 1 ppf and post = el 2 ppf and frame = el 3 ppf in + let sv, preb = dest_abs pre in + let sv2, postb = dest_abs post in + let fev = `f_ev_scalar_tail d res buf pc (inlist:byte list) p` in + let eq_pre = `read events (s:x86state) = e` in + let eq_post = mk_eq(`read events (s:x86state)`, + mk_comb(mk_comb(`APPEND:(uarch_event)list->(uarch_event)list->(uarch_event)list`, fev), `e:(uarch_event)list`)) in + let pre' = mk_abs(sv, conj_append_right preb (vsubst[sv,`s:x86state`] eq_pre)) in + let post' = mk_abs(sv2, conj_append_right postb (vsubst[sv2,`s:x86state`] eq_post)) in + let ens' = list_mk_comb(ensc,[el 0 ppf; pre'; post'; frame]) in + list_mk_forall(qvars @ [`e:(uarch_event)list`], mk_imp(hyps_tm, ens'));; + + +let SCALAR_TAIL_RUN_SAFE_ETA2 = prove + (scalar_run_safe_eta2_tm, + INDUCT_TAC THENL + [(* ================= BASE CASE: d = 0 => p = 136 ================= *) + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN `p = 136` SUBST_ALL_TAC THENL + [REPEAT(FIRST_X_ASSUM(MP_TAC o check (fun th -> let c=concl th in c=`136 - p <= 0` || c=`p <= 136`))) THEN ARITH_TAC; ALL_TAC] THEN + MP_TAC(SPEC `inlist:byte list` SUB_LIST_BYTE_136) THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN + RULE_ASSUM_TAC(REWRITE_RULE[ASSUME `SUB_LIST(0,136) (inlist:byte list) = inlist`]) THEN + REWRITE_TAC[ASSUME `SUB_LIST(0,136) (inlist:byte list) = inlist`] THEN + ASM_CASES_TAC `LENGTH(REJ_SAMPLE_ETA2_BYTES inlist:int32 list) = 256` THENL + [(* --- BASE COUNT-EXIT: outlen = 256 --- *) + MP_TAC(SPEC `REJ_SAMPLE_ETA2_BYTES inlist:int32 list` SUB_LIST_256_LE) THEN + ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN DISCH_TAC THEN + REWRITE_TAC[ASSUME `LENGTH(REJ_SAMPLE_ETA2_BYTES inlist:int32 list) = 256`] THEN + REWRITE_TAC[ASSUME `SUB_LIST(0,256)(REJ_SAMPLE_ETA2_BYTES inlist:int32 list) = REJ_SAMPLE_ETA2_BYTES inlist`] THEN + ENSURES_INIT_TAC "s0" THEN + SUBGOAL_THEN `&(val(word_zx(word 256:int64):int32)):int - &256 = &(val(word_sub(word_zx(word 256:int64):int32) (word 256):int32))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_TAKEN_GE_ETA2 THEN CONJ_TAC THENL [ARITH_TAC; CONV_TAC NUM_REDUCE_CONV]; ALL_TAC] THEN + X86_VSTEPS_TAC EXEC_ETA2 (1--2) THEN + ENSURES_FINAL_STATE_TAC THEN + SUBGOAL_THEN `f_ev_scalar_tail 0 res buf pc (inlist:byte list) 136 = [EventJump (word (pc + 410),word (pc + 542))]` SUBST1_TAC THENL + [MATCH_MP_TAC FEV_TAIL_COUNT THEN + SUBGOAL_THEN `SUB_LIST(0,136)(inlist:byte list) = inlist` SUBST1_TAC THENL + [MATCH_MP_TAC SUB_LIST_BYTE_136 THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + REWRITE_TAC[ASSUME `LENGTH(REJ_SAMPLE_ETA2_BYTES inlist:int32 list) = 256`] THEN + REWRITE_TAC[LENGTH_BUTLAST_TMC_ETA2] THEN ASM_REWRITE_TAC[APPEND]; + (* --- BASE OFFSET-EXIT: outlen < 256, p = 136 --- *) + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA2_BYTES inlist:int32 list) < 256` ASSUME_TAC THENL + [REPEAT(FIRST_X_ASSUM(MP_TAC o check (fun th -> let c=concl th in c=`LENGTH(REJ_SAMPLE_ETA2_BYTES inlist:int32 list) <= 256` || c=`~(LENGTH(REJ_SAMPLE_ETA2_BYTES inlist:int32 list) = 256)`))) THEN ARITH_TAC; ALL_TAC] THEN + MP_TAC(SPEC `REJ_SAMPLE_ETA2_BYTES inlist:int32 list` SUB_LIST_256_LE) THEN + ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN DISCH_TAC THEN + REWRITE_TAC[ASSUME `SUB_LIST(0,256)(REJ_SAMPLE_ETA2_BYTES inlist:int32 list) = REJ_SAMPLE_ETA2_BYTES inlist`] THEN + ENSURES_INIT_TAC "s0" THEN + SUBGOAL_THEN `~(&(val(word_zx(word(LENGTH(REJ_SAMPLE_ETA2_BYTES inlist:int32 list)):int64):int32)):int - &256 = &(val(word_sub(word_zx(word(LENGTH(REJ_SAMPLE_ETA2_BYTES inlist:int32 list)):int64):int32) (word 256):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT_ETA2 THEN ASM_REWRITE_TAC[] THEN CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + SUBGOAL_THEN `&(val(word_zx(word 136:int64):int32)):int - &136 = &(val(word_sub(word_zx(word 136:int64):int32) (word 136):int32))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_TAKEN_GE_ETA2 THEN CONJ_TAC THENL [ARITH_TAC; CONV_TAC NUM_REDUCE_CONV]; ALL_TAC] THEN + X86_VSTEPS_TAC EXEC_ETA2 (1--4) THEN + ENSURES_FINAL_STATE_TAC THEN + SUBGOAL_THEN `f_ev_scalar_tail 0 res buf pc (inlist:byte list) 136 = + [EventJump (word (pc + 418),word (pc + 542)); EventJump (word (pc + 410),word (pc + 410))]` SUBST1_TAC THENL + [MATCH_MP_TAC FEV_TAIL_OFFSET THEN + SUBGOAL_THEN `SUB_LIST(0,136)(inlist:byte list) = inlist` SUBST1_TAC THENL + [MATCH_MP_TAC SUB_LIST_BYTE_136 THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + REWRITE_TAC[NOT_LE] THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + REWRITE_TAC[LENGTH_BUTLAST_TMC_ETA2] THEN ASM_REWRITE_TAC[APPEND]]; + (* ================= STEP CASE: SUC d ================= *) + REPEAT GEN_TAC THEN STRIP_TAC THEN + ASM_CASES_TAC `256 <= LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list)` THENL + [(* --- STEP COUNT-EXIT: outlen >= 256 (=256 by invariant) --- *) + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list) = 256` ASSUME_TAC THENL + [ASM_ARITH_TAC; ALL_TAC] THEN + MP_TAC(SPECL [`inlist:byte list`; `p:num`] SUB_LIST_256_PREFIX_GE) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN DISCH_TAC THEN + MP_TAC(SPEC `REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list` SUB_LIST_256_LE) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[LE_REFL]; ALL_TAC] THEN DISCH_TAC THEN + SUBGOAL_THEN `SUB_LIST(0,256)(REJ_SAMPLE_ETA2_BYTES inlist:int32 list) = REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist)` ASSUME_TAC THENL + [ASM_REWRITE_TAC[]; ALL_TAC] THEN + REWRITE_TAC[ASSUME `SUB_LIST(0,256)(REJ_SAMPLE_ETA2_BYTES inlist:int32 list) = REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist)`; + ASSUME `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list) = 256`] THEN + ENSURES_INIT_TAC "s0" THEN + SUBGOAL_THEN `&(val(word_zx(word 256:int64):int32)):int - &256 = &(val(word_sub(word_zx(word 256:int64):int32) (word 256):int32))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_TAKEN_GE_ETA2 THEN CONJ_TAC THENL [ARITH_TAC; CONV_TAC NUM_REDUCE_CONV]; ALL_TAC] THEN + X86_VSTEPS_TAC EXEC_ETA2 (1--2) THEN + ENSURES_FINAL_STATE_TAC THEN + SUBGOAL_THEN `f_ev_scalar_tail (SUC d) res buf pc (inlist:byte list) p = [EventJump (word (pc + 410),word (pc + 542))]` SUBST1_TAC THENL + [MATCH_MP_TAC FEV_TAIL_COUNT THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + REWRITE_TAC[ASSUME `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list) = 256`; LENGTH_BUTLAST_TMC_ETA2] THEN + ASM_REWRITE_TAC[APPEND]; + (* --- not count-exit: outlen < 256 --- *) + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list) < 256` ASSUME_TAC THENL + [ASM_ARITH_TAC; ALL_TAC] THEN + ASM_CASES_TAC `p = 136` THENL + [(* --- STEP OFFSET-EXIT: p = 136 --- *) + FIRST_X_ASSUM(SUBST_ALL_TAC o check (fun th -> concl th = `p = 136`)) THEN + MP_TAC(SPEC `inlist:byte list` SUB_LIST_BYTE_136) THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN + RULE_ASSUM_TAC(REWRITE_RULE[ASSUME `SUB_LIST(0,136) (inlist:byte list) = inlist`]) THEN + REWRITE_TAC[ASSUME `SUB_LIST(0,136) (inlist:byte list) = inlist`] THEN + MP_TAC(SPEC `REJ_SAMPLE_ETA2_BYTES inlist:int32 list` SUB_LIST_256_LE) THEN + ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN DISCH_TAC THEN + REWRITE_TAC[ASSUME `SUB_LIST(0,256)(REJ_SAMPLE_ETA2_BYTES inlist:int32 list) = REJ_SAMPLE_ETA2_BYTES inlist`] THEN + ENSURES_INIT_TAC "s0" THEN + SUBGOAL_THEN `~(&(val(word_zx(word(LENGTH(REJ_SAMPLE_ETA2_BYTES inlist:int32 list)):int64):int32)):int - &256 = &(val(word_sub(word_zx(word(LENGTH(REJ_SAMPLE_ETA2_BYTES inlist:int32 list)):int64):int32) (word 256):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT_ETA2 THEN ASM_REWRITE_TAC[] THEN CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + SUBGOAL_THEN `&(val(word_zx(word 136:int64):int32)):int - &136 = &(val(word_sub(word_zx(word 136:int64):int32) (word 136):int32))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_TAKEN_GE_ETA2 THEN CONJ_TAC THENL [ARITH_TAC; CONV_TAC NUM_REDUCE_CONV]; ALL_TAC] THEN + X86_VSTEPS_TAC EXEC_ETA2 (1--4) THEN + ENSURES_FINAL_STATE_TAC THEN + SUBGOAL_THEN `f_ev_scalar_tail (SUC d) res buf pc (inlist:byte list) 136 = + [EventJump (word (pc + 418),word (pc + 542)); EventJump (word (pc + 410),word (pc + 410))]` SUBST1_TAC THENL + [MATCH_MP_TAC FEV_TAIL_OFFSET THEN + SUBGOAL_THEN `SUB_LIST(0,136)(inlist:byte list) = inlist` SUBST1_TAC THENL + [MATCH_MP_TAC SUB_LIST_BYTE_136 THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + REWRITE_TAC[NOT_LE] THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + REWRITE_TAC[LENGTH_BUTLAST_TMC_ETA2] THEN ASM_REWRITE_TAC[APPEND]; + (* --- p < 136 --- *) + SUBGOAL_THEN `p < 136` ASSUME_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN + ASM_CASES_TAC `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list) = 255 /\ val(EL p (inlist:byte list)) MOD 16 < 15` THENL + [(* --- STEP MID-BYTE EXIT: outlen=255, low<15 --- *) + FIRST_X_ASSUM(CONJUNCTS_THEN ASSUME_TAC o check (fun th -> is_conj(concl th) && can(find_term(fun t->t=`val(EL p (inlist:byte list)) MOD 16`))(concl th))) THEN + SUBGOAL_THEN `256 <= LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p+1) inlist):int32 list)` ASSUME_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] LENGTH_REJ_SAMPLE_ETA2_BYTES_STEP_1) THEN + ASM_REWRITE_TAC[] THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `?rest. REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p+1) inlist):int32 list = + APPEND (APPEND (REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist)) + [word_sx(word_sub (word 2:int16) (word_umod (word(val(EL p (inlist:byte list)) MOD 16)) (word 5:int16))):int32]) rest` + STRIP_ASSUME_TAC THENL + [ASM_CASES_TAC `val(EL p (inlist:byte list)) DIV 16 < 15` THENL + [EXISTS_TAC `[word_sx(word_sub (word 2:int16) (word_umod (word(val(EL p (inlist:byte list)) DIV 16)) (word 5:int16))):int32]` THEN + MP_TAC(SPECL[`inlist:byte list`;`p:num`] REJ_STEP_BOTH_ETA2) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[APPEND; GSYM APPEND_ASSOC]; + EXISTS_TAC `[]:int32 list` THEN + MP_TAC(SPECL[`inlist:byte list`;`p:num`] REJ_STEP_LO_ETA2) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[APPEND_NIL]]; ALL_TAC] THEN + MP_TAC(SPECL [`inlist:byte list`; `p+1`] SUB_LIST_256_PREFIX_GE) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN DISCH_TAC THEN + SUBGOAL_THEN `LENGTH(APPEND (REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist)) + [word_sx(word_sub (word 2:int16) (word_umod (word(val(EL p (inlist:byte list)) MOD 16)) (word 5:int16))):int32]:int32 list) = 256` ASSUME_TAC THENL + [REWRITE_TAC[LENGTH_APPEND; LENGTH] THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `SUB_LIST(0,256)(REJ_SAMPLE_ETA2_BYTES inlist:int32 list) = + APPEND (REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist)) + [word_sx(word_sub (word 2:int16) (word_umod (word(val(EL p (inlist:byte list)) MOD 16)) (word 5:int16))):int32]` ASSUME_TAC THENL + [FIRST_X_ASSUM(fun th -> if is_eq(concl th) && (try lhs(concl th) = `SUB_LIST(0,256)(REJ_SAMPLE_ETA2_BYTES inlist:int32 list)` with _->false) then SUBST1_TAC th else NO_TAC) THEN + FIRST_X_ASSUM(fun th -> if is_eq(concl th) && (try lhs(concl th) = `REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p+1) inlist):int32 list` with _->false) then SUBST1_TAC th else NO_TAC) THEN + W(fun (asl,gl) -> let lt = rhs gl in + MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC (mk_comb(`SUB_LIST(0,256):(int32)list->(int32)list`, lt)) THEN + CONJ_TAC THENL + [MATCH_MP_TAC SUB_LIST_APPEND_LEFT THEN ASM_REWRITE_TAC[LE_REFL]; + MATCH_MP_TAC SUB_LIST_256_LE THEN ASM_REWRITE_TAC[LE_REFL]]); ALL_TAC] THEN + REWRITE_TAC[ASSUME `SUB_LIST(0,256)(REJ_SAMPLE_ETA2_BYTES inlist:int32 list) = + APPEND (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p) inlist)) + [word_sx (word_sub (word 2:int16) (word_umod (word (val (EL p (inlist:byte list)) MOD 16)) (word 5:int16))):int32]`] THEN + REWRITE_TAC[ASSUME `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list) = 255`] THEN + ENSURES_INIT_TAC "s0" THEN + MP_TAC(ISPECL [`inlist:byte list`; `buf:int64`; `s0:x86state`; `p:num`; `136`] READ_1BYTE_EL_ETA2) THEN + ASM_REWRITE_TAC[] THEN DISCH_TAC THEN + SUBGOAL_THEN `~(&(val(word_zx(word 255:int64):int32)):int - &256 = &(val(word_sub(word_zx(word 255:int64):int32) (word 256):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT_ETA2 THEN CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + SUBGOAL_THEN `~(&(val(word_zx(word p:int64):int32)):int - &136 = &(val(word_sub(word_zx(word p:int64):int32) (word 136):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT_ETA2 THEN ASM_REWRITE_TAC[] THEN CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + X86_VSTEPS_TAC EXEC_ETA2 (1--8) THEN + SUBGOAL_THEN `word_add buf (word (1 * val (word p:int64))) = word_add buf (word p):int64` ASSUME_TAC THENL + [AP_TERM_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[MULT_CLAUSES] THEN + MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN MP_TAC(ASSUME `p < 136`) THEN ARITH_TAC; ALL_TAC] THEN + RULE_ASSUM_TAC(REWRITE_RULE[ASSUME `word_add buf (word (1 * val (word p:int64))) = word_add buf (word p):int64`; + ASSUME `read (memory :> bytes8 (word_add buf (word p))) s4 = EL p (inlist:byte list)`; + R10_NIBBLE_VAL_ETA2]) THEN + DISCARD_OLDSTATE_TAC "s8" THEN + SUBGOAL_THEN `~(&(val(word_zx(word(val(EL p (inlist:byte list)) MOD 16):int64):int32)):int - &15 = &(val(word_sub(word_zx(word(val(EL p (inlist:byte list)) MOD 16):int64):int32) (word 15):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT_ETA2 THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `val(word 255:int64) = 255` ASSUME_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN ARITH_TAC; ALL_TAC] THEN + X86_VSTEPS_TAC EXEC_ETA2 (9--19) THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->t=`RAX`))c && can(find_term(fun t->t=`s19:x86state`))c + then ASSUME_TAC(REWRITE_RULE[MATCH_MP RAX_INC_ETA2 (ARITH_RULE `255<256`)] th) else NO_TAC) THEN + SUBGOAL_THEN `&(val(word_zx(word(255+1):int64):int32)):int - &256 = &(val(word_sub(word_zx(word(255+1):int64):int32) (word 256):int32))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_TAKEN_GE_ETA2 THEN CONJ_TAC THENL [ARITH_TAC; CONV_TAC NUM_REDUCE_CONV]; ALL_TAC] THEN + X86_VSTEPS_TAC EXEC_ETA2 (20--21) THEN + ENSURES_FINAL_STATE_TAC THEN + SUBGOAL_THEN `f_ev_scalar_tail (SUC d) res buf pc (inlist:byte list) p = + [EventJump (word (pc + 481),word (pc + 542)); + EventStore (word_add res (word 1020),4); + EventJump (word (pc + 438),word (pc + 438)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 418),word (pc + 418)); + EventJump (word (pc + 410),word (pc + 410))]` SUBST1_TAC THENL + [MATCH_MP_TAC FEV_TAIL_MIDBYTE THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + REWRITE_TAC[ASSUME `SUB_LIST(0,256)(REJ_SAMPLE_ETA2_BYTES inlist:int32 list) = + APPEND (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,p) inlist)) + [word_sx (word_sub (word 2:int16) (word_umod (word (val (EL p (inlist:byte list)) MOD 16)) (word 5:int16))):int32]`] THEN + CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + REWRITE_TAC[ASSUME `LENGTH(APPEND (REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist)) + [word_sx(word_sub (word 2:int16) (word_umod (word(val(EL p (inlist:byte list)) MOD 16)) (word 5:int16))):int32]:int32 list) = 256`] THEN + REWRITE_TAC[LENGTH_BUTLAST_TMC_ETA2] THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL + [REPEAT CONJ_TAC THEN + (* memory fold: bytes(res,4*256) = APPEND prefix [lo] *) + SUBGOAL_THEN `4 * 256 = 4 * 255 + 4` SUBST1_TAC THENL [ARITH_TAC; ALL_TAC] THEN + MP_TAC(ISPECL [`memory:(x86state,int64->byte)component`; `res:int64`; `s21:x86state`; + `REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list`; + `[word_sx(word_sub (word 2:int16) (word_umod (word(val(EL p (inlist:byte list)) MOD 16)) (word 5:int16))):int32]`; + `4*255`; `4`] BYTES_EQ_NUM_OF_WORDLIST_APPEND) THEN + ANTS_TAC THENL [REWRITE_TAC[DIMINDEX_32] THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[NUM_OF_WORDLIST_SINGLETON_INT32] THEN + CONJ_TAC THENL + [ASM_REWRITE_TAC[]; + SUBGOAL_THEN `word(4 * 255):int64 = word 1020` SUBST1_TAC THENL [CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + ETA2_STORE_SPEC_TAC `s21:x86state` `val(EL p (inlist:byte list)) MOD 16` THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->try fst(dest_const t)="bytes32" with _->false))c && can(find_term(fun t->t=`val(EL p (inlist:byte list)) MOD 16`))c && not(can(find_term is_cond)c) + then MP_TAC th else NO_TAC) THEN + ASM_REWRITE_TAC[] THEN + STORE4_FROM_SPEC `s21:x86state` `word_add res (word 1020):int64`]; + REWRITE_TAC[APPEND] THEN ASM_REWRITE_TAC[]]; + (* --- STEP CLEAN-RECURSIVE: body trip then IH at p+1 --- *) + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p+1) inlist):int32 list) <= 256` ASSUME_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] LENGTH_REJ_SAMPLE_ETA2_BYTES_STEP_1) THEN ASM_REWRITE_TAC[] THEN + DISCH_THEN SUBST1_TAC THEN + REPEAT(FIRST_X_ASSUM(MP_TAC o check(fun th -> let c=concl th in + c = `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list) < 256` || + c = `~(LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list) = 255 /\ val(EL p (inlist:byte list)) MOD 16 < 15)`))) THEN + REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN ARITH_TAC; ALL_TAC] THEN + (* rewrite the goal's f_ev(SUC d) to expose the recursive APPEND *) + MP_TAC(SPECL[`d:num`;`res:int64`;`buf:int64`;`pc:num`;`inlist:byte list`;`p:num`] FEV_TAIL_REC) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN + DISCH_THEN(fun th -> REWRITE_TAC[th; GSYM APPEND_ASSOC]) THEN + (* body lemma instance at (p, outlen(p)) with events e *) + MP_TAC(SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`p:num`; + `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list)`;`stackpointer:int64`;`e:(uarch_event)list`] SCALAR_TAIL_BODY_SAFE_ETA2) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(fun body_th -> + let bodyQ = rand(rator(concl body_th)) in + ENSURES_SEQUENCE_TAC `pc + 399` bodyQ THEN + CONJ_TAC THENL + [(* leg1: P -> bodyQ via the body lemma *) + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN + EXISTS_TAC (rand(rator(concl body_th))) THEN CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + MATCH_MP_TAC ENSURES_PRECONDITION_THM THEN + EXISTS_TAC (rand(rator(rator(concl body_th)))) THEN CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + ACCEPT_TAC body_th]]; + ALL_TAC]) THEN + (* leg2: weaken pre to IH's expanded pre, then apply IH@(p+1) w/ e' *) + W(fun (asl,g) -> + let ih = snd(List.find (fun (_,th) -> is_forall(concl th) && + can (find_term (fun x -> x = `136 - p <= d`)) (concl th)) asl) in + let ih_inst = SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`p+1`;`stackpointer:int64`; + `APPEND (f_ev_scalar_body res buf pc (inlist:byte list) p (LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,p) inlist):int32 list))) (e:(uarch_event)list)`] ih in + let ih_pre = rand(rator(rator(snd(dest_imp(concl ih_inst))))) in + MATCH_MP_TAC ENSURES_PRECONDITION_THM THEN EXISTS_TAC ih_pre THEN CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + MP_TAC ih_inst THEN ANTS_TAC THENL + [ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THEN TRY ASM_ARITH_TAC; DISCH_THEN ACCEPT_TAC]])]]]]);; + + +(* --- MLDSA_REJ_UNIFORM_ETA2_SCALAR_TAIL_AT_P_SAFE --- *) +(* MLDSA_REJ_UNIFORM_ETA2_SCALAR_TAIL_AT_P_SAFE — the scalar-tail SAFE *) +(* (constant-time) contract at an arbitrary exit position p, a trivial *) +(* corollary of SCALAR_TAIL_RUN_SAFE_ETA2 with budget d := 136 - p (136-p<=d *) +(* by LE_REFL). Events threaded deep-right; concrete tail events = *) +(* f_ev_scalar_tail (136 - p) res buf pc inlist p. Mirrors *) +(* MLDSA_REJ_UNIFORM_ETA2_SCALAR_TAIL_AT_P_MEMSAFE. *) + +let rec conj_append_right t ev = + if is_conj t then + let l,r = dest_conj t in mk_conj(l, conj_append_right r ev) + else mk_conj(t, ev);; + +let scalar_at_p_safe_eta2_tm = + let qvars, body = strip_forall (concl MLDSA_REJ_UNIFORM_ETA2_SCALAR_TAIL_AT_P) in + let hyps_tm, ens = dest_imp body in + let ensc, ppf = strip_comb ens in + let pre = el 1 ppf and post = el 2 ppf and frame = el 3 ppf in + let sv, preb = dest_abs pre in + let sv2, postb = dest_abs post in + let fev = `f_ev_scalar_tail (136 - p) res buf pc (inlist:byte list) p` in + let eq_pre = `read events (s:x86state) = e` in + let eq_post = mk_eq(`read events (s:x86state)`, + mk_comb(mk_comb(`APPEND:(uarch_event)list->(uarch_event)list->(uarch_event)list`, fev), `e:(uarch_event)list`)) in + let pre' = mk_abs(sv, conj_append_right preb (vsubst[sv,`s:x86state`] eq_pre)) in + let post' = mk_abs(sv2, conj_append_right postb (vsubst[sv2,`s:x86state`] eq_post)) in + let ens' = list_mk_comb(ensc,[el 0 ppf; pre'; post'; frame]) in + list_mk_forall(qvars @ [`e:(uarch_event)list`], mk_imp(hyps_tm, ens'));; + +let MLDSA_REJ_UNIFORM_ETA2_SCALAR_TAIL_AT_P_SAFE = prove + (scalar_at_p_safe_eta2_tm, + REPEAT STRIP_TAC THEN + MP_TAC(SPECL [`136 - p`; `res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`p:num`;`stackpointer:int64`;`e:(uarch_event)list`] SCALAR_TAIL_RUN_SAFE_ETA2) THEN + ASM_REWRITE_TAC[LE_REFL]);; + + +(* --- MEMACCESS_F_EV_SCALAR_{BODY,TAIL} + HEADGUARD --- *) +(* MEMACCESS_F_EV_SCALAR_TAIL: per-budget memaccess bound for the eta2 scalar *) +(* tail's public event trace f_ev_scalar_tail. Mirror of *) +(* MEMACCESS_F_EV_LOOP_ETA2 — the memaccess-recovery half that core_safe *) +(* feeds into MEMACCESS_ENUM_ACC + MEMACCESS_INBOUNDS_APPEND. Read window *) +(* [buf,136; table,2048] and write window [res,1024] MATCH the loop's window *) +(* lists (table unused by the tail, harmless). *) +(* ========================================================================= *) + +(* -- containment helpers (STORE_CONTAINED / BUF_CONTAINED) -- *) + +(* 4-byte compaction store res + 4*cnt within [res,1024]: 4*255 + 4 = 1024. *) +let STORE4_CONTAINED = prove + (`!(res:int64) cnt. cnt <= 255 + ==> contained_modulo (2 EXP 64) + (val(word_add res (word(4 * cnt))),4) (val res,1024)`, + REPEAT STRIP_TAC THEN + GEN_REWRITE_TAC I [GSYM CONTAINED_MODULO_MOD2] THEN + REWRITE_TAC[VAL_WORD_ADD; VAL_WORD; DIMINDEX_64] THEN + CONV_TAC(ONCE_DEPTH_CONV MOD_DOWN_CONV) THEN + REWRITE_TAC[CONTAINED_MODULO_MOD2] THEN + MATCH_MP_TAC CONTAINED_MODULO_OFFSET_SIMPLE THEN ASM_ARITH_TAC);; + +(* 1-byte input load buf + p within [buf,136]: p < 136 ==> p + 1 <= 136. *) +let LOAD1_CONTAINED = prove + (`!(buf:int64) p. p < 136 + ==> contained_modulo (2 EXP 64) + (val(word_add buf (word p)),1) (val buf,136)`, + REPEAT STRIP_TAC THEN + GEN_REWRITE_TAC I [GSYM CONTAINED_MODULO_MOD2] THEN + REWRITE_TAC[VAL_WORD_ADD; VAL_WORD; DIMINDEX_64] THEN + CONV_TAC(ONCE_DEPTH_CONV MOD_DOWN_CONV) THEN + REWRITE_TAC[CONTAINED_MODULO_MOD2] THEN + MATCH_MP_TAC CONTAINED_MODULO_OFFSET_SIMPLE THEN ASM_ARITH_TAC);; + +(* -- per-byte body memaccess: the 4-branch COND of f_ev_scalar_body. -- + Hyps: p<136 (loads), outlen0<=255 (single-store branches), + ~(outlen0=255 /\ low<15) (so the accept-accept branch's +1 store fits: + under low<15 it forces outlen0<>255, hence outlen0+1<=255). *) +let MEMACCESS_F_EV_SCALAR_BODY = prove + (`!res buf table pc (inlist:byte list) p outlen0. + p < 136 /\ outlen0 <= 255 /\ + ~(outlen0 = 255 /\ val(EL p inlist) MOD 16 < 15) + ==> memaccess_inbounds (f_ev_scalar_body res buf pc inlist p outlen0) + [(buf:int64),136; (table:int64),2048] [(res:int64),1024]`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN `val(word outlen0:int64) = outlen0` ASSUME_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN ASM_ARITH_TAC; + ALL_TAC] THEN + REWRITE_TAC[f_ev_scalar_body] THEN REPEAT COND_CASES_TAC THEN + ASM_REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND] THEN + REPEAT CONJ_TAC THEN + FIRST [MATCH_MP_TAC STORE4_CONTAINED THEN ASM_ARITH_TAC; + DISJ1_TAC THEN MATCH_MP_TAC LOAD1_CONTAINED THEN FIRST_ASSUM ACCEPT_TAC]);; + +(* -- the induction: every access in f_ev_scalar_tail d @ p is in-bounds, -- + from the single public bound p+d<=136. The store-count bound (L<=255) + is supplied per-step by the recursive branch's own ~(256<=L) guard, so no + separate LENGTH<=256 bookkeeping hyp is needed. *) +let MEMACCESS_F_EV_SCALAR_TAIL = prove + (`!d res buf table pc (inlist:byte list) p. + p + d <= 136 + ==> memaccess_inbounds (f_ev_scalar_tail d res buf pc inlist p) + [(buf:int64),136; (table:int64),2048] [(res:int64),1024]`, + INDUCT_TAC THENL + [(* base d=0: both terminals (count / offset exit) are Jumps-only. *) + REPEAT GEN_TAC THEN STRIP_TAC THEN + REWRITE_TAC[f_ev_scalar_tail] THEN COND_CASES_TAC THEN + REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND]; + (* step d=SUC d: 4 tail-level branches (body stays folded). *) + REPEAT GEN_TAC THEN STRIP_TAC THEN + REWRITE_TAC[f_ev_scalar_tail] THEN REPEAT COND_CASES_TAC THENL + [(* G0: 256<=L -> [Jump] *) + REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND]; + (* G1: p=136 -> [Jump;Jump] *) + REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND]; + (* G2: mid-byte exit (outlen=255, low<15) -> Store(res+1020,4)+Load(buf+p,1) *) + REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND] THEN REPEAT CONJ_TAC THEN + FIRST [REWRITE_TAC[ARITH_RULE `1020 = 4 * 255`] THEN + MATCH_MP_TAC STORE4_CONTAINED THEN ARITH_TAC; + DISJ1_TAC THEN MATCH_MP_TAC LOAD1_CONTAINED THEN ASM_ARITH_TAC]; + (* G3: recursive -> APPEND (tail d @ p+1) (body @ p L) *) + REWRITE_TAC[MEMACCESS_INBOUNDS_APPEND] THEN CONJ_TAC THENL + [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC; + MATCH_MP_TAC MEMACCESS_F_EV_SCALAR_BODY THEN REPEAT CONJ_TAC THENL + [ASM_ARITH_TAC; ASM_ARITH_TAC; FIRST_ASSUM ACCEPT_TAC]]]]);; + +(* -- trivial: the head-guard segment is Jumps-only -> in-bounds for any -- + read/write windows. A core_safe ingredient (mirrors the exit-block glue's + f_ev_headguard segment; sits alongside MEMACCESS_ENUM_ACC + F_EV_LOOP + + F_EV_SCALAR_TAIL for recovering the full-f_events memaccess). *) +let MEMACCESS_F_EV_HEADGUARD = prove + (`!pc rr wr. memaccess_inbounds (f_ev_headguard_eta2 pc) rr wr`, + REWRITE_TAC[f_ev_headguard_eta2; memaccess_inbounds; ALL; EX; FST; SND]);; + + +(* ========================================================================= *) +(* Constant-time (SAFE) loop-side, mid-exit, exit-block, core, and *) +(* SUBROUTINE_SAFE cluster. *) +(* ========================================================================= *) + +(* ------------------------------------------------------------------------- *) +(* f_ev_loop_eta2 — the per-iteration PUBLIC events delta. *) +(* A fully type-annotated concrete definition, bound to the ML name *) +(* f_ev_loop_eta2_def. *) +(* ------------------------------------------------------------------------- *) +let f_ev_loop_eta2_def = new_definition `((((=):(uarch_event)list->(uarch_event)list->bool) ((((((((f_ev_loop_eta2):(64)word->(64)word->(64)word->num->(bool)list->num->(uarch_event)list) (res:(64)word)) (buf:(64)word)) (table:(64)word)) (pc:num)) (mask:(bool)list)) (i:num))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (399:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (86:num)))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventX86POPCNT):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) (((word_zx):(32)word->(64)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) (((PACK_MASK8):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (24:num))) (8:num))) (mask:(bool)list))))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventStore):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (res:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (4:num)) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (24:num)))) (mask:(bool)list))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (table:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (8:num)) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) (((PACK_MASK8):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (24:num))) (8:num))) (mask:(bool)list))))))))))) (8:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (339:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (339:num)))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventX86POPCNT):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) (((word_zx):(32)word->(64)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) (((PACK_MASK8):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (16:num))) (8:num))) (mask:(bool)list))))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventStore):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (res:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (4:num)) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (16:num)))) (mask:(bool)list))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (table:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (8:num)) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) (((PACK_MASK8):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (16:num))) (8:num))) (mask:(bool)list))))))))))) (8:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (273:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (273:num)))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventX86POPCNT):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) (((word_zx):(32)word->(64)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) (((PACK_MASK8):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (8:num))) (8:num))) (mask:(bool)list))))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventStore):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (res:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (4:num)) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (8:num)))) (mask:(bool)list))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (table:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (8:num)) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) (((PACK_MASK8):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (8:num))) (8:num))) (mask:(bool)list))))))))))) (8:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (207:num)))) (((((COND):bool->(64)word->(64)word->(64)word) (((~):bool->bool) ((((\/):bool->bool->bool) (((~):bool->bool) ((((=):int->int->bool) ((((int_sub):int->int->int) (((int_of_num):num->int) (((val):(32)word->num) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((*):num->num->num) (32:num)) (i:num)))) (mask:(bool)list)))))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((*):num->num->num) (32:num)) (i:num))) (8:num))) (mask:(bool)list)))))))))))) (((int_of_num):num->int) (248:num)))) (((int_of_num):num->int) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((*):num->num->num) (32:num)) (i:num)))) (mask:(bool)list)))))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((*):num->num->num) (32:num)) (i:num))) (8:num))) (mask:(bool)list)))))))))) (((word):num->(32)word) (248:num)))))))) ((((=):num->num->bool) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((*):num->num->num) (32:num)) (i:num)))) (mask:(bool)list)))))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((*):num->num->num) (32:num)) (i:num))) (8:num))) (mask:(bool)list)))))))))) (((word):num->(32)word) (248:num))))) (0:num))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (399:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (207:num))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventX86POPCNT):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) (((word_zx):(32)word->(64)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) (((PACK_MASK8):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((*):num->num->num) (32:num)) (i:num))) (8:num))) (mask:(bool)list))))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventStore):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (res:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (4:num)) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((*):num->num->num) (32:num)) (i:num)))) (mask:(bool)list))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (table:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (8:num)) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) (((PACK_MASK8):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((*):num->num->num) (32:num)) (i:num))) (8:num))) (mask:(bool)list))))))))))) (8:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (buf:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (16:num)) (i:num))))) (16:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (106:num)))) (((((COND):bool->(64)word->(64)word->(64)word) (((~):bool->bool) ((((\/):bool->bool->bool) (((~):bool->bool) ((((=):int->int->bool) ((((int_sub):int->int->int) (((int_of_num):num->int) (((val):(32)word->num) (((word_zx):(64)word->(32)word) (((word):num->(64)word) ((((*):num->num->num) (16:num)) (i:num))))))) (((int_of_num):num->int) (120:num)))) (((int_of_num):num->int) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) ((((*):num->num->num) (16:num)) (i:num))))) (((word):num->(32)word) (120:num)))))))) ((((=):num->num->bool) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) ((((*):num->num->num) (16:num)) (i:num))))) (((word):num->(32)word) (120:num))))) (0:num))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (399:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (106:num))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (97:num)))) (((((COND):bool->(64)word->(64)word->(64)word) (((~):bool->bool) ((((\/):bool->bool->bool) (((~):bool->bool) ((((=):int->int->bool) ((((int_sub):int->int->int) (((int_of_num):num->int) (((val):(32)word->num) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((*):num->num->num) (32:num)) (i:num)))) (mask:(bool)list)))))))) (((int_of_num):num->int) (248:num)))) (((int_of_num):num->int) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((*):num->num->num) (32:num)) (i:num)))) (mask:(bool)list)))))) (((word):num->(32)word) (248:num)))))))) ((((=):num->num->bool) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((*):num->num->num) (32:num)) (i:num)))) (mask:(bool)list)))))) (((word):num->(32)word) (248:num))))) (0:num))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (399:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (97:num))))))) ((NIL):(uarch_event)list)))))))))))))))))))))`;; + +(* --- Value bridges (pack_byte) --- *) +let BYTE_SLICE = prove + (`!e lo mid hi. + lo < 2 EXP e /\ mid < 256 + ==> (lo + 2 EXP e * (mid + 256 * hi)) DIV (2 EXP e) MOD 256 = mid`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN `(lo + 2 EXP e * (mid + 256 * hi)) DIV (2 EXP e) = mid + 256 * hi` + SUBST1_TAC THENL + [ASM_SIMP_TAC[DIV_MULT_ADD; EXP_EQ_0; ARITH_EQ; DIV_LT; ADD_CLAUSES]; + ONCE_REWRITE_TAC[ARITH_RULE `mid + 256 * hi = hi * 256 + mid`] THEN + ASM_SIMP_TAC[MOD_MULT_ADD; MOD_LT]]);; + +let bs = map (fun k -> mk_var("b" ^ string_of_int k, `:bool`)) (0--31);; +let bv k = mk_comb(`bitval:bool->num`, el k bs);; +let mulc = `( * ):num->num->num` and addc = `(+):num->num->num`;; +let term_at k = + if k = 0 then bv 0 + else mk_comb(mk_comb(mulc, mk_numeral(Num.num_of_int(1 lsl k))), bv k);; +let weighted a b = mk_comb(mk_comb(addc, a), b);; +let full = List.fold_left (fun acc k -> weighted acc (term_at k)) (term_at 0) (1--31);; + +let mk_pack_byte g = + let sh = 8 * g in + let mid = + List.fold_left (fun acc j -> + weighted acc (mk_comb(mk_comb(mulc, mk_numeral(Num.num_of_int(1 lsl j))), bv (sh+j)))) + (bv sh) (1--7) in + let lhs = mk_comb(mk_comb(`MOD`, + mk_comb(mk_comb(`DIV`, full), + mk_comb(mk_comb(`EXP`,`2`), mk_small_numeral sh))), + `256`) in + let rhs = mk_comb(`PACK_MASK8`, mk_list(map (fun j -> el (sh+j) bs) (0--7), `:bool`)) in + let goal = list_mk_forall(bs, mk_eq(lhs, rhs)) in + goal;; + +let restructure g = + let sh = 8 * g in + let lo = if sh = 0 then `0` else + List.fold_left (fun acc k -> weighted acc (term_at k)) (term_at 0) (1--(sh-1)) in + let mid = + List.fold_left (fun acc j -> + weighted acc (mk_comb(mk_comb(mulc, mk_numeral(Num.num_of_int(1 lsl j))), bv (sh+j)))) + (bv sh) (1--7) in + let hi = + if sh + 8 > 31 then `0` else + List.fold_left (fun acc k -> + weighted acc (mk_comb(mk_comb(mulc, mk_numeral(Num.num_of_int(1 lsl (k-sh-8)))), bv k))) + (bv (sh+8)) ((sh+9)--31) in + (mk_small_numeral sh, lo, mid, hi);; + +let prove_pack_byte g = + let goal = mk_pack_byte g in + let (sh_tm, lo, mid, hi) = restructure g in + let restr = mk_eq(full, + weighted lo (mk_comb(mk_comb(mulc, mk_comb(mk_comb(`EXP`,`2`), sh_tm)), + weighted mid (mk_comb(mk_comb(mulc,`256`), hi))))) in + prove(goal, + REPEAT GEN_TAC THEN + SUBGOAL_THEN restr SUBST1_TAC THENL + [CONV_TAC NUM_REDUCE_CONV THEN ARITH_TAC; ALL_TAC] THEN + MP_TAC(SPECL [sh_tm; lo; mid; hi] BYTE_SLICE) THEN + ANTS_TAC THENL + [CONJ_TAC THENL + [MAP_EVERY (fun k -> MP_TAC(ISPEC (el k bs) BITVAL_BOUND)) (0--(8*g-1)) THEN + CONV_TAC NUM_REDUCE_CONV THEN ARITH_TAC; + MAP_EVERY (fun j -> MP_TAC(ISPEC (el (8*g+j) bs) BITVAL_BOUND)) (0--7) THEN + ARITH_TAC]; + ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN + REWRITE_TAC[PACK_MASK8] THEN CONV_TAC(ONCE_DEPTH_CONV EL_CONV) THEN ARITH_TAC);; + +(* --- Group-link bridges (pack_group) --- *) +let VAL_WORD_NIB16 = prove + (`!x. x < 16 ==> val(word x:int16) = x`, + REPEAT STRIP_TAC THEN REWRITE_TAC[VAL_WORD; DIMINDEX_16] THEN + MATCH_MP_TAC MOD_LT THEN ASM_ARITH_TAC);; + +let mk_group_link gm = + let mb = eta2_mk_maskbit_forall gm in + let boff = gm / 2 in + let bytelist = + mk_list(map (fun j -> subst[mk_small_numeral(8*(boff+j)),`OFF:num`] + `word_subword (chunk0:int128) (OFF,8):byte`) (0--3), `:byte`) in + let sublhs = subst[mk_small_numeral boff, `BOFF:num`] + `SUB_LIST(16*i+BOFF,4) (inlist:byte list)` in + let link = mk_eq(sublhs, bytelist) in + let lhs_bits = + mk_list(map (fun k -> subst[mk_small_numeral(8*(k+gm)),`OFF:num`] + `bit 7 (word_subword (f1bnd:int256) (OFF,8):byte)`) (0--7), `:bool`) in + let moff = 32*0 + gm in + ignore moff; + let rhs = subst[mk_small_numeral gm, `GM:num`] + `SUB_LIST(32*i+GM,8)(REJ_MASK_ETA2 (inlist:byte list))` in + mk_imp(mb, mk_imp(link, mk_eq(lhs_bits, rhs)));; + +let VAL_WORD_NIB_LO = prove + (`!w:byte. val(word(val w MOD 16):int16) = val w MOD 16`, + GEN_TAC THEN MATCH_MP_TAC VAL_WORD_NIB16 THEN + MP_TAC(SPECL[`val(w:byte)`;`16`] MOD_LT_EQ) THEN ARITH_TAC);; +let VAL_WORD_NIB_HI = prove + (`!w:byte. val(word(val w DIV 16):int16) = val w DIV 16`, + GEN_TAC THEN MATCH_MP_TAC VAL_WORD_NIB16 THEN + MP_TAC(ISPEC `w:byte` VAL_BOUND) THEN REWRITE_TAC[DIMINDEX_8] THEN ARITH_TAC);; + +let prove_group_link gm = + let goal = mk_group_link gm in + let boff = gm / 2 in + let arith_off = ARITH_RULE(mk_eq( + `2 * (16 * i + BOFF)`, `32 * i + GM`) + |> subst[mk_small_numeral boff,`BOFF:num`; mk_small_numeral gm,`GM:num`]) in + let rhs_reduced = subst[mk_small_numeral boff,`BOFF:num`] + `REJ_MASK_ETA2(SUB_LIST(16*i+BOFF,4) (inlist:byte list))` in + let goal_rhs = subst[mk_small_numeral gm,`GM:num`] + `SUB_LIST(32*i+GM,8)(REJ_MASK_ETA2 (inlist:byte list))` in + prove(goal, + DISCH_THEN(fun mb -> DISCH_THEN(fun link -> + SUBGOAL_THEN (mk_eq(goal_rhs, rhs_reduced)) SUBST1_TAC THENL + [ONCE_REWRITE_TAC[REJ_MASK_ETA2_SUB_LIST] THEN + REWRITE_TAC[arith_off] THEN CONV_TAC NUM_REDUCE_CONV; + ALL_TAC] THEN + REWRITE_TAC[link] THEN + REWRITE_TAC[REJ_MASK_ETA2; NIBBLES_OF_BYTES; NIBBLE_PAIR; APPEND; MAP] THEN + REWRITE_TAC[VAL_WORD_NIB_LO; VAL_WORD_NIB_HI] THEN + (let mbs = map (fun k -> let th = SPEC (mk_small_numeral k) mb in + CONV_RULE (NUM_REDUCE_CONV THENC ONCE_DEPTH_CONV EL_CONV) + (MP th (EQT_ELIM(NUM_REDUCE_CONV(lhand(concl th)))))) [0;1;2;3;4;5;6;7] in + REWRITE_TAC mbs) THEN + REFL_TAC)));; + +let ETA2_PACK_GROUP0 = prove_group_link 0;; +let ETA2_PACK_GROUP1 = prove_group_link 8;; +let ETA2_PACK_GROUP2 = prove_group_link 16;; +let ETA2_PACK_GROUP3 = prove_group_link 24;; + +(* --- BYTE0_DIVMOD (build_p0) --- *) +let BYTE0_DIVMOD = prove + (`!p:num->bool. + (bitval(p 0) + 2*bitval(p 1) + 4*bitval(p 2) + 8*bitval(p 3) + + 16*bitval(p 4) + 32*bitval(p 5) + 64*bitval(p 6) + 128*bitval(p 7) + + 256*bitval(p 8) + 512*bitval(p 9) + 1024*bitval(p 10) + 2048*bitval(p 11) + + 4096*bitval(p 12) + 8192*bitval(p 13) + 16384*bitval(p 14) + 32768*bitval(p 15) + + 65536*bitval(p 16) + 131072*bitval(p 17) + 262144*bitval(p 18) + 524288*bitval(p 19) + + 1048576*bitval(p 20) + 2097152*bitval(p 21) + 4194304*bitval(p 22) + 8388608*bitval(p 23) + + 16777216*bitval(p 24) + 33554432*bitval(p 25) + 67108864*bitval(p 26) + 134217728*bitval(p 27) + + 268435456*bitval(p 28) + 536870912*bitval(p 29) + 1073741824*bitval(p 30) + 2147483648*bitval(p 31)) MOD 256 = + bitval(p 0) + 2*bitval(p 1) + 4*bitval(p 2) + 8*bitval(p 3) + + 16*bitval(p 4) + 32*bitval(p 5) + 64*bitval(p 6) + 128*bitval(p 7)`, + GEN_TAC THEN + SUBGOAL_THEN + `(bitval(p 0) + 2*bitval(p 1) + 4*bitval(p 2) + 8*bitval(p 3) + + 16*bitval(p 4) + 32*bitval(p 5) + 64*bitval(p 6) + 128*bitval(p 7) + + 256*bitval(p 8) + 512*bitval(p 9) + 1024*bitval(p 10) + 2048*bitval(p 11) + + 4096*bitval(p 12) + 8192*bitval(p 13) + 16384*bitval(p 14) + 32768*bitval(p 15) + + 65536*bitval(p 16) + 131072*bitval(p 17) + 262144*bitval(p 18) + 524288*bitval(p 19) + + 1048576*bitval(p 20) + 2097152*bitval(p 21) + 4194304*bitval(p 22) + 8388608*bitval(p 23) + + 16777216*bitval(p 24) + 33554432*bitval(p 25) + 67108864*bitval(p 26) + 134217728*bitval(p 27) + + 268435456*bitval(p 28) + 536870912*bitval(p 29) + 1073741824*bitval(p 30) + 2147483648*bitval(p 31)) = + (bitval(p 0) + 2*bitval(p 1) + 4*bitval(p 2) + 8*bitval(p 3) + + 16*bitval(p 4) + 32*bitval(p 5) + 64*bitval(p 6) + 128*bitval(p 7)) + + 256 * (bitval(p 8) + 2*bitval(p 9) + 4*bitval(p 10) + 8*bitval(p 11) + + 16*bitval(p 12) + 32*bitval(p 13) + 64*bitval(p 14) + 128*bitval(p 15) + + 256*(bitval(p 16) + 2*bitval(p 17) + 4*bitval(p 18) + 8*bitval(p 19) + + 16*bitval(p 20) + 32*bitval(p 21) + 64*bitval(p 22) + 128*bitval(p 23) + + 256*(bitval(p 24) + 2*bitval(p 25) + 4*bitval(p 26) + 8*bitval(p 27) + + 16*bitval(p 28) + 32*bitval(p 29) + 64*bitval(p 30) + 128*bitval(p 31))))` + SUBST1_TAC THENL [ARITH_TAC; ALL_TAC] THEN + MATCH_MP_TAC ADD256_MOD THEN + MAP_EVERY (fun k -> MP_TAC(ISPEC (mk_comb(`p:num->bool`,mk_small_numeral k)) BITVAL_BOUND)) + [0;1;2;3;4;5;6;7] THEN ARITH_TAC);; + +(* --- STORE_BRIDGE + GATHER_BRIDGE1 (bridge_values) --- *) +let STORE_BRIDGE = prove + (`!inlist:byte list. !B. + LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,B) inlist):int32 list) = + NUM_ACCEPTED(SUB_LIST(0,2*B)(REJ_MASK_ETA2 inlist))`, + REPEAT GEN_TAC THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA2_BYTES; LENGTH_REJ_NIBBLES_ETA2_EQ_MASK; + NUM_ACCEPTED] THEN + REWRITE_TAC[REJ_MASK_ETA2_SUB_LIST; MULT_CLAUSES]);; + +let pinst = `\k. bit 7 (word_subword (f1bnd:int256) (8*k,8):byte)`;; +let byte1_inst = CONV_RULE(DEPTH_CONV BETA_CONV THENC ONCE_DEPTH_CONV NUM_REDUCE_CONV) + (SPEC pinst BYTE1_DIVMOD);; +let bigsum = lhand(lhand(lhand(concl byte1_inst)));; +let tower8 = subst[bigsum,`S:num`] + `word_zx(word_ushr(word_zx(word_zx(word (S:num):int32):int64):int32) 8):int64`;; + +let GATHER_BRIDGE1 = prove + (mk_imp(mk_eq(tower8,`mask8b:int64`), + mk_imp(eta2_mk_maskbit_forall 8, + mk_imp(`SUB_LIST(16*i+4,4) (inlist:byte list) = + [word_subword (chunk0:int128) (32,8); word_subword chunk0 (40,8); + word_subword chunk0 (48,8); word_subword chunk0 (56,8)]`, + `val (mask8b:int64) MOD 256 = + PACK_MASK8(SUB_LIST(32*i+8,8)(REJ_MASK_ETA2 (inlist:byte list)))`))), + STRIP_TAC THEN STRIP_TAC THEN STRIP_TAC THEN + FIRST_X_ASSUM(SUBST1_TAC o SYM o + check (fun th -> try rand(concl th) = `mask8b:int64` with _ -> false)) THEN + REWRITE_TAC[MASK_SHIFT8_MOD256] THEN + MP_TAC(SPEC pinst BYTE1_DIVMOD) THEN + CONV_TAC(DEPTH_CONV BETA_CONV THENC ONCE_DEPTH_CONV NUM_REDUCE_CONV) THEN + DISCH_THEN SUBST1_TAC THEN + W(fun (asl,w) -> + let mb = find (fun th -> is_forall(concl th)) (map snd asl) in + let link = find (fun th -> is_eq(concl th) && + (try fst(dest_const(fst(strip_comb(lhand(concl th))))) = "SUB_LIST" + with _ -> false)) (map snd asl) in + let pg = MP (MP (SPEC_ALL ETA2_PACK_GROUP1) mb) link in + GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [SYM pg]) THEN + REWRITE_TAC[PACK_MASK8] THEN CONV_TAC(ONCE_DEPTH_CONV EL_CONV) THEN ARITH_TAC);; + +(* --- GATHER_BRIDGE2/3 (gather_all) --- *) +let byte2_inst = CONV_RULE(DEPTH_CONV BETA_CONV THENC ONCE_DEPTH_CONV NUM_REDUCE_CONV) + (SPEC pinst BYTE2_DIVMOD);; +let byte3_inst = CONV_RULE(DEPTH_CONV BETA_CONV THENC ONCE_DEPTH_CONV NUM_REDUCE_CONV) + (SPEC pinst BYTE3_DIVMOD);; +let bigsum = lhand(lhand(lhand(concl byte2_inst)));; + +let link_of gm = + let boff = gm / 2 in + mk_eq(subst[mk_small_numeral boff,`BOFF:num`] `SUB_LIST(16*i+BOFF,4)(inlist:byte list)`, + mk_list(map (fun j -> subst[mk_small_numeral(8*(boff+j)),`OFF:num`] + `word_subword (chunk0:int128) (OFF,8):byte`) (0--3), `:byte`));; + +let prove_gather gm maskv shiftlem byteinst packgrp tower = + let goal = + mk_imp(mk_eq(tower, maskv), + mk_imp(eta2_mk_maskbit_forall gm, + mk_imp(link_of gm, + mk_eq(mk_comb(mk_comb(`MOD`,mk_comb(`val:int64->num`,maskv)),`256`), + subst[mk_small_numeral gm,`GM:num`] + `PACK_MASK8(SUB_LIST(32*i+GM,8)(REJ_MASK_ETA2 (inlist:byte list)))`)))) in + prove(goal, + STRIP_TAC THEN STRIP_TAC THEN STRIP_TAC THEN + FIRST_X_ASSUM(SUBST1_TAC o SYM o + check (fun th -> try rand(concl th) = maskv with _ -> false)) THEN + REWRITE_TAC[shiftlem] THEN + MP_TAC byteinst THEN DISCH_THEN SUBST1_TAC THEN + W(fun (asl,w) -> + let mb = find (fun th -> is_forall(concl th)) (map snd asl) in + let link = find (fun th -> is_eq(concl th) && + (try fst(dest_const(fst(strip_comb(lhand(concl th))))) = "SUB_LIST" + with _ -> false)) (map snd asl) in + let pg = MP (MP (SPEC_ALL packgrp) mb) link in + GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [SYM pg]) THEN + REWRITE_TAC[PACK_MASK8] THEN CONV_TAC(ONCE_DEPTH_CONV EL_CONV) THEN ARITH_TAC);; + +let tower16 = subst[bigsum,`S:num`] + `word_zx(word_ushr(word_zx(word_zx(word_ushr(word_zx(word_zx(word (S:num):int32):int64):int32) 8):int64):int32) 8):int64`;; +let tower24 = subst[bigsum,`S:num`] + `word_zx(word_ushr(word_zx(word_zx(word_ushr(word_zx(word_zx(word_ushr(word_zx(word_zx(word (S:num):int32):int64):int32) 8):int64):int32) 8):int64):int32) 8):int64`;; + +let GATHER_BRIDGE2 = prove_gather 16 `mask8c:int64` MASK_SHIFT16_MOD256 byte2_inst ETA2_PACK_GROUP2 tower16;; +let GATHER_BRIDGE3 = prove_gather 24 `mask8d:int64` MASK_SHIFT24_MOD256 byte3_inst ETA2_PACK_GROUP3 tower24;; + +(* ------------------------------------------------------------------------- *) +(* Events-bridge linchpin: f_ev_loop_eta2 (above) + P0_BRIDGE + *) +(* ETA2_EVENTS_BRIDGE. P0_BRIDGE is a fully type-annotated term proved by *) +(* the build_p0 tactic; ETA2_EVENTS_BRIDGE is proved by EB_TAC, which *) +(* rebuilds the 9 value facts (P0_BRIDGE / GATHER_BRIDGE1-3 / STORE_BRIDGE + *) +(* a niblen identity) from the stripped antecedent and rewrites raw->public. *) +(* ------------------------------------------------------------------------- *) + +let MS0 = prove + (`!S:num. val(word_zx(word S:int32):int64) MOD 256 = S MOD 256`, + GEN_TAC THEN + REWRITE_TAC[VAL_WORD_ZX_GEN; VAL_WORD; DIMINDEX_32; DIMINDEX_64] THEN + REWRITE_TAC[ARITH_RULE `256 = 2 EXP 8`; MOD_MOD_EXP_MIN] THEN + CONV_TAC NUM_REDUCE_CONV);; + +let pinst = `\k. bit 7 (word_subword (f1bnd:int256) (8*k,8):byte)`;; + +let P0_BRIDGE = prove(`((((==>):bool->bool->bool) (((!):(num->bool)->bool) (\(k:num). ((((==>):bool->bool->bool) ((((<):num->num->bool) (k:num)) (8:num))) ((((=):bool->bool->bool) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) ((((*):num->num->num) (8:num)) ((((+):num->num->num) (k:num)) (0:num)))) (8:num))))) ((((<):num->num->bool) ((((EL):num->(num)list->num) (k:num)) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (0:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (0:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (8:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (8:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (16:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (16:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (24:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (24:num)) (8:num))))) (16:num))) ((NIL):(num)list))))))))))) (15:num))))))) ((((==>):bool->bool->bool) ((((=):((8)word)list->((8)word)list->bool) ((((SUB_LIST):num#num->((8)word)list->((8)word)list) ((((,):num->num->num#num) ((((*):num->num->num) (16:num)) (i:num))) (4:num))) (inlist:((8)word)list))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (0:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (8:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (16:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (24:num)) (8:num)))) ((NIL):((8)word)list))))))) ((((=):num->num->bool) ((((MOD):num->num->num) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word):num->(32)word) ((((+):num->num->num) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (0:num)) (8:num)))))) ((((+):num->num->num) ((((*):num->num->num) (2:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (8:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (4:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (16:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (8:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (24:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (16:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (32:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (40:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (64:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (48:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (128:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (56:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (256:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (64:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (512:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (72:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (1024:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (80:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (2048:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (88:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (4096:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (96:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (8192:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (104:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (16384:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (112:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (32768:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (120:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (65536:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (128:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (131072:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (136:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (262144:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (144:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (524288:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (152:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (1048576:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (160:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (2097152:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (168:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (4194304:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (176:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (8388608:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (184:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (16777216:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (192:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (33554432:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (200:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (67108864:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (208:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (134217728:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (216:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (268435456:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (224:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (536870912:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (232:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (1073741824:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (240:num)) (8:num))))))) ((((*):num->num->num) (2147483648:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (248:num)) (8:num))))))))))))))))))))))))))))))))))))))))) (256:num))) (((PACK_MASK8):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((*):num->num->num) (32:num)) (i:num))) (8:num))) (((REJ_MASK_ETA2):((8)word)list->(bool)list) (inlist:((8)word)list)))))))`, + STRIP_TAC THEN STRIP_TAC THEN + REWRITE_TAC[MS0] THEN + MP_TAC(SPEC pinst BYTE0_DIVMOD) THEN + CONV_TAC(DEPTH_CONV BETA_CONV THENC ONCE_DEPTH_CONV NUM_REDUCE_CONV) THEN + DISCH_THEN SUBST1_TAC THEN + W(fun (asl,w) -> + let mb = find (fun th -> is_forall(concl th)) (map snd asl) in + let link = find (fun th -> is_eq(concl th) && + (try fst(dest_const(fst(strip_comb(lhand(concl th))))) = "SUB_LIST" with _ -> false)) (map snd asl) in + let pg0 = REWRITE_RULE[ARITH_RULE `16*i+0 = 16*i`; ARITH_RULE `32*i+0 = 32*i`] (SPEC_ALL ETA2_PACK_GROUP0) in + let pg = MP (MP pg0 mb) link in + GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [SYM pg]) THEN + REWRITE_TAC[PACK_MASK8] THEN CONV_TAC(ONCE_DEPTH_CONV EL_CONV) THEN ARITH_TAC);; + +let EB_TAC : tactic = + STRIP_TAC THEN REWRITE_TAC[f_ev_loop_eta2_def] THEN + W(fun (asl,w) -> + let assoc_asl = map snd asl in + let fnd p = find (fun th -> p (concl th)) assoc_asl in + let tower8_mask8b = fnd (fun c -> is_eq c && rand c=`mask8b:int64` && can(find_term(fun u->match u with Const("word_ushr",_)->true|_->false)) c) in + let mask8c_def = fnd (fun c -> is_eq c && rand c=`mask8c:int64`) in + let mask8d_def = fnd (fun c -> is_eq c && rand c=`mask8d:int64` && can(find_term(fun u->match u with Const("word_ushr",_)->true|_->false)) c) in + let mb g = fnd (fun c -> is_forall c && can(find_term(fun u->u=`f1bnd:int256`)) c && can(find_term(fun u->u = mk_binop `( * ):num->num->num` `8` (mk_binop `(+):num->num->num` `k:num` (mk_small_numeral g)))) c) in + let ol_def = fnd (fun c -> is_eq c && rand c=`outlen0:num` && can(find_term(fun u->match u with Const("REJ_SAMPLE_ETA2_BYTES",_)->true|_->false)) c) in + let a1_def = fnd (fun c -> is_eq c && rand c=`acc1:num` && can(find_term(fun u->match u with Const("REJ_SAMPLE_ETA2_BYTES",_)->true|_->false)) c) in + let a2_def = fnd (fun c -> is_eq c && rand c=`acc2:num` && can(find_term(fun u->match u with Const("REJ_SAMPLE_ETA2_BYTES",_)->true|_->false)) c) in + let a3_def = fnd (fun c -> is_eq c && rand c=`acc3:num` && can(find_term(fun u->match u with Const("REJ_SAMPLE_ETA2_BYTES",_)->true|_->false)) c) in + let i_le = fnd (fun c -> c = `16 * i <= 120`) in + let leninl = fnd (fun c -> c = `LENGTH(inlist:byte list) = 136`) in + let blk16 = fnd (fun c -> is_eq c && (try fst(dest_const(fst(strip_comb(lhand c))))="SUB_LIST" && length(dest_list(rand c))=16 with _->false)) in + let bb = MP (ISPECL [`inlist:byte list`;`i:num`;`chunk0:int128`] SUBITER_BLOCK_BYTES) + (CONJ (REWRITE_RULE[GSYM leninl] (MP (ARITH_RULE `16*i<=120 ==> 16*i+16<=136`) i_le)) blk16) in + let links = CONJUNCTS bb in + let t16m8c = REWRITE_RULE[SYM tower8_mask8b] mask8c_def in + let t24m8d = REWRITE_RULE[SYM t16m8c] mask8d_def in + let f0 = MP (MP P0_BRIDGE (mb 0)) (el 0 links) in + let f1 = MP (MP (MP GATHER_BRIDGE1 tower8_mask8b) (mb 8)) (el 1 links) in + let f2 = MP (MP (MP GATHER_BRIDGE2 t16m8c) (mb 16)) (el 2 links) in + let f3 = MP (MP (MP GATHER_BRIDGE3 t24m8d) (mb 24)) (el 3 links) in + let so = TRANS (SYM ol_def) (REWRITE_RULE[ARITH_RULE `2*(16*i)=32*i`] (SPECL[`inlist:byte list`;`16*i`] STORE_BRIDGE)) in + let s1 = TRANS (SYM a1_def) (REWRITE_RULE[ARITH_RULE `2*(16*i+4)=32*i+8`] (SPECL[`inlist:byte list`;`16*i+4`] STORE_BRIDGE)) in + let s2 = TRANS (SYM a2_def) (REWRITE_RULE[ARITH_RULE `2*(16*i+8)=32*i+16`] (SPECL[`inlist:byte list`;`16*i+8`] STORE_BRIDGE)) in + let s3 = TRANS (SYM a3_def) (REWRITE_RULE[ARITH_RULE `2*(16*i+12)=32*i+24`] (SPECL[`inlist:byte list`;`16*i+12`] STORE_BRIDGE)) in + let niblen0_gen = prove + (`LENGTH(REJ_NIBBLES_ETA2(SUB_LIST(16*i,4) inlist):int16 list) = + NUM_ACCEPTED(SUB_LIST(32*i,8)(REJ_MASK_ETA2 (inlist:byte list)))`, + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA2_EQ_MASK; GSYM NUM_ACCEPTED] THEN + REWRITE_TAC[REJ_MASK_ETA2_SUB_LIST] THEN + REWRITE_TAC[ARITH_RULE `2*(16*i)=32*i`; ARITH_RULE `2*4=8`]) in + let niblen0 = REWRITE_RULE[el 0 links] niblen0_gen in + let facts = [f0;f1;f2;f3;so;s1;s2;s3;niblen0] in + CONV_TAC(LAND_CONV(GEN_REWRITE_CONV TOP_DEPTH_CONV facts THENC REWRITE_CONV[]))) THEN + REFL_TAC;; + +let ETA2_EVENTS_BRIDGE = prove(`((((==>):bool->bool->bool) ((((/\):bool->bool->bool) (((!):(num->bool)->bool) (\(k:num). ((((==>):bool->bool->bool) ((((<):num->num->bool) (k:num)) (8:num))) ((((=):bool->bool->bool) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) ((((*):num->num->num) (8:num)) ((((+):num->num->num) (k:num)) (0:num)))) (8:num))))) ((((<):num->num->bool) ((((EL):num->(num)list->num) (k:num)) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (0:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (0:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (8:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (8:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (16:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (16:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (24:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (24:num)) (8:num))))) (16:num))) ((NIL):(num)list))))))))))) (15:num))))))) ((((/\):bool->bool->bool) (((!):(num->bool)->bool) (\(k:num). ((((==>):bool->bool->bool) ((((<):num->num->bool) (k:num)) (8:num))) ((((=):bool->bool->bool) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) ((((*):num->num->num) (8:num)) ((((+):num->num->num) (k:num)) (16:num)))) (8:num))))) ((((<):num->num->bool) ((((EL):num->(num)list->num) (k:num)) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (64:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (64:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (72:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (72:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (80:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (80:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (88:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (88:num)) (8:num))))) (16:num))) ((NIL):(num)list))))))))))) (15:num))))))) ((((/\):bool->bool->bool) (((!):(num->bool)->bool) (\(k:num). ((((==>):bool->bool->bool) ((((<):num->num->bool) (k:num)) (8:num))) ((((=):bool->bool->bool) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) ((((*):num->num->num) (8:num)) ((((+):num->num->num) (k:num)) (8:num)))) (8:num))))) ((((<):num->num->bool) ((((EL):num->(num)list->num) (k:num)) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (32:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (32:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (40:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (40:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (48:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (48:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (56:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (56:num)) (8:num))))) (16:num))) ((NIL):(num)list))))))))))) (15:num))))))) ((((/\):bool->bool->bool) (((!):(num->bool)->bool) (\(k:num). ((((==>):bool->bool->bool) ((((<):num->num->bool) (k:num)) (8:num))) ((((=):bool->bool->bool) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) ((((*):num->num->num) (8:num)) ((((+):num->num->num) (k:num)) (24:num)))) (8:num))))) ((((<):num->num->bool) ((((EL):num->(num)list->num) (k:num)) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (96:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (96:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (104:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (104:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (112:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (112:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (120:num)) (8:num))))) (16:num))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (120:num)) (8:num))))) (16:num))) ((NIL):(num)list))))))))))) (15:num))))))) ((((/\):bool->bool->bool) ((((<=):num->num->bool) ((((*):num->num->num) (16:num)) (i:num))) (120:num))) ((((/\):bool->bool->bool) ((((=):((8)word)list->((8)word)list->bool) ((((SUB_LIST):num#num->((8)word)list->((8)word)list) ((((,):num->num->num#num) ((((*):num->num->num) (16:num)) (i:num))) (16:num))) (inlist:((8)word)list))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (0:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (8:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (16:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (24:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (32:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (40:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (48:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (56:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (64:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (72:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (80:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (88:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (96:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (104:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (112:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (120:num)) (8:num)))) ((NIL):((8)word)list))))))))))))))))))) ((((/\):bool->bool->bool) ((((=):num->num->bool) (((LENGTH):((8)word)list->num) (inlist:((8)word)list))) (136:num))) ((((/\):bool->bool->bool) ((((=):num->num->bool) (((LENGTH):((32)word)list->num) (((REJ_SAMPLE_ETA2_BYTES):((8)word)list->((32)word)list) ((((SUB_LIST):num#num->((8)word)list->((8)word)list) ((((,):num->num->num#num) (0:num)) ((((*):num->num->num) (16:num)) (i:num)))) (inlist:((8)word)list))))) (outlen0:num))) ((((/\):bool->bool->bool) ((((=):num->num->bool) (((LENGTH):((32)word)list->num) (((REJ_SAMPLE_ETA2_BYTES):((8)word)list->((32)word)list) ((((SUB_LIST):num#num->((8)word)list->((8)word)list) ((((,):num->num->num#num) (0:num)) ((((+):num->num->num) ((((*):num->num->num) (16:num)) (i:num))) (8:num)))) (inlist:((8)word)list))))) (acc2:num))) ((((/\):bool->bool->bool) ((((=):num->num->bool) (((LENGTH):((32)word)list->num) (((REJ_SAMPLE_ETA2_BYTES):((8)word)list->((32)word)list) ((((SUB_LIST):num#num->((8)word)list->((8)word)list) ((((,):num->num->num#num) (0:num)) ((((+):num->num->num) ((((*):num->num->num) (16:num)) (i:num))) (4:num)))) (inlist:((8)word)list))))) (acc1:num))) ((((/\):bool->bool->bool) ((((=):num->num->bool) (((LENGTH):((32)word)list->num) (((REJ_SAMPLE_ETA2_BYTES):((8)word)list->((32)word)list) ((((SUB_LIST):num#num->((8)word)list->((8)word)list) ((((,):num->num->num#num) (0:num)) ((((+):num->num->num) ((((*):num->num->num) (16:num)) (i:num))) (12:num)))) (inlist:((8)word)list))))) (acc3:num))) ((((/\):bool->bool->bool) ((((=):(64)word->(64)word->bool) (((word_zx):(32)word->(64)word) ((((word_ushr):(32)word->num->(32)word) (((word_zx):(64)word->(32)word) (mask8b:(64)word))) (8:num)))) (mask8c:(64)word))) ((((/\):bool->bool->bool) ((((=):(64)word->(64)word->bool) (((word_zx):(32)word->(64)word) ((((word_ushr):(32)word->num->(32)word) (((word_zx):(64)word->(32)word) (mask8c:(64)word))) (8:num)))) (mask8d:(64)word))) ((((=):(64)word->(64)word->bool) (((word_zx):(32)word->(64)word) ((((word_ushr):(32)word->num->(32)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) ((((+):num->num->num) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (0:num)) (8:num)))))) ((((+):num->num->num) ((((*):num->num->num) (2:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (8:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (4:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (16:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (8:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (24:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (16:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (32:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (40:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (64:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (48:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (128:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (56:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (256:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (64:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (512:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (72:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (1024:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (80:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (2048:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (88:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (4096:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (96:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (8192:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (104:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (16384:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (112:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (32768:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (120:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (65536:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (128:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (131072:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (136:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (262144:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (144:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (524288:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (152:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (1048576:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (160:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (2097152:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (168:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (4194304:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (176:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (8388608:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (184:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (16777216:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (192:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (33554432:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (200:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (67108864:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (208:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (134217728:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (216:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (268435456:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (224:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (536870912:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (232:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (1073741824:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (240:num)) (8:num))))))) ((((*):num->num->num) (2147483648:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (248:num)) (8:num))))))))))))))))))))))))))))))))))))))))) (8:num)))) (mask8b:(64)word)))))))))))))))) ((((=):(uarch_event)list->(uarch_event)list->bool) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (399:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (86:num)))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventX86POPCNT):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) (((word_zx):(32)word->(64)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) ((((MOD):num->num->num) (((val):(64)word->num) (mask8d:(64)word))) (256:num)))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventStore):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (res:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (4:num)) (acc3:num))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (table:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (8:num)) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) ((((MOD):num->num->num) (((val):(64)word->num) (mask8d:(64)word))) (256:num)))))))))) (8:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (339:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (339:num)))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventX86POPCNT):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) (((word_zx):(32)word->(64)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) ((((MOD):num->num->num) (((val):(64)word->num) (mask8c:(64)word))) (256:num)))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventStore):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (res:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (4:num)) (acc2:num))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (table:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (8:num)) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) ((((MOD):num->num->num) (((val):(64)word->num) (mask8c:(64)word))) (256:num)))))))))) (8:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (273:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (273:num)))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventX86POPCNT):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) (((word_zx):(32)word->(64)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) ((((MOD):num->num->num) (((val):(64)word->num) (mask8b:(64)word))) (256:num)))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventStore):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (res:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (4:num)) (acc1:num))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (table:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (8:num)) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) ((((MOD):num->num->num) (((val):(64)word->num) (mask8b:(64)word))) (256:num)))))))))) (8:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (207:num)))) (((((COND):bool->(64)word->(64)word->(64)word) (((~):bool->bool) ((((\/):bool->bool->bool) (((~):bool->bool) ((((=):int->int->bool) ((((int_sub):int->int->int) (((int_of_num):num->int) (((val):(32)word->num) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (outlen0:num)))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((LENGTH):((16)word)list->num) (((REJ_NIBBLES_ETA2):((8)word)list->((16)word)list) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (0:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (8:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (16:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (24:num)) (8:num)))) ((NIL):((8)word)list)))))))))))))))) (((int_of_num):num->int) (248:num)))) (((int_of_num):num->int) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (outlen0:num)))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((LENGTH):((16)word)list->num) (((REJ_NIBBLES_ETA2):((8)word)list->((16)word)list) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (0:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (8:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (16:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (24:num)) (8:num)))) ((NIL):((8)word)list)))))))))))))) (((word):num->(32)word) (248:num)))))))) ((((=):num->num->bool) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (outlen0:num)))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((LENGTH):((16)word)list->num) (((REJ_NIBBLES_ETA2):((8)word)list->((16)word)list) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (0:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (8:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (16:num)) (8:num)))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (24:num)) (8:num)))) ((NIL):((8)word)list)))))))))))))) (((word):num->(32)word) (248:num))))) (0:num))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (399:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (207:num))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventX86POPCNT):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) (((word_zx):(32)word->(64)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) ((((MOD):num->num->num) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word):num->(32)word) ((((+):num->num->num) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (0:num)) (8:num)))))) ((((+):num->num->num) ((((*):num->num->num) (2:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (8:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (4:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (16:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (8:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (24:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (16:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (32:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (40:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (64:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (48:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (128:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (56:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (256:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (64:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (512:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (72:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (1024:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (80:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (2048:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (88:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (4096:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (96:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (8192:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (104:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (16384:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (112:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (32768:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (120:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (65536:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (128:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (131072:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (136:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (262144:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (144:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (524288:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (152:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (1048576:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (160:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (2097152:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (168:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (4194304:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (176:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (8388608:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (184:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (16777216:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (192:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (33554432:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (200:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (67108864:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (208:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (134217728:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (216:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (268435456:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (224:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (536870912:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (232:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (1073741824:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (240:num)) (8:num))))))) ((((*):num->num->num) (2147483648:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (248:num)) (8:num))))))))))))))))))))))))))))))))))))))))) (256:num)))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventStore):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (res:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (4:num)) (outlen0:num))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (table:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (8:num)) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) ((((MOD):num->num->num) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word):num->(32)word) ((((+):num->num->num) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (0:num)) (8:num)))))) ((((+):num->num->num) ((((*):num->num->num) (2:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (8:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (4:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (16:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (8:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (24:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (16:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (32:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (40:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (64:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (48:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (128:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (56:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (256:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (64:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (512:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (72:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (1024:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (80:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (2048:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (88:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (4096:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (96:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (8192:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (104:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (16384:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (112:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (32768:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (120:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (65536:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (128:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (131072:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (136:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (262144:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (144:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (524288:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (152:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (1048576:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (160:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (2097152:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (168:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (4194304:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (176:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (8388608:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (184:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (16777216:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (192:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (33554432:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (200:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (67108864:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (208:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (134217728:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (216:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (268435456:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (224:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (536870912:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (232:num)) (8:num))))))) ((((+):num->num->num) ((((*):num->num->num) (1073741824:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (240:num)) (8:num))))))) ((((*):num->num->num) (2147483648:num)) (((bitval):bool->num) ((((bit):num->(8)word->bool) (7:num)) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (248:num)) (8:num))))))))))))))))))))))))))))))))))))))))) (256:num)))))))))) (8:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (buf:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (16:num)) (i:num))))) (16:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (106:num)))) (((((COND):bool->(64)word->(64)word->(64)word) (((~):bool->bool) ((((\/):bool->bool->bool) (((~):bool->bool) ((((=):int->int->bool) ((((int_sub):int->int->int) (((int_of_num):num->int) (((val):(32)word->num) (((word_zx):(64)word->(32)word) (((word):num->(64)word) ((((*):num->num->num) (16:num)) (i:num))))))) (((int_of_num):num->int) (120:num)))) (((int_of_num):num->int) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) ((((*):num->num->num) (16:num)) (i:num))))) (((word):num->(32)word) (120:num)))))))) ((((=):num->num->bool) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) ((((*):num->num->num) (16:num)) (i:num))))) (((word):num->(32)word) (120:num))))) (0:num))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (399:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (106:num))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (97:num)))) (((((COND):bool->(64)word->(64)word->(64)word) (((~):bool->bool) ((((\/):bool->bool->bool) (((~):bool->bool) ((((=):int->int->bool) ((((int_sub):int->int->int) (((int_of_num):num->int) (((val):(32)word->num) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (outlen0:num)))))) (((int_of_num):num->int) (248:num)))) (((int_of_num):num->int) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (outlen0:num)))) (((word):num->(32)word) (248:num)))))))) ((((=):num->num->bool) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (outlen0:num)))) (((word):num->(32)word) (248:num))))) (0:num))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (399:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (97:num))))))) ((NIL):(uarch_event)list))))))))))))))))))))) ((((((((f_ev_loop_eta2):(64)word->(64)word->(64)word->num->(bool)list->num->(uarch_event)list) (res:(64)word)) (buf:(64)word)) (table:(64)word)) (pc:num)) (((REJ_MASK_ETA2):((8)word)list->(bool)list) (inlist:((8)word)list))) (i:num))))`, EB_TAC);; + +(* --- memacc helpers --- *) +let NUM_ACCEPTED_PREFIX_MONO = prove + (`!mask:bool list a b. a <= b + ==> NUM_ACCEPTED(SUB_LIST(0,a) mask) <= NUM_ACCEPTED(SUB_LIST(0,b) mask)`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN `SUB_LIST(0,b) (mask:bool list) = + APPEND (SUB_LIST(0,a) mask) (SUB_LIST(a,b-a) mask)` SUBST1_TAC THENL + [MP_TAC(ISPECL [`mask:bool list`; `a:num`; `b - a`; `0`] SUB_LIST_SPLIT) THEN + ASM_SIMP_TAC[ARITH_RULE `a <= b ==> a + (b - a) = b`; ADD_CLAUSES]; + REWRITE_TAC[NUM_ACCEPTED_APPEND] THEN ARITH_TAC]);; + +let STORE_CONTAINED = prove + (`!(res:int64) cnt. cnt <= 248 + ==> contained_modulo (2 EXP 64) + (val(word_add res (word(4 * cnt))),32) (val res,1024)`, + REPEAT STRIP_TAC THEN + GEN_REWRITE_TAC I [GSYM CONTAINED_MODULO_MOD2] THEN + REWRITE_TAC[VAL_WORD_ADD; VAL_WORD; DIMINDEX_64] THEN + CONV_TAC(ONCE_DEPTH_CONV MOD_DOWN_CONV) THEN + REWRITE_TAC[CONTAINED_MODULO_MOD2] THEN + MATCH_MP_TAC CONTAINED_MODULO_OFFSET_SIMPLE THEN ASM_ARITH_TAC);; + +let BUF_CONTAINED = prove + (`!(buf:int64) j. 16 * j + 16 <= 136 + ==> contained_modulo (2 EXP 64) + (val(word_add buf (word(16 * j))),16) (val buf,136)`, + REPEAT STRIP_TAC THEN + GEN_REWRITE_TAC I [GSYM CONTAINED_MODULO_MOD2] THEN + REWRITE_TAC[VAL_WORD_ADD; VAL_WORD; DIMINDEX_64] THEN + CONV_TAC(ONCE_DEPTH_CONV MOD_DOWN_CONV) THEN + REWRITE_TAC[CONTAINED_MODULO_MOD2] THEN + MATCH_MP_TAC CONTAINED_MODULO_OFFSET_SIMPLE THEN ASM_ARITH_TAC);; + +let PACK_MASK8_MOD256 = prove + (`!bs:bool list. PACK_MASK8 bs = PACK_MASK8 bs MOD 256`, + GEN_TAC THEN MATCH_MP_TAC(GSYM MOD_LT) THEN REWRITE_TAC[PACK_MASK8_BOUND]);; + +let MEMACCESS_F_EV_LOOP_ETA2 = prove + (`!res buf table pc mask j. + 16 * j + 16 <= 136 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * j + 24) mask) <= 248 + ==> memaccess_inbounds (f_ev_loop_eta2 res buf table pc mask j) + [(buf:int64),136; (table:int64),2048] [(res:int64),1024]`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN + `NUM_ACCEPTED (SUB_LIST (0,32 * j) mask) <= 248 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * j + 8) mask) <= 248 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * j + 16) mask) <= 248` + STRIP_ASSUME_TAC THENL + [REPEAT CONJ_TAC THEN + TRANS_TAC LE_TRANS `NUM_ACCEPTED (SUB_LIST (0,32 * j + 24) mask)` THEN + ASM_REWRITE_TAC[] THEN MATCH_MP_TAC NUM_ACCEPTED_PREFIX_MONO THEN ARITH_TAC; + ALL_TAC] THEN + REWRITE_TAC[f_ev_loop_eta2_def; memaccess_inbounds; ALL; EX; FST; SND] THEN + ONCE_REWRITE_TAC[PACK_MASK8_MOD256] THEN + REPEAT CONJ_TAC THEN + FIRST + [MATCH_MP_TAC STORE_CONTAINED THEN FIRST_ASSUM ACCEPT_TAC; + DISJ1_TAC THEN MATCH_MP_TAC BUF_CONTAINED THEN FIRST_ASSUM ACCEPT_TAC; + DISJ2_TAC THEN MATCH_MP_TAC GATHER_CONTAINED THEN + MATCH_ACCEPT_TAC TABLE_IDX_LT_256]);; + +(* --- SAFE clean-block defs/closer + ETA2_CLEAN_BLOCK_SAFE --- *) +(* ETA2_SAFE_CLOSER references ETA2_EVENTS_BRIDGE (the events-bridge linchpin *) +(* above). *) +let clean_block_safe_eta2_tm = + let qvars, body = strip_forall clean_block_eta2_tm in + let hyps_tm, ens = dest_imp body in + let ensc, ppf = strip_comb ens in + let pre = el 1 ppf and post = el 2 ppf and frame = el 3 ppf in + let sv, preb = dest_abs pre in + let sv2, postb = dest_abs post in + let pretempl = `read events (s:x86state) = (e:(uarch_event)list)` in + let posttempl = + `read events (s:x86state) = + APPEND (f_ev_loop_eta2 res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) i) + (e:(uarch_event)list) /\ + memaccess_inbounds + (f_ev_loop_eta2 res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) i) + [(buf:int64),136; (table:int64),2048] [(res:int64),1024]` in + let pre' = mk_abs(sv, mk_conj(preb, vsubst[sv,`s:x86state`] pretempl)) in + let post' = mk_abs(sv2, mk_conj(postb, vsubst[sv2,`s:x86state`] posttempl)) in + let ens' = list_mk_comb(ensc,[el 0 ppf; pre'; post'; frame]) in + list_mk_forall(qvars @ [`e:(uarch_event)list`], mk_imp(hyps_tm, ens'));; + +let ETA2_SAFE_STEP_TAC : tactic = + mk_eta2_prefix_to_s11 false THEN + ETA2_SI1_FOLD THEN ETA2_SI1_COUNTER_MS_TAC THEN + ETA2_SI2_FOLD THEN ETA2_SI2_COUNTER_TAC THEN + ETA2_SI3_FOLD THEN ETA2_SI3_COUNTER_TAC THEN + ETA2_SI4_FOLD THEN ETA2_SI4_COUNTER_TAC THEN + RULE_ASSUM_TAC(REWRITE_RULE[ARITH_RULE `16*i+16 = 16*(i+1)`]) THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN + CONJ_TAC THENL [ETA2_RAX_FINAL_TAC; ALL_TAC] THEN + CONJ_TAC THENL [ETA2_RCX_FINAL_TAC; ALL_TAC];; + +let ETA2_SAFE_CLOSER : tactic = + MP_TAC ETA2_EVENTS_BRIDGE THEN + ANTS_TAC THENL + [ REPEAT CONJ_TAC THEN FIRST_ASSUM ACCEPT_TAC; + DISCH_THEN(fun bridge -> + CONJ_TAC THENL + [ REWRITE_TAC[GSYM bridge; APPEND] THEN + (REFL_TAC ORELSE FIRST_ASSUM ACCEPT_TAC ORELSE ASM_REWRITE_TAC[APPEND]); + REWRITE_TAC[GSYM bridge] THEN + REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND] THEN + REPEAT CONJ_TAC THEN + TRY(REPEAT ((DISJ1_TAC THEN CONTAINED_ASM_TAC) ORELSE DISJ2_TAC ORELSE + CONTAINED_ASM_TAC) THEN NO_TAC) THEN + GATHER_BOUND_TAC ]) ];; + +let ETA2_CLEAN_BLOCK_SAFE = + prove(clean_block_safe_eta2_tm, ETA2_SAFE_STEP_TAC THEN ETA2_SAFE_CLOSER);; + +(* --- SAFE loop scaffold + ETA2_LOOP_SAFE + MEMACCESS_ENUM_ACC --- *) +let SAFE_THREAD_EVENTS_STEP = prove + (`!(d:num->(uarch_event)list) i e. + APPEND (d i) (APPEND (ENUMERATEL i d) e) = APPEND (ENUMERATEL (i+1) d) e`, + REWRITE_TAC[ENUMERATEL_ADD1; APPEND_ASSOC]);; + +let ev_concrete_eta2 = + `read events (s:x86state) = + APPEND (ENUMERATEL i (f_ev_loop_eta2 res buf table pc + (REJ_MASK_ETA2 (inlist:byte list)))) (e:(uarch_event)list)`;; + +let SAFE_LOOPINV_ETA2 = + let iv,rest = dest_abs CORRECT_LOOPINV_ETA2 in + let sv,body = dest_abs rest in + mk_abs(iv, mk_abs(sv, + conj_append_right body (vsubst[sv,`s:x86state`; iv,`i:num`] ev_concrete_eta2)));; + +let loop_safe_eta2_tm = + let qvars,body = strip_forall core_ms_eta2_tm in + let hyps_tm,ens = dest_imp body in + let ensc,ppf = strip_comb ens in + let pre = el 1 ppf and frame = el 3 ppf in + let wop = `!m. m < N ==> 16 * m <= 120 /\ + LENGTH(REJ_NIBBLES_ETA2(SUB_LIST(0,16*m) inlist):int16 list) <= 248` in + let hyps' = list_mk_conj (conjuncts hyps_tm @ [`~(N = 0)`; `~(N = 1)`; wop]) in + let sv = `s:x86state` in + let svp,preb = dest_abs pre in + let pre' = mk_abs(svp, conj_append_right preb + (vsubst[svp,sv] `read RSP (s:x86state) = stackpointer`)) in + let iv2,rest2 = dest_abs SAFE_LOOPINV_ETA2 in + let sv2,invbody = dest_abs rest2 in + let inv_body = vsubst[`N-1`,iv2; sv,sv2] invbody in + let post = mk_abs(sv, list_mk_conj + [ `bytes_loaded s (word pc) (BUTLAST mldsa_rej_uniform_eta2_tmc)`; + `read RIP s = word(pc + 86)`; + inv_body ]) in + let ens' = list_mk_comb(ensc,[el 0 ppf; pre'; post; frame]) in + list_mk_forall(qvars @ [`N:num`; `stackpointer:int64`], mk_imp(hyps', ens'));; + +let G2_SAFE_BODY_BRIDGE_ETA2_TAC : tactic = + REPEAT STRIP_TAC THEN + MP_TAC(SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`N:num`;`i:num`;`stackpointer:int64`; + `APPEND (ENUMERATEL i (f_ev_loop_eta2 res buf table pc (REJ_MASK_ETA2 inlist))) (e:(uarch_event)list)`] + ETA2_CLEAN_BLOCK_SAFE) THEN + ANTS_TAC THENL + [FIRST_X_ASSUM(MP_TAC o SPEC `i+1` o check(is_forall o concl)) THEN + ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN STRIP_TAC THEN + REPEAT CONJ_TAC THEN + (FIRST [FIRST_ASSUM ACCEPT_TAC; ASM_ARITH_TAC; ASM_REWRITE_TAC[]]); ALL_TAC] THEN + DISCH_THEN(fun bth -> + W(fun (asl,gl) -> + let lframe = rand(concl bth) in + let lpost = rand(rator(concl bth)) in + let lpre = rand(rator(rator(concl bth))) in + let gframe = rand gl in + let subsumed_tm = mk_binop `(subsumed):(x86state->x86state->bool)->(x86state->x86state->bool)->bool` lframe gframe in + let subsumed_th = prove(subsumed_tm, + REPEAT(MATCH_MP_TAC SUBSUMED_SEQ THEN REWRITE_TAC[SUBSUMED_REFL]) THEN SUBSUMED_MAYCHANGE_TAC) in + let bth' = MATCH_MP ENSURES_FRAME_SUBSUMED (CONJ subsumed_th bth) in + MATCH_MP_TAC ENSURES_PRECONDITION_THM THEN EXISTS_TAC lpre THEN + CONJ_TAC THENL + [GEN_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN TRY(ASM_MESON_TAC[]); + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN EXISTS_TAC lpost THEN + CONJ_TAC THENL + [GEN_TAC THEN STRIP_TAC THEN + ASM_REWRITE_TAC[GSYM SAFE_THREAD_EVENTS_STEP] THEN TRY(ASM_MESON_TAC[]); + ACCEPT_TAC bth']]));; + +let SAFE_LOOP_SCAFFOLD_ETA2_TAC : tactic = + MAP_EVERY X_GEN_TAC [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`; + `e:(uarch_event)list`;`pc:num`;`N:num`;`stackpointer:int64`] THEN + REWRITE_TAC[C_ARGUMENTS; C_RETURN; SOME_FLAGS; NONOVERLAPPING_CLAUSES; + LENGTH_MLDSA_REJ_UNIFORM_ETA2_TMC] THEN + STRIP_TAC THEN + ENSURES_WHILE_UP_TAC `N - 1` `pc + 86` `pc + 86` SAFE_LOOPINV_ETA2 THEN + REPEAT CONJ_TAC THENL + [REPEAT(FIRST_X_ASSUM(MP_TAC o check(fun th->concl th=`~(N=0)`||concl th=`~(N=1)`))) THEN ARITH_TAC; + ENSURES_INIT_TAC "s0" THEN + X86_STEPS_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC (1--10) THEN + X86_VERBOSE_STEP_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC "s11" THEN + X86_VERBOSE_STEP_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC "s12" THEN + COLLAPSE_VPBW_TAC `read YMM6 s12` YMM6_CONST_ETA2 THEN + X86_STEPS_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC (13--13) THEN + X86_VERBOSE_STEP_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC "s14" THEN + X86_VERBOSE_STEP_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC "s15" THEN + COLLAPSE_VPBW_TAC `read YMM7 s15` YMM7_CONST_ETA2 THEN + X86_STEPS_TAC MLDSA_REJ_UNIFORM_ETA2_EXEC (16--17) THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN + REWRITE_TAC[MULT_CLAUSES; ADD_CLAUSES; SUB_LIST_CLAUSES; REJ_SAMPLE_ETA2_BYTES; + REJ_NIBBLES_ETA2; NIBBLES_OF_BYTES; FILTER; MAP; LENGTH; num_of_wordlist] THEN + CONV_TAC NUM_REDUCE_CONV THEN + REWRITE_TAC[READ_COMPONENT_COMPOSE; READ_MEMORY_BYTES_TRIVIAL] THEN + CONV_TAC WORD_REDUCE_CONV THEN + ASM_REWRITE_TAC[ENUMERATEL; APPEND]; + G2_SAFE_BODY_BRIDGE_ETA2_TAC; + REPEAT STRIP_TAC THEN ENSURES_INIT_TAC "s0" THEN ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[]; + ENSURES_INIT_TAC "s0" THEN ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[]];; + +let ETA2_LOOP_SAFE = prove(loop_safe_eta2_tm, SAFE_LOOP_SCAFFOLD_ETA2_TAC);; + +let MEMACCESS_ENUM_ACC = prove + (`!(d:num->(uarch_event)list) rr wr J. + (!j. j < J ==> memaccess_inbounds (d j) rr wr) + ==> memaccess_inbounds (ENUMERATEL J d) rr wr`, + REPLICATE_TAC 3 GEN_TAC THEN INDUCT_TAC THENL + [REWRITE_TAC[ENUMERATEL; memaccess_inbounds; ALL]; + REWRITE_TAC[ADD1] THEN ONCE_REWRITE_TAC[ENUMERATEL_ADD1] THEN + REWRITE_TAC[MEMACCESS_INBOUNDS_APPEND] THEN STRIP_TAC THEN CONJ_TAC THENL + [FIRST_X_ASSUM MATCH_MP_TAC THEN ARITH_TAC; + FIRST_X_ASSUM MATCH_MP_TAC THEN GEN_TAC THEN DISCH_TAC THEN + FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC]]);; + +(* --- EXIT_OFFSET_SAFE_ETA2 (+ bridges) --- *) +let ev_append_op = `APPEND:(uarch_event)list->(uarch_event)list->(uarch_event)list`;; +let tail_events_e1 = + `APPEND (f_ev_loop_eta2 res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) (N-1)) + (e:(uarch_event)list)`;; +let tail_events_e2 = mk_comb(mk_comb(ev_append_op,`f_ev_headguard_eta2 pc`), tail_events_e1);; +let scalar_tail_events = `f_ev_scalar_tail (136 - 128) res buf pc (inlist:byte list) 128`;; +let exit_events_offset = mk_comb(mk_comb(ev_append_op, scalar_tail_events), tail_events_e2);; + +let q86_pred_e1 = vsubst[tail_events_e1,`ec:(uarch_event)list`] q86_safe_eta2;; +let q399_pred_e1 = vsubst[tail_events_e1,`ec:(uarch_event)list`] q399_safe_eta2;; + +let exit_offset_safe_eta2_tm = + let exoff_ms = snd(strip_forall exit_offset_ms_eta2_tm) in + let hyps_tm, ens = dest_imp exoff_ms in + let ensc, ppf = strip_comb ens in + let pre = el 1 ppf and post = el 2 ppf and frame = el 3 ppf in + let sv, preb = dest_abs pre in + let pre_val = lhand preb in + let pre' = mk_abs(sv, mk_conj(pre_val, vsubst[sv,`s:x86state`] `read events (s:x86state) = e`)) in + let sv2, postb = dest_abs post in + let post_rip = lhand postb in + let post_ev = vsubst[sv2,`s:x86state`] (mk_eq(`read events (s:x86state)`, exit_events_offset)) in + let post' = mk_abs(sv2, mk_conj(post_rip, post_ev)) in + list_mk_forall + ([`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`; + `N:num`;`stackpointer:int64`;`e:(uarch_event)list`], + mk_imp(hyps_tm, list_mk_comb(ensc,[el 0 ppf; pre'; post'; frame])));; + +let EXIT_BRIDGE_CLOSE_TAC : tactic = + GEN_TAC THEN STRIP_TAC THEN RULE_ASSUM_TAC BETA_RULE THEN + RULE_ASSUM_TAC(REWRITE_RULE[ASSUME `16 * N = 128`]) THEN ASM_REWRITE_TAC[];; + +let SAFE_BRIDGE_FROM_ETA2 (bth:thm) : tactic = + W(fun (asl,gl) -> + let lframe = rand(concl bth) in + let lpost = rand(rator(concl bth)) in + let lpre = rand(rator(rator(concl bth))) in + let gframe = rand gl in + let subsumed_tm = mk_binop `(subsumed):(x86state->x86state->bool)->(x86state->x86state->bool)->bool` lframe gframe in + let subsumed_th = prove(subsumed_tm, + REPEAT(MATCH_MP_TAC SUBSUMED_SEQ THEN REWRITE_TAC[SUBSUMED_REFL]) THEN SUBSUMED_MAYCHANGE_TAC) in + let bth' = MATCH_MP ENSURES_FRAME_SUBSUMED (CONJ subsumed_th bth) in + MATCH_MP_TAC ENSURES_PRECONDITION_THM THEN EXISTS_TAC lpre THEN + CONJ_TAC THENL + [EXIT_BRIDGE_CLOSE_TAC; + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN EXISTS_TAC lpost THEN + CONJ_TAC THENL [EXIT_BRIDGE_CLOSE_TAC; ACCEPT_TAC bth']]);; + +let SCALAR_TAIL_LEG2_SAFE_ETA2 (p:term) (etail:term) : tactic = + W(fun (asl,gl) -> + let atp = SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;p;`stackpointer:int64`;etail] + MLDSA_REJ_UNIFORM_ETA2_SCALAR_TAIL_AT_P_SAFE in + let atp_ens = snd(dest_imp(concl atp)) in + let _,ppf = strip_comb atp_ens in + let atp_pre = el 1 ppf and atp_post = el 2 ppf in + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN EXISTS_TAC atp_post THEN + CONJ_TAC THENL + [EXIT_BRIDGE_CLOSE_TAC; + MATCH_MP_TAC ENSURES_PRECONDITION_THM THEN EXISTS_TAC atp_pre THEN + CONJ_TAC THENL + [EXIT_BRIDGE_CLOSE_TAC; + MP_TAC atp THEN + ANTS_TAC THENL + [REPEAT CONJ_TAC THEN + (fun (a,g) -> + if is_le256_rej g then (FIRST [FIRST_ASSUM ACCEPT_TAC; CLOSE_LE256_TAC]) (a,g) + else (FIRST [FIRST_ASSUM ACCEPT_TAC; ASM_ARITH_TAC]) (a,g)); + MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] ENSURES_FRAME_SUBSUMED) THEN + REPEAT(MATCH_MP_TAC SUBSUMED_SEQ THEN REWRITE_TAC[SUBSUMED_REFL]) THEN + SUBSUMED_MAYCHANGE_TAC]]]);; + +let EXIT_OFFSET_SAFE_ETA2 = prove(exit_offset_safe_eta2_tm, + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN `~(N = 0)` ASSUME_TAC THENL + [UNDISCH_TAC `16 * N = 128` THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248` ASSUME_TAC THENL + [REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA2_BYTES] THEN + FIRST_X_ASSUM(fun th -> if concl th = `LENGTH(REJ_NIBBLES_ETA2(SUB_LIST(0,16*N) inlist):int16 list) <= 248` then ACCEPT_TAC th else NO_TAC); ALL_TAC] THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,128) inlist):int32 list) <= 248` ASSUME_TAC THENL + [UNDISCH_TAC `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248` THEN + SUBST1_TAC(ASSUME `16 * N = 128`) THEN REWRITE_TAC[]; ALL_TAC] THEN + MATCH_MP_TAC ENSURES_TRANS_SIMPLE THEN EXISTS_TAC q399_pred_e1 THEN + CONJ_TAC THENL [MAYCHANGE_IDEMPOT_TAC; ALL_TAC] THEN CONJ_TAC THENL + [MATCH_MP_TAC ENSURES_TRANS_SIMPLE THEN EXISTS_TAC q86_pred_e1 THEN + CONJ_TAC THENL [MAYCHANGE_IDEMPOT_TAC; ALL_TAC] THEN CONJ_TAC THENL + [MP_TAC(SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`N:num`;`N-1`;`stackpointer:int64`;`e:(uarch_event)list`] ETA2_CLEAN_BLOCK_SAFE) THEN + SUBGOAL_THEN `N - 1 + 1 = N` (fun th -> REWRITE_TAC[th]) THENL [ASM_ARITH_TAC; ALL_TAC] THEN + ANTS_TAC THENL + [REPEAT CONJ_TAC THEN (FIRST [FIRST_ASSUM ACCEPT_TAC; ASM_ARITH_TAC]); ALL_TAC] THEN + DISCH_THEN(fun bth -> SAFE_BRIDGE_FROM_ETA2 bth); + MP_TAC(SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`N:num`;`stackpointer:int64`;`e:(uarch_event)list`; tail_events_e1] LEG1B_HEADGUARD_SAFE_ETA2) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN + DISCH_THEN ACCEPT_TAC]; + SCALAR_TAIL_LEG2_SAFE_ETA2 `128` tail_events_e2]);; + +(* --- f_ev_midexit_subiter{1..4} + MEMACCESS_F_EV_MIDEXIT --- *) +let feld138 = SPEC_ALL f_ev_loop_eta2_def;; +let evs138 = dest_list (rand(concl feld138));; +let ejc138 = rator (el 0 evs138);; +let w399_138 = fst(dest_pair(rand(el 0 evs138)));; +let midsrc138 j = fst(dest_pair(rand(el j evs138)));; +let xover138 src = mk_comb(ejc138, mk_pair(src, w399_138));; +let evty138 = type_of (el 0 evs138);; +let midlist138 idxs headx = + mk_list(headx :: map (fun j -> el j evs138) idxs, evty138);; + +let mid_lhs_vars138 = [`res:int64`;`buf:int64`;`table:int64`;`pc:num`;`mask:bool list`;`i:num`];; +let mkmiddef138 name l = + let listty = type_of l in + let fnty = itlist (fun v ty -> mk_fun_ty (type_of v) ty) mid_lhs_vars138 listty in + define(mk_eq(list_mk_comb(mk_var(name, fnty), mid_lhs_vars138), l));; + +let f_ev_midexit_subiter1 = + mkmiddef138 "f_ev_midexit_subiter1" + (midlist138 [13;14;15;16;17;18] (xover138 (midsrc138 12)));; +let f_ev_midexit_subiter2 = + mkmiddef138 "f_ev_midexit_subiter2" + (midlist138 [9;10;11;12;13;14;15;16;17;18] (xover138 (midsrc138 8)));; +let f_ev_midexit_subiter3 = + mkmiddef138 "f_ev_midexit_subiter3" + (midlist138 [5;6;7;8;9;10;11;12;13;14;15;16;17;18] (xover138 (midsrc138 4)));; +let f_ev_midexit_subiter4 = + mkmiddef138 "f_ev_midexit_subiter4" + (midlist138 [0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16;17;18] (xover138 (midsrc138 18)));; + +let MIDEXIT_MEMACC_CORE_TAC (def:thm) : tactic = + REWRITE_TAC[def; memaccess_inbounds; ALL; EX; FST; SND] THEN + ONCE_REWRITE_TAC[PACK_MASK8_MOD256] THEN + REPEAT CONJ_TAC THEN + FIRST + [MATCH_MP_TAC STORE_CONTAINED THEN FIRST_ASSUM ACCEPT_TAC; + DISJ1_TAC THEN MATCH_MP_TAC BUF_CONTAINED THEN FIRST_ASSUM ACCEPT_TAC; + DISJ2_TAC THEN MATCH_MP_TAC GATHER_CONTAINED THEN MATCH_ACCEPT_TAC TABLE_IDX_LT_256];; + +let MEMACCESS_F_EV_MIDEXIT_SUBITER1 = prove + (`!res buf table pc mask i. + 16 * i + 16 <= 136 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * i) mask) <= 248 + ==> memaccess_inbounds (f_ev_midexit_subiter1 res buf table pc mask i) + [(buf:int64),136; (table:int64),2048] [(res:int64),1024]`, + REPEAT GEN_TAC THEN STRIP_TAC THEN MIDEXIT_MEMACC_CORE_TAC f_ev_midexit_subiter1);; + +let MEMACCESS_F_EV_MIDEXIT_SUBITER2 = prove + (`!res buf table pc mask i. + 16 * i + 16 <= 136 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * i + 8) mask) <= 248 + ==> memaccess_inbounds (f_ev_midexit_subiter2 res buf table pc mask i) + [(buf:int64),136; (table:int64),2048] [(res:int64),1024]`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN `NUM_ACCEPTED (SUB_LIST (0,32 * i) mask) <= 248` ASSUME_TAC THENL + [TRANS_TAC LE_TRANS `NUM_ACCEPTED (SUB_LIST (0,32 * i + 8) mask)` THEN + ASM_REWRITE_TAC[] THEN MATCH_MP_TAC NUM_ACCEPTED_PREFIX_MONO THEN ARITH_TAC; ALL_TAC] THEN + MIDEXIT_MEMACC_CORE_TAC f_ev_midexit_subiter2);; + +let MEMACCESS_F_EV_MIDEXIT_SUBITER3 = prove + (`!res buf table pc mask i. + 16 * i + 16 <= 136 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * i + 16) mask) <= 248 + ==> memaccess_inbounds (f_ev_midexit_subiter3 res buf table pc mask i) + [(buf:int64),136; (table:int64),2048] [(res:int64),1024]`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN + `NUM_ACCEPTED (SUB_LIST (0,32 * i) mask) <= 248 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * i + 8) mask) <= 248` + STRIP_ASSUME_TAC THENL + [CONJ_TAC THEN TRANS_TAC LE_TRANS `NUM_ACCEPTED (SUB_LIST (0,32 * i + 16) mask)` THEN + ASM_REWRITE_TAC[] THEN MATCH_MP_TAC NUM_ACCEPTED_PREFIX_MONO THEN ARITH_TAC; ALL_TAC] THEN + MIDEXIT_MEMACC_CORE_TAC f_ev_midexit_subiter3);; + +let MEMACCESS_F_EV_MIDEXIT_SUBITER4 = prove + (`!res buf table pc mask i. + 16 * i + 16 <= 136 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * i + 24) mask) <= 248 + ==> memaccess_inbounds (f_ev_midexit_subiter4 res buf table pc mask i) + [(buf:int64),136; (table:int64),2048] [(res:int64),1024]`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN + `NUM_ACCEPTED (SUB_LIST (0,32 * i) mask) <= 248 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * i + 8) mask) <= 248 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * i + 16) mask) <= 248` + STRIP_ASSUME_TAC THENL + [REPEAT CONJ_TAC THEN TRANS_TAC LE_TRANS `NUM_ACCEPTED (SUB_LIST (0,32 * i + 24) mask)` THEN + ASM_REWRITE_TAC[] THEN MATCH_MP_TAC NUM_ACCEPTED_PREFIX_MONO THEN ARITH_TAC; ALL_TAC] THEN + MIDEXIT_MEMACC_CORE_TAC f_ev_midexit_subiter4);; + +(* --- The 4 MID_EXIT_SUBITER SAFE arms --- *) +let EXEC = MLDSA_REJ_UNIFORM_ETA2_EXEC;; + +let midexit_safe_eta2_tm value_tm fev_tm = + let qvars, body = strip_forall value_tm in + let hyps_tm, ens = dest_imp body in + let ensc, ppf = strip_comb ens in + let pre = el 1 ppf and post = el 2 ppf and frame = el 3 ppf in + let sv, preb = dest_abs pre in + let sv2, postb = dest_abs post in + let pretempl = `read events (s:x86state) = (e:(uarch_event)list)` in + let posttempl = + mk_conj(`read events (s:x86state) = APPEND FEV (e:(uarch_event)list)`, + `memaccess_inbounds FEV [(buf:int64),136; (table:int64),2048] [(res:int64),1024]`) in + let posttempl = subst [fev_tm, `FEV:(uarch_event)list`] posttempl in + let pre' = mk_abs(sv, mk_conj(preb, vsubst[sv,`s:x86state`] pretempl)) in + let post' = mk_abs(sv2, mk_conj(postb, vsubst[sv2,`s:x86state`] posttempl)) in + let ens' = list_mk_comb(ensc,[el 0 ppf; pre'; post'; frame]) in + list_mk_forall(qvars @ [`e:(uarch_event)list`], mk_imp(hyps_tm, ens'));; + +let midexit1_safe_eta2_tm = + midexit_safe_eta2_tm midexit1_eta2_tm + `f_ev_midexit_subiter1 res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) i`;; + +let ETA2_MIDEXIT_OPEN_SAFE_TAC : tactic = + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN `16 * i <= 120` ASSUME_TAC THENL + [UNDISCH_TAC `16 * (i + 1) <= 136` THEN ARITH_TAC; ALL_TAC] THEN + ENSURES_INIT_TAC "s0" THEN + MP_TAC(SPECL [`buf:int64`;`136`;`inlist:byte list`;`i:num`;`s0:x86state`] SUB_LIST_16_BYTES_FROM_INT128) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN UNDISCH_TAC `16 * (i + 1) <= 136` THEN ARITH_TAC; ALL_TAC] THEN + ABBREV_TAC `chunk0 = read(memory:>bytes128(word_add buf (word(16*i)))) s0` THEN DISCH_TAC THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0, 16*i) inlist):int32 list) <= 248` ASSUME_TAC THENL + [FIRST [FIRST_ASSUM ACCEPT_TAC; + (FIRST_X_ASSUM(fun th -> match concl th with + Comb(Comb(Const("<=",_),Comb(Const("LENGTH",_),Comb(Const("REJ_SAMPLE_ETA2_BYTES",_),_))),k) when k=`248` + -> MP_TAC th | _ -> NO_TAC) THEN + MATCH_MP_TAC(ARITH_RULE `a <= b ==> b <= 248 ==> a <= 248`) THEN + MATCH_MP_TAC REJ_SAMPLE_ETA2_PREFIX_MONO THEN ARITH_TAC)]; ALL_TAC] THEN + ABBREV_TAC `outlen0 = LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0, 16*i) inlist):int32 list)` THEN + FIRST_ASSUM(fun th -> if concl th = + `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0, 16*i) inlist):int32 list) = outlen0` + then (RULE_ASSUM_TAC(REWRITE_RULE[th]) THEN ASSUME_TAC th) else NO_TAC) THEN + MP_TAC(SPECL [`outlen0:num`;`248`] JA_NOT_TAKEN_LE) THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN + MP_TAC(SPECL [`16*i`;`120`] JA_NOT_TAKEN_LE) THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN + VAL_INT64_TAC `outlen0:num` THEN + X86_STEPS_TAC EXEC (1--2) THEN + SUBGOAL_THEN `read RIP s2 = word(pc + 97):int64` ASSUME_TAC THENL + [FIRST_X_ASSUM(fun th -> if is_imp(concl th) && can(find_term((=)`&248:int`))(concl th) + then ASSUME_TAC(MP th (EQT_ELIM(NUM_REDUCE_CONV(lhand(concl th))))) else NO_TAC) THEN + FIRST_X_ASSUM(fun th -> if can(find_term((=)`pc + 399`))(concl th) && + (match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("read",_),Const("RIP",_)),Var("s2",_))),_) -> true + | _ -> false) + then MP_TAC th else NO_TAC) THEN + ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN REFL_TAC; ALL_TAC] THEN + X86_STEPS_TAC EXEC (3--4) THEN + SUBGOAL_THEN `read RIP s4 = word(pc + 106):int64` ASSUME_TAC THENL + [FIRST_X_ASSUM(fun th -> if is_imp(concl th) && can(find_term((=)`&120:int`))(concl th) + then ASSUME_TAC(MP th (EQT_ELIM(NUM_REDUCE_CONV(lhand(concl th))))) else NO_TAC) THEN + FIRST_X_ASSUM(fun th -> if can(find_term((=)`pc + 399`))(concl th) && + (match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("read",_),Const("RIP",_)),Var("s4",_))),_) -> true + | _ -> false) + then MP_TAC th else NO_TAC) THEN + ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST1_TAC THEN REFL_TAC; ALL_TAC];; + +let ETA2_MIDEXIT_PREFIX_SAFE_TAC : tactic = + ETA2_MIDEXIT_OPEN_SAFE_TAC THEN + X86_VSTEPS_TAC EXEC (5--5) THEN + SUBGOAL_THEN `val(word(16*i):int64) = 16*i` ASSUME_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN + UNDISCH_TAC `16*i <= 120` THEN ARITH_TAC; ALL_TAC] THEN + RULE_ASSUM_TAC(REWRITE_RULE[ASSUME `val(word(16*i):int64) = 16*i`; ARITH_RULE `1 * x = x`]) THEN + RULE_ASSUM_TAC(REWRITE_RULE[ASSUME `read (memory :> bytes128 (word_add buf (word (16 * i)))) s4 = chunk0`]) THEN + SUBGOAL_THEN `read YMM0 s5 = usimd16 (\b:byte. word_zx b:int16) chunk0:int256` ASSUME_TAC THENL + [FIRST_X_ASSUM(fun th -> if is_eq(concl th) && can(find_term((=)`read YMM0 s5`))(lhand(concl th)) then SUBST1_TAC th else NO_TAC) THEN + REWRITE_TAC[usimd16;usimd8;usimd4;usimd2;DIMINDEX_8;DIMINDEX_16;DIMINDEX_32;DIMINDEX_64;DIMINDEX_128] THEN + CONV_TAC WORD_BLAST; ALL_TAC] THEN + DROP_WORDJOIN_TAC THEN PURGE_STALE_STATES_TAC ["s4"] THEN + X86_VSTEPS_TAC EXEC (6--6) THEN + RULE_ASSUM_TAC(REWRITE_RULE[ASSUME `read YMM0 s5 = usimd16 (\b:byte. word_zx b:int16) chunk0:int256`]) THEN + X86_VSTEPS_TAC EXEC (7--7) THEN X86_VSTEPS_TAC EXEC (8--8) THEN + RULE_ASSUM_TAC(REWRITE_RULE[ASSUME `read YMM3 s5 = + word 6811299366900952671974763824040465167839410862684739061144563765171360567055:int256`]) THEN + SUBGOAL_THEN (mk_eq(`read YMM0 s8:int256`, F0NIB_CHUNK0)) ASSUME_TAC THENL + [FIRST_X_ASSUM(fun th -> if is_eq(concl th) && can(find_term((=)`read YMM0 s8`))(lhand(concl th)) then SUBST1_TAC th else NO_TAC) THEN + REWRITE_TAC[usimd16;usimd8;usimd4;usimd2;DIMINDEX_8;DIMINDEX_16;DIMINDEX_32;DIMINDEX_64;DIMINDEX_128] THEN + CONV_TAC WORD_BLAST; ALL_TAC] THEN + DROP_WORDJOIN_TAC THEN PURGE_STALE_STATES_TAC ["s5";"s6";"s7"] THEN + X86_VSTEPS_TAC EXEC (9--9) THEN + ABBREV_TAC `f1bnd:int256 = read YMM1 s9` THEN + ETA2_MASKBIT_ASSUME_TAC 0 THEN + ETA2_MASKBIT_ASSUME_TAC 8 THEN + ETA2_MASKBIT_ASSUME_TAC 16 THEN + ETA2_MASKBIT_ASSUME_TAC 24 THEN + REPEAT(FIRST_X_ASSUM(fun th -> + if is_eq(concl th) && lhand(concl th) = `f1bnd:int256` + then ALL_TAC else failwith "keep")) THEN + X86_VSTEPS_TAC EXEC (10--10) THEN + X86_VSTEPS_TAC EXEC (11--11) THEN + ABBREV_TAC `f0sub:int256 = read YMM0 s11` THEN + eta2_gather_block g1_eta2 (eta2_ellist 0) false THEN + eta2_gather_block g2_eta2 (eta2_ellist 32) true THEN + eta2_gather_block g3_eta2 (eta2_ellist 64) false THEN + eta2_gather_block g4_eta2 (eta2_ellist 96) true THEN + ETA2_SI1_FOLD;; + +let SUBITER1_BODY_TAC : tactic = + SUBGOAL_THEN `16 * i + 4 <= LENGTH(inlist:byte list)` ASSUME_TAC THENL + [UNDISCH_TAC `16 * (i+1) <= 136` THEN UNDISCH_TAC `LENGTH(inlist:byte list)=136` THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*i+4) inlist):int32 list) <= 256` ASSUME_TAC THENL + [MATCH_MP_TAC OUTLEN0_LE_256_FROM_SUBITER_ETA2 THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*i+4) inlist):int32 list) < 2 EXP 32` ASSUME_TAC THENL + [UNDISCH_TAC `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*i+4) inlist):int32 list) <= 256` THEN ARITH_TAC; ALL_TAC] THEN + X86_STEPS_TAC EXEC (21--24) THEN + MP_TAC(ISPECL[`inlist:byte list`;`i:num`;`chunk0:int128`] SUBITER_BLOCK_BYTES) THEN + ANTS_TAC THENL + [ASM_REWRITE_TAC[] THEN UNDISCH_TAC `LENGTH(inlist:byte list) = 136` THEN + UNDISCH_TAC `16 * i <= 120` THEN ARITH_TAC; STRIP_TAC] THEN + W(fun (asl,w) -> + let m8def = find (fun th -> match concl th with Comb(Comb(Const("=",_),_),Var("mask8",_)) -> true | _ -> false) (map snd asl) in + RULE_ASSUM_TAC(fun th -> if concl th = maskbit_tgt || + can(find_term(fun u->match u with Const("TABLE_ENTRY",_)->true|_->false))(concl th) + then th else REWRITE_RULE[GSYM m8def] th)) THEN + W(fun (asl,w) -> + let r9 = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("read",_),Const("R9",_)),Var("s24",_))),_) -> true | _ -> false) asl in + let goal_pc = find_term (fun t -> match t with Comb(Const("word_popcount",_),_) -> true | _ -> false) (concl(snd r9)) in + let low8 = `bitval(bit 7 (word_subword (f1bnd:int256) (0,8):byte)) + bitval(bit 7 (word_subword f1bnd (8,8):byte)) + + bitval(bit 7 (word_subword f1bnd (16,8):byte)) + bitval(bit 7 (word_subword f1bnd (24,8):byte)) + + bitval(bit 7 (word_subword f1bnd (32,8):byte)) + bitval(bit 7 (word_subword f1bnd (40,8):byte)) + + bitval(bit 7 (word_subword f1bnd (48,8):byte)) + bitval(bit 7 (word_subword f1bnd (56,8):byte))` in + let mr = CONV_RULE(DEPTH_CONV BETA_CONV THENC NUM_REDUCE_CONV) + (SPEC `\k. bit 7 (word_subword (f1bnd:int256) (8*k,8):byte)` MOD_RED) in + let popeq = prove(mk_eq(goal_pc, low8), + REWRITE_TAC[VAL_WORD_ZX_GEN; VAL_WORD; DIMINDEX_8; DIMINDEX_32; DIMINDEX_64] THEN + REWRITE_TAC[ARITH_RULE `256 = 2 EXP 8`; MOD_MOD_EXP_MIN] THEN + CONV_TAC(ONCE_DEPTH_CONV NUM_REDUCE_CONV) THEN + REWRITE_TAC[ARITH_RULE `2 EXP 8 = 256`; mr] THEN + MAP_EVERY (fun b -> BOOL_CASES_TAC b) + [`bit 7 (word_subword (f1bnd:int256) (0,8):byte)`;`bit 7 (word_subword (f1bnd:int256) (8,8):byte)`; + `bit 7 (word_subword (f1bnd:int256) (16,8):byte)`;`bit 7 (word_subword (f1bnd:int256) (24,8):byte)`; + `bit 7 (word_subword (f1bnd:int256) (32,8):byte)`;`bit 7 (word_subword (f1bnd:int256) (40,8):byte)`; + `bit 7 (word_subword (f1bnd:int256) (48,8):byte)`;`bit 7 (word_subword (f1bnd:int256) (56,8):byte)`] THEN + REWRITE_TAC[BITVAL_CLAUSES] THEN CONV_TAC NUM_REDUCE_CONV THEN CONV_TAC WORD_REDUCE_CONV) in + let maskbit = snd(find (fun (_,th) -> let c=concl th in is_forall c && + can(find_term(fun u->u=`f1bnd:int256`))c && can(find_term(fun u->match u with Comb(Const("bit",_),_)->true|_->false))c && + not(can(find_term(fun u->match u with Const("word_zx",_)->true|_->false))c) && + can(find_term(fun u->u=`word_subword (chunk0:int128) (24,8):byte`))c && + not(can(find_term(fun u->u=`word_subword (chunk0:int128) (32,8):byte`))c)) asl) in + let mb_tm = concl maskbit in + let blk0 = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),l),_) -> (try let h,args=strip_comb l in fst(dest_const h)="SUB_LIST" && + (match args with [Comb(Comb(_,off),wid);_] -> wid=`4` && (match off with Comb(Comb(Const("*",_),_),_)->true|_->false) | _->false) with _->false) | _ -> false) asl in + let blkeq = mk_eq(low8, `LENGTH(REJ_NIBBLES_ETA2 (SUB_LIST(16*i,4) inlist):int16 list)`) in + let blk0_tm = concl(snd blk0) in + let bsum_raw = prove(mk_imp(mb_tm, mk_imp(blk0_tm, blkeq)), + DISCH_THEN(fun mbthm -> + let mbs = map (fun k -> let th=SPEC(mk_small_numeral k) mbthm in + CONV_RULE (NUM_REDUCE_CONV THENC ONCE_DEPTH_CONV EL_CONV) (MP th (EQT_ELIM(NUM_REDUCE_CONV(lhand(concl th)))))) [0;1;2;3;4;5;6;7] in + REWRITE_TAC mbs) THEN DISCH_THEN(fun b -> REWRITE_TAC[b]) THEN + GEN_REWRITE_TAC RAND_CONV [GSYM LENGTH_FILTER_BYTE_NIBBLES_4_BYTES] THEN + REWRITE_TAC[GSYM BITVAL_SUM_8_EQ_LENGTH_FILTER_ETA2] THEN + ASM_SIMP_TAC[VAL_WORD_BYTE_LT256; BYTE_DIV16_LT; BYTE_MOD16_LT]) in + let bsum = MP (MP bsum_raw maskbit) (snd blk0) in + let pop_len = TRANS popeq bsum in + ASSUME_TAC pop_len) THEN + SUBGOAL_THEN `outlen0 + LENGTH(REJ_NIBBLES_ETA2 (SUB_LIST(16*i,4) inlist):int16 list) = LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*i+4) inlist):int32 list)` ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`;`16*i`] SUBITER_BRIDGE_ETA2) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN + DISCH_THEN(CONJUNCTS_THEN2 (K ALL_TAC) (CONJUNCTS_THEN2 MP_TAC (K ALL_TAC))) THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA2_BYTES] THEN + UNDISCH_TAC `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*i) inlist):int32 list) = outlen0` THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA2_BYTES] THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `outlen0 + LENGTH(REJ_NIBBLES_ETA2 (SUB_LIST(16*i,4) inlist):int16 list) < 2 EXP 32` ASSUME_TAC THENL + [FIRST_X_ASSUM(fun th -> if (match concl th with Comb(Comb(Const("=",_),Comb(Comb(Const("+",_),Var("outlen0",_)),_)),_)->true|_->false) then SUBST1_TAC th else NO_TAC) THEN + UNDISCH_TAC `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*i+4) inlist):int32 list) < 2 EXP 32` THEN REWRITE_TAC[]; ALL_TAC] THEN + W(fun (asl,w) -> + let block0len = `LENGTH(REJ_NIBBLES_ETA2 (SUB_LIST(16*i,4) inlist):int16 list)` in + let sum = mk_binop `(+):num->num->num` `outlen0:num` block0len in + let lt32 = snd(find (fun (_,th) -> concl th = mk_binop `(<):num->num->bool` sum `2 EXP 32`) asl) in + let pop_len = snd(find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_popcount",_),_)),_) -> true | _ -> false) asl) in + let bridge = snd(find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("+",_),Var("outlen0",_)),_)),_) -> true | _ -> false) asl) in + let rax_red0 = MATCH_MP RAX_NEST_REDUCE lt32 in + let gt248 = REWRITE_RULE[SYM bridge] (snd(find (fun (_,th) -> concl th = `248 < LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*i+4) inlist):int32 list)`) asl)) in + let ja_taken = MP (ISPECL [sum; `248`] JA_TAKEN_GT) (CONJ gt248 lt32) in + ASSUME_TAC pop_len THEN ASSUME_TAC rax_red0 THEN ASSUME_TAC ja_taken) THEN + X86_STEPS_TAC EXEC (25--26) THEN + SUBGOAL_THEN `read RIP s26 = word (pc + 399):int64` ASSUME_TAC THENL + [W(fun (asl,w) -> + let blk0 = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),l),_) -> (try let h,args=strip_comb l in fst(dest_const h)="SUB_LIST" && + (match args with [Comb(Comb(_,off),wid);_] -> wid=`4` && (match off with Comb(Comb(Const("*",_),_),_)->true|_->false) | _->false) with _->false) | _ -> false) asl in + let rax_red0 = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_zx",_),Comb(Comb(Const("word_add",_),_),_))),_) -> true | _ -> false) asl in + let ja = find (fun (_,th) -> is_neg(concl th) && + can(find_term(fun u->match u with Const("word_sub",_)->true|_->false))(concl th) && + can(find_term(fun u->u=`248`))(concl th)) asl in + let ifrip = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("read",_),Const("RIP",_)),Var("s26",_))),r) -> + (match r with Comb(Comb(Comb(Const("COND",_),_),_),_) -> true | _ -> false) | _ -> false) asl in + MP_TAC (snd ifrip) THEN + REWRITE_TAC[GSYM(snd blk0)] THEN REWRITE_TAC[snd rax_red0] THEN + REWRITE_TAC[snd ja] THEN DISCH_THEN SUBST1_TAC THEN REFL_TAC); + ALL_TAC] THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN + W(fun (asl,w) -> + let blk0 = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),l),_) -> (try let h,args=strip_comb l in fst(dest_const h)="SUB_LIST" && + (match args with [Comb(Comb(_,off),wid);_] -> wid=`4` && (match off with Comb(Comb(Const("*",_),_),_)->true|_->false) | _->false) with _->false) | _ -> false) asl in + let rax_red0 = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_zx",_),Comb(Comb(Const("word_add",_),_),_))),_) -> true | _ -> false) asl in + let bridge = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("+",_),Var("outlen0",_)),_)),_) -> true | _ -> false) asl in + REWRITE_TAC[GSYM(snd blk0); snd rax_red0; snd bridge]) THEN + W(fun (asl,w) -> + let ntake = MP (ISPECL [`LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*i+4) inlist):int32 list)`;`248`] JA_TAKEN_GT) + (CONJ (ASSUME `248 < LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*i+4) inlist):int32 list)`) + (ASSUME `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*i+4) inlist):int32 list) < 2 EXP 32`)) in + REWRITE_TAC[ntake]) THEN + SUBGOAL_THEN `val(word(16*i):int64) = 16*i` ASSUME_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN UNDISCH_TAC `16*i<=120` THEN ARITH_TAC; ALL_TAC] THEN + MP_TAC(SPEC `16*i` RCX4_COLLAPSE) THEN + ANTS_TAC THENL [UNDISCH_TAC `16*i<=120` THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(fun th -> REWRITE_TAC[th]);; + +let MID_EXIT_SUBITER1_SAFE_CLOSER : tactic = + CONJ_TAC THENL + [FIRST_ASSUM(fun a1 -> FIRST_ASSUM(fun a2 -> ASSUME_TAC(MP (MP P0_BRIDGE a1) a2))) THEN + SUBGOAL_THEN `outlen0 = NUM_ACCEPTED(SUB_LIST(0,32*i)(REJ_MASK_ETA2 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,16 * i) inlist):int32 list) = outlen0` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i) = 32 * i`](ISPECL[`inlist:byte list`;`16*i`] STORE_BRIDGE)); + ALL_TAC] THEN + ASM_REWRITE_TAC[f_ev_midexit_subiter1; APPEND]; + MATCH_MP_TAC MEMACCESS_F_EV_MIDEXIT_SUBITER1 THEN + CONJ_TAC THENL + [UNDISCH_TAC `16 * (i + 1) <= 136` THEN ARITH_TAC; + MP_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i) = 32 * i`] + (ISPECL[`inlist:byte list`;`16*i`] STORE_BRIDGE)) THEN + DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_REWRITE_TAC[]]];; + +let MID_EXIT_SUBITER1_SAFE_ETA2 = prove(midexit1_safe_eta2_tm, + ETA2_MIDEXIT_PREFIX_SAFE_TAC THEN SUBITER1_BODY_TAC THEN MID_EXIT_SUBITER1_SAFE_CLOSER);; + +(* --- SUBITER2 (s140) --- *) +let midexit2_safe_eta2_tm = + midexit_safe_eta2_tm midexit2_eta2_tm + `f_ev_midexit_subiter2 res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) i`;; + +let MP_BRIDGE_FROM_ASL (bridge:thm) : tactic = + W(fun (asl,w) -> + let asms = map snd asl in + let rec go th = + if is_imp (concl th) then + let ante = lhand (concl th) in + let a = try find (fun a -> aconv (concl a) ante) asms + with Failure _ -> + failwith ("MP_BRIDGE_FROM_ASL: unmatched antecedent: " ^ + string_of_term ante) in + go (MP th a) + else th in + ASSUME_TAC (go bridge));; + +let SUBITER2_SAFE_DISCH : tactic = + CONJ_TAC THENL + [MP_BRIDGE_FROM_ASL P0_BRIDGE THEN + MP_BRIDGE_FROM_ASL GATHER_BRIDGE1 THEN + SUBGOAL_THEN `outlen0 = NUM_ACCEPTED(SUB_LIST(0,32*i)(REJ_MASK_ETA2 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,16 * i) inlist):int32 list) = outlen0` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i) = 32 * i`](ISPECL[`inlist:byte list`;`16*i`] STORE_BRIDGE)); ALL_TAC] THEN + SUBGOAL_THEN `acc1 = NUM_ACCEPTED(SUB_LIST(0,32*i+8)(REJ_MASK_ETA2 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,16 * i + 4) inlist):int32 list) = acc1` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 4) = 32 * i + 8`](ISPECL[`inlist:byte list`;`16*i+4`] STORE_BRIDGE)); ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_NIBBLES_ETA2 [word_subword (chunk0:int128) (0,8); word_subword chunk0 (8,8); + word_subword chunk0 (16,8); word_subword chunk0 (24,8)]:int16 list) = + NUM_ACCEPTED(SUB_LIST(32*i,8)(REJ_MASK_ETA2 (inlist:byte list)))` + ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if (match concl th with + Comb(Comb(Const("=",_),l),_) -> l = `SUB_LIST (16 * i,4) (inlist:byte list)` | _ -> false) + then SUBST1_TAC(SYM th) else NO_TAC) THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA2_EQ_MASK; GSYM NUM_ACCEPTED; REJ_MASK_ETA2_SUB_LIST] THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * i) = 32 * i`; ARITH_RULE `2 * 4 = 8`]; ALL_TAC] THEN + ASM_REWRITE_TAC[f_ev_midexit_subiter2; APPEND]; + MATCH_MP_TAC MEMACCESS_F_EV_MIDEXIT_SUBITER2 THEN + CONJ_TAC THENL + [UNDISCH_TAC `16 * (i + 1) <= 136` THEN ARITH_TAC; + MP_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 4) = 32 * i + 8`] + (ISPECL[`inlist:byte list`;`16*i+4`] STORE_BRIDGE)) THEN + DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_REWRITE_TAC[]]];; + +let MID_EXIT_SUBITER2_SAFE_ETA2 = prove(midexit2_safe_eta2_tm, + mk_midexit2_eta2 true ETA2_MIDEXIT_PREFIX_SAFE_TAC SUBITER2_SAFE_DISCH);; + +(* --- SUBITER3 (s142) --- *) +let midexit3_safe_eta2_tm = + midexit_safe_eta2_tm midexit3_eta2_tm + `f_ev_midexit_subiter3 res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) i`;; + +let ASSUME_MASK_TOWERS : tactic = + W(fun (asl,w) -> + let asms = map snd asl in + let fnd p = find (fun th -> p (concl th)) asms in + let tower8_mask8b = fnd (fun c -> is_eq c && rand c = `mask8b:int64` && + can (find_term (fun u -> match u with Const("word_ushr",_)->true|_->false)) c) in + let mask8c_def = fnd (fun c -> is_eq c && rand c = `mask8c:int64`) in + let t16m8c = REWRITE_RULE[SYM tower8_mask8b] mask8c_def in + let t24opt = + try let mask8d_def = fnd (fun c -> is_eq c && rand c = `mask8d:int64` && + can (find_term (fun u -> match u with Const("word_ushr",_)->true|_->false)) c) in + [REWRITE_RULE[SYM t16m8c] mask8d_def] + with Failure _ -> [] in + EVERY (map ASSUME_TAC (t16m8c :: t24opt)));; + +let SUBITER3_SAFE_DISCH : tactic = + CONJ_TAC THENL + [ASSUME_MASK_TOWERS THEN + MP_BRIDGE_FROM_ASL P0_BRIDGE THEN + MP_BRIDGE_FROM_ASL GATHER_BRIDGE1 THEN + MP_BRIDGE_FROM_ASL GATHER_BRIDGE2 THEN + SUBGOAL_THEN `outlen0 = NUM_ACCEPTED(SUB_LIST(0,32*i)(REJ_MASK_ETA2 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,16 * i) inlist):int32 list) = outlen0` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i) = 32 * i`](ISPECL[`inlist:byte list`;`16*i`] STORE_BRIDGE)); ALL_TAC] THEN + SUBGOAL_THEN `acc1 = NUM_ACCEPTED(SUB_LIST(0,32*i+8)(REJ_MASK_ETA2 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,16 * i + 4) inlist):int32 list) = acc1` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 4) = 32 * i + 8`](ISPECL[`inlist:byte list`;`16*i+4`] STORE_BRIDGE)); ALL_TAC] THEN + SUBGOAL_THEN `acc2 = NUM_ACCEPTED(SUB_LIST(0,32*i+16)(REJ_MASK_ETA2 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,16 * i + 8) inlist):int32 list) = acc2` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 8) = 32 * i + 16`](ISPECL[`inlist:byte list`;`16*i+8`] STORE_BRIDGE)); ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_NIBBLES_ETA2 [word_subword (chunk0:int128) (0,8); word_subword chunk0 (8,8); + word_subword chunk0 (16,8); word_subword chunk0 (24,8)]:int16 list) = + NUM_ACCEPTED(SUB_LIST(32*i,8)(REJ_MASK_ETA2 (inlist:byte list)))` + ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if (match concl th with + Comb(Comb(Const("=",_),l),_) -> l = `SUB_LIST (16 * i,4) (inlist:byte list)` | _ -> false) + then SUBST1_TAC(SYM th) else NO_TAC) THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA2_EQ_MASK; GSYM NUM_ACCEPTED; REJ_MASK_ETA2_SUB_LIST] THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * i) = 32 * i`; ARITH_RULE `2 * 4 = 8`]; ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_NIBBLES_ETA2 [word_subword (chunk0:int128) (32,8); word_subword chunk0 (40,8); + word_subword chunk0 (48,8); word_subword chunk0 (56,8)]:int16 list) = + NUM_ACCEPTED(SUB_LIST(32*i+8,8)(REJ_MASK_ETA2 (inlist:byte list)))` + ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if (match concl th with + Comb(Comb(Const("=",_),l),_) -> l = `SUB_LIST (16 * i + 4,4) (inlist:byte list)` | _ -> false) + then SUBST1_TAC(SYM th) else NO_TAC) THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA2_EQ_MASK; GSYM NUM_ACCEPTED; REJ_MASK_ETA2_SUB_LIST] THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * i + 4) = 32 * i + 8`; ARITH_RULE `2 * 4 = 8`]; ALL_TAC] THEN + ASM_REWRITE_TAC[f_ev_midexit_subiter3; APPEND]; + MATCH_MP_TAC MEMACCESS_F_EV_MIDEXIT_SUBITER3 THEN + CONJ_TAC THENL + [UNDISCH_TAC `16 * (i + 1) <= 136` THEN ARITH_TAC; + MP_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 8) = 32 * i + 16`] + (ISPECL[`inlist:byte list`;`16*i+8`] STORE_BRIDGE)) THEN + DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_REWRITE_TAC[]]];; + +let MID_EXIT_SUBITER3_SAFE_ETA2 = prove(midexit3_safe_eta2_tm, + mk_midexit3_eta2 true ETA2_MIDEXIT_PREFIX_SAFE_TAC SUBITER3_SAFE_DISCH);; + +(* --- SUBITER4 (s143) --- *) +let midexit4_safe_eta2_tm = + midexit_safe_eta2_tm midexit4_eta2_tm + `f_ev_midexit_subiter4 res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) i`;; + +let SUB4_MG3_REDUCE : tactic = + W(fun (asl,w) -> + let asms = map snd asl in + let find_a p = find p asms in + let i_le = find_a (fun th -> concl th = `16 * i <= 120`) in + let leninl = find_a (fun th -> concl th = `LENGTH(inlist:byte list) = 136`) in + let blk16 = find_a (fun th -> is_eq(concl th) && + (try fst(dest_const(fst(strip_comb(lhand(concl th)))))="SUB_LIST" && + length(dest_list(rand(concl th)))=16 with _->false)) in + let bb = MP (ISPECL [`inlist:byte list`; `i:num`; `chunk0:int128`] SUBITER_BLOCK_BYTES) + (CONJ (REWRITE_RULE[GSYM leninl] (MP (ARITH_RULE `16*i<=120 ==> 16*i+16<=136`) i_le)) blk16) in + let blk2_eq = el 2 (CONJUNCTS bb) in + let ident = find_a (fun th -> match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("+",_),Var("acc2",_)),_)),Var("acc3",_)) -> true + | _ -> false) in + let acc3_le = find_a (fun th -> concl th = `acc3 <= 248`) in + let bnd_sublist = REWRITE_RULE[SYM ident] acc3_le in + let bnd_chunk = REWRITE_RULE[blk2_eq] bnd_sublist in + let sum = lhand(concl bnd_chunk) in + let lt32 = MATCH_MP (ARITH_RULE `a + b <= 248 ==> a + b < 2 EXP 32`) bnd_chunk in + let rax_red = MATCH_MP RAX_NEST_REDUCE lt32 in + let ja = MP (ISPECL [sum; `248`] JA_NOT_TAKEN_LE) (CONJ bnd_chunk (ARITH_RULE `248 < 2 EXP 32`)) in + REWRITE_TAC[rax_red; ja]);; + +let SUB4_EVENTS_CLOSER : tactic = + ASSUME_MASK_TOWERS THEN + MP_BRIDGE_FROM_ASL P0_BRIDGE THEN + MP_BRIDGE_FROM_ASL GATHER_BRIDGE1 THEN + MP_BRIDGE_FROM_ASL GATHER_BRIDGE2 THEN + MP_BRIDGE_FROM_ASL GATHER_BRIDGE3 THEN + SUBGOAL_THEN `outlen0 = NUM_ACCEPTED(SUB_LIST(0,32*i)(REJ_MASK_ETA2 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,16 * i) inlist):int32 list) = outlen0` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i) = 32 * i`](ISPECL[`inlist:byte list`;`16*i`] STORE_BRIDGE)); ALL_TAC] THEN + SUBGOAL_THEN `acc1 = NUM_ACCEPTED(SUB_LIST(0,32*i+8)(REJ_MASK_ETA2 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,16 * i + 4) inlist):int32 list) = acc1` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 4) = 32 * i + 8`](ISPECL[`inlist:byte list`;`16*i+4`] STORE_BRIDGE)); ALL_TAC] THEN + SUBGOAL_THEN `acc2 = NUM_ACCEPTED(SUB_LIST(0,32*i+16)(REJ_MASK_ETA2 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,16 * i + 8) inlist):int32 list) = acc2` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 8) = 32 * i + 16`](ISPECL[`inlist:byte list`;`16*i+8`] STORE_BRIDGE)); ALL_TAC] THEN + SUBGOAL_THEN `acc3 = NUM_ACCEPTED(SUB_LIST(0,32*i+24)(REJ_MASK_ETA2 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,16 * i + 12) inlist):int32 list) = acc3` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 12) = 32 * i + 24`](ISPECL[`inlist:byte list`;`16*i+12`] STORE_BRIDGE)); ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_NIBBLES_ETA2 [word_subword (chunk0:int128) (0,8); word_subword chunk0 (8,8); + word_subword chunk0 (16,8); word_subword chunk0 (24,8)]:int16 list) = + NUM_ACCEPTED(SUB_LIST(32*i,8)(REJ_MASK_ETA2 (inlist:byte list)))` + ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if (match concl th with + Comb(Comb(Const("=",_),l),_) -> l = `SUB_LIST (16 * i,4) (inlist:byte list)` | _ -> false) + then SUBST1_TAC(SYM th) else NO_TAC) THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA2_EQ_MASK; GSYM NUM_ACCEPTED; REJ_MASK_ETA2_SUB_LIST] THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * i) = 32 * i`; ARITH_RULE `2 * 4 = 8`]; ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_NIBBLES_ETA2 [word_subword (chunk0:int128) (32,8); word_subword chunk0 (40,8); + word_subword chunk0 (48,8); word_subword chunk0 (56,8)]:int16 list) = + NUM_ACCEPTED(SUB_LIST(32*i+8,8)(REJ_MASK_ETA2 (inlist:byte list)))` + ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if (match concl th with + Comb(Comb(Const("=",_),l),_) -> l = `SUB_LIST (16 * i + 4,4) (inlist:byte list)` | _ -> false) + then SUBST1_TAC(SYM th) else NO_TAC) THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA2_EQ_MASK; GSYM NUM_ACCEPTED; REJ_MASK_ETA2_SUB_LIST] THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * i + 4) = 32 * i + 8`; ARITH_RULE `2 * 4 = 8`]; ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_NIBBLES_ETA2 [word_subword (chunk0:int128) (64,8); word_subword chunk0 (72,8); + word_subword chunk0 (80,8); word_subword chunk0 (88,8)]:int16 list) = + NUM_ACCEPTED(SUB_LIST(32*i+16,8)(REJ_MASK_ETA2 (inlist:byte list)))` + ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if (match concl th with + Comb(Comb(Const("=",_),l),_) -> l = `SUB_LIST (16 * i + 8,4) (inlist:byte list)` | _ -> false) + then SUBST1_TAC(SYM th) else NO_TAC) THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA2_EQ_MASK; GSYM NUM_ACCEPTED; REJ_MASK_ETA2_SUB_LIST] THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * i + 8) = 32 * i + 16`; ARITH_RULE `2 * 4 = 8`]; ALL_TAC] THEN + SUB4_MG3_REDUCE THEN + ASM_REWRITE_TAC[f_ev_midexit_subiter4; APPEND];; + +let SUB4_MEMACCESS_CLOSER : tactic = + MATCH_MP_TAC MEMACCESS_F_EV_MIDEXIT_SUBITER4 THEN + CONJ_TAC THENL + [UNDISCH_TAC `16 * (i + 1) <= 136` THEN ARITH_TAC; + MP_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 12) = 32 * i + 24`] + (ISPECL[`inlist:byte list`;`16*i+12`] STORE_BRIDGE)) THEN + DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_REWRITE_TAC[]];; + +let SUBITER4_SAFE_DISCH : tactic = + W(fun (asl,w) -> if is_eq w then SUB4_EVENTS_CLOSER else SUB4_MEMACCESS_CLOSER);; + +let MID_EXIT_SUBITER4_SAFE_ETA2 = prove(midexit4_safe_eta2_tm, + mk_midexit4_eta2 true ETA2_MIDEXIT_PREFIX_SAFE_TAC SUBITER4_SAFE_DISCH);; + +(* --- nibble<->mask bridges --- *) +let LENGTH_NIBBLES_OF_BYTES = prove + (`!l:byte list. LENGTH(NIBBLES_OF_BYTES l) = 2 * LENGTH l`, + LIST_INDUCT_TAC THEN + ASM_REWRITE_TAC[NIBBLES_OF_BYTES; NIBBLE_PAIR; LENGTH; LENGTH_APPEND] THEN + ARITH_TAC);; + +let EL_NIBBLES_OF_BYTES = prove + (`!(l:byte list) p. p < LENGTH l + ==> EL (2*p) (NIBBLES_OF_BYTES l) = (word(val(EL p l) MOD 16):int16) /\ + EL (2*p+1) (NIBBLES_OF_BYTES l) = (word(val(EL p l) DIV 16):int16)`, + LIST_INDUCT_TAC THENL + [REWRITE_TAC[LENGTH; LT]; + GEN_TAC THEN REWRITE_TAC[LENGTH] THEN + STRUCT_CASES_TAC(SPEC `p:num` num_CASES) THEN + REWRITE_TAC[NIBBLES_OF_BYTES; NIBBLE_PAIR; APPEND] THENL + [REWRITE_TAC[ARITH_RULE `2 * 0 = 0`; ARITH_RULE `2 * 0 + 1 = SUC 0`; + EL; HD; TL]; + REWRITE_TAC[LT_SUC] THEN DISCH_TAC THEN + REWRITE_TAC[ARITH_RULE `2 * SUC n = SUC(SUC(2*n))`; + ARITH_RULE `2 * SUC n + 1 = SUC(SUC(2*n+1))`; + EL; TL; HD] THEN + FIRST_X_ASSUM(MP_TAC o SPEC `n:num`) THEN ASM_REWRITE_TAC[]]]);; + +let REJ_MASK_EL_ETA2 = prove + (`!(l:byte list) p. p < LENGTH l + ==> (EL (2*p) (REJ_MASK_ETA2 l) <=> val(EL p l) MOD 16 < 15) /\ + (EL (2*p+1) (REJ_MASK_ETA2 l) <=> val(EL p l) DIV 16 < 15)`, + REPEAT GEN_TAC THEN DISCH_TAC THEN + MP_TAC(SPECL [`l:byte list`; `p:num`] EL_NIBBLES_OF_BYTES) THEN + ASM_REWRITE_TAC[] THEN STRIP_TAC THEN + REWRITE_TAC[REJ_MASK_ETA2] THEN + SUBGOAL_THEN `2 * p < LENGTH(NIBBLES_OF_BYTES(l:byte list)) /\ + 2 * p + 1 < LENGTH(NIBBLES_OF_BYTES(l:byte list))` STRIP_ASSUME_TAC THENL + [REWRITE_TAC[LENGTH_NIBBLES_OF_BYTES] THEN + UNDISCH_TAC `p < LENGTH(l:byte list)` THEN ARITH_TAC; ALL_TAC] THEN + ASM_SIMP_TAC[EL_MAP] THEN ASM_REWRITE_TAC[] THEN + MP_TAC(ISPEC `EL p (l:byte list)` VAL_BOUND) THEN REWRITE_TAC[DIMINDEX_8] THEN + DISCH_TAC THEN + MP_TAC(SPECL [`val(EL p (l:byte list))`; `16`] DIVISION) THEN + ANTS_TAC THENL [ARITH_TAC; ALL_TAC] THEN STRIP_TAC THEN + SUBGOAL_THEN + `val(word(val(EL p (l:byte list)) MOD 16):int16) = val(EL p l) MOD 16 /\ + val(word(val(EL p (l:byte list)) DIV 16):int16) = val(EL p l) DIV 16` + STRIP_ASSUME_TAC THENL + [CONJ_TAC THEN REWRITE_TAC[VAL_WORD; DIMINDEX_16] THEN MATCH_MP_TAC MOD_LT THEN + CONV_TAC(RAND_CONV NUM_REDUCE_CONV) THEN ASM_ARITH_TAC; + ASM_REWRITE_TAC[]]);; + +let newrhs_body = + let eqn = snd(strip_forall(concl f_ev_scalar_body)) in + let _,rhs = dest_eq eqn in + let condlo = `val(EL p (inlist:byte list)) MOD 16 < 15` in + let condhi = `val(EL p (inlist:byte list)) DIV 16 < 15` in + subst [`EL (2*p) (mask:bool list)`, condlo; + `EL (2*p+1) (mask:bool list)`, condhi] rhs;; + +let f_ev_scalar_body_mask = + let fty = `:int64->int64->num->(bool)list->num->num->(uarch_event)list` in + let hd = mk_var("f_ev_scalar_body_mask", fty) in + let lhs = list_mk_comb(hd, [`res:int64`;`buf:int64`;`pc:num`; + `mask:bool list`;`p:num`;`outlen0:num`]) in + define (mk_eq(lhs, newrhs_body));; + +let FEV_SCALAR_BODY_MASK = prove + (`!res buf pc (inlist:byte list) p outlen0. + p < LENGTH inlist + ==> f_ev_scalar_body res buf pc inlist p outlen0 = + f_ev_scalar_body_mask res buf pc (REJ_MASK_ETA2 inlist) p outlen0`, + REPEAT STRIP_TAC THEN + REWRITE_TAC[f_ev_scalar_body; f_ev_scalar_body_mask] THEN + ASM_SIMP_TAC[REJ_MASK_EL_ETA2]);; + +let f_ev_scalar_tail_mask = define + `(f_ev_scalar_tail_mask 0 (res:int64) (buf:int64) (pc:num) (mask:bool list) (p:num) = + (if 256 <= NUM_ACCEPTED(SUB_LIST(0,2*p) mask) + then [EventJump (word (pc + 410),word (pc + 542))] + else [EventJump (word (pc + 418),word (pc + 542)); + EventJump (word (pc + 410),word (pc + 410))])) /\ + (f_ev_scalar_tail_mask (SUC d) (res:int64) (buf:int64) (pc:num) (mask:bool list) (p:num) = + (if 256 <= NUM_ACCEPTED(SUB_LIST(0,2*p) mask) + then [EventJump (word (pc + 410),word (pc + 542))] + else if p = 136 + then [EventJump (word (pc + 418),word (pc + 542)); + EventJump (word (pc + 410),word (pc + 410))] + else if NUM_ACCEPTED(SUB_LIST(0,2*p) mask) = 255 /\ EL (2*p) mask + then [EventJump (word (pc + 481),word (pc + 542)); + EventStore (word_add res (word 1020),4); + EventJump (word (pc + 438),word (pc + 438)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 418),word (pc + 418)); + EventJump (word (pc + 410),word (pc + 410))] + else APPEND (f_ev_scalar_tail_mask d res buf pc mask (p+1)) + (f_ev_scalar_body_mask res buf pc mask p + (NUM_ACCEPTED(SUB_LIST(0,2*p) mask)))))`;; + +let FEV_SCALAR_TAIL_MASK = prove + (`!d res buf pc (inlist:byte list) p. + LENGTH inlist = 136 /\ p <= 136 + ==> f_ev_scalar_tail d res buf pc inlist p = + f_ev_scalar_tail_mask d res buf pc (REJ_MASK_ETA2 inlist) p`, + INDUCT_TAC THEN REPEAT GEN_TAC THEN STRIP_TAC THENL + [REWRITE_TAC[f_ev_scalar_tail; f_ev_scalar_tail_mask; STORE_BRIDGE]; + ASM_CASES_TAC `p = 136` THENL + [ASM_REWRITE_TAC[f_ev_scalar_tail; f_ev_scalar_tail_mask; STORE_BRIDGE]; + SUBGOAL_THEN `p < LENGTH(inlist:byte list) /\ p + 1 <= 136` STRIP_ASSUME_TAC THENL + [ASM_ARITH_TAC; ALL_TAC] THEN + REWRITE_TAC[f_ev_scalar_tail; f_ev_scalar_tail_mask] THEN + REWRITE_TAC[STORE_BRIDGE] THEN + SUBGOAL_THEN + `f_ev_scalar_tail d res buf pc inlist (p+1) = + f_ev_scalar_tail_mask d res buf pc (REJ_MASK_ETA2 inlist) (p+1)` + SUBST1_TAC THENL + [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + ASM_SIMP_TAC[REJ_MASK_EL_ETA2; FEV_SCALAR_BODY_MASK]]]);; + +(* --- mask-side memacc (STORE4/LOAD1_CONTAINED) --- *) +let MEMACCESS_F_EV_SCALAR_BODY_MASK = prove + (`!res buf table pc (mask:bool list) p outlen0. + p < 136 /\ outlen0 <= 255 /\ + ~(outlen0 = 255 /\ EL (2 * p) mask) + ==> memaccess_inbounds (f_ev_scalar_body_mask res buf pc mask p outlen0) + [(buf:int64),136; (table:int64),2048] [(res:int64),1024]`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN `val(word outlen0:int64) = outlen0` ASSUME_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN ASM_ARITH_TAC; + ALL_TAC] THEN + REWRITE_TAC[f_ev_scalar_body_mask] THEN REPEAT COND_CASES_TAC THEN + ASM_REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND] THEN + REPEAT CONJ_TAC THEN + FIRST + [DISJ1_TAC THEN MATCH_MP_TAC LOAD1_CONTAINED THEN FIRST_ASSUM ACCEPT_TAC; + MATCH_MP_TAC STORE4_CONTAINED THEN + TRY(FIRST_X_ASSUM + ((fun th -> MP_TAC th THEN ASM_REWRITE_TAC[]) o + check (fun th -> is_neg(concl th) && is_conj(rand(concl th))))) THEN + ASM_ARITH_TAC]);; + +let MEMACCESS_F_EV_SCALAR_TAIL_MASK = prove + (`!d res buf table pc (mask:bool list) p. + p + d <= 136 + ==> memaccess_inbounds (f_ev_scalar_tail_mask d res buf pc mask p) + [(buf:int64),136; (table:int64),2048] [(res:int64),1024]`, + INDUCT_TAC THENL + [REPEAT GEN_TAC THEN STRIP_TAC THEN + REWRITE_TAC[f_ev_scalar_tail_mask] THEN COND_CASES_TAC THEN + REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND]; + REPEAT GEN_TAC THEN STRIP_TAC THEN + REWRITE_TAC[f_ev_scalar_tail_mask] THEN REPEAT COND_CASES_TAC THENL + [REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND]; + REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND]; + REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND] THEN REPEAT CONJ_TAC THEN + FIRST [REWRITE_TAC[ARITH_RULE `1020 = 4 * 255`] THEN + MATCH_MP_TAC STORE4_CONTAINED THEN ARITH_TAC; + DISJ1_TAC THEN MATCH_MP_TAC LOAD1_CONTAINED THEN ASM_ARITH_TAC]; + REWRITE_TAC[MEMACCESS_INBOUNDS_APPEND] THEN CONJ_TAC THENL + [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC; + MATCH_MP_TAC MEMACCESS_F_EV_SCALAR_BODY_MASK THEN REPEAT CONJ_TAC THENL + [ASM_ARITH_TAC; ASM_ARITH_TAC; FIRST_ASSUM ACCEPT_TAC]]]]);; + +let f_ev_exit = define + `f_ev_exit (res:int64) (buf:int64) (table:int64) (pc:num) (mask:bool list) (N:num) + : (uarch_event)list = + if NUM_ACCEPTED(SUB_LIST(0,32 * N) mask) <= 248 + then APPEND (f_ev_scalar_tail_mask (136 - 16 * N) res buf pc mask (16 * N)) + (APPEND (f_ev_headguard_eta2 pc) + (f_ev_loop_eta2 res buf table pc mask (N-1))) + else if NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8) mask) <= 248 + then (if NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16) mask) <= 248 + then (if NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 24) mask) <= 248 + then APPEND (f_ev_scalar_tail_mask (136 - 16 * N) res buf pc mask (16 * N)) + (f_ev_midexit_subiter4 res buf table pc mask (N-1)) + else APPEND (f_ev_scalar_tail_mask (136 - (16 * (N-1) + 12)) res buf pc mask + (16 * (N-1) + 12)) + (f_ev_midexit_subiter3 res buf table pc mask (N-1))) + else APPEND (f_ev_scalar_tail_mask (136 - (16 * (N-1) + 8)) res buf pc mask + (16 * (N-1) + 8)) + (f_ev_midexit_subiter2 res buf table pc mask (N-1))) + else APPEND (f_ev_scalar_tail_mask (136 - (16 * (N-1) + 4)) res buf pc mask + (16 * (N-1) + 4)) + (f_ev_midexit_subiter1 res buf table pc mask (N-1))`;; + +let MEMACCESS_F_EV_EXIT = prove + (`!res buf table pc (mask:bool list) N. + 16 * N <= 136 /\ ~(N = 0) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1)) mask) <= 248 + ==> memaccess_inbounds (f_ev_exit res buf table pc mask N) + [(buf:int64),136; (table:int64),2048] [(res:int64),1024]`, + REPEAT STRIP_TAC THEN REWRITE_TAC[f_ev_exit] THEN + REPEAT COND_CASES_TAC THEN + REWRITE_TAC[MEMACCESS_INBOUNDS_APPEND] THEN REPEAT CONJ_TAC THEN + FIRST + [MATCH_MP_TAC MEMACCESS_F_EV_SCALAR_TAIL_MASK THEN ASM_ARITH_TAC; + MATCH_ACCEPT_TAC MEMACCESS_F_EV_HEADGUARD; + MATCH_MP_TAC MEMACCESS_F_EV_LOOP_ETA2 THEN CONJ_TAC THENL + [ASM_ARITH_TAC; + MATCH_MP_TAC LE_TRANS THEN + EXISTS_TAC `NUM_ACCEPTED(SUB_LIST(0,32 * N) (mask:bool list))` THEN + CONJ_TAC THENL + [MATCH_MP_TAC NUM_ACCEPTED_PREFIX_MONO THEN ASM_ARITH_TAC; + FIRST_ASSUM ACCEPT_TAC]]; + MATCH_MP_TAC MEMACCESS_F_EV_MIDEXIT_SUBITER1 THEN + CONJ_TAC THENL [ASM_ARITH_TAC; FIRST_ASSUM ACCEPT_TAC]; + MATCH_MP_TAC MEMACCESS_F_EV_MIDEXIT_SUBITER2 THEN + CONJ_TAC THENL [ASM_ARITH_TAC; FIRST_ASSUM ACCEPT_TAC]; + MATCH_MP_TAC MEMACCESS_F_EV_MIDEXIT_SUBITER3 THEN + CONJ_TAC THENL [ASM_ARITH_TAC; FIRST_ASSUM ACCEPT_TAC]; + MATCH_MP_TAC MEMACCESS_F_EV_MIDEXIT_SUBITER4 THEN + CONJ_TAC THENL [ASM_ARITH_TAC; FIRST_ASSUM ACCEPT_TAC]]);; + +(* --- events bridges + exists helpers --- *) +let OFFSET_EVENTS_BRIDGE = prove + (`!res buf table (inlist:byte list) pc N e. + LENGTH inlist = 136 /\ 16 * N = 128 /\ + NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA2 inlist)) <= 248 + ==> APPEND (f_ev_scalar_tail (136 - 128) res buf pc inlist 128) + (APPEND (f_ev_headguard_eta2 pc) + (APPEND (f_ev_loop_eta2 res buf table pc + (REJ_MASK_ETA2 (inlist:byte list)) (N-1)) + (e:(uarch_event)list))) + = APPEND (f_ev_exit res buf table pc (REJ_MASK_ETA2 inlist) N) e`, + REPEAT STRIP_TAC THEN REWRITE_TAC[f_ev_exit] THEN + ASM_REWRITE_TAC[COND_CLAUSES] THEN + MP_TAC(SPECL [`136 - 128`;`res:int64`;`buf:int64`;`pc:num`;`inlist:byte list`;`128`] + FEV_SCALAR_TAIL_MASK) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN + REWRITE_TAC[APPEND_ASSOC]);; + +let MIDEXIT1_EVENTS_BRIDGE = prove + (`!res buf table (inlist:byte list) pc N e. + LENGTH inlist = 136 /\ 16 * N <= 136 /\ ~(N = 0) /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA2 inlist)) <= 248) /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA2 inlist)) <= 248) + ==> APPEND (f_ev_scalar_tail (136 - (16 * (N-1) + 4)) res buf pc inlist (16 * (N-1) + 4)) + (APPEND (f_ev_midexit_subiter1 res buf table pc (REJ_MASK_ETA2 inlist) (N-1)) + (e:(uarch_event)list)) + = APPEND (f_ev_exit res buf table pc (REJ_MASK_ETA2 inlist) N) e`, + REPEAT STRIP_TAC THEN REWRITE_TAC[f_ev_exit] THEN + ASM_REWRITE_TAC[COND_CLAUSES] THEN + MP_TAC(SPECL [`136 - (16 * (N-1) + 4)`;`res:int64`;`buf:int64`;`pc:num`;`inlist:byte list`; + `16 * (N-1) + 4`] FEV_SCALAR_TAIL_MASK) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[APPEND_ASSOC]);; + +let MIDEXIT2_EVENTS_BRIDGE = prove + (`!res buf table (inlist:byte list) pc N e. + LENGTH inlist = 136 /\ 16 * N <= 136 /\ ~(N = 0) /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA2 inlist)) <= 248) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA2 inlist)) <= 248 /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA2 inlist)) <= 248) + ==> APPEND (f_ev_scalar_tail (136 - (16 * (N-1) + 8)) res buf pc inlist (16 * (N-1) + 8)) + (APPEND (f_ev_midexit_subiter2 res buf table pc (REJ_MASK_ETA2 inlist) (N-1)) + (e:(uarch_event)list)) + = APPEND (f_ev_exit res buf table pc (REJ_MASK_ETA2 inlist) N) e`, + REPEAT STRIP_TAC THEN REWRITE_TAC[f_ev_exit] THEN + ASM_REWRITE_TAC[COND_CLAUSES] THEN + MP_TAC(SPECL [`136 - (16 * (N-1) + 8)`;`res:int64`;`buf:int64`;`pc:num`;`inlist:byte list`; + `16 * (N-1) + 8`] FEV_SCALAR_TAIL_MASK) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[APPEND_ASSOC]);; + +let MIDEXIT3_EVENTS_BRIDGE = prove + (`!res buf table (inlist:byte list) pc N e. + LENGTH inlist = 136 /\ 16 * N <= 136 /\ ~(N = 0) /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA2 inlist)) <= 248) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA2 inlist)) <= 248 /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA2 inlist)) <= 248 /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 24)(REJ_MASK_ETA2 inlist)) <= 248) + ==> APPEND (f_ev_scalar_tail (136 - (16 * (N-1) + 12)) res buf pc inlist (16 * (N-1) + 12)) + (APPEND (f_ev_midexit_subiter3 res buf table pc (REJ_MASK_ETA2 inlist) (N-1)) + (e:(uarch_event)list)) + = APPEND (f_ev_exit res buf table pc (REJ_MASK_ETA2 inlist) N) e`, + REPEAT STRIP_TAC THEN REWRITE_TAC[f_ev_exit] THEN + ASM_REWRITE_TAC[COND_CLAUSES] THEN + MP_TAC(SPECL [`136 - (16 * (N-1) + 12)`;`res:int64`;`buf:int64`;`pc:num`;`inlist:byte list`; + `16 * (N-1) + 12`] FEV_SCALAR_TAIL_MASK) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[APPEND_ASSOC]);; + +let MIDEXIT4_EVENTS_BRIDGE = prove + (`!res buf table (inlist:byte list) pc N e. + LENGTH inlist = 136 /\ 16 * N <= 136 /\ ~(N = 0) /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA2 inlist)) <= 248) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA2 inlist)) <= 248 /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA2 inlist)) <= 248 /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 24)(REJ_MASK_ETA2 inlist)) <= 248 + ==> APPEND (f_ev_scalar_tail (136 - 16 * N) res buf pc inlist (16 * N)) + (APPEND (f_ev_midexit_subiter4 res buf table pc (REJ_MASK_ETA2 inlist) (N-1)) + (e:(uarch_event)list)) + = APPEND (f_ev_exit res buf table pc (REJ_MASK_ETA2 inlist) N) e`, + REPEAT STRIP_TAC THEN REWRITE_TAC[f_ev_exit] THEN + ASM_REWRITE_TAC[COND_CLAUSES] THEN + MP_TAC(SPECL [`136 - 16 * N`;`res:int64`;`buf:int64`;`pc:num`;`inlist:byte list`; + `16 * N`] FEV_SCALAR_TAIL_MASK) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[APPEND_ASSOC]);; + +let OFFSET_EXISTS = prove + (`!res buf table (inlist:byte list) pc N (e:(uarch_event)list) s. + LENGTH inlist = 136 /\ 16 * N = 128 /\ ~(N = 0) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA2 inlist)) <= 248 /\ + read events s = + APPEND (f_ev_scalar_tail (136 - 128) res buf pc inlist 128) + (APPEND (f_ev_headguard_eta2 pc) + (APPEND (f_ev_loop_eta2 res buf table pc + (REJ_MASK_ETA2 inlist) (N-1)) e)) + ==> ?e2. read events s = APPEND e2 e /\ + e2 = f_ev_exit res buf table pc (REJ_MASK_ETA2 inlist) N /\ + memaccess_inbounds e2 [(buf:int64),136; (table:int64),2048] [(res:int64),1024]`, + REPEAT STRIP_TAC THEN + EXISTS_TAC `f_ev_exit res buf table pc (REJ_MASK_ETA2 inlist) N` THEN + REPEAT CONJ_TAC THENL + [ONCE_ASM_REWRITE_TAC[] THEN MATCH_MP_TAC OFFSET_EVENTS_BRIDGE THEN ASM_REWRITE_TAC[]; + REFL_TAC; + MATCH_MP_TAC MEMACCESS_F_EV_EXIT THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL + [ASM_ARITH_TAC; + MATCH_MP_TAC LE_TRANS THEN + EXISTS_TAC `NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA2 inlist))` THEN + CONJ_TAC THENL + [MATCH_MP_TAC NUM_ACCEPTED_PREFIX_MONO THEN ARITH_TAC; + FIRST_ASSUM ACCEPT_TAC]]]);; + +let MIDEXIT1_EXISTS = prove + (`!res buf table (inlist:byte list) pc N (e:(uarch_event)list) s. + LENGTH inlist = 136 /\ 16 * N <= 136 /\ ~(N = 0) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1))(REJ_MASK_ETA2 inlist)) <= 248 /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA2 inlist)) <= 248) /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA2 inlist)) <= 248) /\ + read events s = + APPEND (f_ev_scalar_tail (136 - (16 * (N-1) + 4)) res buf pc inlist (16 * (N-1) + 4)) + (APPEND (f_ev_midexit_subiter1 res buf table pc (REJ_MASK_ETA2 inlist) (N-1)) e) + ==> ?e2. read events s = APPEND e2 e /\ + e2 = f_ev_exit res buf table pc (REJ_MASK_ETA2 inlist) N /\ + memaccess_inbounds e2 [(buf:int64),136; (table:int64),2048] [(res:int64),1024]`, + REPEAT STRIP_TAC THEN + EXISTS_TAC `f_ev_exit res buf table pc (REJ_MASK_ETA2 inlist) N` THEN + REPEAT CONJ_TAC THENL + [ONCE_ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MIDEXIT1_EVENTS_BRIDGE THEN ASM_REWRITE_TAC[]; + REFL_TAC; + MATCH_MP_TAC MEMACCESS_F_EV_EXIT THEN ASM_REWRITE_TAC[]]);; + +let MIDEXIT2_EXISTS = prove + (`!res buf table (inlist:byte list) pc N (e:(uarch_event)list) s. + LENGTH inlist = 136 /\ 16 * N <= 136 /\ ~(N = 0) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1))(REJ_MASK_ETA2 inlist)) <= 248 /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA2 inlist)) <= 248) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA2 inlist)) <= 248 /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA2 inlist)) <= 248) /\ + read events s = + APPEND (f_ev_scalar_tail (136 - (16 * (N-1) + 8)) res buf pc inlist (16 * (N-1) + 8)) + (APPEND (f_ev_midexit_subiter2 res buf table pc (REJ_MASK_ETA2 inlist) (N-1)) e) + ==> ?e2. read events s = APPEND e2 e /\ + e2 = f_ev_exit res buf table pc (REJ_MASK_ETA2 inlist) N /\ + memaccess_inbounds e2 [(buf:int64),136; (table:int64),2048] [(res:int64),1024]`, + REPEAT STRIP_TAC THEN + EXISTS_TAC `f_ev_exit res buf table pc (REJ_MASK_ETA2 inlist) N` THEN + REPEAT CONJ_TAC THENL + [ONCE_ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MIDEXIT2_EVENTS_BRIDGE THEN ASM_REWRITE_TAC[]; + REFL_TAC; + MATCH_MP_TAC MEMACCESS_F_EV_EXIT THEN ASM_REWRITE_TAC[]]);; + +let MIDEXIT3_EXISTS = prove + (`!res buf table (inlist:byte list) pc N (e:(uarch_event)list) s. + LENGTH inlist = 136 /\ 16 * N <= 136 /\ ~(N = 0) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1))(REJ_MASK_ETA2 inlist)) <= 248 /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA2 inlist)) <= 248) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA2 inlist)) <= 248 /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA2 inlist)) <= 248 /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 24)(REJ_MASK_ETA2 inlist)) <= 248) /\ + read events s = + APPEND (f_ev_scalar_tail (136 - (16 * (N-1) + 12)) res buf pc inlist (16 * (N-1) + 12)) + (APPEND (f_ev_midexit_subiter3 res buf table pc (REJ_MASK_ETA2 inlist) (N-1)) e) + ==> ?e2. read events s = APPEND e2 e /\ + e2 = f_ev_exit res buf table pc (REJ_MASK_ETA2 inlist) N /\ + memaccess_inbounds e2 [(buf:int64),136; (table:int64),2048] [(res:int64),1024]`, + REPEAT STRIP_TAC THEN + EXISTS_TAC `f_ev_exit res buf table pc (REJ_MASK_ETA2 inlist) N` THEN + REPEAT CONJ_TAC THENL + [ONCE_ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MIDEXIT3_EVENTS_BRIDGE THEN ASM_REWRITE_TAC[]; + REFL_TAC; + MATCH_MP_TAC MEMACCESS_F_EV_EXIT THEN ASM_REWRITE_TAC[]]);; + +let MIDEXIT4_EXISTS = prove + (`!res buf table (inlist:byte list) pc N (e:(uarch_event)list) s. + LENGTH inlist = 136 /\ 16 * N <= 136 /\ ~(N = 0) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1))(REJ_MASK_ETA2 inlist)) <= 248 /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA2 inlist)) <= 248) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA2 inlist)) <= 248 /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA2 inlist)) <= 248 /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 24)(REJ_MASK_ETA2 inlist)) <= 248 /\ + read events s = + APPEND (f_ev_scalar_tail (136 - 16 * N) res buf pc inlist (16 * N)) + (APPEND (f_ev_midexit_subiter4 res buf table pc (REJ_MASK_ETA2 inlist) (N-1)) e) + ==> ?e2. read events s = APPEND e2 e /\ + e2 = f_ev_exit res buf table pc (REJ_MASK_ETA2 inlist) N /\ + memaccess_inbounds e2 [(buf:int64),136; (table:int64),2048] [(res:int64),1024]`, + REPEAT STRIP_TAC THEN + EXISTS_TAC `f_ev_exit res buf table pc (REJ_MASK_ETA2 inlist) N` THEN + REPEAT CONJ_TAC THENL + [ONCE_ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MIDEXIT4_EVENTS_BRIDGE THEN ASM_REWRITE_TAC[]; + REFL_TAC; + MATCH_MP_TAC MEMACCESS_F_EV_EXIT THEN ASM_REWRITE_TAC[]]);; + +(* --- SAFE dispatch tactics --- *) +let midexit_qpost_safe_eta2 (midthm:thm) : term = + let post = rand(rator(snd(dest_imp(snd(strip_forall(concl midthm)))))) in + let post = vsubst [`N-1`,`i:num`] post in + let sv, body = dest_abs post in + let value_post = lhand body in + let ev_and_ma = rand body in + let ev_eq = lhand ev_and_ma in + mk_abs(sv, mk_conj(value_post, ev_eq));; + +let MIDEXIT_DISPATCH_SAFE_ETA2 (safearm:thm) (fev_tm:term) (pexpr:term) (prevpos:term) : tactic = + let qpost = midexit_qpost_safe_eta2 safearm in + let _, qbody = dest_abs qpost in + let etail = rand (rand qbody) in + MATCH_MP_TAC ENSURES_TRANS_SIMPLE THEN EXISTS_TAC qpost THEN + CONJ_TAC THENL [MAYCHANGE_IDEMPOT_TAC; ALL_TAC] THEN + CONJ_TAC THENL + [MP_TAC(SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`N-1`;`stackpointer:int64`;`e:(uarch_event)list`] safearm) THEN + ANTS_TAC THENL + [REPEAT CONJ_TAC THEN (FIRST [FIRST_ASSUM ACCEPT_TAC; ASM_ARITH_TAC]); ALL_TAC] THEN + DISCH_THEN(fun bth -> SAFE_BRIDGE_FROM_ETA2 bth); + SUBGOAL_THEN (mk_comb(mk_comb(`(<=):num->num->bool`, + mk_comb(`LENGTH:(int32)list->num`, mk_comb(`REJ_SAMPLE_ETA2_BYTES:byte list->int32 list`, + mk_comb(mk_comb(`SUB_LIST:num#num->byte list->byte list`,mk_pair(`0`,pexpr)),`inlist:byte list`)))), `256`)) ASSUME_TAC THENL + [SUBGOAL_THEN (mk_eq(pexpr, mk_binop `(+):num->num->num` prevpos `4`)) SUBST1_TAC THENL + [UNDISCH_TAC `~(N=0)` THEN UNDISCH_TAC `16 * N <= 136` THEN ARITH_TAC; ALL_TAC] THEN + MATCH_MP_TAC OUTLEN0_LE_256_FROM_SUBITER_ETA2 THEN CONJ_TAC THENL + [UNDISCH_TAC `16 * N <= 136` THEN UNDISCH_TAC `~(N=0)` THEN UNDISCH_TAC `LENGTH(inlist:byte list)=136` THEN ARITH_TAC; + FIRST_ASSUM ACCEPT_TAC]; ALL_TAC] THEN + SCALAR_TAIL_LEG2_SAFE_ETA2 pexpr etail];; + +let OFFSET_ARM_SAFE_ETA2_TAC : tactic = + SUBGOAL_THEN `16 * N = 128` ASSUME_TAC THENL + [SUBGOAL_THEN `120 < 16 * N` ASSUME_TAC THENL + [UNDISCH_TAC `120 < 16 * N \/ 248 < LENGTH (REJ_NIBBLES_ETA2 (SUB_LIST (0,16 * N) inlist):int16 list)` THEN + REWRITE_TAC[GSYM LENGTH_REJ_SAMPLE_ETA2_BYTES] THEN + UNDISCH_TAC `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248` THEN + ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `N = 8` (fun th -> REWRITE_TAC[th] THEN CONV_TAC NUM_REDUCE_CONV) THEN + SUBGOAL_THEN `16 * N <= 136` ASSUME_TAC THENL + [UNDISCH_TAC `16 * (N-1) <= 120` THEN UNDISCH_TAC `~(N=0)` THEN + SPEC_TAC(`N:num`,`N:num`) THEN INDUCT_TAC THEN ARITH_TAC; ALL_TAC] THEN + UNDISCH_TAC `120 < 16 * N` THEN UNDISCH_TAC `16 * N <= 136` THEN ARITH_TAC; ALL_TAC] THEN + MP_TAC(SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`N:num`;`stackpointer:int64`;`e:(uarch_event)list`] EXIT_OFFSET_SAFE_ETA2) THEN + ANTS_TAC THENL + [ASM_REWRITE_TAC[] THEN + REWRITE_TAC[GSYM LENGTH_REJ_SAMPLE_ETA2_BYTES] THEN ASM_REWRITE_TAC[] THEN + UNDISCH_TAC `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248` THEN + SUBST1_TAC(ASSUME `16 * N = 128`) THEN REWRITE_TAC[]; ALL_TAC] THEN + DISCH_THEN(fun bth -> SAFE_BRIDGE_FROM_ETA2 bth);; + +let MIDEXIT_ARM_SAFE_ETA2_TAC : tactic = + SUBGOAL_THEN `248 < LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*N) inlist):int32 list)` ASSUME_TAC THENL + [UNDISCH_TAC `~(LENGTH (REJ_SAMPLE_ETA2_BYTES (SUB_LIST (0,16 * N) inlist):int32 list) <= 248)` THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `16 * N <= 136` ASSUME_TAC THENL + [UNDISCH_TAC `16 * (N-1) <= 120` THEN UNDISCH_TAC `~(N=0)` THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `16 * ((N-1)+1) <= 136` ASSUME_TAC THENL + [UNDISCH_TAC `16 * N <= 136` THEN UNDISCH_TAC `~(N=0)` THEN ARITH_TAC; ALL_TAC] THEN + ASM_CASES_TAC `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*(N-1)+4) inlist):int32 list) <= 248` THENL + [ASM_CASES_TAC `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*(N-1)+8) inlist):int32 list) <= 248` THENL + [ASM_CASES_TAC `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*(N-1)+12) inlist):int32 list) <= 248` THENL + [SUBGOAL_THEN `248 < LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*((N-1)+1)) inlist):int32 list)` ASSUME_TAC THENL + [SUBGOAL_THEN `16*((N-1)+1) = 16*N` SUBST1_TAC THENL + [UNDISCH_TAC `~(N=0)` THEN ARITH_TAC; ALL_TAC] THEN FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN + MIDEXIT_DISPATCH_SAFE_ETA2 MID_EXIT_SUBITER4_SAFE_ETA2 + `f_ev_midexit_subiter4 res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) (N-1)` + `16*((N-1)+1)` `16*(N-1)+12`; + MIDEXIT_DISPATCH_SAFE_ETA2 MID_EXIT_SUBITER3_SAFE_ETA2 + `f_ev_midexit_subiter3 res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) (N-1)` + `16*(N-1)+12` `16*(N-1)+8`]; + MIDEXIT_DISPATCH_SAFE_ETA2 MID_EXIT_SUBITER2_SAFE_ETA2 + `f_ev_midexit_subiter2 res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) (N-1)` + `16*(N-1)+8` `16*(N-1)+4`]; + MIDEXIT_DISPATCH_SAFE_ETA2 MID_EXIT_SUBITER1_SAFE_ETA2 + `f_ev_midexit_subiter1 res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) (N-1)` + `16*(N-1)+4` `16*(N-1)`];; + +(* --- EXIT_BLOCK_SAFE arms 2/3/4 (defines shared builder) --- *) +let MASK_DBL_N1 = ARITH_RULE `2 * (16 * (N - 1)) = 32 * (N - 1)`;; +let MASK_DBL_N = ARITH_RULE `2 * (16 * N) = 32 * N`;; +let MASK_DBL_N1_4 = ARITH_RULE `2 * (16 * (N - 1) + 4) = 32 * (N - 1) + 8`;; +let MASK_DBL_N1_8 = ARITH_RULE `2 * (16 * (N - 1) + 8) = 32 * (N - 1) + 16`;; +let MASK_DBL_N1_12 = ARITH_RULE `2 * (16 * (N - 1) + 12) = 32 * (N - 1) + 24`;; + +let MASK_OF (maskgoal:term) (bexp:term) (redthm:thm) : tactic = + SUBGOAL_THEN maskgoal ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`; bexp] STORE_BRIDGE) THEN + REWRITE_TAC[redthm] THEN + DISCH_THEN(fun th -> REWRITE_TAC[GSYM th]) THEN FIRST_ASSUM ACCEPT_TAC; + ALL_TAC];; + +let mk_midexit_safe_tm (extraconds:term list) : term = + let body = snd(strip_forall(concl EXIT_OFFSET_SAFE_ETA2)) in + let hyps_off, ens = dest_imp body in + let ensc, ppf = strip_comb ens in + let step = el 0 ppf and pre = el 1 ppf and frame = el 3 ppf in + let shared = fst(chop_list 6 (conjuncts hyps_off)) in + let wopf = `!m. m < N ==> 16 * m <= 120 /\ + LENGTH(REJ_NIBBLES_ETA2(SUB_LIST(0,16*m) inlist):int16 list) <= 248` in + let pN = `120 < 16 * N \/ + 248 < LENGTH(REJ_NIBBLES_ETA2(SUB_LIST(0,16*N) inlist):int16 list)` in + let hyps' = list_mk_conj (shared @ [`~(N = 0)`; `~(N = 1)`; wopf; pN] @ extraconds) in + let sv = `s:x86state` in + let ctpost = mk_abs(sv, + `read RIP s = word(pc + LENGTH(BUTLAST mldsa_rej_uniform_eta2_tmc)) /\ + (?e2. read events s = APPEND e2 (e:(uarch_event)list) /\ + e2 = f_ev_exit res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) N /\ + memaccess_inbounds e2 [(buf:int64),136; (table:int64),2048] + [(res:int64),1024])`) in + let ens' = list_mk_comb(ensc,[step; pre; ctpost; frame]) in + list_mk_forall + ([`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`; + `N:num`;`stackpointer:int64`;`e:(uarch_event)list`], + mk_imp(hyps', ens'));; + +let MIDEXIT_SETUP_TAC : tactic = + REPEAT GEN_TAC THEN DISCH_THEN(MAP_EVERY ASSUME_TAC o CONJUNCTS) THEN + SUBGOAL_THEN + `16 * (N-1) <= 120 /\ + LENGTH(REJ_NIBBLES_ETA2(SUB_LIST(0,16*(N-1)) inlist):int16 list) <= 248` + STRIP_ASSUME_TAC THENL + [FIRST_X_ASSUM(MP_TAC o SPEC `N-1` o check(is_forall o concl)) THEN + ANTS_TAC THENL [UNDISCH_TAC `~(N = 0)` THEN ARITH_TAC; REWRITE_TAC[]]; + ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*(N-1)) inlist):int32 list) <= 248` + ASSUME_TAC THENL + [ASM_REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA2_BYTES]; ALL_TAC] THEN + SUBGOAL_THEN `16 * N <= 136` ASSUME_TAC THENL + [UNDISCH_TAC `16 * (N-1) <= 120` THEN UNDISCH_TAC `~(N = 0)` THEN + SPEC_TAC(`N:num`,`N:num`) THEN INDUCT_TAC THEN ARITH_TAC; + ALL_TAC];; + +let exit_block_midexit2_safe_tm = mk_midexit_safe_tm + [`~(LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248)`; + `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*(N-1)+4) inlist):int32 list) <= 248`; + `~(LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*(N-1)+8) inlist):int32 list) <= 248)`];; + +let midexit2_concrete_post = + `\s. read RIP s = word(pc + LENGTH(BUTLAST mldsa_rej_uniform_eta2_tmc)) /\ + read events s = + APPEND (f_ev_scalar_tail (136 - (16 * (N-1) + 8)) res buf pc inlist (16 * (N-1) + 8)) + (APPEND (f_ev_midexit_subiter2 res buf table pc (REJ_MASK_ETA2 inlist) (N-1)) + (e:(uarch_event)list))`;; + +let EXIT_BLOCK_SAFE_MIDEXIT2 = prove + (exit_block_midexit2_safe_tm, + MIDEXIT_SETUP_TAC THEN + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN + EXISTS_TAC midexit2_concrete_post THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN + CONJ_TAC THENL [FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN + MASK_OF `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1))(REJ_MASK_ETA2 inlist)) <= 248` + `16 * (N-1)` MASK_DBL_N1 THEN + MASK_OF `~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA2 inlist)) <= 248)` + `16 * N` MASK_DBL_N THEN + MASK_OF `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA2 inlist)) <= 248` + `16 * (N-1) + 4` MASK_DBL_N1_4 THEN + MASK_OF `~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA2 inlist)) <= 248)` + `16 * (N-1) + 8` MASK_DBL_N1_8 THEN + MATCH_MP_TAC MIDEXIT2_EXISTS THEN ASM_REWRITE_TAC[]; + MIDEXIT_DISPATCH_SAFE_ETA2 MID_EXIT_SUBITER2_SAFE_ETA2 + `f_ev_midexit_subiter2 res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) (N-1)` + `16*(N-1)+8` `16*(N-1)+4`]);; + +let exit_block_midexit3_safe_tm = mk_midexit_safe_tm + [`~(LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248)`; + `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*(N-1)+4) inlist):int32 list) <= 248`; + `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*(N-1)+8) inlist):int32 list) <= 248`; + `~(LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*(N-1)+12) inlist):int32 list) <= 248)`];; + +let midexit3_concrete_post = + `\s. read RIP s = word(pc + LENGTH(BUTLAST mldsa_rej_uniform_eta2_tmc)) /\ + read events s = + APPEND (f_ev_scalar_tail (136 - (16 * (N-1) + 12)) res buf pc inlist (16 * (N-1) + 12)) + (APPEND (f_ev_midexit_subiter3 res buf table pc (REJ_MASK_ETA2 inlist) (N-1)) + (e:(uarch_event)list))`;; + +let EXIT_BLOCK_SAFE_MIDEXIT3 = prove + (exit_block_midexit3_safe_tm, + MIDEXIT_SETUP_TAC THEN + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN + EXISTS_TAC midexit3_concrete_post THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN + CONJ_TAC THENL [FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN + MASK_OF `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1))(REJ_MASK_ETA2 inlist)) <= 248` + `16 * (N-1)` MASK_DBL_N1 THEN + MASK_OF `~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA2 inlist)) <= 248)` + `16 * N` MASK_DBL_N THEN + MASK_OF `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA2 inlist)) <= 248` + `16 * (N-1) + 4` MASK_DBL_N1_4 THEN + MASK_OF `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA2 inlist)) <= 248` + `16 * (N-1) + 8` MASK_DBL_N1_8 THEN + MASK_OF `~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 24)(REJ_MASK_ETA2 inlist)) <= 248)` + `16 * (N-1) + 12` MASK_DBL_N1_12 THEN + MATCH_MP_TAC MIDEXIT3_EXISTS THEN ASM_REWRITE_TAC[]; + MIDEXIT_DISPATCH_SAFE_ETA2 MID_EXIT_SUBITER3_SAFE_ETA2 + `f_ev_midexit_subiter3 res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) (N-1)` + `16*(N-1)+12` `16*(N-1)+8`]);; + +(* --- OFFSET arm --- *) +let exit_block_offset_safe_tm = + let body = snd(strip_forall(concl EXIT_OFFSET_SAFE_ETA2)) in + let hyps_off, ens = dest_imp body in + let ensc, ppf = strip_comb ens in + let step = el 0 ppf and pre = el 1 ppf and frame = el 3 ppf in + let shared = fst(chop_list 6 (conjuncts hyps_off)) in + let wopf = `!m. m < N ==> 16 * m <= 120 /\ + LENGTH(REJ_NIBBLES_ETA2(SUB_LIST(0,16*m) inlist):int16 list) <= 248` in + let pN = `120 < 16 * N \/ + 248 < LENGTH(REJ_NIBBLES_ETA2(SUB_LIST(0,16*N) inlist):int16 list)` in + let offbyte = `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248` in + let hyps' = list_mk_conj (shared @ [`~(N = 0)`; `~(N = 1)`; wopf; pN; offbyte]) in + let sv = `s:x86state` in + let ctpost = mk_abs(sv, + `read RIP s = word(pc + LENGTH(BUTLAST mldsa_rej_uniform_eta2_tmc)) /\ + (?e2. read events s = APPEND e2 (e:(uarch_event)list) /\ + e2 = f_ev_exit res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) N /\ + memaccess_inbounds e2 [(buf:int64),136; (table:int64),2048] + [(res:int64),1024])`) in + let ens' = list_mk_comb(ensc,[step; pre; ctpost; frame]) in + list_mk_forall + ([`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`; + `N:num`;`stackpointer:int64`;`e:(uarch_event)list`], + mk_imp(hyps', ens'));; + +let EXIT_BLOCK_SAFE_OFFSET = prove + (exit_block_offset_safe_tm, + REPEAT GEN_TAC THEN DISCH_THEN(MAP_EVERY ASSUME_TAC o CONJUNCTS) THEN + SUBGOAL_THEN + `16 * (N-1) <= 120 /\ + LENGTH(REJ_NIBBLES_ETA2(SUB_LIST(0,16*(N-1)) inlist):int16 list) <= 248` + STRIP_ASSUME_TAC THENL + [FIRST_X_ASSUM(MP_TAC o SPEC `N-1` o check(is_forall o concl)) THEN + ANTS_TAC THENL [UNDISCH_TAC `~(N = 0)` THEN ARITH_TAC; REWRITE_TAC[]]; + ALL_TAC] THEN + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN + EXISTS_TAC (rand(rator(snd(dest_imp(snd(strip_forall(concl EXIT_OFFSET_SAFE_ETA2))))))) THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN + CONJ_TAC THENL [FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN + SUBGOAL_THEN `16 * N = 128` ASSUME_TAC THENL + [SUBGOAL_THEN `N = 8` (fun th -> REWRITE_TAC[th] THEN CONV_TAC NUM_REDUCE_CONV) THEN + SUBGOAL_THEN `120 < 16 * N` ASSUME_TAC THENL + [UNDISCH_TAC `120 < 16 * N \/ + 248 < LENGTH(REJ_NIBBLES_ETA2(SUB_LIST(0,16*N) inlist):int16 list)` THEN + REWRITE_TAC[GSYM LENGTH_REJ_SAMPLE_ETA2_BYTES] THEN + UNDISCH_TAC `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248` THEN + ARITH_TAC; + ALL_TAC] THEN + SUBGOAL_THEN `16 * N <= 136` ASSUME_TAC THENL + [UNDISCH_TAC `16 * (N-1) <= 120` THEN UNDISCH_TAC `~(N = 0)` THEN + SPEC_TAC(`N:num`,`N:num`) THEN INDUCT_TAC THEN ARITH_TAC; + ALL_TAC] THEN + UNDISCH_TAC `120 < 16 * N` THEN UNDISCH_TAC `16 * N <= 136` THEN ARITH_TAC; + ALL_TAC] THEN + SUBGOAL_THEN + `NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA2 inlist)) <= 248` + ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`; `16 * N`] STORE_BRIDGE) THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * N) = 32 * N`] THEN + DISCH_THEN(fun th -> REWRITE_TAC[GSYM th]) THEN FIRST_ASSUM ACCEPT_TAC; + ALL_TAC] THEN + MATCH_MP_TAC OFFSET_EXISTS THEN ASM_REWRITE_TAC[]; + OFFSET_ARM_SAFE_ETA2_TAC]);; + +(* --- MIDEXIT1 arm --- *) +let exit_block_midexit1_safe_tm = + let body = snd(strip_forall(concl EXIT_OFFSET_SAFE_ETA2)) in + let hyps_off, ens = dest_imp body in + let ensc, ppf = strip_comb ens in + let step = el 0 ppf and pre = el 1 ppf and frame = el 3 ppf in + let shared = fst(chop_list 6 (conjuncts hyps_off)) in + let wopf = `!m. m < N ==> 16 * m <= 120 /\ + LENGTH(REJ_NIBBLES_ETA2(SUB_LIST(0,16*m) inlist):int16 list) <= 248` in + let pN = `120 < 16 * N \/ + 248 < LENGTH(REJ_NIBBLES_ETA2(SUB_LIST(0,16*N) inlist):int16 list)` in + let midcase = `~(LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248)` in + let sub1sel = `~(LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*(N-1)+4) inlist):int32 list) <= 248)` in + let hyps' = list_mk_conj + (shared @ [`~(N = 0)`; `~(N = 1)`; wopf; pN; midcase; sub1sel]) in + let sv = `s:x86state` in + let ctpost = mk_abs(sv, + `read RIP s = word(pc + LENGTH(BUTLAST mldsa_rej_uniform_eta2_tmc)) /\ + (?e2. read events s = APPEND e2 (e:(uarch_event)list) /\ + e2 = f_ev_exit res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) N /\ + memaccess_inbounds e2 [(buf:int64),136; (table:int64),2048] + [(res:int64),1024])`) in + let ens' = list_mk_comb(ensc,[step; pre; ctpost; frame]) in + list_mk_forall + ([`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`; + `N:num`;`stackpointer:int64`;`e:(uarch_event)list`], + mk_imp(hyps', ens'));; + +let midexit1_concrete_post = + `\s. read RIP s = word(pc + LENGTH(BUTLAST mldsa_rej_uniform_eta2_tmc)) /\ + read events s = + APPEND (f_ev_scalar_tail (136 - (16 * (N-1) + 4)) res buf pc inlist (16 * (N-1) + 4)) + (APPEND (f_ev_midexit_subiter1 res buf table pc (REJ_MASK_ETA2 inlist) (N-1)) + (e:(uarch_event)list))`;; + +let EXIT_BLOCK_SAFE_MIDEXIT1 = prove + (exit_block_midexit1_safe_tm, + REPEAT GEN_TAC THEN DISCH_THEN(MAP_EVERY ASSUME_TAC o CONJUNCTS) THEN + SUBGOAL_THEN + `16 * (N-1) <= 120 /\ + LENGTH(REJ_NIBBLES_ETA2(SUB_LIST(0,16*(N-1)) inlist):int16 list) <= 248` + STRIP_ASSUME_TAC THENL + [FIRST_X_ASSUM(MP_TAC o SPEC `N-1` o check(is_forall o concl)) THEN + ANTS_TAC THENL [UNDISCH_TAC `~(N = 0)` THEN ARITH_TAC; REWRITE_TAC[]]; + ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*(N-1)) inlist):int32 list) <= 248` + ASSUME_TAC THENL + [ASM_REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA2_BYTES]; ALL_TAC] THEN + SUBGOAL_THEN `16 * N <= 136` ASSUME_TAC THENL + [UNDISCH_TAC `16 * (N-1) <= 120` THEN UNDISCH_TAC `~(N = 0)` THEN + SPEC_TAC(`N:num`,`N:num`) THEN INDUCT_TAC THEN ARITH_TAC; + ALL_TAC] THEN + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN + EXISTS_TAC midexit1_concrete_post THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN + CONJ_TAC THENL [FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN + SUBGOAL_THEN `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1))(REJ_MASK_ETA2 inlist)) <= 248` + ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`; `16 * (N-1)`] STORE_BRIDGE) THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * (N-1)) = 32 * (N-1)`] THEN + DISCH_THEN(fun th -> REWRITE_TAC[GSYM th]) THEN FIRST_ASSUM ACCEPT_TAC; + ALL_TAC] THEN + SUBGOAL_THEN `~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA2 inlist)) <= 248)` + ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`; `16 * N`] STORE_BRIDGE) THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * N) = 32 * N`] THEN + DISCH_THEN(fun th -> REWRITE_TAC[GSYM th]) THEN FIRST_ASSUM ACCEPT_TAC; + ALL_TAC] THEN + SUBGOAL_THEN `~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA2 inlist)) <= 248)` + ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`; `16 * (N-1) + 4`] STORE_BRIDGE) THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * (N-1) + 4) = 32 * (N-1) + 8`] THEN + DISCH_THEN(fun th -> REWRITE_TAC[GSYM th]) THEN FIRST_ASSUM ACCEPT_TAC; + ALL_TAC] THEN + MATCH_MP_TAC MIDEXIT1_EXISTS THEN ASM_REWRITE_TAC[]; + MIDEXIT_DISPATCH_SAFE_ETA2 MID_EXIT_SUBITER1_SAFE_ETA2 + `f_ev_midexit_subiter1 res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) (N-1)` + `16*(N-1)+4` `16*(N-1)`]);; + +(* --- MIDEXIT4 arm --- *) +let SAFE_BRIDGE_CLEAN (bth:thm) : tactic = + W(fun (asl,gl) -> + let lframe = rand(concl bth) in + let lpost = rand(rator(concl bth)) in + let lpre = rand(rator(rator(concl bth))) in + let gframe = rand gl in + let subsumed_tm = mk_binop + `(subsumed):(x86state->x86state->bool)->(x86state->x86state->bool)->bool` + lframe gframe in + let subsumed_th = prove(subsumed_tm, + REPEAT(MATCH_MP_TAC SUBSUMED_SEQ THEN REWRITE_TAC[SUBSUMED_REFL]) THEN + SUBSUMED_MAYCHANGE_TAC) in + let bth2 = MATCH_MP ENSURES_FRAME_SUBSUMED (CONJ subsumed_th bth) in + MATCH_MP_TAC ENSURES_PRECONDITION_THM THEN EXISTS_TAC lpre THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN EXISTS_TAC lpost THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + ACCEPT_TAC bth2]]);; + +let SCALAR_TAIL_LEG2_CLEAN (p:term) (etail:term) : tactic = + W(fun (asl,gl) -> + let atp = SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`; + `pc:num`;p;`stackpointer:int64`;etail] + MLDSA_REJ_UNIFORM_ETA2_SCALAR_TAIL_AT_P_SAFE in + let atp_ens = snd(dest_imp(concl atp)) in + let _,ppf = strip_comb atp_ens in + let atp_pre = el 1 ppf and atp_post = el 2 ppf in + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN EXISTS_TAC atp_post THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + MATCH_MP_TAC ENSURES_PRECONDITION_THM THEN EXISTS_TAC atp_pre THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + MP_TAC atp THEN ANTS_TAC THENL + [REPEAT CONJ_TAC THEN FIRST_ASSUM ACCEPT_TAC; + MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] ENSURES_FRAME_SUBSUMED) THEN + REPEAT(MATCH_MP_TAC SUBSUMED_SEQ THEN REWRITE_TAC[SUBSUMED_REFL]) THEN + SUBSUMED_MAYCHANGE_TAC]]]);; + +let exit_block_midexit4_safe_tm = mk_midexit_safe_tm + [`~(LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248)`; + `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*(N-1)+4) inlist):int32 list) <= 248`; + `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*(N-1)+8) inlist):int32 list) <= 248`; + `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*(N-1)+12) inlist):int32 list) <= 248`];; + +let midexit4_concrete_post = + `\s. read RIP s = word(pc + LENGTH(BUTLAST mldsa_rej_uniform_eta2_tmc)) /\ + read events s = + APPEND (f_ev_scalar_tail (136 - (16 * ((N-1) + 1))) res buf pc inlist (16 * ((N-1) + 1))) + (APPEND (f_ev_midexit_subiter4 res buf table pc (REJ_MASK_ETA2 inlist) (N-1)) + (e:(uarch_event)list))`;; + +let EXIT_BLOCK_SAFE_MIDEXIT4 = prove + (exit_block_midexit4_safe_tm, + MIDEXIT_SETUP_TAC THEN + SUBGOAL_THEN `16 * ((N-1) + 1) = 16 * N` ASSUME_TAC THENL + [UNDISCH_TAC `~(N = 0)` THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN + `248 < LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*((N-1)+1)) inlist):int32 list)` + ASSUME_TAC THENL + [SUBST1_TAC(ASSUME `16 * ((N-1) + 1) = 16 * N`) THEN + UNDISCH_TAC `~(LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248)` THEN + ARITH_TAC; ALL_TAC] THEN + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN + EXISTS_TAC midexit4_concrete_post THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN + CONJ_TAC THENL [FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN + RULE_ASSUM_TAC(REWRITE_RULE[ASSUME `16 * ((N-1) + 1) = 16 * N`]) THEN + MASK_OF `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1))(REJ_MASK_ETA2 inlist)) <= 248` + `16 * (N-1)` MASK_DBL_N1 THEN + MASK_OF `~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA2 inlist)) <= 248)` + `16 * N` MASK_DBL_N THEN + MASK_OF `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA2 inlist)) <= 248` + `16 * (N-1) + 4` MASK_DBL_N1_4 THEN + MASK_OF `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA2 inlist)) <= 248` + `16 * (N-1) + 8` MASK_DBL_N1_8 THEN + MASK_OF `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 24)(REJ_MASK_ETA2 inlist)) <= 248` + `16 * (N-1) + 12` MASK_DBL_N1_12 THEN + MATCH_MP_TAC MIDEXIT4_EXISTS THEN ASM_REWRITE_TAC[]; + MATCH_MP_TAC ENSURES_TRANS_SIMPLE THEN + EXISTS_TAC (midexit_qpost_safe_eta2 MID_EXIT_SUBITER4_SAFE_ETA2) THEN + CONJ_TAC THENL [MAYCHANGE_IDEMPOT_TAC; ALL_TAC] THEN + CONJ_TAC THENL + [MP_TAC(SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`; + `pc:num`;`N-1`;`stackpointer:int64`;`e:(uarch_event)list`] + MID_EXIT_SUBITER4_SAFE_ETA2) THEN + ANTS_TAC THENL + [REPEAT CONJ_TAC THEN (FIRST[FIRST_ASSUM ACCEPT_TAC; ASM_ARITH_TAC]); ALL_TAC] THEN + DISCH_THEN(fun bth -> SAFE_BRIDGE_CLEAN bth); + SUBGOAL_THEN `16 * ((N-1) + 1) <= 136` ASSUME_TAC THENL + [UNDISCH_TAC `16 * N <= 136` THEN UNDISCH_TAC `16 * ((N-1) + 1) = 16 * N` THEN + ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*((N-1)+1)) inlist):int32 list) <= 256` + ASSUME_TAC THENL + [SUBGOAL_THEN `16 * ((N-1) + 1) = (16 * (N-1) + 12) + 4` SUBST1_TAC THENL + [UNDISCH_TAC `~(N = 0)` THEN ARITH_TAC; ALL_TAC] THEN + MATCH_MP_TAC OUTLEN0_LE_256_FROM_SUBITER_ETA2 THEN CONJ_TAC THENL + [UNDISCH_TAC `16 * N <= 136` THEN UNDISCH_TAC `16 * ((N-1) + 1) = 16 * N` THEN + UNDISCH_TAC `LENGTH(inlist:byte list) = 136` THEN ARITH_TAC; + FIRST_ASSUM ACCEPT_TAC]; ALL_TAC] THEN + SCALAR_TAIL_LEG2_CLEAN `16 * ((N-1) + 1)` + `APPEND (f_ev_midexit_subiter4 res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) (N-1)) + (e:(uarch_event)list)`]]);; + +(* --- EXIT_BLOCK_SAFE_ETA2 (assembled) --- *) +let exit_block_safe_eta2_tm = mk_midexit_safe_tm [];; + +let EXIT_BLOCK_SAFE_ETA2 = prove + (exit_block_safe_eta2_tm, + MIDEXIT_SETUP_TAC THEN + ASM_CASES_TAC + `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248` THENL + [MATCH_MP_TAC EXIT_BLOCK_SAFE_OFFSET THEN ASM_REWRITE_TAC[]; + ASM_CASES_TAC + `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*(N-1)+4) inlist):int32 list) <= 248` THENL + [ASM_CASES_TAC + `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*(N-1)+8) inlist):int32 list) <= 248` THENL + [ASM_CASES_TAC + `LENGTH(REJ_SAMPLE_ETA2_BYTES(SUB_LIST(0,16*(N-1)+12) inlist):int32 list) <= 248` THENL + [MATCH_MP_TAC EXIT_BLOCK_SAFE_MIDEXIT4 THEN ASM_REWRITE_TAC[]; + MATCH_MP_TAC EXIT_BLOCK_SAFE_MIDEXIT3 THEN ASM_REWRITE_TAC[]]; + MATCH_MP_TAC EXIT_BLOCK_SAFE_MIDEXIT2 THEN ASM_REWRITE_TAC[]]; + MATCH_MP_TAC EXIT_BLOCK_SAFE_MIDEXIT1 THEN ASM_REWRITE_TAC[]]]);; + +(* --- CORE_SAFE_FREEN_ETA2 --- *) +let MEMACCESS_ENUM_LOOP_ETA2 = prove + (`!res buf table inlist pc N. + ~(N = 0) /\ 16 * (N - 1) <= 120 /\ + (!m. m < N ==> 16 * m <= 120 /\ + LENGTH(REJ_NIBBLES_ETA2(SUB_LIST(0,16*m) inlist):int16 list) <= 248) + ==> memaccess_inbounds + (ENUMERATEL (N-1) (f_ev_loop_eta2 res buf table pc (REJ_MASK_ETA2 inlist))) + [buf,136; table,2048] [res,1024]`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + MATCH_MP_TAC MEMACCESS_ENUM_ACC THEN + X_GEN_TAC `j:num` THEN DISCH_TAC THEN + MATCH_MP_TAC MEMACCESS_F_EV_LOOP_ETA2 THEN + CONJ_TAC THENL + [MAP_EVERY UNDISCH_TAC [`j < N - 1`; `16 * (N - 1) <= 120`] THEN ARITH_TAC; + MATCH_MP_TAC LE_TRANS THEN + EXISTS_TAC `NUM_ACCEPTED(SUB_LIST(0,32*(j+1))(REJ_MASK_ETA2 inlist))` THEN + CONJ_TAC THENL + [MATCH_MP_TAC NUM_ACCEPTED_PREFIX_MONO THEN ARITH_TAC; + MP_TAC(SPECL[`inlist:byte list`;`16*(j+1)`] STORE_BRIDGE) THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * (j + 1)) = 32 * (j + 1)`] THEN + DISCH_THEN(fun th -> REWRITE_TAC[GSYM th]) THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA2_BYTES] THEN + FIRST_X_ASSUM(MP_TAC o SPEC `j + 1` o check(is_forall o concl)) THEN + ANTS_TAC THENL + [UNDISCH_TAC `j < N - 1` THEN UNDISCH_TAC `~(N = 0)` THEN ARITH_TAC; + REWRITE_TAC[] THEN STRIP_TAC THEN FIRST_ASSUM ACCEPT_TAC]]]);; + +let core_safe_freeN_tm = + let bod = snd(strip_forall(concl ETA2_LOOP_SAFE)) in + let hyps,ens = dest_imp bod in + let comb,args = strip_comb ens in + let step = el 0 args and pre = el 1 args and frame = el 3 args in + let pN = `120 < 16 * N \/ + 248 < LENGTH(REJ_NIBBLES_ETA2(SUB_LIST(0,16*N) inlist):int16 list)` in + let hyps' = list_mk_conj (conjuncts hyps @ [pN]) in + let sv = `s:x86state` in + let post = mk_abs(sv, + `read RIP s = word (pc + LENGTH (BUTLAST mldsa_rej_uniform_eta2_tmc)) /\ + (?e2. read events s = APPEND e2 (e:(uarch_event)list) /\ + e2 = APPEND (f_ev_exit res buf table pc (REJ_MASK_ETA2 (inlist:byte list)) N) + (ENUMERATEL (N - 1) + (f_ev_loop_eta2 res buf table pc (REJ_MASK_ETA2 inlist))) /\ + memaccess_inbounds e2 [(buf:int64),136; (table:int64),2048] + [(res:int64),1024])`) in + let ens' = list_mk_comb(comb, [step; pre; post; frame]) in + list_mk_forall(fst(strip_forall(concl ETA2_LOOP_SAFE)), mk_imp(hyps', ens'));; + +let LOOP' = REWRITE_RULE[SOME_FLAGS] ETA2_LOOP_SAFE;; +let loop_post_tm = el 2 (snd(strip_comb(snd(dest_imp(snd(strip_forall(concl ETA2_LOOP_SAFE)))))));; +let EXIT_INST = SPECL + [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`N:num`; + `stackpointer:int64`; + `APPEND (ENUMERATEL (N-1) (f_ev_loop_eta2 res buf table pc (REJ_MASK_ETA2 inlist))) + (e:(uarch_event)list)`] + EXIT_BLOCK_SAFE_ETA2;; +let q_inter = el 1 (snd(strip_comb(snd(dest_imp(concl EXIT_INST)))));; +let exit_post_tm = el 2 (snd(strip_comb(snd(dest_imp(concl EXIT_INST)))));; + +let CORE_SAFE_FREEN_ETA2 = prove + (core_safe_freeN_tm, + REPEAT GEN_TAC THEN + REWRITE_TAC[SOME_FLAGS] THEN + DISCH_THEN(MAP_EVERY ASSUME_TAC o CONJUNCTS) THEN + MATCH_MP_TAC ENSURES_TRANS_SIMPLE THEN + EXISTS_TAC q_inter THEN + CONJ_TAC THENL [MAYCHANGE_IDEMPOT_TAC; ALL_TAC] THEN + CONJ_TAC THENL + [MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN + EXISTS_TAC loop_post_tm THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + MATCH_MP_TAC LOOP' THEN ASM_REWRITE_TAC[]]; + SUBGOAL_THEN `16 * (N - 1) <= 120` ASSUME_TAC THENL + [FIRST_ASSUM(MP_TAC o SPEC `N-1` o check(is_forall o concl)) THEN + ANTS_TAC THENL + [UNDISCH_TAC `~(N=0)` THEN ARITH_TAC; + DISCH_THEN(ACCEPT_TAC o CONJUNCT1)]; + ALL_TAC] THEN + MP_TAC EXIT_INST THEN ANTS_TAC THENL + [RULE_ASSUM_TAC(REWRITE_RULE[NONOVERLAPPING_CLAUSES; + LENGTH_MLDSA_REJ_UNIFORM_ETA2_TMC]) THEN + ASM_REWRITE_TAC[]; + DISCH_THEN(fun exitth -> + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN + EXISTS_TAC exit_post_tm THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN + FIRST_X_ASSUM(SUBST_ALL_TAC o + check (fun th -> is_eq(concl th) && is_var(lhs(concl th)))) THEN + CONJ_TAC THENL + [ASM_REWRITE_TAC[]; + EXISTS_TAC + `APPEND (f_ev_exit res buf table pc (REJ_MASK_ETA2 inlist) N) + (ENUMERATEL (N-1) + (f_ev_loop_eta2 res buf table pc (REJ_MASK_ETA2 inlist)))` THEN + REPEAT CONJ_TAC THENL + [ASM_REWRITE_TAC[APPEND_ASSOC]; + REFL_TAC; + REWRITE_TAC[MEMACCESS_INBOUNDS_APPEND] THEN CONJ_TAC THENL + [FIRST_ASSUM ACCEPT_TAC; + MATCH_MP_TAC MEMACCESS_ENUM_LOOP_ETA2 THEN ASM_REWRITE_TAC[]]]]; + ACCEPT_TAC exitth])]]);; + +(* --- CORE_SAFE + SUBROUTINE_SAFE --- *) +let f_ev_core_eta2 = + `\(res:int64) (buf:int64) (table:int64) (pc:num) (mask:(bool)list). + APPEND (f_ev_exit res buf table pc mask (N_OF_MASK_ETA2 mask)) + (ENUMERATEL (N_OF_MASK_ETA2 mask - 1) + (f_ev_loop_eta2 res buf table pc mask)) + :(uarch_event)list`;; + +let core_safe_eta2_tm = + `?f_events:int64->int64->int64->num->(bool)list->(uarch_event)list. + !res buf table (inlist:byte list) e pc. + LENGTH inlist = 136 /\ + nonoverlapping (word pc,LENGTH mldsa_rej_uniform_eta2_tmc) (res,1024) /\ + nonoverlapping (word pc,LENGTH mldsa_rej_uniform_eta2_tmc) (buf,136) /\ + nonoverlapping (word pc,LENGTH mldsa_rej_uniform_eta2_tmc) (table,2048) /\ + nonoverlapping (res,1024) (buf,136) /\ + nonoverlapping (res,1024) (table,2048) + ==> ensures x86 + (\s. bytes_loaded s (word pc) (BUTLAST mldsa_rej_uniform_eta2_tmc) /\ + read RIP s = word pc /\ + C_ARGUMENTS [res; buf; table] s /\ + read (memory :> bytes (buf,136)) s = num_of_wordlist inlist /\ + read (memory :> bytes (table,2048)) s = + num_of_wordlist mldsa_rej_uniform_table /\ + read events s = e) + (\s. read RIP s = + word (pc + LENGTH (BUTLAST mldsa_rej_uniform_eta2_tmc)) /\ + (?e2. read events s = APPEND e2 e /\ + e2 = f_events res buf table pc (REJ_MASK_ETA2 inlist) /\ + memaccess_inbounds e2 [buf,136; table,2048] [res,1024])) + (MAYCHANGE [RIP; RAX; RCX; R8; R9; R10; R11] ,, + MAYCHANGE + [ZMM0; ZMM1; ZMM2; ZMM3; ZMM4; ZMM5; ZMM6; ZMM7; ZMM8; ZMM9] ,, + MAYCHANGE SOME_FLAGS ,, + MAYCHANGE [events] ,, + MAYCHANGE [memory :> bytes (res,1024)])`;; + +let MLDSA_REJ_UNIFORM_ETA2_CORE_SAFE = prove + (core_safe_eta2_tm, + EXISTS_TAC f_ev_core_eta2 THEN + REPEAT GEN_TAC THEN STRIP_TAC THEN + GHOST_INTRO_TAC `stackpointer:int64` `read RSP` THEN + CONV_TAC(TOP_DEPTH_CONV BETA_CONV) THEN + MATCH_MP_TAC CORE_SAFE_FREEN_ETA2 THEN + ASM_REWRITE_TAC[] THEN + MP_TAC(SPEC `REJ_MASK_ETA2 (inlist:byte list)` N_OF_MASK_ETA2_MINIMAL) THEN + REWRITE_TAC[GSYM NIBLEN_EQ_NUMACC_ETA2] THEN + ABBREV_TAC `NN = N_OF_MASK_ETA2 (REJ_MASK_ETA2 (inlist:byte list))` THEN + DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC ASSUME_TAC) THEN + REPEAT CONJ_TAC THENL + [DISCH_TAC THEN + FIRST_X_ASSUM(MP_TAC o check(is_disj o concl)) THEN + ASM_REWRITE_TAC[MULT_CLAUSES; ADD_CLAUSES; SUB_LIST_CLAUSES; + REJ_NIBBLES_ETA2_EMPTY; LENGTH] THEN + ARITH_TAC; + DISCH_TAC THEN + FIRST_X_ASSUM(MP_TAC o check(is_disj o concl)) THEN + ASM_REWRITE_TAC[ARITH_RULE `16 * 1 = 16`; ARITH_RULE `~(120 < 16)`] THEN + MP_TAC(ISPECL [`inlist:byte list`; `16`] + LENGTH_REJ_SAMPLE_ETA2_BYTES_SUB_LIST_BOUND) THEN + ASM_REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA2_BYTES] THEN ARITH_TAC; + X_GEN_TAC `m:num` THEN DISCH_TAC THEN + FIRST_X_ASSUM(MP_TAC o SPEC `m:num` o check(is_forall o concl)) THEN + ASM_REWRITE_TAC[] THEN REWRITE_TAC[NOT_LT] THEN DISCH_THEN ACCEPT_TAC; + FIRST_ASSUM ACCEPT_TAC]);; + +let MLDSA_REJ_UNIFORM_ETA2_CORE_SAFE_CONCRETE = + CONV_RULE(REWRITE_CONV[LENGTH_MLDSA_REJ_UNIFORM_ETA2_TMC; + fst MLDSA_REJ_UNIFORM_ETA2_EXEC]) + MLDSA_REJ_UNIFORM_ETA2_CORE_SAFE;; + +let MLDSA_REJ_UNIFORM_ETA2_NOIBT_SUBROUTINE_SAFE = + let saved_tic = !type_invention_error in + type_invention_error := false; + let th = prove + (`?f_events:int64->int64->int64->num->(bool)list->int64->int64-> + (uarch_event)list. + !res buf table (inlist:byte list) e pc stackpointer returnaddress. + LENGTH inlist = 136 /\ + nonoverlapping (word pc, LENGTH mldsa_rej_uniform_eta2_tmc) (res, 1024) /\ + nonoverlapping (word pc, LENGTH mldsa_rej_uniform_eta2_tmc) (buf, 136) /\ + nonoverlapping (word pc, LENGTH mldsa_rej_uniform_eta2_tmc) (table, 2048) /\ + nonoverlapping (res, 1024) (buf, 136) /\ + nonoverlapping (res, 1024) (table, 2048) /\ + nonoverlapping (stackpointer, 8) (res, 1024) /\ + nonoverlapping (stackpointer, 8) (buf, 136) /\ + nonoverlapping (stackpointer, 8) (table, 2048) /\ + nonoverlapping (stackpointer, 8) (word pc, LENGTH mldsa_rej_uniform_eta2_tmc) + ==> ensures x86 + (\s. bytes_loaded s (word pc) mldsa_rej_uniform_eta2_tmc /\ + read RIP s = word pc /\ + read RSP s = stackpointer /\ + read (memory :> bytes64 stackpointer) s = returnaddress /\ + C_ARGUMENTS [res; buf; table] s /\ + read(memory :> bytes(buf, 136)) s = num_of_wordlist inlist /\ + read(memory :> bytes(table,2048)) s = + num_of_wordlist mldsa_rej_uniform_table /\ + read events s = e) + (\s. read RIP s = returnaddress /\ + read RSP s = word_add stackpointer (word 8) /\ + (?e2. read events s = APPEND e2 e /\ + e2 = f_events res buf table pc (REJ_MASK_ETA2 inlist) + stackpointer returnaddress /\ + memaccess_inbounds e2 + [buf,136; table,2048; stackpointer,8] + [res,1024])) + (MAYCHANGE [RSP] ,, MAYCHANGE_REGS_AND_FLAGS_PERMITTED_BY_ABI ,, + MAYCHANGE [memory :> bytes(res,1024)])`, + REWRITE_TAC[LENGTH_MLDSA_REJ_UNIFORM_ETA2_TMC] THEN + X86_PROMOTE_RETURN_NOSTACK_TAC mldsa_rej_uniform_eta2_tmc + MLDSA_REJ_UNIFORM_ETA2_CORE_SAFE_CONCRETE THEN + ABBREV_TAC `mask:(bool)list = REJ_MASK_ETA2 (inlist:byte list)` THEN + DISCHARGE_SAFETY_PROPERTY_TAC) in + type_invention_error := saved_tic; + th;; + +let MLDSA_REJ_UNIFORM_ETA2_SUBROUTINE_SAFE = + ADD_IBT_RULE MLDSA_REJ_UNIFORM_ETA2_NOIBT_SUBROUTINE_SAFE;; + diff --git a/proofs/hol_light/x86_64/proofs/mldsa_rej_uniform_eta4_avx2_asm.ml b/proofs/hol_light/x86_64/proofs/mldsa_rej_uniform_eta4_avx2_asm.ml index 6455fd1255..6e2b944d50 100644 --- a/proofs/hol_light/x86_64/proofs/mldsa_rej_uniform_eta4_avx2_asm.ml +++ b/proofs/hol_light/x86_64/proofs/mldsa_rej_uniform_eta4_avx2_asm.ml @@ -265,7 +265,7 @@ let READ_BYTES_SLICE = prove canonical `usimd8 (\b. word_sx b) (word_zx(word_zx pshuf))` form in-context (where the term is fully typed by the simulator) via `REWRITE_TAC[usimd8;usimd4;usimd2] THEN SIMP_TAC[WORD_SUBWORD_SUBWORD;DIMINDEX_*;ARITH] THEN CONV_TAC NUM_REDUCE_CONV`, after which - the committed VPMOVSXBD_LANE_EXTRACT gives each int32 lane = word_sx of the pshuf byte. + VPMOVSXBD_LANE_EXTRACT gives each int32 lane = word_sx of the pshuf byte. (Kept as an in-body step rather than a standalone lemma because the word_join associativity/widths are simulator-determined.) *) @@ -2549,17 +2549,22 @@ let PF_PROOF : tactic = mk_pf_proof `pshuf1:int256` `tab1:int256`;; (* memory-safety chain must additionally require RIP on the LHS at state *) (* `s` (the anchored events fact also mentions `pc + pcoff`, so the bare *) (* find_term would grab it and REFL_TAC would fail). *) +(* EVENTS-ROBUST rip_mp (else-branch structural read-RIP guard): + BOTH branches require a structural `read RIP _ = _` assumption, so a threaded + `read events s = e` fact (whose EventJump targets embed pc+N) can never be + selected on the SAFE clean-block/midexit proofs. memsafe=true behaviour is + unchanged (still pins the exact state var); memsafe=false additionally requires + the read-RIP shape (neutral for the events-free CORRECT proofs). *) let rip_mp (memsafe:bool) (pcoff:int) (st:int) : tactic = let pctm = mk_binop `(+):num->num->num` `pc:num` (mk_small_numeral pcoff) in let stv = mk_var("s"^string_of_int st,`:x86state`) in - if memsafe then - FIRST_ASSUM(fun th -> if can(find_term(fun u->u=pctm))(concl th) && - (match concl th with - Comb(Comb(Const("=",_),Comb(Comb(Const("read",_),Const("RIP",_)),v)),_) -> v=stv - | _ -> false) - then MP_TAC th else NO_TAC) - else - FIRST_ASSUM(fun th -> if can(find_term(fun u->u=pctm))(concl th) then MP_TAC th else NO_TAC);; + let is_rip_read th = + match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("read",_),Const("RIP",_)),v)),_) -> + (not memsafe) || v = stv + | _ -> false in + FIRST_ASSUM(fun th -> if can(find_term(fun u->u=pctm))(concl th) && is_rip_read th + then MP_TAC th else NO_TAC);; let mk_prefix_g_full (memsafe:bool) : tactic = REPEAT GEN_TAC THEN @@ -4896,8 +4901,7 @@ let OFFSET_ARM_TAC : tactic = (* PREFIX_TO_S21_TAC: the bound-independent body of PREFIX_G_FULL_TAC (gather/store s17 + counter steps 18-21 + SUBITER_BLOCK_BYTES + m8def rewrite), reaching s21 with RAX=acc-popcount, RCX, store(16i+4). Uses ONLY niblen(16i)<=248 (true in all exit cases). - Shared by the clean (not-taken) and MID-EXIT (taken) guard resolutions. Extracted verbatim - from .prefix_g_full_tac.ml lines 2-333. *) + Shared by the clean (not-taken) and MID-EXIT (taken) guard resolutions. *) (* Generator for the value + memory-safety twins of the prefix-to-s21 body *) (* stepping. The two are identical except the MS variant strips the events *) (* existential right after ENSURES_INIT (STRIP_EXISTS_ASSUM_TAC), so it is a *) @@ -7993,3 +7997,3800 @@ let MLDSA_REJ_UNIFORM_ETA4_SUBROUTINE_MEMSAFE = (* Trailing subroutine-signature load for the constant-time harness. Loads *) (* AFTER both MEMSAFE theorems. *) needs "mldsa_native/x86_64/proofs/subroutine_signatures.ml";; + +(* ========================================================================= *) +(* Constant-time (SAFE) machinery for rej_uniform_eta4. *) +(* *) +(* Arch-neutral CT-mask prelude, the eta4 analogue of the eta2 prelude. The *) +(* only eta-specific changes vs the eta2 source are: *) +(* - REJ_MASK_ETA4 accept condition val x < 9 (eta2: val x < 15) *) +(* - LENGTH_REJ_NIBBLES_ETA4_EQ_MASK references REJ_NIBBLES_ETA4/REJ_MASK_ETA4*) +(* - REJ_MASK_ETA4_SUB_LIST references REJ_MASK_ETA4 *) +(* Everything else (NUM_ACCEPTED, PACK_MASK8, NIBBLES_OF_BYTES_SUB_LIST, *) +(* SUB_LIST_MAP_GEN, PACK_CONNECT) is eta-neutral, identical to eta2. *) +(* ========================================================================= *) + +(* eta4 public reject mask: for each nibble, accept iff its value < 9. *) +let REJ_MASK_ETA4 = define + `REJ_MASK_ETA4 (l:byte list) : bool list = + MAP (\x:int16. val x < 9) (NIBBLES_OF_BYTES l)`;; + +(* Abstract core: #elements passing P = #`true`s in the boolean image. *) +let LENGTH_FILTER_EQ_LENGTH_FILTER_MAP = prove + (`!(P:A->bool) xs. + LENGTH(FILTER (\b:bool. b) (MAP P xs)) = LENGTH(FILTER P xs)`, + GEN_TAC THEN LIST_INDUCT_TAC THEN + REWRITE_TAC[MAP; FILTER; LENGTH] THEN + COND_CASES_TAC THEN ASM_REWRITE_TAC[LENGTH]);; + +(* Store-advance / trip-count bridge: #ACCEPTED nibbles = #`true`s in the *) +(* PUBLIC reject mask. Value-free. *) +let LENGTH_REJ_NIBBLES_ETA4_EQ_MASK = prove + (`!l:byte list. + LENGTH(REJ_NIBBLES_ETA4 l) = LENGTH(FILTER (\b:bool. b) (REJ_MASK_ETA4 l))`, + REWRITE_TAC[REJ_NIBBLES_ETA4; REJ_MASK_ETA4; + LENGTH_FILTER_EQ_LENGTH_FILTER_MAP]);; + +(* Public "accepted count" over a mask, additive over APPEND. (eta-neutral) *) +let NUM_ACCEPTED = define + `NUM_ACCEPTED (m:bool list) = LENGTH(FILTER (\b:bool. b) m)`;; + +let NUM_ACCEPTED_APPEND = prove + (`!m1 m2. NUM_ACCEPTED(APPEND m1 m2) = NUM_ACCEPTED m1 + NUM_ACCEPTED m2`, + REWRITE_TAC[NUM_ACCEPTED; FILTER_APPEND; LENGTH_APPEND]);; + +(* Public table-index witness: 8-bit LSB-first packing of an accept-mask *) +(* group. The compaction table is indexed by this 0..255 value. (eta-neutral)*) +let PACK_MASK8 = define + `PACK_MASK8 (bs:bool list) = + bitval(EL 0 bs) + 2 * bitval(EL 1 bs) + + 4 * bitval(EL 2 bs) + 8 * bitval(EL 3 bs) + + 16 * bitval(EL 4 bs) + 32 * bitval(EL 5 bs) + + 64 * bitval(EL 6 bs) + 128 * bitval(EL 7 bs)`;; + +let PACK_MASK8_BOUND = prove + (`!bs:bool list. PACK_MASK8 bs < 256`, + GEN_TAC THEN REWRITE_TAC[PACK_MASK8] THEN + MAP_EVERY (fun t -> MP_TAC(SPEC t BITVAL_BOUND)) + [`EL 0 (bs:bool list)`; `EL 1 (bs:bool list)`; `EL 2 (bs:bool list)`; + `EL 3 (bs:bool list)`; `EL 4 (bs:bool list)`; `EL 5 (bs:bool list)`; + `EL 6 (bs:bool list)`; `EL 7 (bs:bool list)`] THEN + ARITH_TAC);; + +(* weighted-sum <-> PACK_MASK8 of the nibble-ordered accept mask. (eta-neutral)*) +let PACK_CONNECT = prove + (`!b0 b1 b2 b3 b4 b5 b6 b7:bool. + 128 * bitval b0 + 64 * bitval b1 + 32 * bitval b2 + 16 * bitval b3 + + 8 * bitval b4 + 4 * bitval b5 + 2 * bitval b6 + bitval b7 = + PACK_MASK8 [b7;b6;b5;b4;b3;b2;b1;b0]`, + REWRITE_TAC[PACK_MASK8] THEN + CONV_TAC(ONCE_DEPTH_CONV EL_CONV) THEN ARITH_TAC);; + +(* byte-index SUB_LIST maps to nibble-index SUB_LIST at 2x offset/length. (n) *) +let NIBBLES_OF_BYTES_SUB_LIST = prove + (`!l a b. NIBBLES_OF_BYTES(SUB_LIST(a,b) l) = + SUB_LIST(2*a,2*b)(NIBBLES_OF_BYTES l)`, + LIST_INDUCT_TAC THEN REPEAT GEN_TAC THEN + MAP_EVERY (fun v -> STRUCT_CASES_TAC(SPEC v num_CASES)) [`a:num`;`b:num`] THEN + ASM_REWRITE_TAC[NIBBLES_OF_BYTES; NIBBLE_PAIR; SUB_LIST_CLAUSES; APPEND; + MULT_CLAUSES; ADD_CLAUSES; ARITH_RULE `2 * SUC n = SUC(SUC(2*n))`] THEN + ASM_REWRITE_TAC[SUB_LIST_CLAUSES; APPEND]);; + +(* General-offset MAP/SUB_LIST commutation. (eta-neutral) *) +let SUB_LIST_MAP_GEN = prove + (`!(f:A->B) l a b. SUB_LIST(a,b)(MAP f l) = MAP f (SUB_LIST(a,b) l)`, + GEN_TAC THEN LIST_INDUCT_TAC THEN REPEAT GEN_TAC THEN + MAP_EVERY (fun v -> STRUCT_CASES_TAC(SPEC v num_CASES)) [`a:num`;`b:num`] THEN + ASM_REWRITE_TAC[MAP; SUB_LIST_CLAUSES]);; + +(* mask-level length-doubling commutation: REJ_MASK_ETA4(SUB_LIST) into *) +(* SUB_LIST of the ATOMIC mask. *) +let REJ_MASK_ETA4_SUB_LIST = prove + (`!l a b. REJ_MASK_ETA4(SUB_LIST(a,b) l) = SUB_LIST(2*a,2*b)(REJ_MASK_ETA4 l)`, + REWRITE_TAC[REJ_MASK_ETA4; NIBBLES_OF_BYTES_SUB_LIST; SUB_LIST_MAP_GEN]);; + +(* ========================================================================= *) +(* Trip-count lemmas. *) +(* *) +(* eta4 analogue of the eta2 trip lemmas (NIBLEN_EQ_NUMACC, N_OF_MASK + *) +(* _MINIMAL, IVAL_WORD_SMALL). eta-specific changes vs eta2: WOP buffer bound *) +(* 120 -> 256 (= buflen 272 - 16) and existence witness 8 -> 17 *) +(* (256 < 16*17 = 272); count bound 248 unchanged. *) +(* ========================================================================= *) + +(* niblen(16N,inlist) = NUM_ACCEPTED(SUB_LIST(0,32N) mask): public re-expression *) +(* of the (inlist-based) exit predicate over the mask. *) +let NIBLEN_EQ_NUMACC_ETA4 = prove + (`!(inlist:byte list) (N:num). + LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(0,16 * N) inlist):int16 list) = + NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA4 inlist))`, + REPEAT GEN_TAC THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA4_EQ_MASK; NUM_ACCEPTED; + REJ_MASK_ETA4_SUB_LIST] THEN + REWRITE_TAC[MULT_CLAUSES; ARITH_RULE `2 * (16 * N) = 32 * N`]);; + +(* The mask-based trip count (public loop iteration count). Buffer bound 256 *) +(* (=buflen 272 - 16); count bound 248. *) +let N_OF_MASK_ETA4 = define + `N_OF_MASK_ETA4 (mask:bool list) : num = + minimal N. 256 < 16 * N \/ 248 < NUM_ACCEPTED(SUB_LIST(0,32 * N) mask)`;; + +(* Trip minimality (dual-exit crux), analogue of N_OF_MASK_ETA2_MINIMAL. *) +let N_OF_MASK_ETA4_MINIMAL = prove + (`!(mask:bool list). + (256 < 16 * N_OF_MASK_ETA4 mask \/ + 248 < NUM_ACCEPTED(SUB_LIST(0,32 * N_OF_MASK_ETA4 mask) mask)) /\ + (!i. i < N_OF_MASK_ETA4 mask + ==> ~(256 < 16 * i) /\ + ~(248 < NUM_ACCEPTED(SUB_LIST(0,32 * i) mask)))`, + GEN_TAC THEN REWRITE_TAC[N_OF_MASK_ETA4] THEN + SUBGOAL_THEN + `?n. 256 < 16 * n \/ 248 < NUM_ACCEPTED(SUB_LIST(0,32 * n)(mask:bool list))` + ASSUME_TAC THENL + [EXISTS_TAC `17` THEN DISJ1_TAC THEN ARITH_TAC; ALL_TAC] THEN + FIRST_X_ASSUM(STRIP_ASSUME_TAC o REWRITE_RULE[MINIMAL]) THEN + ASM_REWRITE_TAC[] THEN + X_GEN_TAC `i:num` THEN DISCH_TAC THEN + REWRITE_TAC[GSYM DE_MORGAN_THM] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN + ASM_REWRITE_TAC[]);; + +(* ival(word m) = &m for m below 2^63 (branch-condition normalization). *) +(* eta-neutral. *) +let IVAL_WORD_SMALL = prove + (`!m. m < 2 EXP 63 ==> ival(word m:int64) = &m`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN `val(word m:int64) = m` ASSUME_TAC THENL + [REWRITE_TAC[VAL_WORD; DIMINDEX_64] THEN MATCH_MP_TAC MOD_LT THEN + ASM_ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `~bit 63 (word m:int64)` ASSUME_TAC THENL + [REWRITE_TAC[BIT_WORD; DIMINDEX_64] THEN + SUBGOAL_THEN `m DIV 2 EXP 63 = 0` SUBST1_TAC THENL + [MATCH_MP_TAC DIV_LT THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + ASM_REWRITE_TAC[IVAL_VAL; DIMINDEX_64; ARITH_RULE `64 - 1 = 63`; + BITVAL_CLAUSES] THEN + INT_ARITH_TAC);; + +(* ========================================================================= *) +(* f_ev_loop_eta4 — the eta4 per-iteration PUBLIC events delta. *) +(* *) +(* A fully type-annotated concrete new_definition, the eta4 analogue of *) +(* f_ev_loop_eta2_def under the eta4 pc-offset map (offsets confirmed against *) +(* the proven eta4 MEMSAFE head/mid-guard proofs, *) +(* RIP=word(pc+{52,63,75,163,215,268,314})): *) +(* eta2 pc+399 -> eta4 pc+314 (crossover to scalar tail, JA-taken tgt) *) +(* eta2 pc+86 -> eta4 pc+52 (loop entry / back-edge) *) +(* eta2 pc+339 -> eta4 pc+268 (mid-guard-3: COND, not self-jump) *) +(* eta2 pc+273 -> eta4 pc+215 (sub-iter-3 self-jump) *) +(* eta2 pc+207 -> eta4 pc+163 (mid-guard-1, count-check COND) *) +(* eta2 pc+106 -> eta4 pc+75 (head-guard-2, buffer-position COND) *) +(* eta2 pc+97 -> eta4 pc+63 (head-guard-1, count-check COND) *) +(* WOP buffer bound 120 -> 256 (= buflen 272 - 16); count bound 248 *) +(* unchanged. *) +(* *) +(* The body is purely PUBLIC (PACK_MASK8 / NUM_ACCEPTED / SUB_LIST over the *) +(* mask, zero raw stepped terms), so the port is a numeral+name substitution *) +(* of the eta2 definition. *) +(* ========================================================================= *) +let f_ev_loop_eta4_def = new_definition `((((=):(uarch_event)list->(uarch_event)list->bool) ((((((((f_ev_loop_eta4):(64)word->(64)word->(64)word->num->(bool)list->num->(uarch_event)list) (res:(64)word)) (buf:(64)word)) (table:(64)word)) (pc:num)) (mask:(bool)list)) (i:num))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (314:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (52:num)))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventX86POPCNT):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) (((word_zx):(32)word->(64)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) (((PACK_MASK8):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (24:num))) (8:num))) (mask:(bool)list))))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventStore):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (res:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (4:num)) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (24:num)))) (mask:(bool)list))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (table:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (8:num)) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) (((PACK_MASK8):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (24:num))) (8:num))) (mask:(bool)list))))))))))) (8:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (268:num)))) (((((COND):bool->(64)word->(64)word->(64)word) (((~):bool->bool) ((((\/):bool->bool->bool) (((~):bool->bool) ((((=):int->int->bool) ((((int_sub):int->int->int) (((int_of_num):num->int) (((val):(32)word->num) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (16:num)))) (mask:(bool)list)))))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (16:num))) (8:num))) (mask:(bool)list)))))))))))) (((int_of_num):num->int) (248:num)))) (((int_of_num):num->int) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (16:num)))) (mask:(bool)list)))))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (16:num))) (8:num))) (mask:(bool)list)))))))))) (((word):num->(32)word) (248:num)))))))) ((((=):num->num->bool) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (16:num)))) (mask:(bool)list)))))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (16:num))) (8:num))) (mask:(bool)list)))))))))) (((word):num->(32)word) (248:num))))) (0:num))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (314:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (268:num))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventX86POPCNT):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) (((word_zx):(32)word->(64)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) (((PACK_MASK8):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (16:num))) (8:num))) (mask:(bool)list))))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventStore):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (res:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (4:num)) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (16:num)))) (mask:(bool)list))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (table:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (8:num)) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) (((PACK_MASK8):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (16:num))) (8:num))) (mask:(bool)list))))))))))) (8:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (215:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (215:num)))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventX86POPCNT):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) (((word_zx):(32)word->(64)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) (((PACK_MASK8):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (8:num))) (8:num))) (mask:(bool)list))))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventStore):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (res:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (4:num)) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (8:num)))) (mask:(bool)list))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (table:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (8:num)) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) (((PACK_MASK8):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((+):num->num->num) ((((*):num->num->num) (32:num)) (i:num))) (8:num))) (8:num))) (mask:(bool)list))))))))))) (8:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (163:num)))) (((((COND):bool->(64)word->(64)word->(64)word) (((~):bool->bool) ((((\/):bool->bool->bool) (((~):bool->bool) ((((=):int->int->bool) ((((int_sub):int->int->int) (((int_of_num):num->int) (((val):(32)word->num) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((*):num->num->num) (32:num)) (i:num)))) (mask:(bool)list)))))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((*):num->num->num) (32:num)) (i:num))) (8:num))) (mask:(bool)list)))))))))))) (((int_of_num):num->int) (248:num)))) (((int_of_num):num->int) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((*):num->num->num) (32:num)) (i:num)))) (mask:(bool)list)))))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((*):num->num->num) (32:num)) (i:num))) (8:num))) (mask:(bool)list)))))))))) (((word):num->(32)word) (248:num)))))))) ((((=):num->num->bool) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((*):num->num->num) (32:num)) (i:num)))) (mask:(bool)list)))))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((*):num->num->num) (32:num)) (i:num))) (8:num))) (mask:(bool)list)))))))))) (((word):num->(32)word) (248:num))))) (0:num))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (314:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (163:num))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventX86POPCNT):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) (((word_zx):(32)word->(64)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) (((PACK_MASK8):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((*):num->num->num) (32:num)) (i:num))) (8:num))) (mask:(bool)list))))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventStore):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (res:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (4:num)) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((*):num->num->num) (32:num)) (i:num)))) (mask:(bool)list))))))) (32:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (table:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (8:num)) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) (((PACK_MASK8):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) ((((*):num->num->num) (32:num)) (i:num))) (8:num))) (mask:(bool)list))))))))))) (8:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (buf:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (16:num)) (i:num))))) (16:num)))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (75:num)))) (((((COND):bool->(64)word->(64)word->(64)word) (((~):bool->bool) ((((\/):bool->bool->bool) (((~):bool->bool) ((((=):int->int->bool) ((((int_sub):int->int->int) (((int_of_num):num->int) (((val):(32)word->num) (((word_zx):(64)word->(32)word) (((word):num->(64)word) ((((*):num->num->num) (16:num)) (i:num))))))) (((int_of_num):num->int) (256:num)))) (((int_of_num):num->int) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) ((((*):num->num->num) (16:num)) (i:num))))) (((word):num->(32)word) (256:num)))))))) ((((=):num->num->bool) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) ((((*):num->num->num) (16:num)) (i:num))))) (((word):num->(32)word) (256:num))))) (0:num))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (314:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (75:num))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (63:num)))) (((((COND):bool->(64)word->(64)word->(64)word) (((~):bool->bool) ((((\/):bool->bool->bool) (((~):bool->bool) ((((=):int->int->bool) ((((int_sub):int->int->int) (((int_of_num):num->int) (((val):(32)word->num) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((*):num->num->num) (32:num)) (i:num)))) (mask:(bool)list)))))))) (((int_of_num):num->int) (248:num)))) (((int_of_num):num->int) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((*):num->num->num) (32:num)) (i:num)))) (mask:(bool)list)))))) (((word):num->(32)word) (248:num)))))))) ((((=):num->num->bool) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (((NUM_ACCEPTED):(bool)list->num) ((((SUB_LIST):num#num->(bool)list->(bool)list) ((((,):num->num->num#num) (0:num)) ((((*):num->num->num) (32:num)) (i:num)))) (mask:(bool)list)))))) (((word):num->(32)word) (248:num))))) (0:num))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (314:num)))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (63:num))))))) ((NIL):(uarch_event)list)))))))))))))))))))))`;; + + +(* ========================================================================= *) +(* eta4 value bridges (step 2 of SUBROUTINE_SAFE). *) +(* ========================================================================= *) + +(* ---- eta4 maskbit forall (accept < 9); group 0 offset = 8*k, *) +(* groups>0 = 8*(k+g). ---- *) +let eta4_mk_maskbit_forall g = + let b = 4*g in + let nib off hi = + let v = subst [mk_small_numeral off, `OFF:num`] `val(word_subword (chunk0:int128) (OFF,8):byte)` in + if hi then mk_binop `DIV` v `16` else mk_binop `MOD` v `16` in + let ellist = end_itlist (fun a b -> mk_binop `CONS:num->(num)list->(num)list` a b) + ([nib b false; nib b true; nib (b+8) false; nib (b+8) true; + nib (b+16) false; nib (b+16) true; nib (b+24) false; nib (b+24) true] @ [`[]:num list`]) in + let bitapp = + if g = 0 then `bit 7 (word_subword (f1bnd:int256) (8*k,8):byte)` + else subst [mk_small_numeral g, `G:num`] + `bit 7 (word_subword (f1bnd:int256) (8*(k+G),8):byte)` in + mk_forall(`k:num`, + mk_imp(`k < 8`, + mk_eq(bitapp, + mk_binop `(<):num->num->bool` (mk_comb(mk_comb(`EL:num->(num)list->num`,`k:num`), ellist)) `9`)));; + +(* ---- eta-neutral int16 nibble round-trip lemmas (reproved inline here) ---- *) +let VAL_WORD_NIB16 = prove + (`!x. x < 16 ==> val(word x:int16) = x`, + REPEAT STRIP_TAC THEN REWRITE_TAC[VAL_WORD; DIMINDEX_16] THEN + MATCH_MP_TAC MOD_LT THEN ASM_ARITH_TAC);; + +let VAL_WORD_NIB_LO = prove + (`!w:byte. val(word(val w MOD 16):int16) = val w MOD 16`, + GEN_TAC THEN MATCH_MP_TAC VAL_WORD_NIB16 THEN + MP_TAC(SPECL[`val(w:byte)`;`16`] MOD_LT_EQ) THEN ARITH_TAC);; +let VAL_WORD_NIB_HI = prove + (`!w:byte. val(word(val w DIV 16):int16) = val w DIV 16`, + GEN_TAC THEN MATCH_MP_TAC VAL_WORD_NIB16 THEN + MP_TAC(ISPEC `w:byte` VAL_BOUND) THEN REWRITE_TAC[DIMINDEX_8] THEN ARITH_TAC);; + +(* ---- group-link builder (port of eta2 mk_group_link/prove_group_link) ---- *) +let mk_group_link_eta4 gm = + let mb = eta4_mk_maskbit_forall gm in + let boff = gm / 2 in + let bytelist = + mk_list(map (fun j -> subst[mk_small_numeral(8*(boff+j)),`OFF:num`] + `word_subword (chunk0:int128) (OFF,8):byte`) (0--3), `:byte`) in + let sublhs = subst[mk_small_numeral boff, `BOFF:num`] + `SUB_LIST(16*i+BOFF,4) (inlist:byte list)` in + let link = mk_eq(sublhs, bytelist) in + let lhs_bits = + mk_list(map (fun k -> subst[mk_small_numeral(8*(k+gm)),`OFF:num`] + `bit 7 (word_subword (f1bnd:int256) (OFF,8):byte)`) (0--7), `:bool`) in + let rhs = subst[mk_small_numeral gm, `GM:num`] + `SUB_LIST(32*i+GM,8)(REJ_MASK_ETA4 (inlist:byte list))` in + mk_imp(mb, mk_imp(link, mk_eq(lhs_bits, rhs)));; + +let prove_group_link_eta4 gm = + let goal = mk_group_link_eta4 gm in + let boff = gm / 2 in + let arith_off = ARITH_RULE(mk_eq( + `2 * (16 * i + BOFF)`, `32 * i + GM`) + |> subst[mk_small_numeral boff,`BOFF:num`; mk_small_numeral gm,`GM:num`]) in + let rhs_reduced = subst[mk_small_numeral boff,`BOFF:num`] + `REJ_MASK_ETA4(SUB_LIST(16*i+BOFF,4) (inlist:byte list))` in + let goal_rhs = subst[mk_small_numeral gm,`GM:num`] + `SUB_LIST(32*i+GM,8)(REJ_MASK_ETA4 (inlist:byte list))` in + prove(goal, + DISCH_THEN(fun mb -> DISCH_THEN(fun link -> + SUBGOAL_THEN (mk_eq(goal_rhs, rhs_reduced)) SUBST1_TAC THENL + [ONCE_REWRITE_TAC[REJ_MASK_ETA4_SUB_LIST] THEN + REWRITE_TAC[arith_off] THEN CONV_TAC NUM_REDUCE_CONV; + ALL_TAC] THEN + REWRITE_TAC[link] THEN + REWRITE_TAC[REJ_MASK_ETA4; NIBBLES_OF_BYTES; NIBBLE_PAIR; APPEND; MAP] THEN + REWRITE_TAC[VAL_WORD_NIB_LO; VAL_WORD_NIB_HI] THEN + (let mbs = map (fun k -> let th = SPEC (mk_small_numeral k) mb in + CONV_RULE (NUM_REDUCE_CONV THENC ONCE_DEPTH_CONV EL_CONV) + (MP th (EQT_ELIM(NUM_REDUCE_CONV(lhand(concl th)))))) [0;1;2;3;4;5;6;7] in + REWRITE_TAC mbs) THEN + REFL_TAC)));; + +let ETA4_PACK_GROUP0 = prove_group_link_eta4 0;; +let ETA4_PACK_GROUP1 = prove_group_link_eta4 8;; +let ETA4_PACK_GROUP2 = prove_group_link_eta4 16;; +let ETA4_PACK_GROUP3 = prove_group_link_eta4 24;; + +(* ---- BYTE0_DIVMOD (eta-neutral, port of eta2) ---- *) +let BYTE0_DIVMOD = prove + (`!p:num->bool. + (bitval(p 0) + 2*bitval(p 1) + 4*bitval(p 2) + 8*bitval(p 3) + + 16*bitval(p 4) + 32*bitval(p 5) + 64*bitval(p 6) + 128*bitval(p 7) + + 256*bitval(p 8) + 512*bitval(p 9) + 1024*bitval(p 10) + 2048*bitval(p 11) + + 4096*bitval(p 12) + 8192*bitval(p 13) + 16384*bitval(p 14) + 32768*bitval(p 15) + + 65536*bitval(p 16) + 131072*bitval(p 17) + 262144*bitval(p 18) + 524288*bitval(p 19) + + 1048576*bitval(p 20) + 2097152*bitval(p 21) + 4194304*bitval(p 22) + 8388608*bitval(p 23) + + 16777216*bitval(p 24) + 33554432*bitval(p 25) + 67108864*bitval(p 26) + 134217728*bitval(p 27) + + 268435456*bitval(p 28) + 536870912*bitval(p 29) + 1073741824*bitval(p 30) + 2147483648*bitval(p 31)) MOD 256 = + bitval(p 0) + 2*bitval(p 1) + 4*bitval(p 2) + 8*bitval(p 3) + + 16*bitval(p 4) + 32*bitval(p 5) + 64*bitval(p 6) + 128*bitval(p 7)`, + GEN_TAC THEN + SUBGOAL_THEN + `(bitval(p 0) + 2*bitval(p 1) + 4*bitval(p 2) + 8*bitval(p 3) + + 16*bitval(p 4) + 32*bitval(p 5) + 64*bitval(p 6) + 128*bitval(p 7) + + 256*bitval(p 8) + 512*bitval(p 9) + 1024*bitval(p 10) + 2048*bitval(p 11) + + 4096*bitval(p 12) + 8192*bitval(p 13) + 16384*bitval(p 14) + 32768*bitval(p 15) + + 65536*bitval(p 16) + 131072*bitval(p 17) + 262144*bitval(p 18) + 524288*bitval(p 19) + + 1048576*bitval(p 20) + 2097152*bitval(p 21) + 4194304*bitval(p 22) + 8388608*bitval(p 23) + + 16777216*bitval(p 24) + 33554432*bitval(p 25) + 67108864*bitval(p 26) + 134217728*bitval(p 27) + + 268435456*bitval(p 28) + 536870912*bitval(p 29) + 1073741824*bitval(p 30) + 2147483648*bitval(p 31)) = + (bitval(p 0) + 2*bitval(p 1) + 4*bitval(p 2) + 8*bitval(p 3) + + 16*bitval(p 4) + 32*bitval(p 5) + 64*bitval(p 6) + 128*bitval(p 7)) + + 256 * (bitval(p 8) + 2*bitval(p 9) + 4*bitval(p 10) + 8*bitval(p 11) + + 16*bitval(p 12) + 32*bitval(p 13) + 64*bitval(p 14) + 128*bitval(p 15) + + 256*(bitval(p 16) + 2*bitval(p 17) + 4*bitval(p 18) + 8*bitval(p 19) + + 16*bitval(p 20) + 32*bitval(p 21) + 64*bitval(p 22) + 128*bitval(p 23) + + 256*(bitval(p 24) + 2*bitval(p 25) + 4*bitval(p 26) + 8*bitval(p 27) + + 16*bitval(p 28) + 32*bitval(p 29) + 64*bitval(p 30) + 128*bitval(p 31))))` + SUBST1_TAC THENL [ARITH_TAC; ALL_TAC] THEN + MATCH_MP_TAC ADD256_MOD THEN + MAP_EVERY (fun k -> MP_TAC(ISPEC (mk_comb(`p:num->bool`,mk_small_numeral k)) BITVAL_BOUND)) + [0;1;2;3;4;5;6;7] THEN ARITH_TAC);; + +let MS0 = prove + (`!S:num. val(word_zx(word S:int32):int64) MOD 256 = S MOD 256`, + GEN_TAC THEN + REWRITE_TAC[VAL_WORD_ZX_GEN; VAL_WORD; DIMINDEX_32; DIMINDEX_64] THEN + REWRITE_TAC[ARITH_RULE `256 = 2 EXP 8`; MOD_MOD_EXP_MIN] THEN + CONV_TAC NUM_REDUCE_CONV);; + +(* ---- STORE_BRIDGE_ETA4 (port of eta2 STORE_BRIDGE) ---- *) +let STORE_BRIDGE_ETA4 = prove + (`!inlist:byte list. !B. + LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,B) inlist):int32 list) = + NUM_ACCEPTED(SUB_LIST(0,2*B)(REJ_MASK_ETA4 inlist))`, + REPEAT GEN_TAC THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES; LENGTH_REJ_NIBBLES_ETA4_EQ_MASK; + NUM_ACCEPTED] THEN + REWRITE_TAC[REJ_MASK_ETA4_SUB_LIST; MULT_CLAUSES]);; + +(* ---- GATHER bridges (port of eta2 prove_gather + GATHER_BRIDGE1/2/3) ---- *) +let pinst = `\k. bit 7 (word_subword (f1bnd:int256) (8*k,8):byte)`;; +let byte1_inst = CONV_RULE(DEPTH_CONV BETA_CONV THENC ONCE_DEPTH_CONV NUM_REDUCE_CONV) + (SPEC pinst BYTE1_DIVMOD);; +let byte2_inst = CONV_RULE(DEPTH_CONV BETA_CONV THENC ONCE_DEPTH_CONV NUM_REDUCE_CONV) + (SPEC pinst BYTE2_DIVMOD);; +let byte3_inst = CONV_RULE(DEPTH_CONV BETA_CONV THENC ONCE_DEPTH_CONV NUM_REDUCE_CONV) + (SPEC pinst BYTE3_DIVMOD);; +let bigsum = lhand(lhand(lhand(concl byte1_inst)));; +let tower8 = subst[bigsum,`S:num`] + `word_zx(word_ushr(word_zx(word_zx(word (S:num):int32):int64):int32) 8):int64`;; +let tower16 = subst[bigsum,`S:num`] + `word_zx(word_ushr(word_zx(word_zx(word_ushr(word_zx(word_zx(word (S:num):int32):int64):int32) 8):int64):int32) 8):int64`;; +let tower24 = subst[bigsum,`S:num`] + `word_zx(word_ushr(word_zx(word_zx(word_ushr(word_zx(word_zx(word_ushr(word_zx(word_zx(word (S:num):int32):int64):int32) 8):int64):int32) 8):int64):int32) 8):int64`;; + +let link_of gm = + let boff = gm / 2 in + mk_eq(subst[mk_small_numeral boff,`BOFF:num`] `SUB_LIST(16*i+BOFF,4)(inlist:byte list)`, + mk_list(map (fun j -> subst[mk_small_numeral(8*(boff+j)),`OFF:num`] + `word_subword (chunk0:int128) (OFF,8):byte`) (0--3), `:byte`));; + +let prove_gather_eta4 gm maskv shiftlem byteinst packgrp tower = + let goal = + mk_imp(mk_eq(tower, maskv), + mk_imp(eta4_mk_maskbit_forall gm, + mk_imp(link_of gm, + mk_eq(mk_comb(mk_comb(`MOD`,mk_comb(`val:int64->num`,maskv)),`256`), + subst[mk_small_numeral gm,`GM:num`] + `PACK_MASK8(SUB_LIST(32*i+GM,8)(REJ_MASK_ETA4 (inlist:byte list)))`)))) in + prove(goal, + STRIP_TAC THEN STRIP_TAC THEN STRIP_TAC THEN + FIRST_X_ASSUM(SUBST1_TAC o SYM o + check (fun th -> try rand(concl th) = maskv with _ -> false)) THEN + REWRITE_TAC[shiftlem] THEN + MP_TAC byteinst THEN DISCH_THEN SUBST1_TAC THEN + W(fun (asl,w) -> + let mb = find (fun th -> is_forall(concl th)) (map snd asl) in + let link = find (fun th -> is_eq(concl th) && + (try fst(dest_const(fst(strip_comb(lhand(concl th))))) = "SUB_LIST" + with _ -> false)) (map snd asl) in + let pg = MP (MP (SPEC_ALL packgrp) mb) link in + GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [SYM pg]) THEN + REWRITE_TAC[PACK_MASK8] THEN CONV_TAC(ONCE_DEPTH_CONV EL_CONV) THEN ARITH_TAC);; + +let GATHER_BRIDGE1_ETA4 = prove_gather_eta4 8 `mask8b:int64` MASK_SHIFT8_MOD256 byte1_inst ETA4_PACK_GROUP1 tower8;; +let GATHER_BRIDGE2_ETA4 = prove_gather_eta4 16 `mask8c:int64` MASK_SHIFT16_MOD256 byte2_inst ETA4_PACK_GROUP2 tower16;; +let GATHER_BRIDGE3_ETA4 = prove_gather_eta4 24 `mask8d:int64` MASK_SHIFT24_MOD256 byte3_inst ETA4_PACK_GROUP3 tower24;; + +(* ---- P0_BRIDGE_ETA4 (group-0 gather; programmatic statement). *) +(* p0_bigsum = the SAME 32-term pinst sum extracted from byte1_inst, so it is *) +(* guaranteed syntactically identical to the raw stepper's group-0 BIGSUM *) +(* (both instantiate pinst = \k. bit 7 (word_subword f1bnd (8*k,8))). ---- *) +let p0_bigsum = bigsum;; + +(* group-0 link in REDUCED form (16*i, not 16*i+0) to match SUBITER_BLOCK_BYTES *) +(* conjunct 0 in EB_TAC's asl (raw dump: `SUB_LIST (16*i,4) inlist = ...`) and *) +(* pg0 = REWRITE_RULE[16*i+0=16*i]. link_of 0 would give 16*i+0 -> MP mismatch. *) +let link0_reduced_eta4 = + mk_eq(`SUB_LIST(16*i,4)(inlist:byte list)`, + mk_list([`word_subword (chunk0:int128) (0,8):byte`; + `word_subword (chunk0:int128) (8,8):byte`; + `word_subword (chunk0:int128) (16,8):byte`; + `word_subword (chunk0:int128) (24,8):byte`], `:byte`));; + +let P0_BRIDGE_ETA4 = prove + (mk_imp(eta4_mk_maskbit_forall 0, + mk_imp(link0_reduced_eta4, + mk_eq(mk_comb(mk_comb(`MOD`, + mk_comb(`val:int64->num`, + subst[p0_bigsum,`S:num`] `word_zx(word (S:num):int32):int64`)), `256`), + `PACK_MASK8(SUB_LIST(32*i,8)(REJ_MASK_ETA4 (inlist:byte list)))`))), + STRIP_TAC THEN STRIP_TAC THEN + REWRITE_TAC[MS0] THEN + MP_TAC(SPEC pinst BYTE0_DIVMOD) THEN + CONV_TAC(DEPTH_CONV BETA_CONV THENC ONCE_DEPTH_CONV NUM_REDUCE_CONV) THEN + DISCH_THEN SUBST1_TAC THEN + W(fun (asl,w) -> + let mb = find (fun th -> is_forall(concl th)) (map snd asl) in + let link = find (fun th -> is_eq(concl th) && + (try fst(dest_const(fst(strip_comb(lhand(concl th))))) = "SUB_LIST" with _ -> false)) (map snd asl) in + let pg0 = REWRITE_RULE[ARITH_RULE `16*i+0 = 16*i`; ARITH_RULE `32*i+0 = 32*i`] (SPEC_ALL ETA4_PACK_GROUP0) in + let pg = MP (MP pg0 mb) link in + GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [SYM pg]) THEN + REWRITE_TAC[PACK_MASK8] THEN CONV_TAC(ONCE_DEPTH_CONV EL_CONV) THEN ARITH_TAC);; + + +(* ------------------------------------------------------------------------- *) +(* eta4 SAFE-cluster prerequisites: ETA4_EVENTS_BRIDGE + containment prereqs *) +(* + MEMACCESS_F_EV_LOOP_ETA4. *) +(* ------------------------------------------------------------------------- *) + +(* ========================================================================= *) +(* ETA4_EVENTS_BRIDGE. *) +(* Proves [raw eta4 loop 19-event trace] = f_ev_loop_eta4 res buf table pc *) +(* (REJ_MASK_ETA4 inlist) i (the folded PUBLIC per-iteration event delta), *) +(* the eta4 analogue of ETA2_EVENTS_BRIDGE. The EB_TAC tactic is inlined into *) +(* the prove call. Requires only: f_ev_loop_eta4_def, SUBITER_BLOCK_BYTES, *) +(* P0_BRIDGE_ETA4, GATHER_BRIDGE1/2/3_ETA4, STORE_BRIDGE_ETA4, *) +(* LENGTH_REJ_NIBBLES_ETA4_EQ_MASK, NUM_ACCEPTED, REJ_MASK_ETA4_SUB_LIST. *) +(* ========================================================================= *) +let ETA4_EVENTS_BRIDGE = prove( +`((((==>):bool->bool->bool) ((((/\):bool->bool->bool) (((!):(num->bool)->bool) (\(k:num). ((((==>):bool->bool->bool) ((((<):num->num->bool) (k:num)) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) ((((=):bool->bool->bool) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) (k:num))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) ((((<):num->num->bool) ((((EL):num->(num)list->num) (k:num)) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) ((_0):num))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) ((_0):num))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((NIL):(num)list))))))))))) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((/\):bool->bool->bool) (((!):(num->bool)->bool) (\(k:num). ((((==>):bool->bool->bool) ((((<):num->num->bool) (k:num)) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) ((((=):bool->bool->bool) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) ((((+):num->num->num) (k:num)) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) ((((<):num->num->bool) ((((EL):num->(num)list->num) (k:num)) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((NIL):(num)list))))))))))) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((/\):bool->bool->bool) (((!):(num->bool)->bool) (\(k:num). ((((==>):bool->bool->bool) ((((<):num->num->bool) (k:num)) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) ((((=):bool->bool->bool) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) ((((+):num->num->num) (k:num)) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) ((((<):num->num->bool) ((((EL):num->(num)list->num) (k:num)) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((NIL):(num)list))))))))))) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((/\):bool->bool->bool) (((!):(num->bool)->bool) (\(k:num). ((((==>):bool->bool->bool) ((((<):num->num->bool) (k:num)) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) ((((=):bool->bool->bool) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) ((((+):num->num->num) (k:num)) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) ((((<):num->num->bool) ((((EL):num->(num)list->num) (k:num)) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((MOD):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):num->(num)list->(num)list) ((((DIV):num->num->num) (((val):(8)word->num) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((NIL):(num)list))))))))))) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((/\):bool->bool->bool) ((((<=):num->num->bool) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (i:num))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))) ((((/\):bool->bool->bool) ((((=):((8)word)list->((8)word)list->bool) ((((SUB_LIST):num#num->((8)word)list->((8)word)list) ((((,):num->num->num#num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (i:num))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (inlist:((8)word)list))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) ((_0):num))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((NIL):((8)word)list))))))))))))))))))) ((((/\):bool->bool->bool) ((((=):num->num->bool) (((LENGTH):((8)word)list->num) (inlist:((8)word)list))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))) ((((/\):bool->bool->bool) ((((=):num->num->bool) (((LENGTH):((32)word)list->num) (((REJ_SAMPLE_ETA4_BYTES):((8)word)list->((32)word)list) ((((SUB_LIST):num#num->((8)word)list->((8)word)list) ((((,):num->num->num#num) (((NUMERAL):num->num) ((_0):num))) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (i:num)))) (inlist:((8)word)list))))) (outlen0:num))) ((((/\):bool->bool->bool) ((((=):num->num->bool) (((LENGTH):((32)word)list->num) (((REJ_SAMPLE_ETA4_BYTES):((8)word)list->((32)word)list) ((((SUB_LIST):num#num->((8)word)list->((8)word)list) ((((,):num->num->num#num) (((NUMERAL):num->num) ((_0):num))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (i:num))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (inlist:((8)word)list))))) (acc2:num))) ((((/\):bool->bool->bool) ((((=):num->num->bool) (((LENGTH):((32)word)list->num) (((REJ_SAMPLE_ETA4_BYTES):((8)word)list->((32)word)list) ((((SUB_LIST):num#num->((8)word)list->((8)word)list) ((((,):num->num->num#num) (((NUMERAL):num->num) ((_0):num))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (i:num))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (inlist:((8)word)list))))) (acc1:num))) ((((/\):bool->bool->bool) ((((=):num->num->bool) (((LENGTH):((32)word)list->num) (((REJ_SAMPLE_ETA4_BYTES):((8)word)list->((32)word)list) ((((SUB_LIST):num#num->((8)word)list->((8)word)list) ((((,):num->num->num#num) (((NUMERAL):num->num) ((_0):num))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (i:num))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))) (inlist:((8)word)list))))) (acc3:num))) ((((/\):bool->bool->bool) ((((=):(64)word->(64)word->bool) (((word_zx):(32)word->(64)word) ((((word_ushr):(32)word->num->(32)word) (((word_zx):(64)word->(32)word) (mask8b:(64)word))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (mask8c:(64)word))) ((((/\):bool->bool->bool) ((((=):(64)word->(64)word->bool) (((word_zx):(32)word->(64)word) ((((word_ushr):(32)word->num->(32)word) (((word_zx):(64)word->(32)word) (mask8c:(64)word))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (mask8d:(64)word))) ((((=):(64)word->(64)word->bool) (((word_zx):(32)word->(64)word) ((((word_ushr):(32)word->num->(32)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) ((((+):num->num->num) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) ((_0):num))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))))))))))))))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (mask8b:(64)word)))))))))))))))) ((((=):(uarch_event)list->(uarch_event)list->bool) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventX86POPCNT):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) (((word_zx):(32)word->(64)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) ((((MOD):num->num->num) (((val):(64)word->num) (mask8d:(64)word))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventStore):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (res:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))) (acc3:num))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (table:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) ((((MOD):num->num->num) (((val):(64)word->num) (mask8d:(64)word))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))) (((((COND):bool->(64)word->(64)word->(64)word) (((~):bool->bool) ((((\/):bool->bool->bool) (((~):bool->bool) ((((=):int->int->bool) ((((int_sub):int->int->int) (((int_of_num):num->int) (((val):(32)word->num) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (acc2:num)))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((LENGTH):((16)word)list->num) (((REJ_NIBBLES_ETA4):((8)word)list->((16)word)list) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((NIL):((8)word)list)))))))))))))))) (((int_of_num):num->int) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))))) (((int_of_num):num->int) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (acc2:num)))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((LENGTH):((16)word)list->num) (((REJ_NIBBLES_ETA4):((8)word)list->((16)word)list) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((NIL):((8)word)list)))))))))))))) (((word):num->(32)word) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))) ((((=):num->num->bool) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (acc2:num)))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((LENGTH):((16)word)list->num) (((REJ_NIBBLES_ETA4):((8)word)list->((16)word)list) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((NIL):((8)word)list)))))))))))))) (((word):num->(32)word) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))))))) (((NUMERAL):num->num) ((_0):num)))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventX86POPCNT):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) (((word_zx):(32)word->(64)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) ((((MOD):num->num->num) (((val):(64)word->num) (mask8c:(64)word))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventStore):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (res:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))) (acc2:num))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (table:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) ((((MOD):num->num->num) (((val):(64)word->num) (mask8c:(64)word))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventX86POPCNT):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) (((word_zx):(32)word->(64)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) ((((MOD):num->num->num) (((val):(64)word->num) (mask8b:(64)word))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventStore):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (res:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))) (acc1:num))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (table:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) ((((MOD):num->num->num) (((val):(64)word->num) (mask8b:(64)word))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))) (((((COND):bool->(64)word->(64)word->(64)word) (((~):bool->bool) ((((\/):bool->bool->bool) (((~):bool->bool) ((((=):int->int->bool) ((((int_sub):int->int->int) (((int_of_num):num->int) (((val):(32)word->num) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (outlen0:num)))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((LENGTH):((16)word)list->num) (((REJ_NIBBLES_ETA4):((8)word)list->((16)word)list) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) ((_0):num))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((NIL):((8)word)list)))))))))))))))) (((int_of_num):num->int) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))))) (((int_of_num):num->int) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (outlen0:num)))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((LENGTH):((16)word)list->num) (((REJ_NIBBLES_ETA4):((8)word)list->((16)word)list) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) ((_0):num))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((NIL):((8)word)list)))))))))))))) (((word):num->(32)word) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))) ((((=):num->num->bool) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) ((((word_add):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (outlen0:num)))) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word):num->(32)word) (((LENGTH):((16)word)list->num) (((REJ_NIBBLES_ETA4):((8)word)list->((16)word)list) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) ((_0):num))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):(8)word->((8)word)list->((8)word)list) ((((word_subword):(128)word->num#num->(8)word) (chunk0:(128)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((NIL):((8)word)list)))))))))))))) (((word):num->(32)word) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))))))) (((NUMERAL):num->num) ((_0):num)))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventX86POPCNT):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) (((word_zx):(32)word->(64)word) (((word_zx):(64)word->(32)word) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) ((((MOD):num->num->num) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word):num->(32)word) ((((+):num->num->num) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) ((_0):num))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))))))))))))))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventStore):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (res:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))) (outlen0:num))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (table:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word_zx):(8)word->(32)word) (((word):num->(8)word) ((((MOD):num->num->num) (((val):(64)word->num) (((word_zx):(32)word->(64)word) (((word):num->(32)word) ((((+):num->num->num) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) ((_0):num))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((+):num->num->num) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))))))))))))))))))))) (((bitval):bool->num) ((((bit):num->(8)word->bool) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))) ((((word_subword):(256)word->num#num->(8)word) (f1bnd:(256)word)) ((((,):num->num->num#num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))))))))))))))))))))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventLoad):(64)word#num->uarch_event) ((((,):(64)word->num->(64)word#num) ((((word_add):(64)word->(64)word->(64)word) (buf:(64)word)) (((word):num->(64)word) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (i:num))))) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))) (((((COND):bool->(64)word->(64)word->(64)word) (((~):bool->bool) ((((\/):bool->bool->bool) (((~):bool->bool) ((((=):int->int->bool) ((((int_sub):int->int->int) (((int_of_num):num->int) (((val):(32)word->num) (((word_zx):(64)word->(32)word) (((word):num->(64)word) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (i:num))))))) (((int_of_num):num->int) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))) (((int_of_num):num->int) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (i:num))))) (((word):num->(32)word) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))))))) ((((=):num->num->bool) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) ((((*):num->num->num) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))) (i:num))))) (((word):num->(32)word) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))) (((NUMERAL):num->num) ((_0):num)))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num))))))))))))))) ((((CONS):uarch_event->(uarch_event)list->(uarch_event)list) (((EventJump):(64)word#(64)word->uarch_event) ((((,):(64)word->(64)word->(64)word#(64)word) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))) (((((COND):bool->(64)word->(64)word->(64)word) (((~):bool->bool) ((((\/):bool->bool->bool) (((~):bool->bool) ((((=):int->int->bool) ((((int_sub):int->int->int) (((int_of_num):num->int) (((val):(32)word->num) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (outlen0:num)))))) (((int_of_num):num->int) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))))) (((int_of_num):num->int) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (outlen0:num)))) (((word):num->(32)word) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num))))))))))))))))) ((((=):num->num->bool) (((val):(32)word->num) ((((word_sub):(32)word->(32)word->(32)word) (((word_zx):(64)word->(32)word) (((word):num->(64)word) (outlen0:num)))) (((word):num->(32)word) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))))))) (((NUMERAL):num->num) ((_0):num)))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (((NUMERAL):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT0):num->num) (((BIT0):num->num) (((BIT1):num->num) ((_0):num)))))))))))))) (((word):num->(64)word) ((((+):num->num->num) (pc:num)) (((NUMERAL):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) (((BIT1):num->num) ((_0):num)))))))))))))) ((NIL):(uarch_event)list))))))))))))))))))))) ((((((((f_ev_loop_eta4):(64)word->(64)word->(64)word->num->(bool)list->num->(uarch_event)list) (res:(64)word)) (buf:(64)word)) (table:(64)word)) (pc:num)) (((REJ_MASK_ETA4):((8)word)list->(bool)list) (inlist:((8)word)list))) (i:num))))`, + STRIP_TAC THEN REWRITE_TAC[f_ev_loop_eta4_def] THEN + W(fun (asl,w) -> + let assoc_asl = map snd asl in + let fnd p = find (fun th -> p (concl th)) assoc_asl in + let tower8_mask8b = fnd (fun c -> is_eq c && rand c=`mask8b:int64` && can(find_term(fun u->match u with Const("word_ushr",_)->true|_->false)) c) in + let mask8c_def = fnd (fun c -> is_eq c && rand c=`mask8c:int64`) in + let mask8d_def = fnd (fun c -> is_eq c && rand c=`mask8d:int64` && can(find_term(fun u->match u with Const("word_ushr",_)->true|_->false)) c) in + let mb g = + if g = 0 then + fnd (fun c -> is_forall c && can(find_term(fun u->u=`f1bnd:int256`)) c && + can(find_term(fun u->u=`8*k`)) c) + else + fnd (fun c -> is_forall c && can(find_term(fun u->u=`f1bnd:int256`)) c && + can(find_term(fun u->u = mk_binop `( * ):num->num->num` `8` (mk_binop `(+):num->num->num` `k:num` (mk_small_numeral g)))) c) in + let ol_def = fnd (fun c -> is_eq c && rand c=`outlen0:num` && can(find_term(fun u->match u with Const("REJ_SAMPLE_ETA4_BYTES",_)->true|_->false)) c) in + let a1_def = fnd (fun c -> is_eq c && rand c=`acc1:num` && can(find_term(fun u->match u with Const("REJ_SAMPLE_ETA4_BYTES",_)->true|_->false)) c) in + let a2_def = fnd (fun c -> is_eq c && rand c=`acc2:num` && can(find_term(fun u->match u with Const("REJ_SAMPLE_ETA4_BYTES",_)->true|_->false)) c) in + let a3_def = fnd (fun c -> is_eq c && rand c=`acc3:num` && can(find_term(fun u->match u with Const("REJ_SAMPLE_ETA4_BYTES",_)->true|_->false)) c) in + let i_le = fnd (fun c -> c = `16 * i <= 256`) in + let leninl = fnd (fun c -> c = `LENGTH(inlist:byte list) = 272`) in + let blk16 = fnd (fun c -> is_eq c && (try fst(dest_const(fst(strip_comb(lhand c))))="SUB_LIST" && length(dest_list(rand c))=16 with _->false)) in + let bb = MP (ISPECL [`inlist:byte list`;`i:num`;`chunk0:int128`] SUBITER_BLOCK_BYTES) + (CONJ (REWRITE_RULE[GSYM leninl] (MP (ARITH_RULE `16*i<=256 ==> 16*i+16<=272`) i_le)) blk16) in + let links = CONJUNCTS bb in + let t16m8c = REWRITE_RULE[SYM tower8_mask8b] mask8c_def in + let t24m8d = REWRITE_RULE[SYM t16m8c] mask8d_def in + let f0 = MP (MP P0_BRIDGE_ETA4 (mb 0)) (el 0 links) in + let f1 = MP (MP (MP GATHER_BRIDGE1_ETA4 tower8_mask8b) (mb 8)) (el 1 links) in + let f2 = MP (MP (MP GATHER_BRIDGE2_ETA4 t16m8c) (mb 16)) (el 2 links) in + let f3 = MP (MP (MP GATHER_BRIDGE3_ETA4 t24m8d) (mb 24)) (el 3 links) in + let so = TRANS (SYM ol_def) (REWRITE_RULE[ARITH_RULE `2*(16*i)=32*i`] (SPECL[`inlist:byte list`;`16*i`] STORE_BRIDGE_ETA4)) in + let s1 = TRANS (SYM a1_def) (REWRITE_RULE[ARITH_RULE `2*(16*i+4)=32*i+8`] (SPECL[`inlist:byte list`;`16*i+4`] STORE_BRIDGE_ETA4)) in + let s2 = TRANS (SYM a2_def) (REWRITE_RULE[ARITH_RULE `2*(16*i+8)=32*i+16`] (SPECL[`inlist:byte list`;`16*i+8`] STORE_BRIDGE_ETA4)) in + let s3 = TRANS (SYM a3_def) (REWRITE_RULE[ARITH_RULE `2*(16*i+12)=32*i+24`] (SPECL[`inlist:byte list`;`16*i+12`] STORE_BRIDGE_ETA4)) in + let niblen0_gen = prove + (`LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(16*i,4) inlist):int16 list) = + NUM_ACCEPTED(SUB_LIST(32*i,8)(REJ_MASK_ETA4 (inlist:byte list)))`, + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA4_EQ_MASK; GSYM NUM_ACCEPTED] THEN + REWRITE_TAC[REJ_MASK_ETA4_SUB_LIST] THEN + REWRITE_TAC[ARITH_RULE `2*(16*i)=32*i`; ARITH_RULE `2*4=8`]) in + let niblen0 = REWRITE_RULE[el 0 links] niblen0_gen in + (* niblen2 (group-2): REQUIRED because eta4's mg3 @pc+268 is a COND (over *) + (* acc2 + group-2 niblen), unlike eta2's self-jump. Only meaningful once *) + (* f_ev_loop_eta4_def has mg3 as a COND (not a self-jump). *) + let niblen2_gen = prove + (`LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(16*i+8,4) inlist):int16 list) = + NUM_ACCEPTED(SUB_LIST(32*i+16,8)(REJ_MASK_ETA4 (inlist:byte list)))`, + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA4_EQ_MASK; GSYM NUM_ACCEPTED] THEN + REWRITE_TAC[REJ_MASK_ETA4_SUB_LIST] THEN + REWRITE_TAC[ARITH_RULE `2*(16*i+8)=32*i+16`; ARITH_RULE `2*4=8`]) in + let niblen2 = REWRITE_RULE[el 2 links] niblen2_gen in + let facts = [f0;f1;f2;f3;so;s1;s2;s3;niblen0;niblen2] in + CONV_TAC(LAND_CONV(GEN_REWRITE_CONV TOP_DEPTH_CONV facts THENC REWRITE_CONV[]))) THEN + REFL_TAC);; + +(* ------------------------------------------------------------------------- *) +(* eta4 SAFE-cluster containment prerequisites + MEMACCESS_F_EV_LOOP_ETA4. *) +(* Ports of the eta2 containment lemmas. eta-neutral: NUM_ACCEPTED_PREFIX_MONO,*) +(* STORE_CONTAINED, PACK_MASK8_MOD256. eta4 constant change (buf window *) +(* 136 -> 272): BUF_CONTAINED_ETA4. *) +(* ------------------------------------------------------------------------- *) + +let NUM_ACCEPTED_PREFIX_MONO = prove + (`!mask:bool list a b. a <= b + ==> NUM_ACCEPTED(SUB_LIST(0,a) mask) <= NUM_ACCEPTED(SUB_LIST(0,b) mask)`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN `SUB_LIST(0,b) (mask:bool list) = + APPEND (SUB_LIST(0,a) mask) (SUB_LIST(a,b-a) mask)` SUBST1_TAC THENL + [MP_TAC(ISPECL [`mask:bool list`; `a:num`; `b - a`; `0`] SUB_LIST_SPLIT) THEN + ASM_SIMP_TAC[ARITH_RULE `a <= b ==> a + (b - a) = b`; ADD_CLAUSES]; + REWRITE_TAC[NUM_ACCEPTED_APPEND] THEN ARITH_TAC]);; + +let STORE_CONTAINED = prove + (`!(res:int64) cnt. cnt <= 248 + ==> contained_modulo (2 EXP 64) + (val(word_add res (word(4 * cnt))),32) (val res,1024)`, + REPEAT STRIP_TAC THEN + GEN_REWRITE_TAC I [GSYM CONTAINED_MODULO_MOD2] THEN + REWRITE_TAC[VAL_WORD_ADD; VAL_WORD; DIMINDEX_64] THEN + CONV_TAC(ONCE_DEPTH_CONV MOD_DOWN_CONV) THEN + REWRITE_TAC[CONTAINED_MODULO_MOD2] THEN + MATCH_MP_TAC CONTAINED_MODULO_OFFSET_SIMPLE THEN ASM_ARITH_TAC);; + +(* eta4: buf window is 272 (buflen 272), so the head-guard bound is 16*j+16<=272. *) +let BUF_CONTAINED_ETA4 = prove + (`!(buf:int64) j. 16 * j + 16 <= 272 + ==> contained_modulo (2 EXP 64) + (val(word_add buf (word(16 * j))),16) (val buf,272)`, + REPEAT STRIP_TAC THEN + GEN_REWRITE_TAC I [GSYM CONTAINED_MODULO_MOD2] THEN + REWRITE_TAC[VAL_WORD_ADD; VAL_WORD; DIMINDEX_64] THEN + CONV_TAC(ONCE_DEPTH_CONV MOD_DOWN_CONV) THEN + REWRITE_TAC[CONTAINED_MODULO_MOD2] THEN + MATCH_MP_TAC CONTAINED_MODULO_OFFSET_SIMPLE THEN ASM_ARITH_TAC);; + +let PACK_MASK8_MOD256 = prove + (`!bs:bool list. PACK_MASK8 bs = PACK_MASK8 bs MOD 256`, + GEN_TAC THEN MATCH_MP_TAC(GSYM MOD_LT) THEN REWRITE_TAC[PACK_MASK8_BOUND]);; + +(* MEMACCESS_F_EV_LOOP_ETA4: memaccess of one folded loop iteration. Port of *) +(* eta2 MEMACCESS_F_EV_LOOP_ETA2: buf window 136 -> 272, *) +(* f_ev_loop_eta2_def -> f_ev_loop_eta4_def, BUF_CONTAINED -> BUF_CONTAINED_ETA4.*) +let MEMACCESS_F_EV_LOOP_ETA4 = prove + (`!res buf table pc mask j. + 16 * j + 16 <= 272 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * j + 24) mask) <= 248 + ==> memaccess_inbounds (f_ev_loop_eta4 res buf table pc mask j) + [(buf:int64),272; (table:int64),2048] [(res:int64),1024]`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN + `NUM_ACCEPTED (SUB_LIST (0,32 * j) mask) <= 248 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * j + 8) mask) <= 248 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * j + 16) mask) <= 248` + STRIP_ASSUME_TAC THENL + [REPEAT CONJ_TAC THEN + TRANS_TAC LE_TRANS `NUM_ACCEPTED (SUB_LIST (0,32 * j + 24) mask)` THEN + ASM_REWRITE_TAC[] THEN MATCH_MP_TAC NUM_ACCEPTED_PREFIX_MONO THEN ARITH_TAC; + ALL_TAC] THEN + REWRITE_TAC[f_ev_loop_eta4_def; memaccess_inbounds; ALL; EX; FST; SND] THEN + ONCE_REWRITE_TAC[PACK_MASK8_MOD256] THEN + REPEAT CONJ_TAC THEN + FIRST + [MATCH_MP_TAC STORE_CONTAINED THEN FIRST_ASSUM ACCEPT_TAC; + DISJ1_TAC THEN MATCH_MP_TAC BUF_CONTAINED_ETA4 THEN FIRST_ASSUM ACCEPT_TAC; + DISJ2_TAC THEN MATCH_MP_TAC GATHER_CONTAINED THEN + MATCH_ACCEPT_TAC TABLE_IDX_LT_256]);; + +(* ------------------------------------------------------------------------- *) +(* eta-neutral SAFE loop-side lemmas. SAFE_THREAD_EVENTS_STEP and *) +(* MEMACCESS_ENUM_ACC are generic over d:num->(uarch_event)list (eta2 ports); *) +(* MEMACCESS_ENUM_LOOP_ETA4 is the eta4 loop-side memaccess recovery. *) +(* Dependency order STES -> ACC -> ENUM_LOOP (ENUM_LOOP uses ACC). *) +(* ------------------------------------------------------------------------- *) + +let SAFE_THREAD_EVENTS_STEP = prove + (`!(d:num->(uarch_event)list) i e. + APPEND (d i) (APPEND (ENUMERATEL i d) e) = APPEND (ENUMERATEL (i+1) d) e`, + REWRITE_TAC[ENUMERATEL_ADD1; APPEND_ASSOC]);; + +let MEMACCESS_ENUM_ACC = prove + (`!(d:num->(uarch_event)list) rr wr J. + (!j. j < J ==> memaccess_inbounds (d j) rr wr) + ==> memaccess_inbounds (ENUMERATEL J d) rr wr`, + REPLICATE_TAC 3 GEN_TAC THEN INDUCT_TAC THENL + [REWRITE_TAC[ENUMERATEL; memaccess_inbounds; ALL]; + REWRITE_TAC[ADD1] THEN ONCE_REWRITE_TAC[ENUMERATEL_ADD1] THEN + REWRITE_TAC[MEMACCESS_INBOUNDS_APPEND] THEN STRIP_TAC THEN CONJ_TAC THENL + [FIRST_X_ASSUM MATCH_MP_TAC THEN ARITH_TAC; + FIRST_X_ASSUM MATCH_MP_TAC THEN GEN_TAC THEN DISCH_TAC THEN + FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC]]);; + +let MEMACCESS_ENUM_LOOP_ETA4 = prove + (`!res buf table inlist pc N. + ~(N = 0) /\ 16 * (N - 1) <= 256 /\ + (!m. m < N ==> 16 * m <= 256 /\ + LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(0,16*m) inlist):int16 list) <= 248) + ==> memaccess_inbounds + (ENUMERATEL (N-1) (f_ev_loop_eta4 res buf table pc (REJ_MASK_ETA4 inlist))) + [buf,272; table,2048] [res,1024]`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + MATCH_MP_TAC MEMACCESS_ENUM_ACC THEN + X_GEN_TAC `j:num` THEN DISCH_TAC THEN + MATCH_MP_TAC MEMACCESS_F_EV_LOOP_ETA4 THEN + CONJ_TAC THENL + [MAP_EVERY UNDISCH_TAC [`j < N - 1`; `16 * (N - 1) <= 256`] THEN ARITH_TAC; + MATCH_MP_TAC LE_TRANS THEN + EXISTS_TAC `NUM_ACCEPTED(SUB_LIST(0,32*(j+1))(REJ_MASK_ETA4 inlist))` THEN + CONJ_TAC THENL + [MATCH_MP_TAC NUM_ACCEPTED_PREFIX_MONO THEN ARITH_TAC; + MP_TAC(SPECL[`inlist:byte list`;`16*(j+1)`] STORE_BRIDGE_ETA4) THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * (j + 1)) = 32 * (j + 1)`] THEN + DISCH_THEN(fun th -> REWRITE_TAC[GSYM th]) THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES] THEN + FIRST_X_ASSUM(MP_TAC o SPEC `j + 1` o check(is_forall o concl)) THEN + ANTS_TAC THENL + [UNDISCH_TAC `j < N - 1` THEN UNDISCH_TAC `~(N = 0)` THEN ARITH_TAC; + REWRITE_TAC[] THEN STRIP_TAC THEN FIRST_ASSUM ACCEPT_TAC]]]);; + +(* ------------------------------------------------------------------------- *) +(* eta4 SAFE exit-block step (a) — head-guard segment. *) +(* pc+52 @ pos 16N=272 -> pc+314 (scalar tail), concrete PUBLIC events. *) +(* Port of eta2 LEG1B_HEADGUARD_SAFE_ETA2. The 4-instruction head-guard emits *) +(* exactly two public EventJumps — count-guard (pc+63) not-taken, buffer-guard*) +(* (pc+75) taken -> pc+314. *) +(* ------------------------------------------------------------------------- *) + +let f_ev_headguard_eta4 = define + `f_ev_headguard_eta4 (pc:num) = + [EventJump (word (pc + 75),word (pc + 314)); + EventJump (word (pc + 63),word (pc + 63))]`;; + +let LEG1B_HEADGUARD_SAFE_ETA4 = prove( + (* statement: OFFSET-arm head-guard, q56/q318 with 16N->272 + concrete events, + antecedent+frame lifted directly from EXIT_OFFSET_MS. *) + (let sv56,body56 = dest_abs q56_ms in + let sv318,body318 = dest_abs q318_ms in + let exoff = snd(strip_forall(concl EXIT_OFFSET_MS)) in + let ens = snd(dest_imp exoff) in + let frame = rand ens in + let ens_hd = rator(rator(rator ens)) in + let q52_safe = mk_abs(sv56, + mk_conj(subst[`272`,`16 * N`] (lhand body56), + `read events (s:x86state) = ec`)) in + let q314_safe = mk_abs(sv318, + mk_conj(subst[`272`,`16 * N`] (lhand body318), + `read events (s:x86state) = APPEND (f_ev_headguard_eta4 pc) ec`)) in + list_mk_forall + ([`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`; + `N:num`;`stackpointer:int64`;`e:(uarch_event)list`;`ec:(uarch_event)list`], + mk_imp(lhand exoff, + mk_comb(mk_comb(mk_comb(ens_hd, q52_safe), q314_safe), frame)))), + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,272) inlist):int32 list) <= 248` ASSUME_TAC THENL + [REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES] THEN + SUBST1_TAC(SYM(ASSUME `16 * N = 272`)) THEN FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN + ENSURES_INIT_TAC "s0" THEN + SUBGOAL_THEN + `~(&(val(word_zx(word(LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,272) inlist):int32 list)):int64):int32)):int - &248 = &(val(word_sub(word_zx(word(LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,272) inlist):int32 list)):int64):int32) (word 248):int32))) \/ val(word_sub(word_zx(word(LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,272) inlist):int32 list)):int64):int32) (word 248):int32) = 0` + ASSUME_TAC THENL + [MATCH_MP_TAC JA_NOT_TAKEN_LE THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN + `~(~(&(val(word_zx(word(272):int64):int32)):int - &256 = &(val(word_sub(word_zx(word(272):int64):int32) (word 256):int32))) \/ val(word_sub(word_zx(word(272):int64):int32) (word 256):int32) = 0)` + ASSUME_TAC THENL + [MATCH_MP_TAC JA_TAKEN_GT THEN CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + X86_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (1--4) THEN + ENSURES_FINAL_STATE_TAC THEN + ASM_REWRITE_TAC[f_ev_headguard_eta4; APPEND]);; + +(* ========================================================================= *) +(* eta4 SAFE scalar-tail (constant-time) lemmas. *) +(* Order: body-safe -> tail def+FEV -> run-safe -> memaccess+AT_P corollary. *) +(* ========================================================================= *) + +(* --- eta4 SAFE scalar-tail per-byte BODY (step (b)(ii)) --- *) +(* pc+314 -> pc+314 consuming input byte p, with CONCRETE PUBLIC events. *) +(* f_ev_scalar_body_eta4 is a COND tree over the two PUBLIC nibble conditions *) +(* (low<9, high<9). eta4 differs structurally from eta2 — ONE EventLoad, *) +(* pcs {402,385,371,349,329,321,314}. *) +(* Proof = SCALAR_TAIL_BODY_MEMSAFE with 2 swaps: *) +(* (a) SCALAR_BODY_SETUP_MS -> SCALAR_BODY_SETUP (no-strip, concrete events) *) +(* (b) DISCHARGE_MEMSAFE_ASM_TAC -> SAFE_SCALAR_DISCHARGE_TAC_ETA4 (x4). *) +(* ========================================================================= *) + +let f_ev_scalar_body_eta4 = define + `f_ev_scalar_body_eta4 (res:int64) (buf:int64) (pc:num) (inlist:byte list) + (p:num) (outlen0:num) = + if val(EL p inlist) MOD 16 < 9 then + (if val(EL p inlist) DIV 16 < 9 then + [EventJump (word (pc + 402),word (pc + 314)); + EventStore (word_add res (word (4 * (outlen0 + 1))),4); + EventJump (word (pc + 385),word (pc + 385)); + EventJump (word (pc + 371),word (pc + 371)); + EventStore (word_add res (word (4 * val (word outlen0:int64))),4); + EventJump (word (pc + 349),word (pc + 349)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 329),word (pc + 329)); + EventJump (word (pc + 321),word (pc + 321))] + else + [EventJump (word (pc + 385),word (pc + 314)); + EventJump (word (pc + 371),word (pc + 371)); + EventStore (word_add res (word (4 * val (word outlen0:int64))),4); + EventJump (word (pc + 349),word (pc + 349)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 329),word (pc + 329)); + EventJump (word (pc + 321),word (pc + 321))]) + else + (if val(EL p inlist) DIV 16 < 9 then + [EventJump (word (pc + 402),word (pc + 314)); + EventStore (word_add res (word (4 * outlen0)),4); + EventJump (word (pc + 385),word (pc + 385)); + EventJump (word (pc + 349),word (pc + 371)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 329),word (pc + 329)); + EventJump (word (pc + 321),word (pc + 321))] + else + [EventJump (word (pc + 385),word (pc + 314)); + EventJump (word (pc + 349),word (pc + 371)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 329),word (pc + 329)); + EventJump (word (pc + 321),word (pc + 321))])`;; + +let SCALAR_TAIL_BODY_SAFE_ETA4 = + (* Concrete-events discharge (replaces DISCHARGE_MEMSAFE_ASM_TAC). Goal at + each branch end: read events sN = APPEND (f_ev_scalar_body_eta4 ...) e /\ + memaccess_inbounds (...) [buf,272;table,2048] [res,1024]. Unfold the def; + the branch conds (in the asl) reduce the COND; events-eq closes by APPEND + + the stepped events assumption; memaccess via CONTAINED_ASM_TAC. *) + let SAFE_SCALAR_DISCHARGE_TAC_ETA4 = + REWRITE_TAC[f_ev_scalar_body_eta4] THEN + CONJ_TAC THENL + [ASM_REWRITE_TAC[APPEND]; + ASM_REWRITE_TAC[] THEN + REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND] THEN + REPEAT CONJ_TAC THEN + TRY(REPEAT ((DISJ1_TAC THEN CONTAINED_ASM_TAC) ORELSE DISJ2_TAC ORELSE + CONTAINED_ASM_TAC) THEN NO_TAC)] in + (* Build the SAFE goal term: concrete events conjoined onto SCALAR_TAIL_BODY's + pre & post (events OUTERMOST), universally over the extra `e`. outlen0 slot + uses the statement var `L`; the setup substitutes L->outlen0. *) + let scalar_body_safe_eta4_tm = + let qvars, body = strip_forall (concl SCALAR_TAIL_BODY) in + let hyps_tm, ens = dest_imp body in + let ensc, ppf = strip_comb ens in + let pre = el 1 ppf and post = el 2 ppf and frame = el 3 ppf in + let sv, preb = dest_abs pre in + let sv2, postb = dest_abs post in + let fev = `f_ev_scalar_body_eta4 res buf pc (inlist:byte list) p L` in + let eq_pre = `read events (s:x86state) = e` in + let eq_post = mk_conj + (mk_eq(`read events (s:x86state)`, mk_comb(mk_comb(`APPEND:(uarch_event)list->(uarch_event)list->(uarch_event)list`, fev), `e:(uarch_event)list`)), + list_mk_comb(`memaccess_inbounds`, + [fev; `[(buf:int64),272; (table:int64),2048]`; `[(res:int64),1024]`])) in + let pre' = mk_abs(sv, mk_conj(preb, vsubst[sv,`s:x86state`] eq_pre)) in + let post' = mk_abs(sv2, mk_conj(postb, vsubst[sv2,`s:x86state`] eq_post)) in + let ens' = list_mk_comb(ensc,[el 0 ppf; pre'; post'; frame]) in + list_mk_forall(qvars @ [`e:(uarch_event)list`], mk_imp(hyps_tm, ens')) in + prove + (scalar_body_safe_eta4_tm, + SCALAR_BODY_SETUP THEN + ASM_CASES_TAC `val(EL p (inlist:byte list)) MOD 16 < 9` THENL + [(* ===== ACCEPT-LOW (low<9): step to pc+364, store low, to pc+379 ===== *) + SUBGOAL_THEN `~(&(val(word_zx(word(val(EL p (inlist:byte list)) MOD 16):int64):int32)):int - &9 = &(val(word_sub(word_zx(word(val(EL p (inlist:byte list)) MOD 16):int64):int32) (word 9):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + X86_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (9--14) THEN DISCARD_OLDSTATE_TAC "s14" THEN + SUBGOAL_THEN `outlen0 + 1 < 256` ASSUME_TAC THENL + [REPEAT(FIRST_X_ASSUM(MP_TAC o check(fun th->let c=concl th in c=`outlen0<256`||c=`val(EL p (inlist:byte list)) MOD 16 < 9`||c=`~(outlen0=255/\val(EL p (inlist:byte list)) MOD 16 < 9)`))) THEN ARITH_TAC; ALL_TAC] THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->t=`RAX`))c && can(find_term(fun t->t=`s14:x86state`))c + then ASSUME_TAC(REWRITE_RULE[MATCH_MP RAX_INC (ASSUME `outlen0<256`)] th) else NO_TAC) THEN + SUBGOAL_THEN `~(&(val(word_zx(word(outlen0+1):int64):int32)):int - &256 = &(val(word_sub(word_zx(word(outlen0+1):int64):int32) (word 256):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + X86_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (15--18) THEN + RULE_ASSUM_TAC(REWRITE_RULE[R11_NIBBLE_VAL]) THEN DISCARD_OLDSTATE_TAC "s18" THEN + ASM_CASES_TAC `val(EL p (inlist:byte list)) DIV 16 < 9` THENL + [(* ACCEPT-ACCEPT *) + SUBGOAL_THEN `~(&(val(word_zx(word(val(EL p (inlist:byte list)) DIV 16):int64):int32)):int - &9 = &(val(word_sub(word_zx(word(val(EL p (inlist:byte list)) DIV 16):int64):int32) (word 9):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + X86_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (19--22) THEN + SUBGOAL_THEN `val(word(outlen0+1):int64) = outlen0+1` ASSUME_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN MP_TAC(ASSUME `outlen0+1<256`) THEN ARITH_TAC; ALL_TAC] THEN + X86_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (23--25) THEN DISCARD_OLDSTATE_TAC "s25" THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->t=`RAX`))c && can(find_term(fun t->t=`s25:x86state`))c + then ASSUME_TAC(REWRITE_RULE[MATCH_MP RAX_INC (ASSUME `outlen0+1<256`)] th) else NO_TAC) THEN + ENSURES_FINAL_STATE_TAC THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p+1) inlist):int32 list) = outlen0 + 2` ASSUME_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] LEN_STEP_BOTH) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ASM_ARITH_TAC; ASM_REWRITE_TAC[]]; ALL_TAC] THEN + DISCH_THEN(fun th->REWRITE_TAC[th]) THEN + FIRST_ASSUM(fun th->if concl th=`LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p) inlist):int32 list) = outlen0` then REWRITE_TAC[th] else NO_TAC); ALL_TAC] THEN + ASM_REWRITE_TAC[ARITH_RULE `(outlen0+1)+1 = outlen0+2`] THEN + CONJ_TAC THENL + [CONJ_TAC THENL + [RCX_INC_TAC; + SUBGOAL_THEN `REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p+1) inlist) = + APPEND (REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist)) + [word_sx(word_sub (word 4:int16) (word(val(EL p (inlist:byte list)) MOD 16))):int32; + word_sx(word_sub (word 4:int16) (word(val(EL p (inlist:byte list)) DIV 16))):int32]` SUBST1_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] REJ_STEP_BOTH) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN MATCH_ACCEPT_TAC; ALL_TAC] THEN + SUBGOAL_THEN `4 * (outlen0 + 2) = 4 * outlen0 + 8` SUBST1_TAC THENL [ARITH_TAC; ALL_TAC] THEN + MP_TAC(ISPECL [`memory:(x86state,int64->byte)component`; `res:int64`; `s25:x86state`; + `REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list`; + `[word_sx(word_sub (word 4:int16) (word(val(EL p (inlist:byte list)) MOD 16))):int32; + word_sx(word_sub (word 4:int16) (word(val(EL p (inlist:byte list)) DIV 16))):int32]`; + `4*outlen0`; `8`] BYTES_EQ_NUM_OF_WORDLIST_APPEND) THEN + ANTS_TAC THENL + [REWRITE_TAC[DIMINDEX_32] THEN + FIRST_ASSUM(fun th->if concl th=`LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p) inlist):int32 list) = outlen0` then REWRITE_TAC[th] else NO_TAC) THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN CONJ_TAC THENL + [FIRST_ASSUM ACCEPT_TAC; + GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [GSYM(REWRITE_CONV[APPEND] `APPEND [a:int32] [b:int32]`)] THEN + SUBGOAL_THEN `(8:num) = 4 + 4` SUBST1_TAC THENL [ARITH_TAC; ALL_TAC] THEN + MP_TAC(ISPECL [`memory:(x86state,int64->byte)component`; `word_add res (word(4*outlen0)):int64`; `s25:x86state`; + `[word_sx(word_sub (word 4:int16) (word(val(EL p (inlist:byte list)) MOD 16))):int32]`; + `[word_sx(word_sub (word 4:int16) (word(val(EL p (inlist:byte list)) DIV 16))):int32]`; + `4`; `4`] BYTES_EQ_NUM_OF_WORDLIST_APPEND) THEN + ANTS_TAC THENL [REWRITE_TAC[DIMINDEX_32; LENGTH] THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[NUM_OF_WORDLIST_SINGLETON_INT32] THEN + SUBGOAL_THEN `val(word outlen0:int64) = outlen0` ASSUME_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN MP_TAC(ASSUME `outlen0<256`) THEN ARITH_TAC; ALL_TAC] THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->try fst(dest_const t)="bytes32" with _->false))c && can(find_term(fun t->t=`s25:x86state`))c && can(find_term(fun t->t=`val(EL p (inlist:byte list)) MOD 16`))c + then ASSUME_TAC(REWRITE_RULE[ASSUME `val(word outlen0:int64) = outlen0`; MATCH_MP LO_STORE_VAL (ASSUME `val(EL p (inlist:byte list)) MOD 16 < 9`)] th) else NO_TAC) THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->try fst(dest_const t)="bytes32" with _->false))c && can(find_term(fun t->t=`s25:x86state`))c && can(find_term(fun t->t=`val(EL p (inlist:byte list)) DIV 16`))c + then ASSUME_TAC(REWRITE_RULE[MATCH_MP HI_STORE_VAL (ASSUME `val(EL p (inlist:byte list)) DIV 16 < 9`)] th) else NO_TAC) THEN + CONJ_TAC THENL + [FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->try fst(dest_const t)="bytes32" with _->false))c && can(find_term(fun t->t=`val(EL p (inlist:byte list)) MOD 16`))c && not(can(find_term is_cond)c) + then MP_TAC th else NO_TAC) THEN + STORE4_FROM_SPEC `s25:x86state` `word_add res (word(4 * outlen0)):int64`; + SUBGOAL_THEN `word_add (word_add res (word (4 * outlen0))) (word 4):int64 = word_add res (word (4 * (outlen0+1)))` SUBST1_TAC THENL + [CONV_TAC WORD_RULE; ALL_TAC] THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->try fst(dest_const t)="bytes32" with _->false))c && can(find_term(fun t->t=`val(EL p (inlist:byte list)) DIV 16`))c && not(can(find_term is_cond)c) + then MP_TAC th else NO_TAC) THEN + STORE4_FROM_SPEC `s25:x86state` `word_add res (word(4 * (outlen0+1))):int64`]]]; + SAFE_SCALAR_DISCHARGE_TAC_ETA4]; + (* ===== LO-only (low<9, high>=9): jae pc+383 taken -> pc+314 ===== *) + SUBGOAL_THEN `&(val(word_zx(word(val(EL p (inlist:byte list)) DIV 16):int64):int32)):int - &9 = &(val(word_sub(word_zx(word(val(EL p (inlist:byte list)) DIV 16):int64):int32) (word 9):int32))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_TAKEN_GE THEN CONJ_TAC THENL + [MP_TAC(ASSUME `~(val(EL p (inlist:byte list)) DIV 16 < 9)`) THEN ARITH_TAC; + MP_TAC(ISPEC `EL p (inlist:byte list)` VAL_BOUND) THEN REWRITE_TAC[DIMINDEX_8] THEN + MP_TAC(SPECL[`val(EL p (inlist:byte list))`;`16`] DIV_LE) THEN ARITH_TAC]; ALL_TAC] THEN + X86_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (19--20) THEN DISCARD_OLDSTATE_TAC "s20" THEN + ENSURES_FINAL_STATE_TAC THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p+1) inlist):int32 list) = outlen0 + 1` ASSUME_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] LEN_STEP_LO) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ASM_ARITH_TAC; ASM_REWRITE_TAC[]]; ALL_TAC] THEN + DISCH_THEN(fun th->REWRITE_TAC[th]) THEN + FIRST_ASSUM(fun th->if concl th=`LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p) inlist):int32 list) = outlen0` then REWRITE_TAC[th] else NO_TAC); ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN CONJ_TAC THENL + [CONJ_TAC THENL + [RCX_INC_TAC; + SUBGOAL_THEN `REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p+1) inlist) = + APPEND (REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist)) + [word_sx(word_sub (word 4:int16) (word(val(EL p (inlist:byte list)) MOD 16))):int32]` SUBST1_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] REJ_STEP_LO) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN MATCH_ACCEPT_TAC; ALL_TAC] THEN + SUBGOAL_THEN `4 * (outlen0 + 1) = 4 * outlen0 + 4` SUBST1_TAC THENL [ARITH_TAC; ALL_TAC] THEN + MP_TAC(ISPECL [`memory:(x86state,int64->byte)component`; `res:int64`; `s20:x86state`; + `REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list`; + `[word_sx(word_sub (word 4:int16) (word(val(EL p (inlist:byte list)) MOD 16))):int32]`; + `4*outlen0`; `4`] BYTES_EQ_NUM_OF_WORDLIST_APPEND) THEN + ANTS_TAC THENL + [REWRITE_TAC[DIMINDEX_32] THEN + FIRST_ASSUM(fun th->if concl th=`LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p) inlist):int32 list) = outlen0` then REWRITE_TAC[th] else NO_TAC) THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[NUM_OF_WORDLIST_SINGLETON_INT32] THEN + CONJ_TAC THENL + [FIRST_ASSUM ACCEPT_TAC; + SUBGOAL_THEN `val(word outlen0:int64) = outlen0` ASSUME_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN MP_TAC(ASSUME `outlen0<256`) THEN ARITH_TAC; ALL_TAC] THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->try fst(dest_const t)="bytes32" with _->false))c && can(find_term(fun t->t=`s20:x86state`))c && can(find_term(fun t->t=`val(EL p (inlist:byte list)) MOD 16`))c + then ASSUME_TAC(REWRITE_RULE[ASSUME `val(word outlen0:int64) = outlen0`; MATCH_MP LO_STORE_VAL (ASSUME `val(EL p (inlist:byte list)) MOD 16 < 9`)] th) else NO_TAC) THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->try fst(dest_const t)="bytes32" with _->false))c && can(find_term(fun t->t=`val(EL p (inlist:byte list)) MOD 16`))c && not(can(find_term is_cond)c) + then MP_TAC th else NO_TAC) THEN + STORE4_FROM_SPEC `s20:x86state` `word_add res (word(4 * outlen0)):int64`]]; + SAFE_SCALAR_DISCHARGE_TAC_ETA4]]; + (* ===== REJECT-LOW (low>=9): jae pc+347 taken -> pc+371 ===== *) + SUBGOAL_THEN `&(val(word_zx(word(val(EL p (inlist:byte list)) MOD 16):int64):int32)):int - &9 = &(val(word_sub(word_zx(word(val(EL p (inlist:byte list)) MOD 16):int64):int32) (word 9):int32))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_TAKEN_GE THEN CONJ_TAC THENL + [MP_TAC(ASSUME `~(val(EL p (inlist:byte list)) MOD 16 < 9)`) THEN ARITH_TAC; + MP_TAC(SPECL[`val(EL p (inlist:byte list))`;`16`] MOD_LT_EQ) THEN ARITH_TAC]; ALL_TAC] THEN + X86_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (9--12) THEN + RULE_ASSUM_TAC(REWRITE_RULE[R11_NIBBLE_VAL]) THEN DISCARD_OLDSTATE_TAC "s12" THEN + ASM_CASES_TAC `val(EL p (inlist:byte list)) DIV 16 < 9` THENL + [(* HI-only (low>=9, high<9): jae pc+383 not taken -> store -> pc+314 *) + SUBGOAL_THEN `~(&(val(word_zx(word(val(EL p (inlist:byte list)) DIV 16):int64):int32)):int - &9 = &(val(word_sub(word_zx(word(val(EL p (inlist:byte list)) DIV 16):int64):int32) (word 9):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + X86_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (13--16) THEN + SUBGOAL_THEN `val(word outlen0:int64) = outlen0` ASSUME_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN MP_TAC(ASSUME `outlen0<256`) THEN ARITH_TAC; ALL_TAC] THEN + X86_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (17--19) THEN DISCARD_OLDSTATE_TAC "s19" THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->t=`RAX`))c && can(find_term(fun t->t=`s19:x86state`))c + then ASSUME_TAC(REWRITE_RULE[MATCH_MP RAX_INC (ASSUME `outlen0<256`)] th) else NO_TAC) THEN + ENSURES_FINAL_STATE_TAC THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p+1) inlist):int32 list) = outlen0 + 1` ASSUME_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] LEN_STEP_HI) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ASM_ARITH_TAC; ASM_REWRITE_TAC[]]; ALL_TAC] THEN + DISCH_THEN(fun th->REWRITE_TAC[th]) THEN + FIRST_ASSUM(fun th->if concl th=`LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p) inlist):int32 list) = outlen0` then REWRITE_TAC[th] else NO_TAC); ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN CONJ_TAC THENL + [CONJ_TAC THENL + [RCX_INC_TAC; + SUBGOAL_THEN `REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p+1) inlist) = + APPEND (REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist)) + [word_sx(word_sub (word 4:int16) (word(val(EL p (inlist:byte list)) DIV 16))):int32]` SUBST1_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] REJ_STEP_HI) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN MATCH_ACCEPT_TAC; ALL_TAC] THEN + SUBGOAL_THEN `4 * (outlen0 + 1) = 4 * outlen0 + 4` SUBST1_TAC THENL [ARITH_TAC; ALL_TAC] THEN + MP_TAC(ISPECL [`memory:(x86state,int64->byte)component`; `res:int64`; `s19:x86state`; + `REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list`; + `[word_sx(word_sub (word 4:int16) (word(val(EL p (inlist:byte list)) DIV 16))):int32]`; + `4*outlen0`; `4`] BYTES_EQ_NUM_OF_WORDLIST_APPEND) THEN + ANTS_TAC THENL + [REWRITE_TAC[DIMINDEX_32] THEN + FIRST_ASSUM(fun th->if concl th=`LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p) inlist):int32 list) = outlen0` then REWRITE_TAC[th] else NO_TAC) THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[NUM_OF_WORDLIST_SINGLETON_INT32] THEN + CONJ_TAC THENL + [FIRST_ASSUM ACCEPT_TAC; + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->try fst(dest_const t)="bytes32" with _->false))c && can(find_term(fun t->t=`s19:x86state`))c && can(find_term(fun t->t=`val(EL p (inlist:byte list)) DIV 16`))c + then ASSUME_TAC(REWRITE_RULE[ASSUME `val(word outlen0:int64) = outlen0`; MATCH_MP HI_STORE_VAL (ASSUME `val(EL p (inlist:byte list)) DIV 16 < 9`)] th) else NO_TAC) THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->try fst(dest_const t)="bytes32" with _->false))c && can(find_term(fun t->t=`val(EL p (inlist:byte list)) DIV 16`))c && not(can(find_term is_cond)c) + then MP_TAC th else NO_TAC) THEN + STORE4_FROM_SPEC `s19:x86state` `word_add res (word(4 * outlen0)):int64`]]; + SAFE_SCALAR_DISCHARGE_TAC_ETA4]; + (* NONE (low>=9, high>=9): jae pc+383 taken -> pc+314, no store *) + SUBGOAL_THEN `&(val(word_zx(word(val(EL p (inlist:byte list)) DIV 16):int64):int32)):int - &9 = &(val(word_sub(word_zx(word(val(EL p (inlist:byte list)) DIV 16):int64):int32) (word 9):int32))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_TAKEN_GE THEN CONJ_TAC THENL + [MP_TAC(ASSUME `~(val(EL p (inlist:byte list)) DIV 16 < 9)`) THEN ARITH_TAC; + MP_TAC(ISPEC `EL p (inlist:byte list)` VAL_BOUND) THEN REWRITE_TAC[DIMINDEX_8] THEN + MP_TAC(SPECL[`val(EL p (inlist:byte list))`;`16`] DIV_LE) THEN ARITH_TAC]; ALL_TAC] THEN + X86_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (13--14) THEN DISCARD_OLDSTATE_TAC "s14" THEN + ENSURES_FINAL_STATE_TAC THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p+1) inlist):int32 list) = outlen0` ASSUME_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] LEN_STEP_NONE) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [ASM_ARITH_TAC; ASM_REWRITE_TAC[]]; ALL_TAC] THEN + DISCH_THEN(fun th->REWRITE_TAC[th]) THEN + FIRST_ASSUM(fun th->if concl th=`LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p) inlist):int32 list) = outlen0` then REWRITE_TAC[th] else NO_TAC); ALL_TAC] THEN + SUBGOAL_THEN `REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p+1) inlist):int32 list = REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p) inlist)` ASSUME_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] REJ_STEP_NONE) THEN ASM_REWRITE_TAC[] THEN DISCH_THEN MATCH_ACCEPT_TAC; ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN CONJ_TAC THENL [RCX_INC_TAC; SAFE_SCALAR_DISCHARGE_TAC_ETA4]]]);; + +(* ========================================================================= *) +(* f_ev_scalar_tail_eta4 + the 4 FEV_TAIL reduction lemmas. *) +(* The public event trace of the eta4 scalar tail (byte loop pc+314 -> pc+402),*) +(* by recursion on the byte budget d. Terminals mirror eta2's *) +(* f_ev_scalar_tail under the pc map {410->321, 418->329, 438->349, 481->371, *) +(* 542->402}, offset check p=272, midbyte cond val<9, store res+1020 (=4*255) *) +(* unchanged. Depends on f_ev_scalar_body_eta4 (the body-safe lemma above). *) +(* ========================================================================= *) + +let f_ev_scalar_tail_eta4 = define + `(f_ev_scalar_tail_eta4 0 (res:int64) (buf:int64) (pc:num) (inlist:byte list) (p:num) = + (if 256 <= LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list) + then [EventJump (word (pc + 321),word (pc + 402))] + else [EventJump (word (pc + 329),word (pc + 402)); + EventJump (word (pc + 321),word (pc + 321))])) /\ + (f_ev_scalar_tail_eta4 (SUC d) (res:int64) (buf:int64) (pc:num) (inlist:byte list) (p:num) = + (if 256 <= LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list) + then [EventJump (word (pc + 321),word (pc + 402))] + else if p = 272 + then [EventJump (word (pc + 329),word (pc + 402)); + EventJump (word (pc + 321),word (pc + 321))] + else if LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list) = 255 /\ + val(EL p inlist) MOD 16 < 9 + then [EventJump (word (pc + 371),word (pc + 402)); + EventStore (word_add res (word 1020),4); + EventJump (word (pc + 349),word (pc + 349)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 329),word (pc + 329)); + EventJump (word (pc + 321),word (pc + 321))] + else APPEND (f_ev_scalar_tail_eta4 d res buf pc inlist (p+1)) + (f_ev_scalar_body_eta4 res buf pc inlist p + (LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list)))))`;; + +(* -- Per-terminal reduction lemmas (conditional rewrites, uniform over d). -- *) +let FEV_TAIL_COUNT_ETA4 = prove + (`!d res buf pc (inlist:byte list) p. + 256 <= LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list) + ==> f_ev_scalar_tail_eta4 d res buf pc inlist p = + [EventJump (word (pc + 321),word (pc + 402))]`, + REPEAT GEN_TAC THEN DISCH_TAC THEN + STRUCT_CASES_TAC (SPEC `d:num` num_CASES) THEN + ASM_REWRITE_TAC[f_ev_scalar_tail_eta4]);; + +let FEV_TAIL_OFFSET_ETA4 = prove + (`!d res buf pc (inlist:byte list) p. + ~(256 <= LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list)) /\ + p = 272 + ==> f_ev_scalar_tail_eta4 d res buf pc inlist p = + [EventJump (word (pc + 329),word (pc + 402)); + EventJump (word (pc + 321),word (pc + 321))]`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + STRUCT_CASES_TAC (SPEC `d:num` num_CASES) THEN + ASM_REWRITE_TAC[f_ev_scalar_tail_eta4]);; + +let FEV_TAIL_MIDBYTE_ETA4 = prove + (`!d res buf pc (inlist:byte list) p. + ~(256 <= LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list)) /\ + ~(p = 272) /\ + LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list) = 255 /\ + val(EL p inlist) MOD 16 < 9 + ==> f_ev_scalar_tail_eta4 (SUC d) res buf pc inlist p = + [EventJump (word (pc + 371),word (pc + 402)); + EventStore (word_add res (word 1020),4); + EventJump (word (pc + 349),word (pc + 349)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 329),word (pc + 329)); + EventJump (word (pc + 321),word (pc + 321))]`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + ASM_REWRITE_TAC[f_ev_scalar_tail_eta4]);; + +let FEV_TAIL_REC_ETA4 = prove + (`!d res buf pc (inlist:byte list) p. + ~(256 <= LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list)) /\ + ~(p = 272) /\ + ~(LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list) = 255 /\ + val(EL p inlist) MOD 16 < 9) + ==> f_ev_scalar_tail_eta4 (SUC d) res buf pc inlist p = + APPEND (f_ev_scalar_tail_eta4 d res buf pc inlist (p+1)) + (f_ev_scalar_body_eta4 res buf pc inlist p + (LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list)))`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + ASM_REWRITE_TAC[f_ev_scalar_tail_eta4]);; + +(* ========================================================================= *) +(* SCALAR_TAIL_RUN_SAFE_ETA4 — the SAFE (constant-time) scalar tail run *) +(* (byte loop pc+314 -> pc+402) with CONCRETE PUBLIC events *) +(* (f_ev_scalar_tail_eta4). Merges the eta4 VALUE SCALAR_TAIL_RUN stepping *) +(* with the eta2 SCALAR_TAIL_RUN_SAFE_ETA2 events-injection. Terminals close *) +(* by FEV_TAIL_{COUNT,OFFSET,MIDBYTE}_ETA4 + APPEND; the recursive leg *) +(* composes SCALAR_TAIL_BODY_SAFE_ETA4 + IH (events e' = *) +(* APPEND (f_ev_scalar_body_eta4 .. p L) e) via ENSURES_SEQUENCE @ pc+314, *) +(* R pre-rewritten via FEV_TAIL_REC_ETA4 + GSYM APPEND_ASSOC. *) +(* ========================================================================= *) + +let SCALAR_TAIL_RUN_SAFE_ETA4 = + let rec conj_append_right t ev = + if is_conj t then + let l,r = dest_conj t in mk_conj(l, conj_append_right r ev) + else mk_conj(t, ev) in + let scalar_run_safe_eta4_tm = + let qvars, body = strip_forall (concl SCALAR_TAIL_RUN) in + let hyps_tm, ens = dest_imp body in + let ensc, ppf = strip_comb ens in + let pre = el 1 ppf and post = el 2 ppf and frame = el 3 ppf in + let sv, preb = dest_abs pre in + let sv2, postb = dest_abs post in + let fev = `f_ev_scalar_tail_eta4 d res buf pc (inlist:byte list) p` in + let eq_pre = `read events (s:x86state) = e` in + let eq_post = mk_eq(`read events (s:x86state)`, + mk_comb(mk_comb(`APPEND:(uarch_event)list->(uarch_event)list->(uarch_event)list`, fev), `e:(uarch_event)list`)) in + let pre' = mk_abs(sv, conj_append_right preb (vsubst[sv,`s:x86state`] eq_pre)) in + let post' = mk_abs(sv2, conj_append_right postb (vsubst[sv2,`s:x86state`] eq_post)) in + let ens' = list_mk_comb(ensc,[el 0 ppf; pre'; post'; frame]) in + list_mk_forall(qvars @ [`e:(uarch_event)list`], mk_imp(hyps_tm, ens')) in + prove + (scalar_run_safe_eta4_tm, + INDUCT_TAC THENL + [(* ================= BASE CASE: d = 0 => p = 272 ================= *) + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN `p = 272` SUBST_ALL_TAC THENL + [REPEAT(FIRST_X_ASSUM(MP_TAC o check (fun th -> let c=concl th in c=`272 - p <= 0` || c=`p <= 272`))) THEN ARITH_TAC; ALL_TAC] THEN + MP_TAC(SPEC `inlist:byte list` SUB_LIST_BYTE_272) THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN + RULE_ASSUM_TAC(REWRITE_RULE[ASSUME `SUB_LIST(0,272) (inlist:byte list) = inlist`]) THEN + REWRITE_TAC[ASSUME `SUB_LIST(0,272) (inlist:byte list) = inlist`] THEN + ASM_CASES_TAC `LENGTH(REJ_SAMPLE_ETA4_BYTES inlist:int32 list) = 256` THENL + [(* --- BASE COUNT-EXIT: outlen = 256 --- *) + MP_TAC(SPEC `REJ_SAMPLE_ETA4_BYTES inlist:int32 list` SUB_LIST_256_LE) THEN + ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN DISCH_TAC THEN + REWRITE_TAC[ASSUME `LENGTH(REJ_SAMPLE_ETA4_BYTES inlist:int32 list) = 256`] THEN + REWRITE_TAC[ASSUME `SUB_LIST(0,256)(REJ_SAMPLE_ETA4_BYTES inlist:int32 list) = REJ_SAMPLE_ETA4_BYTES inlist`] THEN + ENSURES_INIT_TAC "s0" THEN + SUBGOAL_THEN `&(val(word_zx(word 256:int64):int32)):int - &256 = &(val(word_sub(word_zx(word 256:int64):int32) (word 256):int32))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_TAKEN_GE THEN CONJ_TAC THENL [ARITH_TAC; CONV_TAC NUM_REDUCE_CONV]; ALL_TAC] THEN + X86_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (1--2) THEN + ENSURES_FINAL_STATE_TAC THEN + SUBGOAL_THEN `f_ev_scalar_tail_eta4 0 res buf pc (inlist:byte list) 272 = [EventJump (word (pc + 321),word (pc + 402))]` SUBST1_TAC THENL + [MATCH_MP_TAC FEV_TAIL_COUNT_ETA4 THEN + SUBGOAL_THEN `SUB_LIST(0,272)(inlist:byte list) = inlist` SUBST1_TAC THENL + [MATCH_MP_TAC SUB_LIST_BYTE_272 THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + REWRITE_TAC[ASSUME `LENGTH(REJ_SAMPLE_ETA4_BYTES inlist:int32 list) = 256`] THEN + REWRITE_TAC[LENGTH_BUTLAST_TMC] THEN ASM_REWRITE_TAC[APPEND]; + (* --- BASE OFFSET-EXIT: outlen < 256, p = 272 --- *) + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA4_BYTES inlist:int32 list) < 256` ASSUME_TAC THENL + [REPEAT(FIRST_X_ASSUM(MP_TAC o check (fun th -> let c=concl th in c=`LENGTH(REJ_SAMPLE_ETA4_BYTES inlist:int32 list) <= 256` || c=`~(LENGTH(REJ_SAMPLE_ETA4_BYTES inlist:int32 list) = 256)`))) THEN ARITH_TAC; ALL_TAC] THEN + MP_TAC(SPEC `REJ_SAMPLE_ETA4_BYTES inlist:int32 list` SUB_LIST_256_LE) THEN + ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN DISCH_TAC THEN + REWRITE_TAC[ASSUME `SUB_LIST(0,256)(REJ_SAMPLE_ETA4_BYTES inlist:int32 list) = REJ_SAMPLE_ETA4_BYTES inlist`] THEN + ENSURES_INIT_TAC "s0" THEN + SUBGOAL_THEN `~(&(val(word_zx(word(LENGTH(REJ_SAMPLE_ETA4_BYTES inlist:int32 list)):int64):int32)):int - &256 = &(val(word_sub(word_zx(word(LENGTH(REJ_SAMPLE_ETA4_BYTES inlist:int32 list)):int64):int32) (word 256):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT THEN ASM_REWRITE_TAC[] THEN CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + SUBGOAL_THEN `&(val(word_zx(word 272:int64):int32)):int - &272 = &(val(word_sub(word_zx(word 272:int64):int32) (word 272):int32))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_TAKEN_GE THEN CONJ_TAC THENL [ARITH_TAC; CONV_TAC NUM_REDUCE_CONV]; ALL_TAC] THEN + X86_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (1--4) THEN + ENSURES_FINAL_STATE_TAC THEN + SUBGOAL_THEN `f_ev_scalar_tail_eta4 0 res buf pc (inlist:byte list) 272 = + [EventJump (word (pc + 329),word (pc + 402)); EventJump (word (pc + 321),word (pc + 321))]` SUBST1_TAC THENL + [MATCH_MP_TAC FEV_TAIL_OFFSET_ETA4 THEN + SUBGOAL_THEN `SUB_LIST(0,272)(inlist:byte list) = inlist` SUBST1_TAC THENL + [MATCH_MP_TAC SUB_LIST_BYTE_272 THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + REWRITE_TAC[NOT_LE] THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + REWRITE_TAC[LENGTH_BUTLAST_TMC] THEN ASM_REWRITE_TAC[APPEND]]; + (* ================= STEP CASE: SUC d ================= *) + REPEAT GEN_TAC THEN STRIP_TAC THEN + ASM_CASES_TAC `256 <= LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list)` THENL + [(* --- STEP COUNT-EXIT: outlen >= 256 (=256 by invariant) --- *) + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list) = 256` ASSUME_TAC THENL + [ASM_ARITH_TAC; ALL_TAC] THEN + MP_TAC(SPECL [`inlist:byte list`; `p:num`] SUB_LIST_256_PREFIX_GE) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN DISCH_TAC THEN + MP_TAC(SPEC `REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list` SUB_LIST_256_LE) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[LE_REFL]; ALL_TAC] THEN DISCH_TAC THEN + SUBGOAL_THEN `SUB_LIST(0,256)(REJ_SAMPLE_ETA4_BYTES inlist:int32 list) = REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist)` ASSUME_TAC THENL + [ASM_REWRITE_TAC[]; ALL_TAC] THEN + REWRITE_TAC[ASSUME `SUB_LIST(0,256)(REJ_SAMPLE_ETA4_BYTES inlist:int32 list) = REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist)`; + ASSUME `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list) = 256`] THEN + ENSURES_INIT_TAC "s0" THEN + SUBGOAL_THEN `&(val(word_zx(word 256:int64):int32)):int - &256 = &(val(word_sub(word_zx(word 256:int64):int32) (word 256):int32))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_TAKEN_GE THEN CONJ_TAC THENL [ARITH_TAC; CONV_TAC NUM_REDUCE_CONV]; ALL_TAC] THEN + X86_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (1--2) THEN + ENSURES_FINAL_STATE_TAC THEN + SUBGOAL_THEN `f_ev_scalar_tail_eta4 (SUC d) res buf pc (inlist:byte list) p = [EventJump (word (pc + 321),word (pc + 402))]` SUBST1_TAC THENL + [MATCH_MP_TAC FEV_TAIL_COUNT_ETA4 THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + REWRITE_TAC[ASSUME `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list) = 256`; LENGTH_BUTLAST_TMC] THEN + ASM_REWRITE_TAC[APPEND]; + (* --- not count-exit: outlen < 256 --- *) + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list) < 256` ASSUME_TAC THENL + [ASM_ARITH_TAC; ALL_TAC] THEN + ASM_CASES_TAC `p = 272` THENL + [(* --- STEP OFFSET-EXIT: p = 272 --- *) + FIRST_X_ASSUM(SUBST_ALL_TAC o check (fun th -> concl th = `p = 272`)) THEN + MP_TAC(SPEC `inlist:byte list` SUB_LIST_BYTE_272) THEN ASM_REWRITE_TAC[] THEN DISCH_TAC THEN + RULE_ASSUM_TAC(REWRITE_RULE[ASSUME `SUB_LIST(0,272) (inlist:byte list) = inlist`]) THEN + REWRITE_TAC[ASSUME `SUB_LIST(0,272) (inlist:byte list) = inlist`] THEN + MP_TAC(SPEC `REJ_SAMPLE_ETA4_BYTES inlist:int32 list` SUB_LIST_256_LE) THEN + ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN DISCH_TAC THEN + REWRITE_TAC[ASSUME `SUB_LIST(0,256)(REJ_SAMPLE_ETA4_BYTES inlist:int32 list) = REJ_SAMPLE_ETA4_BYTES inlist`] THEN + ENSURES_INIT_TAC "s0" THEN + SUBGOAL_THEN `~(&(val(word_zx(word(LENGTH(REJ_SAMPLE_ETA4_BYTES inlist:int32 list)):int64):int32)):int - &256 = &(val(word_sub(word_zx(word(LENGTH(REJ_SAMPLE_ETA4_BYTES inlist:int32 list)):int64):int32) (word 256):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT THEN ASM_REWRITE_TAC[] THEN CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + SUBGOAL_THEN `&(val(word_zx(word 272:int64):int32)):int - &272 = &(val(word_sub(word_zx(word 272:int64):int32) (word 272):int32))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_TAKEN_GE THEN CONJ_TAC THENL [ARITH_TAC; CONV_TAC NUM_REDUCE_CONV]; ALL_TAC] THEN + X86_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (1--4) THEN + ENSURES_FINAL_STATE_TAC THEN + SUBGOAL_THEN `f_ev_scalar_tail_eta4 (SUC d) res buf pc (inlist:byte list) 272 = + [EventJump (word (pc + 329),word (pc + 402)); EventJump (word (pc + 321),word (pc + 321))]` SUBST1_TAC THENL + [MATCH_MP_TAC FEV_TAIL_OFFSET_ETA4 THEN + SUBGOAL_THEN `SUB_LIST(0,272)(inlist:byte list) = inlist` SUBST1_TAC THENL + [MATCH_MP_TAC SUB_LIST_BYTE_272 THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + REWRITE_TAC[NOT_LE] THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + ASM_REWRITE_TAC[] THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + REWRITE_TAC[LENGTH_BUTLAST_TMC] THEN ASM_REWRITE_TAC[APPEND]; + (* --- p < 272 --- *) + SUBGOAL_THEN `p < 272` ASSUME_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN + ASM_CASES_TAC `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list) = 255 /\ val(EL p (inlist:byte list)) MOD 16 < 9` THENL + [(* --- STEP MID-BYTE EXIT: outlen=255, low<9 --- *) + FIRST_X_ASSUM(CONJUNCTS_THEN ASSUME_TAC o check (fun th -> is_conj(concl th) && can(find_term(fun t->t=`val(EL p (inlist:byte list)) MOD 16`))(concl th))) THEN + SUBGOAL_THEN `256 <= LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p+1) inlist):int32 list)` ASSUME_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] LENGTH_REJ_SAMPLE_STEP_1) THEN + ASM_REWRITE_TAC[] THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `?rest. REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p+1) inlist):int32 list = + APPEND (APPEND (REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist)) + [word_sx(word_sub (word 4:int16) (word(val(EL p (inlist:byte list)) MOD 16))):int32]) rest` + STRIP_ASSUME_TAC THENL + [ASM_CASES_TAC `val(EL p (inlist:byte list)) DIV 16 < 9` THENL + [EXISTS_TAC `[word_sx(word_sub (word 4:int16) (word(val(EL p (inlist:byte list)) DIV 16))):int32]` THEN + MP_TAC(SPECL[`inlist:byte list`;`p:num`] REJ_STEP_BOTH) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[APPEND; GSYM APPEND_ASSOC]; + EXISTS_TAC `[]:int32 list` THEN + MP_TAC(SPECL[`inlist:byte list`;`p:num`] REJ_STEP_LO) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[APPEND_NIL]]; ALL_TAC] THEN + MP_TAC(SPECL [`inlist:byte list`; `p+1`] SUB_LIST_256_PREFIX_GE) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN DISCH_TAC THEN + SUBGOAL_THEN `LENGTH(APPEND (REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist)) + [word_sx(word_sub (word 4:int16) (word(val(EL p (inlist:byte list)) MOD 16))):int32]:int32 list) = 256` ASSUME_TAC THENL + [REWRITE_TAC[LENGTH_APPEND; LENGTH] THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `SUB_LIST(0,256)(REJ_SAMPLE_ETA4_BYTES inlist:int32 list) = + APPEND (REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist)) + [word_sx(word_sub (word 4:int16) (word(val(EL p (inlist:byte list)) MOD 16))):int32]` ASSUME_TAC THENL + [FIRST_X_ASSUM(fun th -> if is_eq(concl th) && (try lhs(concl th) = `SUB_LIST(0,256)(REJ_SAMPLE_ETA4_BYTES inlist:int32 list)` with _->false) then SUBST1_TAC th else NO_TAC) THEN + FIRST_X_ASSUM(fun th -> if is_eq(concl th) && (try lhs(concl th) = `REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p+1) inlist):int32 list` with _->false) then SUBST1_TAC th else NO_TAC) THEN + W(fun (asl,gl) -> let lt = rhs gl in + MATCH_MP_TAC EQ_TRANS THEN EXISTS_TAC (mk_comb(`SUB_LIST(0,256):(int32)list->(int32)list`, lt)) THEN + CONJ_TAC THENL + [MATCH_MP_TAC SUB_LIST_APPEND_LEFT THEN ASM_REWRITE_TAC[LE_REFL]; + MATCH_MP_TAC SUB_LIST_256_LE THEN ASM_REWRITE_TAC[LE_REFL]]); ALL_TAC] THEN + REWRITE_TAC[ASSUME `SUB_LIST(0,256)(REJ_SAMPLE_ETA4_BYTES inlist:int32 list) = + APPEND (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p) inlist)) + [word_sx (word_sub (word 4:int16) (word (val (EL p (inlist:byte list)) MOD 16))):int32]`] THEN + REWRITE_TAC[ASSUME `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list) = 255`] THEN + ENSURES_INIT_TAC "s0" THEN + MP_TAC(ISPECL [`inlist:byte list`; `buf:int64`; `s0:x86state`; `p:num`; `272`] READ_1BYTE_EL) THEN + ASM_REWRITE_TAC[] THEN DISCH_TAC THEN + SUBGOAL_THEN `~(&(val(word_zx(word 255:int64):int32)):int - &256 = &(val(word_sub(word_zx(word 255:int64):int32) (word 256):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT THEN CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + SUBGOAL_THEN `~(&(val(word_zx(word p:int64):int32)):int - &272 = &(val(word_sub(word_zx(word p:int64):int32) (word 272):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT THEN ASM_REWRITE_TAC[] THEN CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + X86_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (1--8) THEN + SUBGOAL_THEN `word_add buf (word (1 * val (word p:int64))) = word_add buf (word p):int64` ASSUME_TAC THENL + [AP_TERM_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[MULT_CLAUSES] THEN + MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN MP_TAC(ASSUME `p < 272`) THEN ARITH_TAC; ALL_TAC] THEN + RULE_ASSUM_TAC(REWRITE_RULE[ASSUME `word_add buf (word (1 * val (word p:int64))) = word_add buf (word p):int64`; + ASSUME `read (memory :> bytes8 (word_add buf (word p))) s4 = EL p (inlist:byte list)`; + R10_NIBBLE_VAL]) THEN + DISCARD_OLDSTATE_TAC "s8" THEN + SUBGOAL_THEN `~(&(val(word_zx(word(val(EL p (inlist:byte list)) MOD 16):int64):int32)):int - &9 = &(val(word_sub(word_zx(word(val(EL p (inlist:byte list)) MOD 16):int64):int32) (word 9):int32)))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_NOT_TAKEN_LT THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + X86_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (9--14) THEN + DISCARD_OLDSTATE_TAC "s14" THEN + SUBGOAL_THEN `&(val(word_zx(word 256:int64):int32)):int - &256 = &(val(word_sub(word_zx(word 256:int64):int32) (word 256):int32))` ASSUME_TAC THENL + [MATCH_MP_TAC JAE_TAKEN_GE THEN CONJ_TAC THENL [ARITH_TAC; CONV_TAC NUM_REDUCE_CONV]; ALL_TAC] THEN + X86_VSTEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (15--16) THEN + ENSURES_FINAL_STATE_TAC THEN + SUBGOAL_THEN `f_ev_scalar_tail_eta4 (SUC d) res buf pc (inlist:byte list) p = + [EventJump (word (pc + 371),word (pc + 402)); + EventStore (word_add res (word 1020),4); + EventJump (word (pc + 349),word (pc + 349)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 329),word (pc + 329)); + EventJump (word (pc + 321),word (pc + 321))]` SUBST1_TAC THENL + [MATCH_MP_TAC FEV_TAIL_MIDBYTE_ETA4 THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + REWRITE_TAC[ASSUME `SUB_LIST(0,256)(REJ_SAMPLE_ETA4_BYTES inlist:int32 list) = + APPEND (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,p) inlist)) + [word_sx (word_sub (word 4:int16) (word (val (EL p (inlist:byte list)) MOD 16))):int32]`] THEN + CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN + REWRITE_TAC[ASSUME `LENGTH(APPEND (REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist)) + [word_sx(word_sub (word 4:int16) (word(val(EL p (inlist:byte list)) MOD 16))):int32]:int32 list) = 256`] THEN + REWRITE_TAC[LENGTH_BUTLAST_TMC] THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL + [REPEAT CONJ_TAC THEN + SUBGOAL_THEN `4 * 256 = 4 * 255 + 4` SUBST1_TAC THENL [ARITH_TAC; ALL_TAC] THEN + MP_TAC(ISPECL [`memory:(x86state,int64->byte)component`; `res:int64`; `s16:x86state`; + `REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list`; + `[word_sx(word_sub (word 4:int16) (word(val(EL p (inlist:byte list)) MOD 16))):int32]`; + `4*255`; `4`] BYTES_EQ_NUM_OF_WORDLIST_APPEND) THEN + ANTS_TAC THENL [REWRITE_TAC[DIMINDEX_32] THEN ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[NUM_OF_WORDLIST_SINGLETON_INT32] THEN + CONJ_TAC THENL + [ASM_REWRITE_TAC[]; + SUBGOAL_THEN `word(4 * 255):int64 = word 1020` SUBST1_TAC THENL [CONV_TAC NUM_REDUCE_CONV; ALL_TAC] THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->try fst(dest_const t)="bytes32" with _->false))c && can(find_term(fun t->t=`s16:x86state`))c && can(find_term(fun t->t=`val(EL p (inlist:byte list)) MOD 16`))c + then ASSUME_TAC(REWRITE_RULE[MATCH_MP LO_STORE_VAL (ASSUME `val(EL p (inlist:byte list)) MOD 16 < 9`)] th) else NO_TAC) THEN + FIRST_X_ASSUM(fun th -> let c=concl th in + if is_eq c && can(find_term(fun t->try fst(dest_const t)="bytes32" with _->false))c && can(find_term(fun t->t=`val(EL p (inlist:byte list)) MOD 16`))c && not(can(find_term is_cond)c) && can(find_term(fun t->t=`s16:x86state`))c + then MP_TAC th else NO_TAC) THEN + STORE4_FROM_SPEC `s16:x86state` `word_add res (word 1020):int64`]; + REWRITE_TAC[APPEND] THEN ASM_REWRITE_TAC[]]; + (* --- STEP CLEAN-RECURSIVE: body trip then IH at p+1 --- *) + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p+1) inlist):int32 list) <= 256` ASSUME_TAC THENL + [MP_TAC(SPECL[`inlist:byte list`;`p:num`] LENGTH_REJ_SAMPLE_STEP_1) THEN ASM_REWRITE_TAC[] THEN + DISCH_THEN SUBST1_TAC THEN + REPEAT(FIRST_X_ASSUM(MP_TAC o check(fun th -> let c=concl th in + c = `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list) < 256` || + c = `~(LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list) = 255 /\ val(EL p (inlist:byte list)) MOD 16 < 9)`))) THEN + REPEAT(COND_CASES_TAC THEN ASM_REWRITE_TAC[]) THEN ARITH_TAC; ALL_TAC] THEN + MP_TAC(SPECL[`d:num`;`res:int64`;`buf:int64`;`pc:num`;`inlist:byte list`;`p:num`] FEV_TAIL_REC_ETA4) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN + DISCH_THEN(fun th -> REWRITE_TAC[th; GSYM APPEND_ASSOC]) THEN + MP_TAC(SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`p:num`; + `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list)`;`stackpointer:int64`;`e:(uarch_event)list`] SCALAR_TAIL_BODY_SAFE_ETA4) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(fun body_th -> + let bodyQ = rand(rator(concl body_th)) in + ENSURES_SEQUENCE_TAC `pc + 314` bodyQ THEN + CONJ_TAC THENL + [MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN + EXISTS_TAC (rand(rator(concl body_th))) THEN CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + MATCH_MP_TAC ENSURES_PRECONDITION_THM THEN + EXISTS_TAC (rand(rator(rator(concl body_th)))) THEN CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + ACCEPT_TAC body_th]]; + ALL_TAC]) THEN + W(fun (asl,g) -> + let ih = snd(List.find (fun (_,th) -> is_forall(concl th) && + can (find_term (fun x -> x = `272 - p <= d`)) (concl th)) asl) in + let ih_inst = SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`p+1`;`stackpointer:int64`; + `APPEND (f_ev_scalar_body_eta4 res buf pc (inlist:byte list) p (LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,p) inlist):int32 list))) (e:(uarch_event)list)`] ih in + let ih_pre = rand(rator(rator(snd(dest_imp(concl ih_inst))))) in + MATCH_MP_TAC ENSURES_PRECONDITION_THM THEN EXISTS_TAC ih_pre THEN CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + MP_TAC ih_inst THEN ANTS_TAC THENL + [ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THEN TRY ASM_ARITH_TAC; DISCH_THEN ACCEPT_TAC]])]]]]);; + +(* ========================================================================= *) +(* Final step-(b) pieces — *) +(* STORE4_CONTAINED_ETA4, LOAD1_CONTAINED_ETA4 (scalar 4B store / 1B load) *) +(* MEMACCESS_F_EV_SCALAR_BODY_ETA4, MEMACCESS_F_EV_SCALAR_TAIL_ETA4 *) +(* MLDSA_REJ_UNIFORM_ETA4_SCALAR_TAIL_AT_P_SAFE *) +(* Ports of the eta2 scalar-tail memaccess lemmas with eta4 constants (buf *) +(* 272, val<9, f_ev_scalar_{body,tail}_eta4, budget 272-p), plus the trivial *) +(* RUN-SAFE corollary. The eta4 STORE_CONTAINED/BUF_CONTAINED_ETA4 are 32B/16B *) +(* (SIMD), so the scalar 4B/1B helpers here are distinct new lemmas. *) +(* ========================================================================= *) + +(* 4-byte compaction store res + 4*cnt within [res,1024]: 4*255 + 4 = 1024. *) +let STORE4_CONTAINED_ETA4 = prove + (`!(res:int64) cnt. cnt <= 255 + ==> contained_modulo (2 EXP 64) + (val(word_add res (word(4 * cnt))),4) (val res,1024)`, + REPEAT STRIP_TAC THEN + GEN_REWRITE_TAC I [GSYM CONTAINED_MODULO_MOD2] THEN + REWRITE_TAC[VAL_WORD_ADD; VAL_WORD; DIMINDEX_64] THEN + CONV_TAC(ONCE_DEPTH_CONV MOD_DOWN_CONV) THEN + REWRITE_TAC[CONTAINED_MODULO_MOD2] THEN + MATCH_MP_TAC CONTAINED_MODULO_OFFSET_SIMPLE THEN ASM_ARITH_TAC);; + +(* 1-byte input load buf + p within [buf,272]: p < 272 ==> p + 1 <= 272. *) +let LOAD1_CONTAINED_ETA4 = prove + (`!(buf:int64) p. p < 272 + ==> contained_modulo (2 EXP 64) + (val(word_add buf (word p)),1) (val buf,272)`, + REPEAT STRIP_TAC THEN + GEN_REWRITE_TAC I [GSYM CONTAINED_MODULO_MOD2] THEN + REWRITE_TAC[VAL_WORD_ADD; VAL_WORD; DIMINDEX_64] THEN + CONV_TAC(ONCE_DEPTH_CONV MOD_DOWN_CONV) THEN + REWRITE_TAC[CONTAINED_MODULO_MOD2] THEN + MATCH_MP_TAC CONTAINED_MODULO_OFFSET_SIMPLE THEN ASM_ARITH_TAC);; + +(* per-byte body memaccess: the 4-branch COND of f_ev_scalar_body_eta4. *) +let MEMACCESS_F_EV_SCALAR_BODY_ETA4 = prove + (`!res buf table pc (inlist:byte list) p outlen0. + p < 272 /\ outlen0 <= 255 /\ + ~(outlen0 = 255 /\ val(EL p inlist) MOD 16 < 9) + ==> memaccess_inbounds (f_ev_scalar_body_eta4 res buf pc inlist p outlen0) + [(buf:int64),272; (table:int64),2048] [(res:int64),1024]`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN `val(word outlen0:int64) = outlen0` ASSUME_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN ASM_ARITH_TAC; + ALL_TAC] THEN + REWRITE_TAC[f_ev_scalar_body_eta4] THEN REPEAT COND_CASES_TAC THEN + ASM_REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND] THEN + REPEAT CONJ_TAC THEN + FIRST [MATCH_MP_TAC STORE4_CONTAINED_ETA4 THEN ASM_ARITH_TAC; + DISJ1_TAC THEN MATCH_MP_TAC LOAD1_CONTAINED_ETA4 THEN FIRST_ASSUM ACCEPT_TAC]);; + +(* the induction: every access in f_ev_scalar_tail_eta4 d @ p is in-bounds, + from the single public bound p+d<=272. *) +let MEMACCESS_F_EV_SCALAR_TAIL_ETA4 = prove + (`!d res buf table pc (inlist:byte list) p. + p + d <= 272 + ==> memaccess_inbounds (f_ev_scalar_tail_eta4 d res buf pc inlist p) + [(buf:int64),272; (table:int64),2048] [(res:int64),1024]`, + INDUCT_TAC THENL + [REPEAT GEN_TAC THEN STRIP_TAC THEN + REWRITE_TAC[f_ev_scalar_tail_eta4] THEN COND_CASES_TAC THEN + REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND]; + REPEAT GEN_TAC THEN STRIP_TAC THEN + REWRITE_TAC[f_ev_scalar_tail_eta4] THEN REPEAT COND_CASES_TAC THENL + [REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND]; + REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND]; + REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND] THEN REPEAT CONJ_TAC THEN + FIRST [REWRITE_TAC[ARITH_RULE `1020 = 4 * 255`] THEN + MATCH_MP_TAC STORE4_CONTAINED_ETA4 THEN ARITH_TAC; + DISJ1_TAC THEN MATCH_MP_TAC LOAD1_CONTAINED_ETA4 THEN ASM_ARITH_TAC]; + REWRITE_TAC[MEMACCESS_INBOUNDS_APPEND] THEN CONJ_TAC THENL + [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC; + MATCH_MP_TAC MEMACCESS_F_EV_SCALAR_BODY_ETA4 THEN REPEAT CONJ_TAC THENL + [ASM_ARITH_TAC; ASM_ARITH_TAC; FIRST_ASSUM ACCEPT_TAC]]]]);; + +(* trivial RUN-SAFE corollary at an arbitrary exit position p (budget 272-p). *) +let MLDSA_REJ_UNIFORM_ETA4_SCALAR_TAIL_AT_P_SAFE = + let rec conj_append_right t ev = + if is_conj t then + let l,r = dest_conj t in mk_conj(l, conj_append_right r ev) + else mk_conj(t, ev) in + let scalar_at_p_safe_eta4_tm = + let qvars, body = strip_forall (concl MLDSA_REJ_UNIFORM_ETA4_SCALAR_TAIL_AT_P) in + let hyps_tm, ens = dest_imp body in + let ensc, ppf = strip_comb ens in + let pre = el 1 ppf and post = el 2 ppf and frame = el 3 ppf in + let sv, preb = dest_abs pre in + let sv2, postb = dest_abs post in + let fev = `f_ev_scalar_tail_eta4 (272 - p) res buf pc (inlist:byte list) p` in + let eq_pre = `read events (s:x86state) = e` in + let eq_post = mk_eq(`read events (s:x86state)`, + mk_comb(mk_comb(`APPEND:(uarch_event)list->(uarch_event)list->(uarch_event)list`, fev), `e:(uarch_event)list`)) in + let pre' = mk_abs(sv, conj_append_right preb (vsubst[sv,`s:x86state`] eq_pre)) in + let post' = mk_abs(sv2, conj_append_right postb (vsubst[sv2,`s:x86state`] eq_post)) in + let ens' = list_mk_comb(ensc,[el 0 ppf; pre'; post'; frame]) in + list_mk_forall(qvars @ [`e:(uarch_event)list`], mk_imp(hyps_tm, ens')) in + prove + (scalar_at_p_safe_eta4_tm, + REPEAT STRIP_TAC THEN + MP_TAC(SPECL [`272 - p`; `res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`p:num`;`stackpointer:int64`;`e:(uarch_event)list`] SCALAR_TAIL_RUN_SAFE_ETA4) THEN + ASM_REWRITE_TAC[LE_REFL]);; + +(* ========================================================================== *) +(* Mid-exit sub-iteration event defs + memaccess lemmas — *) +(* f_ev_midexit_subiter{1..4}_eta4 + MEMACCESS_F_EV_MIDEXIT_SUBITER{1..4}_ETA4 *) +(* *) +(* Port of the eta2 mid-exit machinery. The midexit event defs are built *) +(* MECHANICALLY from f_ev_loop_eta4_def (the same index lists as eta2 — same *) +(* 19-event loop skeleton), so they inherit eta4's pcs automatically. The *) +(* MEMACCESS lemmas are pure value-algebra (store/load addresses only) over *) +(* the containment lemmas (STORE_CONTAINED, BUF_CONTAINED_ETA4, *) +(* GATHER_CONTAINED, TABLE_IDX_LT_256, NUM_ACCEPTED_PREFIX_MONO, *) +(* PACK_MASK8_MOD256). eta4 constants: buf window 272, head-guard bound *) +(* 16*i+16<=272 (vs eta2's 136). *) +(* ========================================================================== *) + +(* ---- def-builder machinery (f_ev_loop_eta2_def -> _eta4) ---- *) +let feld_mid_eta4 = SPEC_ALL f_ev_loop_eta4_def;; +let evs_mid_eta4 = dest_list (rand(concl feld_mid_eta4));; +let ejc_mid_eta4 = rator (el 0 evs_mid_eta4);; +let wtgt_mid_eta4 = fst(dest_pair(rand(el 0 evs_mid_eta4)));; +let midsrc_eta4 j = fst(dest_pair(rand(el j evs_mid_eta4)));; +let xover_eta4 src = mk_comb(ejc_mid_eta4, mk_pair(src, wtgt_mid_eta4));; +let evty_mid_eta4 = type_of (el 0 evs_mid_eta4);; +let midlist_eta4 idxs headx = + mk_list(headx :: map (fun j -> el j evs_mid_eta4) idxs, evty_mid_eta4);; +let mid_lhs_vars_eta4 = [`res:int64`;`buf:int64`;`table:int64`;`pc:num`;`mask:bool list`;`i:num`];; +let mkmiddef_eta4 name l = + let listty = type_of l in + let fnty = itlist (fun v ty -> mk_fun_ty (type_of v) ty) mid_lhs_vars_eta4 listty in + define(mk_eq(list_mk_comb(mk_var(name, fnty), mid_lhs_vars_eta4), l));; + +(* ---- the 4 midexit event defs (same index lists as eta2) ---- *) +let f_ev_midexit_subiter1_eta4 = + mkmiddef_eta4 "f_ev_midexit_subiter1_eta4" + (midlist_eta4 [13;14;15;16;17;18] (xover_eta4 (midsrc_eta4 12)));; +let f_ev_midexit_subiter2_eta4 = + mkmiddef_eta4 "f_ev_midexit_subiter2_eta4" + (midlist_eta4 [9;10;11;12;13;14;15;16;17;18] (xover_eta4 (midsrc_eta4 8)));; +let f_ev_midexit_subiter3_eta4 = + mkmiddef_eta4 "f_ev_midexit_subiter3_eta4" + (midlist_eta4 [5;6;7;8;9;10;11;12;13;14;15;16;17;18] (xover_eta4 (midsrc_eta4 4)));; +let f_ev_midexit_subiter4_eta4 = + mkmiddef_eta4 "f_ev_midexit_subiter4_eta4" + (midlist_eta4 [0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16;17;18] (xover_eta4 (midsrc_eta4 18)));; + +(* ---- memaccess core tac (port of eta2 MIDEXIT_MEMACC_CORE_TAC; + BUF_CONTAINED -> BUF_CONTAINED_ETA4) ---- *) +let MIDEXIT_MEMACC_CORE_TAC_ETA4 (def:thm) : tactic = + REWRITE_TAC[def; memaccess_inbounds; ALL; EX; FST; SND] THEN + ONCE_REWRITE_TAC[PACK_MASK8_MOD256] THEN + REPEAT CONJ_TAC THEN + FIRST + [MATCH_MP_TAC STORE_CONTAINED THEN FIRST_ASSUM ACCEPT_TAC; + DISJ1_TAC THEN MATCH_MP_TAC BUF_CONTAINED_ETA4 THEN FIRST_ASSUM ACCEPT_TAC; + DISJ2_TAC THEN MATCH_MP_TAC GATHER_CONTAINED THEN MATCH_ACCEPT_TAC TABLE_IDX_LT_256];; + +(* ---- the 4 MEMACCESS lemmas (buf 136->272, bound 16*i+16<=136 -> <=272) ---- *) +let MEMACCESS_F_EV_MIDEXIT_SUBITER1_ETA4 = prove + (`!res buf table pc mask i. + 16 * i + 16 <= 272 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * i) mask) <= 248 + ==> memaccess_inbounds (f_ev_midexit_subiter1_eta4 res buf table pc mask i) + [(buf:int64),272; (table:int64),2048] [(res:int64),1024]`, + REPEAT GEN_TAC THEN STRIP_TAC THEN MIDEXIT_MEMACC_CORE_TAC_ETA4 f_ev_midexit_subiter1_eta4);; + +let MEMACCESS_F_EV_MIDEXIT_SUBITER2_ETA4 = prove + (`!res buf table pc mask i. + 16 * i + 16 <= 272 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * i + 8) mask) <= 248 + ==> memaccess_inbounds (f_ev_midexit_subiter2_eta4 res buf table pc mask i) + [(buf:int64),272; (table:int64),2048] [(res:int64),1024]`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN `NUM_ACCEPTED (SUB_LIST (0,32 * i) mask) <= 248` ASSUME_TAC THENL + [TRANS_TAC LE_TRANS `NUM_ACCEPTED (SUB_LIST (0,32 * i + 8) mask)` THEN + ASM_REWRITE_TAC[] THEN MATCH_MP_TAC NUM_ACCEPTED_PREFIX_MONO THEN ARITH_TAC; ALL_TAC] THEN + MIDEXIT_MEMACC_CORE_TAC_ETA4 f_ev_midexit_subiter2_eta4);; + +let MEMACCESS_F_EV_MIDEXIT_SUBITER3_ETA4 = prove + (`!res buf table pc mask i. + 16 * i + 16 <= 272 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * i + 16) mask) <= 248 + ==> memaccess_inbounds (f_ev_midexit_subiter3_eta4 res buf table pc mask i) + [(buf:int64),272; (table:int64),2048] [(res:int64),1024]`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN + `NUM_ACCEPTED (SUB_LIST (0,32 * i) mask) <= 248 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * i + 8) mask) <= 248` + STRIP_ASSUME_TAC THENL + [CONJ_TAC THEN TRANS_TAC LE_TRANS `NUM_ACCEPTED (SUB_LIST (0,32 * i + 16) mask)` THEN + ASM_REWRITE_TAC[] THEN MATCH_MP_TAC NUM_ACCEPTED_PREFIX_MONO THEN ARITH_TAC; ALL_TAC] THEN + MIDEXIT_MEMACC_CORE_TAC_ETA4 f_ev_midexit_subiter3_eta4);; + +let MEMACCESS_F_EV_MIDEXIT_SUBITER4_ETA4 = prove + (`!res buf table pc mask i. + 16 * i + 16 <= 272 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * i + 24) mask) <= 248 + ==> memaccess_inbounds (f_ev_midexit_subiter4_eta4 res buf table pc mask i) + [(buf:int64),272; (table:int64),2048] [(res:int64),1024]`, + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN + `NUM_ACCEPTED (SUB_LIST (0,32 * i) mask) <= 248 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * i + 8) mask) <= 248 /\ + NUM_ACCEPTED (SUB_LIST (0,32 * i + 16) mask) <= 248` + STRIP_ASSUME_TAC THENL + [REPEAT CONJ_TAC THEN TRANS_TAC LE_TRANS `NUM_ACCEPTED (SUB_LIST (0,32 * i + 24) mask)` THEN + ASM_REWRITE_TAC[] THEN MATCH_MP_TAC NUM_ACCEPTED_PREFIX_MONO THEN ARITH_TAC; ALL_TAC] THEN + MIDEXIT_MEMACC_CORE_TAC_ETA4 f_ev_midexit_subiter4_eta4);; + +(* ========================================================================= *) +(* eta4 step-(e) cluster: mask-side scalar tail, f_ev_exit, and bridges. *) +(* ========================================================================= *) + +(* ------------------------------------------------------------------------- *) +(* MASK-SIDE scalar-tail cluster (prerequisite for f_ev_exit_eta4). *) +(* ------------------------------------------------------------------------- *) + +(* --- generic nibble helpers (reproved inline here) --- *) +let LENGTH_NIBBLES_OF_BYTES = prove + (`!l:byte list. LENGTH(NIBBLES_OF_BYTES l) = 2 * LENGTH l`, + LIST_INDUCT_TAC THEN + ASM_REWRITE_TAC[NIBBLES_OF_BYTES; NIBBLE_PAIR; LENGTH; LENGTH_APPEND] THEN + ARITH_TAC);; + +let EL_NIBBLES_OF_BYTES = prove + (`!(l:byte list) p. p < LENGTH l + ==> EL (2*p) (NIBBLES_OF_BYTES l) = (word(val(EL p l) MOD 16):int16) /\ + EL (2*p+1) (NIBBLES_OF_BYTES l) = (word(val(EL p l) DIV 16):int16)`, + LIST_INDUCT_TAC THENL + [REWRITE_TAC[LENGTH; LT]; + GEN_TAC THEN REWRITE_TAC[LENGTH] THEN + STRUCT_CASES_TAC(SPEC `p:num` num_CASES) THEN + REWRITE_TAC[NIBBLES_OF_BYTES; NIBBLE_PAIR; APPEND] THENL + [REWRITE_TAC[ARITH_RULE `2 * 0 = 0`; ARITH_RULE `2 * 0 + 1 = SUC 0`; + EL; HD; TL]; + REWRITE_TAC[LT_SUC] THEN DISCH_TAC THEN + REWRITE_TAC[ARITH_RULE `2 * SUC n = SUC(SUC(2*n))`; + ARITH_RULE `2 * SUC n + 1 = SUC(SUC(2*n+1))`; + EL; TL; HD] THEN + FIRST_X_ASSUM(MP_TAC o SPEC `n:num`) THEN ASM_REWRITE_TAC[]]]);; + +(* --- REJ_MASK_EL_ETA4: linchpin nibble<->mask-bit bridge (val<9) --- *) +let REJ_MASK_EL_ETA4 = prove + (`!(l:byte list) p. p < LENGTH l + ==> (EL (2*p) (REJ_MASK_ETA4 l) <=> val(EL p l) MOD 16 < 9) /\ + (EL (2*p+1) (REJ_MASK_ETA4 l) <=> val(EL p l) DIV 16 < 9)`, + REPEAT GEN_TAC THEN DISCH_TAC THEN + MP_TAC(SPECL [`l:byte list`; `p:num`] EL_NIBBLES_OF_BYTES) THEN + ASM_REWRITE_TAC[] THEN STRIP_TAC THEN + REWRITE_TAC[REJ_MASK_ETA4] THEN + SUBGOAL_THEN `2 * p < LENGTH(NIBBLES_OF_BYTES(l:byte list)) /\ + 2 * p + 1 < LENGTH(NIBBLES_OF_BYTES(l:byte list))` STRIP_ASSUME_TAC THENL + [REWRITE_TAC[LENGTH_NIBBLES_OF_BYTES] THEN + UNDISCH_TAC `p < LENGTH(l:byte list)` THEN ARITH_TAC; ALL_TAC] THEN + ASM_SIMP_TAC[EL_MAP] THEN ASM_REWRITE_TAC[] THEN + MP_TAC(ISPEC `EL p (l:byte list)` VAL_BOUND) THEN REWRITE_TAC[DIMINDEX_8] THEN + DISCH_TAC THEN + MP_TAC(SPECL [`val(EL p (l:byte list))`; `16`] DIVISION) THEN + ANTS_TAC THENL [ARITH_TAC; ALL_TAC] THEN STRIP_TAC THEN + SUBGOAL_THEN + `val(word(val(EL p (l:byte list)) MOD 16):int16) = val(EL p l) MOD 16 /\ + val(word(val(EL p (l:byte list)) DIV 16):int16) = val(EL p l) DIV 16` + STRIP_ASSUME_TAC THENL + [CONJ_TAC THEN REWRITE_TAC[VAL_WORD; DIMINDEX_16] THEN MATCH_MP_TAC MOD_LT THEN + CONV_TAC(RAND_CONV NUM_REDUCE_CONV) THEN ASM_ARITH_TAC; + ASM_REWRITE_TAC[]]);; + +(* --- f_ev_scalar_body_mask_eta4 by term-surgery on f_ev_scalar_body_eta4 --- *) +let newrhs_body_eta4 = + let eqn = snd(strip_forall(concl f_ev_scalar_body_eta4)) in + let _,rhs = dest_eq eqn in + let condlo = `val(EL p (inlist:byte list)) MOD 16 < 9` in + let condhi = `val(EL p (inlist:byte list)) DIV 16 < 9` in + subst [`EL (2*p) (mask:bool list)`, condlo; + `EL (2*p+1) (mask:bool list)`, condhi] rhs;; + +let f_ev_scalar_body_mask_eta4 = + let fty = `:int64->int64->num->(bool)list->num->num->(uarch_event)list` in + let hd = mk_var("f_ev_scalar_body_mask_eta4", fty) in + let lhs = list_mk_comb(hd, [`res:int64`;`buf:int64`;`pc:num`; + `mask:bool list`;`p:num`;`outlen0:num`]) in + define (mk_eq(lhs, newrhs_body_eta4));; + +let FEV_SCALAR_BODY_MASK_ETA4 = prove + (`!res buf pc (inlist:byte list) p outlen0. + p < LENGTH inlist + ==> f_ev_scalar_body_eta4 res buf pc inlist p outlen0 = + f_ev_scalar_body_mask_eta4 res buf pc (REJ_MASK_ETA4 inlist) p outlen0`, + REPEAT STRIP_TAC THEN + REWRITE_TAC[f_ev_scalar_body_eta4; f_ev_scalar_body_mask_eta4] THEN + ASM_SIMP_TAC[REJ_MASK_EL_ETA4]);; + +(* --- f_ev_scalar_tail_mask_eta4: recursive mask-form of f_ev_scalar_tail_eta4 --- *) +let f_ev_scalar_tail_mask_eta4 = define + `(f_ev_scalar_tail_mask_eta4 0 (res:int64) (buf:int64) (pc:num) (mask:bool list) (p:num) = + (if 256 <= NUM_ACCEPTED(SUB_LIST(0,2*p) mask) + then [EventJump (word (pc + 321),word (pc + 402))] + else [EventJump (word (pc + 329),word (pc + 402)); + EventJump (word (pc + 321),word (pc + 321))])) /\ + (f_ev_scalar_tail_mask_eta4 (SUC d) (res:int64) (buf:int64) (pc:num) (mask:bool list) (p:num) = + (if 256 <= NUM_ACCEPTED(SUB_LIST(0,2*p) mask) + then [EventJump (word (pc + 321),word (pc + 402))] + else if p = 272 + then [EventJump (word (pc + 329),word (pc + 402)); + EventJump (word (pc + 321),word (pc + 321))] + else if NUM_ACCEPTED(SUB_LIST(0,2*p) mask) = 255 /\ EL (2*p) mask + then [EventJump (word (pc + 371),word (pc + 402)); + EventStore (word_add res (word 1020),4); + EventJump (word (pc + 349),word (pc + 349)); + EventLoad (word_add buf (word p),1); + EventJump (word (pc + 329),word (pc + 329)); + EventJump (word (pc + 321),word (pc + 321))] + else APPEND (f_ev_scalar_tail_mask_eta4 d res buf pc mask (p+1)) + (f_ev_scalar_body_mask_eta4 res buf pc mask p + (NUM_ACCEPTED(SUB_LIST(0,2*p) mask)))))`;; + +let FEV_SCALAR_TAIL_MASK_ETA4 = prove + (`!d res buf pc (inlist:byte list) p. + LENGTH inlist = 272 /\ p <= 272 + ==> f_ev_scalar_tail_eta4 d res buf pc inlist p = + f_ev_scalar_tail_mask_eta4 d res buf pc (REJ_MASK_ETA4 inlist) p`, + INDUCT_TAC THEN REPEAT GEN_TAC THEN STRIP_TAC THENL + [REWRITE_TAC[f_ev_scalar_tail_eta4; f_ev_scalar_tail_mask_eta4; STORE_BRIDGE_ETA4]; + ASM_CASES_TAC `p = 272` THENL + [ASM_REWRITE_TAC[f_ev_scalar_tail_eta4; f_ev_scalar_tail_mask_eta4; STORE_BRIDGE_ETA4]; + SUBGOAL_THEN `p < LENGTH(inlist:byte list) /\ p + 1 <= 272` STRIP_ASSUME_TAC THENL + [ASM_ARITH_TAC; ALL_TAC] THEN + REWRITE_TAC[f_ev_scalar_tail_eta4; f_ev_scalar_tail_mask_eta4] THEN + REWRITE_TAC[STORE_BRIDGE_ETA4] THEN + SUBGOAL_THEN + `f_ev_scalar_tail_eta4 d res buf pc inlist (p+1) = + f_ev_scalar_tail_mask_eta4 d res buf pc (REJ_MASK_ETA4 inlist) (p+1)` + SUBST1_TAC THENL + [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN + ASM_SIMP_TAC[REJ_MASK_EL_ETA4; FEV_SCALAR_BODY_MASK_ETA4]]]);; + +(* --- mask-side memaccess (window [buf,272;table,2048][res,1024]) --- *) +let MEMACCESS_F_EV_SCALAR_BODY_MASK_ETA4 = prove + (`!res buf table pc (mask:bool list) p outlen0. + p < 272 /\ outlen0 <= 255 /\ + ~(outlen0 = 255 /\ EL (2 * p) mask) + ==> memaccess_inbounds (f_ev_scalar_body_mask_eta4 res buf pc mask p outlen0) + [(buf:int64),272; (table:int64),2048] [(res:int64),1024]`, + REPEAT STRIP_TAC THEN + SUBGOAL_THEN `val(word outlen0:int64) = outlen0` ASSUME_TAC THENL + [MATCH_MP_TAC VAL_WORD_EQ THEN REWRITE_TAC[DIMINDEX_64] THEN ASM_ARITH_TAC; + ALL_TAC] THEN + REWRITE_TAC[f_ev_scalar_body_mask_eta4] THEN REPEAT COND_CASES_TAC THEN + ASM_REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND] THEN + REPEAT CONJ_TAC THEN + FIRST + [DISJ1_TAC THEN MATCH_MP_TAC LOAD1_CONTAINED_ETA4 THEN FIRST_ASSUM ACCEPT_TAC; + MATCH_MP_TAC STORE4_CONTAINED_ETA4 THEN + TRY(FIRST_X_ASSUM + ((fun th -> MP_TAC th THEN ASM_REWRITE_TAC[]) o + check (fun th -> is_neg(concl th) && is_conj(rand(concl th))))) THEN + ASM_ARITH_TAC]);; + +let MEMACCESS_F_EV_SCALAR_TAIL_MASK_ETA4 = prove + (`!d res buf table pc (mask:bool list) p. + p + d <= 272 + ==> memaccess_inbounds (f_ev_scalar_tail_mask_eta4 d res buf pc mask p) + [(buf:int64),272; (table:int64),2048] [(res:int64),1024]`, + INDUCT_TAC THENL + [REPEAT GEN_TAC THEN STRIP_TAC THEN + REWRITE_TAC[f_ev_scalar_tail_mask_eta4] THEN COND_CASES_TAC THEN + REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND]; + REPEAT GEN_TAC THEN STRIP_TAC THEN + REWRITE_TAC[f_ev_scalar_tail_mask_eta4] THEN REPEAT COND_CASES_TAC THENL + [REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND]; + REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND]; + REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND] THEN REPEAT CONJ_TAC THEN + FIRST [REWRITE_TAC[ARITH_RULE `1020 = 4 * 255`] THEN + MATCH_MP_TAC STORE4_CONTAINED_ETA4 THEN ARITH_TAC; + DISJ1_TAC THEN MATCH_MP_TAC LOAD1_CONTAINED_ETA4 THEN ASM_ARITH_TAC]; + REWRITE_TAC[MEMACCESS_INBOUNDS_APPEND] THEN CONJ_TAC THENL + [FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_ARITH_TAC; + MATCH_MP_TAC MEMACCESS_F_EV_SCALAR_BODY_MASK_ETA4 THEN REPEAT CONJ_TAC THENL + [ASM_ARITH_TAC; ASM_ARITH_TAC; FIRST_ASSUM ACCEPT_TAC]]]]);; + +(* --- headguard memaccess (jumps-only, trivial) --- *) +let MEMACCESS_F_EV_HEADGUARD_ETA4 = prove + (`!pc rr wr. memaccess_inbounds (f_ev_headguard_eta4 pc) rr wr`, + REWRITE_TAC[f_ev_headguard_eta4; memaccess_inbounds; ALL; EX; FST; SND]);; + +(* ------------------------------------------------------------------------- *) +(* step (e) sub-step 1: f_ev_exit_eta4 + MEMACCESS_F_EV_EXIT_ETA4. *) +(* ------------------------------------------------------------------------- *) + +let f_ev_exit_eta4 = define + `f_ev_exit_eta4 (res:int64) (buf:int64) (table:int64) (pc:num) (mask:bool list) (N:num) + : (uarch_event)list = + if NUM_ACCEPTED(SUB_LIST(0,32 * N) mask) <= 248 + then APPEND (f_ev_scalar_tail_mask_eta4 (272 - 16 * N) res buf pc mask (16 * N)) + (APPEND (f_ev_headguard_eta4 pc) + (f_ev_loop_eta4 res buf table pc mask (N-1))) + else if NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8) mask) <= 248 + then (if NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16) mask) <= 248 + then (if NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 24) mask) <= 248 + then APPEND (f_ev_scalar_tail_mask_eta4 (272 - 16 * N) res buf pc mask (16 * N)) + (f_ev_midexit_subiter4_eta4 res buf table pc mask (N-1)) + else APPEND (f_ev_scalar_tail_mask_eta4 (272 - (16 * (N-1) + 12)) res buf pc mask + (16 * (N-1) + 12)) + (f_ev_midexit_subiter3_eta4 res buf table pc mask (N-1))) + else APPEND (f_ev_scalar_tail_mask_eta4 (272 - (16 * (N-1) + 8)) res buf pc mask + (16 * (N-1) + 8)) + (f_ev_midexit_subiter2_eta4 res buf table pc mask (N-1))) + else APPEND (f_ev_scalar_tail_mask_eta4 (272 - (16 * (N-1) + 4)) res buf pc mask + (16 * (N-1) + 4)) + (f_ev_midexit_subiter1_eta4 res buf table pc mask (N-1))`;; + +let MEMACCESS_F_EV_EXIT_ETA4 = prove + (`!res buf table pc (mask:bool list) N. + 16 * N <= 272 /\ ~(N = 0) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1)) mask) <= 248 + ==> memaccess_inbounds (f_ev_exit_eta4 res buf table pc mask N) + [(buf:int64),272; (table:int64),2048] [(res:int64),1024]`, + REPEAT STRIP_TAC THEN REWRITE_TAC[f_ev_exit_eta4] THEN + REPEAT COND_CASES_TAC THEN + REWRITE_TAC[MEMACCESS_INBOUNDS_APPEND] THEN REPEAT CONJ_TAC THEN + FIRST + [MATCH_MP_TAC MEMACCESS_F_EV_SCALAR_TAIL_MASK_ETA4 THEN ASM_ARITH_TAC; + MATCH_ACCEPT_TAC MEMACCESS_F_EV_HEADGUARD_ETA4; + MATCH_MP_TAC MEMACCESS_F_EV_LOOP_ETA4 THEN CONJ_TAC THENL + [ASM_ARITH_TAC; + MATCH_MP_TAC LE_TRANS THEN + EXISTS_TAC `NUM_ACCEPTED(SUB_LIST(0,32 * N) (mask:bool list))` THEN + CONJ_TAC THENL + [MATCH_MP_TAC NUM_ACCEPTED_PREFIX_MONO THEN ASM_ARITH_TAC; + FIRST_ASSUM ACCEPT_TAC]]; + MATCH_MP_TAC MEMACCESS_F_EV_MIDEXIT_SUBITER1_ETA4 THEN + CONJ_TAC THENL [ASM_ARITH_TAC; FIRST_ASSUM ACCEPT_TAC]; + MATCH_MP_TAC MEMACCESS_F_EV_MIDEXIT_SUBITER2_ETA4 THEN + CONJ_TAC THENL [ASM_ARITH_TAC; FIRST_ASSUM ACCEPT_TAC]; + MATCH_MP_TAC MEMACCESS_F_EV_MIDEXIT_SUBITER3_ETA4 THEN + CONJ_TAC THENL [ASM_ARITH_TAC; FIRST_ASSUM ACCEPT_TAC]; + MATCH_MP_TAC MEMACCESS_F_EV_MIDEXIT_SUBITER4_ETA4 THEN + CONJ_TAC THENL [ASM_ARITH_TAC; FIRST_ASSUM ACCEPT_TAC]]);; + +(* ------------------------------------------------------------------------- *) +(* step (e) sub-step 2: 5 events-bridges + 5 EXISTS helpers. *) +(* ------------------------------------------------------------------------- *) + +let OFFSET_EVENTS_BRIDGE_ETA4 = prove + (`!res buf table (inlist:byte list) pc N e. + LENGTH inlist = 272 /\ 16 * N = 272 /\ + NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA4 inlist)) <= 248 + ==> APPEND (f_ev_scalar_tail_eta4 (272 - 272) res buf pc inlist 272) + (APPEND (f_ev_headguard_eta4 pc) + (APPEND (f_ev_loop_eta4 res buf table pc + (REJ_MASK_ETA4 (inlist:byte list)) (N-1)) + (e:(uarch_event)list))) + = APPEND (f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 inlist) N) e`, + REPEAT STRIP_TAC THEN REWRITE_TAC[f_ev_exit_eta4] THEN + ASM_REWRITE_TAC[COND_CLAUSES] THEN + MP_TAC(SPECL [`272 - 272`;`res:int64`;`buf:int64`;`pc:num`;`inlist:byte list`;`272`] + FEV_SCALAR_TAIL_MASK_ETA4) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN + REWRITE_TAC[APPEND_ASSOC]);; + +let MIDEXIT1_EVENTS_BRIDGE_ETA4 = prove + (`!res buf table (inlist:byte list) pc N e. + LENGTH inlist = 272 /\ 16 * N <= 272 /\ ~(N = 0) /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA4 inlist)) <= 248) /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA4 inlist)) <= 248) + ==> APPEND (f_ev_scalar_tail_eta4 (272 - (16 * (N-1) + 4)) res buf pc inlist (16 * (N-1) + 4)) + (APPEND (f_ev_midexit_subiter1_eta4 res buf table pc (REJ_MASK_ETA4 inlist) (N-1)) + (e:(uarch_event)list)) + = APPEND (f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 inlist) N) e`, + REPEAT STRIP_TAC THEN REWRITE_TAC[f_ev_exit_eta4] THEN + ASM_REWRITE_TAC[COND_CLAUSES] THEN + MP_TAC(SPECL [`272 - (16 * (N-1) + 4)`;`res:int64`;`buf:int64`;`pc:num`;`inlist:byte list`; + `16 * (N-1) + 4`] FEV_SCALAR_TAIL_MASK_ETA4) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[APPEND_ASSOC]);; + +let MIDEXIT2_EVENTS_BRIDGE_ETA4 = prove + (`!res buf table (inlist:byte list) pc N e. + LENGTH inlist = 272 /\ 16 * N <= 272 /\ ~(N = 0) /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA4 inlist)) <= 248) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA4 inlist)) <= 248 /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA4 inlist)) <= 248) + ==> APPEND (f_ev_scalar_tail_eta4 (272 - (16 * (N-1) + 8)) res buf pc inlist (16 * (N-1) + 8)) + (APPEND (f_ev_midexit_subiter2_eta4 res buf table pc (REJ_MASK_ETA4 inlist) (N-1)) + (e:(uarch_event)list)) + = APPEND (f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 inlist) N) e`, + REPEAT STRIP_TAC THEN REWRITE_TAC[f_ev_exit_eta4] THEN + ASM_REWRITE_TAC[COND_CLAUSES] THEN + MP_TAC(SPECL [`272 - (16 * (N-1) + 8)`;`res:int64`;`buf:int64`;`pc:num`;`inlist:byte list`; + `16 * (N-1) + 8`] FEV_SCALAR_TAIL_MASK_ETA4) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[APPEND_ASSOC]);; + +let MIDEXIT3_EVENTS_BRIDGE_ETA4 = prove + (`!res buf table (inlist:byte list) pc N e. + LENGTH inlist = 272 /\ 16 * N <= 272 /\ ~(N = 0) /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA4 inlist)) <= 248) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA4 inlist)) <= 248 /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA4 inlist)) <= 248 /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 24)(REJ_MASK_ETA4 inlist)) <= 248) + ==> APPEND (f_ev_scalar_tail_eta4 (272 - (16 * (N-1) + 12)) res buf pc inlist (16 * (N-1) + 12)) + (APPEND (f_ev_midexit_subiter3_eta4 res buf table pc (REJ_MASK_ETA4 inlist) (N-1)) + (e:(uarch_event)list)) + = APPEND (f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 inlist) N) e`, + REPEAT STRIP_TAC THEN REWRITE_TAC[f_ev_exit_eta4] THEN + ASM_REWRITE_TAC[COND_CLAUSES] THEN + MP_TAC(SPECL [`272 - (16 * (N-1) + 12)`;`res:int64`;`buf:int64`;`pc:num`;`inlist:byte list`; + `16 * (N-1) + 12`] FEV_SCALAR_TAIL_MASK_ETA4) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[APPEND_ASSOC]);; + +let MIDEXIT4_EVENTS_BRIDGE_ETA4 = prove + (`!res buf table (inlist:byte list) pc N e. + LENGTH inlist = 272 /\ 16 * N <= 272 /\ ~(N = 0) /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA4 inlist)) <= 248) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA4 inlist)) <= 248 /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA4 inlist)) <= 248 /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 24)(REJ_MASK_ETA4 inlist)) <= 248 + ==> APPEND (f_ev_scalar_tail_eta4 (272 - 16 * N) res buf pc inlist (16 * N)) + (APPEND (f_ev_midexit_subiter4_eta4 res buf table pc (REJ_MASK_ETA4 inlist) (N-1)) + (e:(uarch_event)list)) + = APPEND (f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 inlist) N) e`, + REPEAT STRIP_TAC THEN REWRITE_TAC[f_ev_exit_eta4] THEN + ASM_REWRITE_TAC[COND_CLAUSES] THEN + MP_TAC(SPECL [`272 - 16 * N`;`res:int64`;`buf:int64`;`pc:num`;`inlist:byte list`; + `16 * N`] FEV_SCALAR_TAIL_MASK_ETA4) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC; ALL_TAC] THEN + DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[APPEND_ASSOC]);; + +(* ---- EXISTS helpers: package the CT existential post ---- *) +let OFFSET_EXISTS_ETA4 = prove + (`!res buf table (inlist:byte list) pc N (e:(uarch_event)list) s. + LENGTH inlist = 272 /\ 16 * N = 272 /\ ~(N = 0) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA4 inlist)) <= 248 /\ + read events s = + APPEND (f_ev_scalar_tail_eta4 (272 - 272) res buf pc inlist 272) + (APPEND (f_ev_headguard_eta4 pc) + (APPEND (f_ev_loop_eta4 res buf table pc + (REJ_MASK_ETA4 inlist) (N-1)) e)) + ==> ?e2. read events s = APPEND e2 e /\ + e2 = f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 inlist) N /\ + memaccess_inbounds e2 [(buf:int64),272; (table:int64),2048] [(res:int64),1024]`, + REPEAT STRIP_TAC THEN + EXISTS_TAC `f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 inlist) N` THEN + REPEAT CONJ_TAC THENL + [ONCE_ASM_REWRITE_TAC[] THEN MATCH_MP_TAC OFFSET_EVENTS_BRIDGE_ETA4 THEN ASM_REWRITE_TAC[]; + REFL_TAC; + MATCH_MP_TAC MEMACCESS_F_EV_EXIT_ETA4 THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL + [ASM_ARITH_TAC; + MATCH_MP_TAC LE_TRANS THEN + EXISTS_TAC `NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA4 inlist))` THEN + CONJ_TAC THENL + [MATCH_MP_TAC NUM_ACCEPTED_PREFIX_MONO THEN ARITH_TAC; + FIRST_ASSUM ACCEPT_TAC]]]);; + +let MIDEXIT1_EXISTS_ETA4 = prove + (`!res buf table (inlist:byte list) pc N (e:(uarch_event)list) s. + LENGTH inlist = 272 /\ 16 * N <= 272 /\ ~(N = 0) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1))(REJ_MASK_ETA4 inlist)) <= 248 /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA4 inlist)) <= 248) /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA4 inlist)) <= 248) /\ + read events s = + APPEND (f_ev_scalar_tail_eta4 (272 - (16 * (N-1) + 4)) res buf pc inlist (16 * (N-1) + 4)) + (APPEND (f_ev_midexit_subiter1_eta4 res buf table pc (REJ_MASK_ETA4 inlist) (N-1)) e) + ==> ?e2. read events s = APPEND e2 e /\ + e2 = f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 inlist) N /\ + memaccess_inbounds e2 [(buf:int64),272; (table:int64),2048] [(res:int64),1024]`, + REPEAT STRIP_TAC THEN + EXISTS_TAC `f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 inlist) N` THEN + REPEAT CONJ_TAC THENL + [ONCE_ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MIDEXIT1_EVENTS_BRIDGE_ETA4 THEN ASM_REWRITE_TAC[]; + REFL_TAC; + MATCH_MP_TAC MEMACCESS_F_EV_EXIT_ETA4 THEN ASM_REWRITE_TAC[]]);; + +let MIDEXIT2_EXISTS_ETA4 = prove + (`!res buf table (inlist:byte list) pc N (e:(uarch_event)list) s. + LENGTH inlist = 272 /\ 16 * N <= 272 /\ ~(N = 0) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1))(REJ_MASK_ETA4 inlist)) <= 248 /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA4 inlist)) <= 248) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA4 inlist)) <= 248 /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA4 inlist)) <= 248) /\ + read events s = + APPEND (f_ev_scalar_tail_eta4 (272 - (16 * (N-1) + 8)) res buf pc inlist (16 * (N-1) + 8)) + (APPEND (f_ev_midexit_subiter2_eta4 res buf table pc (REJ_MASK_ETA4 inlist) (N-1)) e) + ==> ?e2. read events s = APPEND e2 e /\ + e2 = f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 inlist) N /\ + memaccess_inbounds e2 [(buf:int64),272; (table:int64),2048] [(res:int64),1024]`, + REPEAT STRIP_TAC THEN + EXISTS_TAC `f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 inlist) N` THEN + REPEAT CONJ_TAC THENL + [ONCE_ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MIDEXIT2_EVENTS_BRIDGE_ETA4 THEN ASM_REWRITE_TAC[]; + REFL_TAC; + MATCH_MP_TAC MEMACCESS_F_EV_EXIT_ETA4 THEN ASM_REWRITE_TAC[]]);; + +let MIDEXIT3_EXISTS_ETA4 = prove + (`!res buf table (inlist:byte list) pc N (e:(uarch_event)list) s. + LENGTH inlist = 272 /\ 16 * N <= 272 /\ ~(N = 0) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1))(REJ_MASK_ETA4 inlist)) <= 248 /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA4 inlist)) <= 248) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA4 inlist)) <= 248 /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA4 inlist)) <= 248 /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 24)(REJ_MASK_ETA4 inlist)) <= 248) /\ + read events s = + APPEND (f_ev_scalar_tail_eta4 (272 - (16 * (N-1) + 12)) res buf pc inlist (16 * (N-1) + 12)) + (APPEND (f_ev_midexit_subiter3_eta4 res buf table pc (REJ_MASK_ETA4 inlist) (N-1)) e) + ==> ?e2. read events s = APPEND e2 e /\ + e2 = f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 inlist) N /\ + memaccess_inbounds e2 [(buf:int64),272; (table:int64),2048] [(res:int64),1024]`, + REPEAT STRIP_TAC THEN + EXISTS_TAC `f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 inlist) N` THEN + REPEAT CONJ_TAC THENL + [ONCE_ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MIDEXIT3_EVENTS_BRIDGE_ETA4 THEN ASM_REWRITE_TAC[]; + REFL_TAC; + MATCH_MP_TAC MEMACCESS_F_EV_EXIT_ETA4 THEN ASM_REWRITE_TAC[]]);; + +let MIDEXIT4_EXISTS_ETA4 = prove + (`!res buf table (inlist:byte list) pc N (e:(uarch_event)list) s. + LENGTH inlist = 272 /\ 16 * N <= 272 /\ ~(N = 0) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1))(REJ_MASK_ETA4 inlist)) <= 248 /\ + ~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA4 inlist)) <= 248) /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA4 inlist)) <= 248 /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA4 inlist)) <= 248 /\ + NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 24)(REJ_MASK_ETA4 inlist)) <= 248 /\ + read events s = + APPEND (f_ev_scalar_tail_eta4 (272 - 16 * N) res buf pc inlist (16 * N)) + (APPEND (f_ev_midexit_subiter4_eta4 res buf table pc (REJ_MASK_ETA4 inlist) (N-1)) e) + ==> ?e2. read events s = APPEND e2 e /\ + e2 = f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 inlist) N /\ + memaccess_inbounds e2 [(buf:int64),272; (table:int64),2048] [(res:int64),1024]`, + REPEAT STRIP_TAC THEN + EXISTS_TAC `f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 inlist) N` THEN + REPEAT CONJ_TAC THENL + [ONCE_ASM_REWRITE_TAC[] THEN MATCH_MP_TAC MIDEXIT4_EVENTS_BRIDGE_ETA4 THEN ASM_REWRITE_TAC[]; + REFL_TAC; + MATCH_MP_TAC MEMACCESS_F_EV_EXIT_ETA4 THEN ASM_REWRITE_TAC[]]);; + +(* ========================================================================= *) +(* eta4 rej_uniform constant-time (SAFE) cluster. Mirrors the eta2 SAFE *) +(* cluster. Prereq: the rip_mp else-branch structural read-RIP guard above. *) +(* Depends only on the eta4 machinery (mk_prefix_g_full, mk_midexit1..4, *) +(* mk_mg*_nt, SI*_*, bridges, f_ev_*, *_EXISTS_ETA4, *_EVENTS_BRIDGE_ETA4, *) +(* MEMSAFE chain, trip lemmas) + the guarded rip_mp. *) +(* ========================================================================= *) + +(* SAFE-midexit machinery (variants that shadow the MEMSAFE machinery above): *) +(* mk_midexit2 tail + mk_mg2/mg3_nt / SI4_BODY4 / mk_si2_mg2_taken / *) +(* mk_si3_mg3_taken differ from the MEMSAFE versions used above. They close *) +(* over the P1-guarded rip_mp. mk_midexit1 is not re-lifted (the MEMSAFE one *) +(* is directly correct). *) +let mk_mg1_nt (memsafe:bool) : tactic = + W(fun (asl,w) -> + let r9 = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("read",_),Const("R9",_)),Var("s21",_))),_) -> true | _ -> false) asl in + let goal_pc = find_term (fun t -> match t with Comb(Const("word_popcount",_),_) -> true | _ -> false) (concl(snd r9)) in + let low8 = `bitval(bit 7 (word_subword (f1bnd:int256) (0,8):byte)) + bitval(bit 7 (word_subword f1bnd (8,8):byte)) + + bitval(bit 7 (word_subword f1bnd (16,8):byte)) + bitval(bit 7 (word_subword f1bnd (24,8):byte)) + + bitval(bit 7 (word_subword f1bnd (32,8):byte)) + bitval(bit 7 (word_subword f1bnd (40,8):byte)) + + bitval(bit 7 (word_subword f1bnd (48,8):byte)) + bitval(bit 7 (word_subword f1bnd (56,8):byte))` in + let mr = CONV_RULE(DEPTH_CONV BETA_CONV THENC NUM_REDUCE_CONV) + (SPEC `\k. bit 7 (word_subword (f1bnd:int256) (8*k,8):byte)` MOD_RED) in + let popeq = prove(mk_eq(goal_pc, low8), + REWRITE_TAC[VAL_WORD_ZX_GEN; VAL_WORD; DIMINDEX_8; DIMINDEX_32; DIMINDEX_64] THEN + REWRITE_TAC[ARITH_RULE `256 = 2 EXP 8`; MOD_MOD_EXP_MIN] THEN + CONV_TAC(ONCE_DEPTH_CONV NUM_REDUCE_CONV) THEN + REWRITE_TAC[ARITH_RULE `2 EXP 8 = 256`; mr] THEN + MAP_EVERY (fun b -> BOOL_CASES_TAC b) + [`bit 7 (word_subword (f1bnd:int256) (0,8):byte)`;`bit 7 (word_subword (f1bnd:int256) (8,8):byte)`; + `bit 7 (word_subword (f1bnd:int256) (16,8):byte)`;`bit 7 (word_subword (f1bnd:int256) (24,8):byte)`; + `bit 7 (word_subword (f1bnd:int256) (32,8):byte)`;`bit 7 (word_subword (f1bnd:int256) (40,8):byte)`; + `bit 7 (word_subword (f1bnd:int256) (48,8):byte)`;`bit 7 (word_subword (f1bnd:int256) (56,8):byte)`] THEN + REWRITE_TAC[BITVAL_CLAUSES] THEN CONV_TAC NUM_REDUCE_CONV THEN CONV_TAC WORD_REDUCE_CONV) in + let maskbit = snd(find (fun (_,th) -> let c=concl th in is_forall c && + can(find_term(fun u->u=`f1bnd:int256`))c && can(find_term(fun u->match u with Comb(Const("bit",_),_)->true|_->false))c && + not(can(find_term(fun u->match u with Const("word_zx",_)->true|_->false))c) && + can(find_term(fun u->u=`word_subword (chunk0:int128) (24,8):byte`))c && + not(can(find_term(fun u->u=`word_subword (chunk0:int128) (32,8):byte`))c)) asl) in + let mb_tm = concl maskbit in + let blk0 = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),l),_) -> (try let h,args=strip_comb l in fst(dest_const h)="SUB_LIST" && + (match args with [Comb(Comb(_,off),wid);_] -> wid=`4` && (match off with Comb(Comb(Const("*",_),_),_)->true|_->false) | _->false) with _->false) | _ -> false) asl in + let blkeq = mk_eq(low8, `LENGTH(REJ_NIBBLES_ETA4 (SUB_LIST(16*i,4) inlist):int16 list)`) in + let blk0_tm = concl(snd blk0) in + let bsum_raw = prove(mk_imp(mb_tm, mk_imp(blk0_tm, blkeq)), + DISCH_THEN(fun mbthm -> + let mbs = map (fun k -> let th=SPEC(mk_small_numeral k) mbthm in + CONV_RULE (NUM_REDUCE_CONV THENC ONCE_DEPTH_CONV EL_CONV) (MP th (EQT_ELIM(NUM_REDUCE_CONV(lhand(concl th)))))) [0;1;2;3;4;5;6;7] in + REWRITE_TAC mbs) THEN DISCH_THEN(fun b -> REWRITE_TAC[b]) THEN + GEN_REWRITE_TAC RAND_CONV [GSYM LENGTH_FILTER_BYTE_NIBBLES_4_BYTES] THEN + REWRITE_TAC[GSYM BITVAL_SUM_8_EQ_LENGTH_FILTER] THEN + ASM_SIMP_TAC[VAL_WORD_BYTE_LT256; BYTE_DIV16_LT; BYTE_MOD16_LT]) in + let bsum = MP (MP bsum_raw maskbit) (snd blk0) in + let pop_len = TRANS popeq bsum in + ASSUME_TAC pop_len) THEN + (* bridge: outlen0 + niblen(SUB(16i,4)) = niblen_sample(16i+4) *) + SUBGOAL_THEN `outlen0 + LENGTH(REJ_NIBBLES_ETA4 (SUB_LIST(16*i,4) inlist):int16 list) = LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+4) inlist):int32 list)` ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`;`16*i`] SUBITER_BRIDGE_ETA4) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[] THEN UNDISCH_TAC `16 * (i+1) <= 272` THEN UNDISCH_TAC `LENGTH(inlist:byte list)=272` THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(CONJUNCTS_THEN2 (K ALL_TAC) (CONJUNCTS_THEN2 MP_TAC (K ALL_TAC))) THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES] THEN + UNDISCH_TAC `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i) inlist):int32 list) = outlen0` THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES] THEN ARITH_TAC; ALL_TAC] THEN + (* bnd1: outlen0 + niblen(SUB(16i,4)) <= 248 (= niblen_sample(16i+4) <= 248, direct hyp) *) + SUBGOAL_THEN `outlen0 + LENGTH(REJ_NIBBLES_ETA4 (SUB_LIST(16*i,4) inlist):int16 list) <= 248` ASSUME_TAC THENL + [FIRST_X_ASSUM(fun th -> if (match concl th with Comb(Comb(Const("=",_),Comb(Comb(Const("+",_),Var("outlen0",_)),_)),_)->true|_->false) then SUBST1_TAC th else NO_TAC) THEN + FIRST [FIRST_ASSUM ACCEPT_TAC; + (* mid-exit cases 3+: niblen(16i+4)<=248 follows from a later sample bound by monotonicity *) + (FIRST_X_ASSUM(fun th -> match concl th with + Comb(Comb(Const("<=",_),Comb(Const("LENGTH",_),Comb(Const("REJ_SAMPLE_ETA4_BYTES",_),_))),k) when k=`248` + -> MP_TAC th | _ -> NO_TAC) THEN + MATCH_MP_TAC(ARITH_RULE `a <= b ==> b <= 248 ==> a <= 248`) THEN + MATCH_MP_TAC REJ_SAMPLE_ETA4_PREFIX_MONO THEN ARITH_TAC)]; ALL_TAC] THEN + W(fun (asl,w) -> + let block0len = `LENGTH(REJ_NIBBLES_ETA4 (SUB_LIST(16*i,4) inlist):int16 list)` in + let sum = mk_binop `(+):num->num->num` `outlen0:num` block0len in + let bnd = snd(find (fun (_,th) -> concl th = mk_binop `(<=):num->num->bool` sum `248`) asl) in + let pop_len = snd(find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_popcount",_),_)),_) -> true | _ -> false) asl) in + let lt32 = MATCH_MP (ARITH_RULE `a + b <= 248 ==> a + b < 2 EXP 32`) bnd in + let rax_red0 = MATCH_MP RAX_NEST_REDUCE lt32 in + let ja = MP (ISPECL[sum; `248`] JA_NOT_TAKEN_LE) (CONJ bnd (ARITH_RULE `248 < 2 EXP 32`)) in + ASSUME_TAC pop_len THEN ASSUME_TAC bnd THEN ASSUME_TAC rax_red0 THEN ASSUME_TAC ja) THEN + X86_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (22--23) THEN + SUBGOAL_THEN `read RIP s23 = word (pc + 163):int64` ASSUME_TAC THENL + [W(fun (asl,w) -> + let blk0 = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),l),_) -> (try let h,args=strip_comb l in fst(dest_const h)="SUB_LIST" && + (match args with [Comb(Comb(_,off),wid);_] -> wid=`4` && (match off with Comb(Comb(Const("*",_),_),_)->true|_->false) | _->false) with _->false) | _ -> false) asl in + let rax_red0 = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_zx",_),Comb(Comb(Const("word_add",_),_),_))),_) -> true | _ -> false) asl in + let ja = find (fun (_,th) -> is_disj(concl th) && + can(find_term(fun u->match u with Const("word_sub",_)->true|_->false))(concl th) && + can(find_term(fun u->u=`248`))(concl th)) asl in + rip_mp memsafe 163 23 THEN + REWRITE_TAC[GSYM(snd blk0)] THEN REWRITE_TAC[snd rax_red0] THEN + REWRITE_TAC[snd ja] THEN DISCH_THEN SUBST1_TAC THEN REFL_TAC); + ALL_TAC] THEN + (* fold RAX s23 read into clean word(acc1) form (mirrors PREFIX_G_FULL lines 426-431) so the + subsequent SI2 store's memsafe can bound val(RAX)=acc1<=248. *) + W(fun (asl,w) -> + let pl = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_popcount",_),_)),_) -> true | _ -> false) asl in + let rr = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_zx",_),Comb(Comb(Const("word_add",_),_),_))),_) -> true | _ -> false) asl in + RULE_ASSUM_TAC(REWRITE_RULE[snd pl]) THEN RULE_ASSUM_TAC(REWRITE_RULE[snd rr]));; + +let MG1_NT_TAC : tactic = mk_mg1_nt false;; +let MG1_NT_MS_TAC : tactic = mk_mg1_nt true;; + +(* --- mg2_nt --- *) +(* MG2_NT_TAC: from s33, resolve mid-guard-2 NOT-taken (niblen(16i+8)<=248 direct) -> RIP s35=pc+215. + = SI2_MG2_TAKEN's pop_len2/bridge2 build but JA_NOT_TAKEN_LE + RIP pc+215, ending with RAX-fold + so the SI3 store memsafe at s41 discharges. *) +let mk_mg2_nt (memsafe:bool) : tactic = + W(fun (asl,w) -> + let asms = map snd asl in + let find_a p = find p asms in + let m8b_def = find_a (fun th -> match concl th with Comb(Comb(Const("=",_),_),r) -> r = `mask8b:int64` | _ -> false) in + let pinst = `\k. bit 7 (word_subword (f1bnd:int256) (8*k,8):byte)` in + let popcnt2 = REWRITE_RULE[m8b_def] + (CONV_RULE(DEPTH_CONV BETA_CONV THENC ONCE_DEPTH_CONV NUM_REDUCE_CONV) (SPEC pinst POPCNT_BYTE1)) in + let lanesum8 = rand(concl popcnt2) in + let mb2 = find_a (fun th -> let c=concl th in is_forall c && + can(find_term(fun u->u=`f1bnd:int256`))c && + can(find_term(fun u-> match u with Comb(Comb(Const("+",_),Var("k",_)),_) -> true | _ -> false))c) in + let mb2_tm = concl mb2 in + let i_le = find_a (fun th -> concl th = `16 * i <= 256`) in + let leninl = find_a (fun th -> concl th = `LENGTH(inlist:byte list) = 272`) in + let blk16 = find_a (fun th -> is_eq(concl th) && + (try fst(dest_const(fst(strip_comb(lhand(concl th)))))="SUB_LIST" && + length(dest_list(rand(concl th)))=16 with _->false)) in + let bb = MP (ISPECL [`inlist:byte list`; `i:num`; `chunk0:int128`] SUBITER_BLOCK_BYTES) + (CONJ (REWRITE_RULE[GSYM leninl] (MP (ARITH_RULE `16*i<=256 ==> 16*i+16<=272`) i_le)) blk16) in + let blk1_eq = el 1 (CONJUNCTS bb) in + let block1 = `[word_subword (chunk0:int128) (32,8); word_subword chunk0 (40,8); + word_subword chunk0 (48,8); word_subword chunk0 (56,8)]:byte list` in + let block1len_x = mk_comb(`LENGTH:(int16)list->num`, mk_comb(`REJ_NIBBLES_ETA4`, block1)) in + let bsum2_raw = prove(mk_imp(mb2_tm, mk_eq(lanesum8, block1len_x)), + DISCH_THEN(fun mbthm -> + let mbs = map (fun k -> let th=SPEC(mk_small_numeral k) mbthm in + CONV_RULE (NUM_REDUCE_CONV THENC ONCE_DEPTH_CONV EL_CONV) + (MP th (EQT_ELIM(NUM_REDUCE_CONV(lhand(concl th)))))) [0;1;2;3;4;5;6;7] in + REWRITE_TAC mbs) THEN + GEN_REWRITE_TAC RAND_CONV [GSYM LENGTH_FILTER_BYTE_NIBBLES_4_BYTES] THEN + REWRITE_TAC[GSYM BITVAL_SUM_8_EQ_LENGTH_FILTER] THEN + SIMP_TAC[VAL_WORD_BYTE_LT256; BYTE_DIV16_LT; BYTE_MOD16_LT]) in + let pop_len2 = REWRITE_RULE[GSYM blk1_eq] (TRANS popcnt2 (MP bsum2_raw mb2)) in + ASSUME_TAC pop_len2) THEN + (* bridge2: acc1 + niblen(SUB(16i+4,4)) = niblen_sample(16i+8) = (acc2 conceptually) *) + SUBGOAL_THEN `acc1 + LENGTH(REJ_NIBBLES_ETA4 (SUB_LIST(16*i+4,4) inlist):int16 list) = LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+8) inlist):int32 list)` ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`;`16*i+4`] SUBITER_BRIDGE_ETA4) THEN + ANTS_TAC THENL [UNDISCH_TAC `16 * (i+1) <= 272` THEN UNDISCH_TAC `LENGTH(inlist:byte list)=272` THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(CONJUNCTS_THEN2 (K ALL_TAC) (CONJUNCTS_THEN2 MP_TAC (K ALL_TAC))) THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES; ARITH_RULE `(16*i+4)+4 = 16*i+8`] THEN + FIRST_X_ASSUM(fun th -> if concl th = `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+4) inlist):int32 list) = acc1` then MP_TAC th else NO_TAC) THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES] THEN ARITH_TAC; ALL_TAC] THEN + (* bnd: acc1 + block1len <= 248 (= niblen(16i+8)<=248 direct hyp) *) + SUBGOAL_THEN `acc1 + LENGTH(REJ_NIBBLES_ETA4 (SUB_LIST(16*i+4,4) inlist):int16 list) <= 248` ASSUME_TAC THENL + [FIRST_X_ASSUM(fun th -> if (match concl th with Comb(Comb(Const("=",_),Comb(Comb(Const("+",_),Var("acc1",_)),_)),_)->true|_->false) then SUBST1_TAC th else NO_TAC) THEN + FIRST [FIRST_ASSUM ACCEPT_TAC; + (* case-4: niblen(16i+8)<=248 follows from niblen(16i+12)<=248 by monotonicity *) + (FIRST_X_ASSUM(fun th -> match concl th with + Comb(Comb(Const("<=",_),Comb(Const("LENGTH",_),Comb(Const("REJ_SAMPLE_ETA4_BYTES",_),_))),k) when k=`248` + -> MP_TAC th | _ -> NO_TAC) THEN + MATCH_MP_TAC(ARITH_RULE `a <= b ==> b <= 248 ==> a <= 248`) THEN + MATCH_MP_TAC REJ_SAMPLE_ETA4_PREFIX_MONO THEN ARITH_TAC)]; ALL_TAC] THEN + W(fun (asl,w) -> + let block1len = `LENGTH(REJ_NIBBLES_ETA4 (SUB_LIST(16*i+4,4) inlist):int16 list)` in + let sum = mk_binop `(+):num->num->num` `acc1:num` block1len in + let bnd = snd(find (fun (_,th) -> concl th = mk_binop `(<=):num->num->bool` sum `248`) asl) in + let pop_len2 = snd(find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_popcount",_),_)),_) -> true | _ -> false) asl) in + let lt32 = MATCH_MP (ARITH_RULE `a + b <= 248 ==> a + b < 2 EXP 32`) bnd in + let rax_red0 = MATCH_MP RAX_NEST_REDUCE lt32 in + let ja = MP (ISPECL [sum; `248`] JA_NOT_TAKEN_LE) (CONJ bnd (ARITH_RULE `248 < 2 EXP 32`)) in + ASSUME_TAC pop_len2 THEN ASSUME_TAC bnd THEN ASSUME_TAC rax_red0 THEN ASSUME_TAC ja) THEN + X86_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (34--35) THEN + SUBGOAL_THEN `read RIP s35 = word (pc + 215):int64` ASSUME_TAC THENL + [W(fun (asl,w) -> + let pop_len2_old = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_popcount",_),_)),_) -> true | _ -> false) asl in + let zbe = MP (SPEC `val (mask8b:int64) MOD 256` zxbyte_eq) (ARITH_RULE `val (mask8b:int64) MOD 256 < 256`) in + let pop_len2_typed = TRANS (AP_TERM `word_popcount:int32->num` zbe) (snd pop_len2_old) in + let rax_red0 = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_zx",_),Comb(Comb(Const("word_add",_),_),_))),_) -> true | _ -> false) asl in + let ja = find (fun (_,th) -> is_disj(concl th) && + can(find_term(fun u->match u with Const("word_sub",_)->true|_->false))(concl th) && + can(find_term(fun u->u=`acc1:num`))(concl th)) asl in + rip_mp memsafe 215 35 THEN + REWRITE_TAC[pop_len2_typed] THEN REWRITE_TAC[snd rax_red0] THEN + REWRITE_TAC[snd ja] THEN DISCH_THEN SUBST1_TAC THEN REFL_TAC); + ALL_TAC] THEN + (* RAX-fold so SI3 store memsafe discharges *) + W(fun (asl,w) -> + let pl = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_popcount",_),_)),_) -> true | _ -> false) asl in + let zbe = MP (SPEC `val (mask8b:int64) MOD 256` zxbyte_eq) (ARITH_RULE `val (mask8b:int64) MOD 256 < 256`) in + let pl_typed = TRANS (AP_TERM `word_popcount:int32->num` zbe) (snd pl) in + let rr = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_zx",_),Comb(Comb(Const("word_add",_),_),_))),_) -> true | _ -> false) asl in + RULE_ASSUM_TAC(REWRITE_RULE[pl_typed]) THEN RULE_ASSUM_TAC(REWRITE_RULE[snd rr]));; + +let MG2_NT_TAC : tactic = mk_mg2_nt false;; +let MG2_NT_MS_TAC : tactic = mk_mg2_nt true;; + +(* --- mg3_nt --- *) +(* MG3_NT_TAC: from s45, mid-guard-3 NOT-taken from direct niblen(16i+12)<=248 -> RIP s47=pc+268, + with RAX-fold so the SI4 store memsafe at s53 discharges. Clone of SI3_MG3_TAKEN w/ JA_NOT_TAKEN_LE. *) +let mk_mg3_nt (memsafe:bool) : tactic = + W(fun (asl,w) -> + let asms = map snd asl in + let find_a p = find p asms in + let m8c_def = find_a (fun th -> match concl th with Comb(Comb(Const("=",_),_),r) -> r = `mask8c:int64` | _ -> false) in + let m8b_def = find_a (fun th -> match concl th with Comb(Comb(Const("=",_),_),r) -> r = `mask8b:int64` | _ -> false) in + let pinst = `\k. bit 7 (word_subword (f1bnd:int256) (8*k,8):byte)` in + let popcnt3 = REWRITE_RULE[m8b_def; m8c_def] + (CONV_RULE(DEPTH_CONV BETA_CONV THENC ONCE_DEPTH_CONV NUM_REDUCE_CONV) (SPEC pinst POPCNT_BYTE2)) in + let lanesum = rand(concl popcnt3) in + let mb3 = find_a (fun th -> let c=concl th in is_forall c && + can(find_term(fun u->u=`f1bnd:int256`))c && + can(find_term(fun u-> match u with Comb(Comb(Const("+",_),Var("k",_)),n) -> n=`16` | _ -> false))c) in + let mb3_tm = concl mb3 in + let i_le = find_a (fun th -> concl th = `16 * i <= 256`) in + let leninl = find_a (fun th -> concl th = `LENGTH(inlist:byte list) = 272`) in + let blk16 = find_a (fun th -> is_eq(concl th) && + (try fst(dest_const(fst(strip_comb(lhand(concl th)))))="SUB_LIST" && + length(dest_list(rand(concl th)))=16 with _->false)) in + let bb = MP (ISPECL [`inlist:byte list`; `i:num`; `chunk0:int128`] SUBITER_BLOCK_BYTES) + (CONJ (REWRITE_RULE[GSYM leninl] (MP (ARITH_RULE `16*i<=256 ==> 16*i+16<=272`) i_le)) blk16) in + let blk2_eq = el 2 (CONJUNCTS bb) in + let block2 = `[word_subword (chunk0:int128) (64,8); word_subword chunk0 (72,8); + word_subword chunk0 (80,8); word_subword chunk0 (88,8)]:byte list` in + let block2len_x = mk_comb(`LENGTH:(int16)list->num`, mk_comb(`REJ_NIBBLES_ETA4`, block2)) in + let bsum3_raw = prove(mk_imp(mb3_tm, mk_eq(lanesum, block2len_x)), + DISCH_THEN(fun mbthm -> + let mbs = map (fun k -> let th=SPEC(mk_small_numeral k) mbthm in + CONV_RULE (NUM_REDUCE_CONV THENC ONCE_DEPTH_CONV EL_CONV) + (MP th (EQT_ELIM(NUM_REDUCE_CONV(lhand(concl th)))))) [0;1;2;3;4;5;6;7] in + REWRITE_TAC mbs) THEN + GEN_REWRITE_TAC RAND_CONV [GSYM LENGTH_FILTER_BYTE_NIBBLES_4_BYTES] THEN + REWRITE_TAC[GSYM BITVAL_SUM_8_EQ_LENGTH_FILTER] THEN + SIMP_TAC[VAL_WORD_BYTE_LT256; BYTE_DIV16_LT; BYTE_MOD16_LT]) in + let pop_len3 = REWRITE_RULE[GSYM blk2_eq] (TRANS popcnt3 (MP bsum3_raw mb3)) in + ASSUME_TAC pop_len3) THEN + (* bridge3: acc2 + niblen(SUB(16i+8,4)) = niblen_sample(16i+12) *) + SUBGOAL_THEN `acc2 + LENGTH(REJ_NIBBLES_ETA4 (SUB_LIST(16*i+8,4) inlist):int16 list) = LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+12) inlist):int32 list)` ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`;`16*i+8`] SUBITER_BRIDGE_ETA4) THEN + ANTS_TAC THENL [UNDISCH_TAC `16 * (i+1) <= 272` THEN UNDISCH_TAC `LENGTH(inlist:byte list)=272` THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(CONJUNCTS_THEN2 (K ALL_TAC) (CONJUNCTS_THEN2 MP_TAC (K ALL_TAC))) THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES; ARITH_RULE `(16*i+8)+4 = 16*i+12`] THEN + FIRST_X_ASSUM(fun th -> if concl th = `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+8) inlist):int32 list) = acc2` then MP_TAC th else NO_TAC) THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES] THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+12) inlist):int32 list) < 2 EXP 32` ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`;`16*i+8`] OUTLEN0_LE_256_FROM_SUBITER) THEN + ANTS_TAC THENL + [CONJ_TAC THENL + [UNDISCH_TAC `16 * (i+1) <= 272` THEN UNDISCH_TAC `LENGTH(inlist:byte list)=272` THEN ARITH_TAC; + FIRST_X_ASSUM(fun th -> if concl th = `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+8) inlist):int32 list) = acc2` then SUBST1_TAC th else NO_TAC) THEN FIRST_ASSUM ACCEPT_TAC]; ALL_TAC] THEN + REWRITE_TAC[ARITH_RULE `(16*i+8)+4 = 16*i+12`] THEN ARITH_TAC; ALL_TAC] THEN + W(fun (asl,w) -> + let block2len = `LENGTH(REJ_NIBBLES_ETA4 (SUB_LIST(16*i+8,4) inlist):int16 list)` in + let sum = mk_binop `(+):num->num->num` `acc2:num` block2len in + let bridge3 = snd(find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("+",_),Var("acc2",_)),_)),_) -> true | _ -> false) asl) in + let lt32 = REWRITE_RULE[SYM bridge3] (snd(find (fun (_,th) -> concl th = `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+12) inlist):int32 list) < 2 EXP 32`) asl)) in + let pop_len3 = snd(find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_popcount",_),_)),_) -> true | _ -> false) asl) in + let rax_red0 = MATCH_MP RAX_NEST_REDUCE lt32 in + let bnd = REWRITE_RULE[SYM bridge3] (snd(find (fun (_,th) -> concl th = `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+12) inlist):int32 list) <= 248`) asl)) in + let ja = MP (ISPECL [sum; `248`] JA_NOT_TAKEN_LE) (CONJ bnd (ARITH_RULE `248 < 2 EXP 32`)) in + ASSUME_TAC pop_len3 THEN ASSUME_TAC rax_red0 THEN ASSUME_TAC ja) THEN + X86_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (46--47) THEN + SUBGOAL_THEN `read RIP s47 = word (pc + 268):int64` ASSUME_TAC THENL + [W(fun (asl,w) -> + let asms = map snd asl in + let find_a p = find p asms in + let i_le = find_a (fun th -> concl th = `16 * i <= 256`) in + let leninl = find_a (fun th -> concl th = `LENGTH(inlist:byte list) = 272`) in + let blk16 = find_a (fun th -> is_eq(concl th) && + (try fst(dest_const(fst(strip_comb(lhand(concl th)))))="SUB_LIST" && length(dest_list(rand(concl th)))=16 with _->false)) in + let bb = MP (ISPECL [`inlist:byte list`; `i:num`; `chunk0:int128`] SUBITER_BLOCK_BYTES) + (CONJ (REWRITE_RULE[GSYM leninl] (MP (ARITH_RULE `16*i<=256 ==> 16*i+16<=272`) i_le)) blk16) in + let blk2_eq = el 2 (CONJUNCTS bb) in + let rax_red0 = find_a (fun th -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_zx",_),Comb(Comb(Const("word_add",_),_),_))),_) -> + can(find_term(fun u->u=`acc2:num`))(concl th) | _ -> false) in + let ja = find_a (fun th -> is_disj(concl th) && + can(find_term(fun u->match u with Const("word_sub",_)->true|_->false))(concl th) && + can(find_term(fun u->u=`acc2:num`))(concl th)) in + rip_mp memsafe 268 47 THEN + REWRITE_TAC[GSYM blk2_eq] THEN REWRITE_TAC[rax_red0] THEN + REWRITE_TAC[ja] THEN DISCH_THEN SUBST1_TAC THEN REFL_TAC); + ALL_TAC] THEN + (* RAX-fold so SI4 store memsafe discharges *) + W(fun (asl,w) -> + let pl = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_popcount",_),_)),_) -> true | _ -> false) asl in + let rr = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_zx",_),Comb(Comb(Const("word_add",_),_),_))),_) -> can(find_term(fun u->u=`acc2:num`))(concl th) | _ -> false) asl in + RULE_ASSUM_TAC(REWRITE_RULE[snd pl]) THEN RULE_ASSUM_TAC(REWRITE_RULE[snd rr]));; + +let MG3_NT_TAC : tactic = mk_mg3_nt false;; +let MG3_NT_MS_TAC : tactic = mk_mg3_nt true;; + +(* --- si4_body4 --- *) +(* SI4_BODY4_TAC: SI4_INTEGRATED body with forked SI4_PRE (acc3<=248 from direct niblen(16i+12)<=248). + From s47/pc+268 (after MG3_NT) to s57/pc+52 at pos16(i+1) (back-edge), store folded to 16(i+1). *) +let SI4_BODY4_TAC : tactic = + ABBREV_TAC `acc3 = acc2 + LENGTH (REJ_NIBBLES_ETA4 (SUB_LIST (16*i+8,4) inlist):int16 list)` THEN + REABBREV_TAC `mask8d = read R8 s47` THEN + SUBGOAL_THEN `acc3 <= 248` ASSUME_TAC THENL + [FIRST_X_ASSUM(fun th -> if (match concl th with Comb(Comb(Const("=",_),Var("acc3",_)),Comb(Const("LENGTH",_),Comb(Const("REJ_SAMPLE_ETA4_BYTES",_),_)))->true|_->false) then SUBST1_TAC th else NO_TAC) THEN + FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN + VAL_INT64_TAC `acc3:num` THEN + ACC3_IDENT_TAC THEN + RULE_ASSUM_TAC(REWRITE_RULE[ASSUME `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+12) inlist):int32 list) = acc3`]) THEN + X86_VSTEPS_TAC EXEC (48--48) THEN + X86_VERBOSE_STEP_TAC EXEC "s49" THEN MOVZBL_R10_CAPTURE_TAC THEN + RULE_ASSUM_TAC(REWRITE_RULE[ASSUME `read R8 s48 = mask8d:int64`]) THEN + X86_VSTEPS_TAC EXEC (50--50) THEN TAB4_TEQ_TAC THEN REABBREV_TAC `tab4 = read YMM6 s50` THEN + X86_VSTEPS_TAC EXEC (51--51) THEN REABBREV_TAC `pshuf4 = read YMM6 s51` THEN + PURGE_STALE_STATES_TAC ["s50"] THEN + X86_VSTEPS_TAC EXEC (52--52) THEN REABBREV_TAC `sx4 = read YMM1 s52` THEN + VAL_INT64_TAC `acc3:num` THEN + X86_STEPS_TAC EXEC (53--53) THEN + SUBGOAL_THEN `sx4:int256 = usimd8 (\b:byte. word_sx b:int32) (word_zx(word_zx (pshuf4:int256):int128):int64)` ASSUME_TAC THENL + [W(fun (asl,w) -> + let sx4def = find (fun th -> is_eq(concl th) && rand(concl th)=`sx4:int256` && + can(find_term(fun u->match u with Const("word_join",_)->true|_->false))(concl th)) (map snd asl) in + SUBST1_TAC(SYM sx4def) THEN + REWRITE_TAC[usimd8;usimd4;usimd2;DIMINDEX_8;DIMINDEX_16;DIMINDEX_32;DIMINDEX_64;DIMINDEX_128;DIMINDEX_256] THEN + CONV_TAC WORD_BLAST); + ALL_TAC] THEN + (SUBGOAL_THEN maskbit_tgt_4 ASSUME_TAC THENL [MASKBIT_TGT_4_TAC; ALL_TAC]) THEN + (SUBGOAL_THEN pf_target_4 ASSUME_TAC THENL [PF_PROOF_4; ALL_TAC]) THEN + ACC3_IDENT_TAC THEN + W(fun (asl,w) -> + let asms = map snd asl in + let hasC nm th = can (find_term (fun u -> match u with Const(n,_) when n=nm -> true | _ -> false)) (concl th) in + let bg4 = find (fun th -> let c=concl th in is_forall c && can(find_term(fun u->u=`f0sub:int256`))c && + can(find_term(fun u->match u with Const("word_ushr",_)->true|_->false))c && + can(find_term(fun u->u=`word_subword (chunk0:int128) (96,8):byte`))c && + can(find_term(fun u->u=`word_subword (f0sub:int256) (128,128):int128`))c) asms in + let mthm4 = find (fun th -> concl th = maskbit_tgt_4) asms in + let pfth4 = find (fun th -> concl th = pf_target_4) asms in + let sx4u = find (fun th -> match concl th with Comb(Comb(Const("=",_),Var("sx4",_)),r)->can(find_term(fun u->match u with Const("usimd8",_)->true|_->false))r|_->false) asms in + let storef0 = find (fun th -> match concl th with Comb(Comb(Const("=",_),Comb(Comb(Const("read",_),m),Var("s53",_))),Var("sx4",_)) -> can(find_term(fun u->match u with Const("bytes256",_)->true|_->false)) m |_->false) asms in + let store_full = REWRITE_RULE[pfth4] (REWRITE_RULE[sx4u] storef0) in + let g4 = `word_zx (word_zx (word_ushr (word_zx (word_zx (word_subword (f0sub:int256) (128,128):int128):int128):int128) 64):int128):int128` in + let m = `word (val (mask8d:int64) MOD 256):byte` in + let pc = ISPECL [`word_add res (word (4 * acc3)):int64`; `s53:x86state`; g4; m; `LENGTH(ACC_IDX (word (val (mask8d:int64) MOD 256):byte))`] SUBITER_STORE_POSTCOND in + let res_th0 = MP pc (CONJ (SPEC m LACC8) store_full) in + let spec = ISPECL [g4; m; `word_subword (chunk0:int128) (96,8):byte`; `word_subword (chunk0:int128) (104,8):byte`; `word_subword (chunk0:int128) (112,8):byte`; `word_subword (chunk0:int128) (120,8):byte`] SUBITER_STORE_SPEC in + let rej_store = REWRITE_RULE[MP spec (CONJ mthm4 bg4)] res_th0 in + let leninl = find (fun th -> concl th = `LENGTH(inlist:byte list)=272`) asms in + let i116 = find (fun th -> concl th = `16 * (i + 1) <= 272`) asms in + let blk16 = find (fun th -> is_eq(concl th) && hasC "SUB_LIST" th && (try length(dest_list(rand(concl th)))=16 with _->false)) asms in + let bb = MP (ISPECL [`inlist:byte list`;`i:num`;`chunk0:int128`] SUBITER_BLOCK_BYTES) + (CONJ (REWRITE_RULE[GSYM leninl] (MP (ARITH_RULE `16*(i+1)<=272 ==> 16*i+16<=272`) i116)) blk16) in + let blk3_eq = el 3 (CONJUNCTS bb) in + let lr0 = MP (ISPECL [m;`word_subword (chunk0:int128) (96,8):byte`;`word_subword (chunk0:int128) (104,8):byte`;`word_subword (chunk0:int128) (112,8):byte`;`word_subword (chunk0:int128) (120,8):byte`] LEN_RECONCILE_GEN) mthm4 in + let lr = REWRITE_RULE[GSYM blk3_eq] lr0 in + let rej_store1 = REWRITE_RULE[GSYM blk3_eq] rej_store in + let acc3_ident = find (fun th -> match concl th with Comb(Comb(Const("=",_),Comb(Const("LENGTH",_),Comb(Const("REJ_SAMPLE_ETA4_BYTES",_),_))),Var("acc3",_)) -> true | _ -> false) asms in + let prefix_store0 = find (fun th -> (match concl th with Comb(Comb(Const("=",_),Comb(Comb(Const("read",_),_),Var("s53",_))),_) -> true | _ -> false) && + hasC "num_of_wordlist" th && hasC "SUB_LIST" th && can(find_term(fun u->u=`acc3:num`))(lhand(concl th)) && not(hasC "ACC_IDX" th) && not(hasC "bytes256" th)) asms in + let prefix_store = REWRITE_RULE[GSYM acc3_ident] prefix_store0 in + let rej_store2 = REWRITE_RULE[GSYM acc3_ident] rej_store1 in + let fold = MP (ISPECL [`res:int64`;`s53:x86state`;m;`SUB_LIST(16*i+12,4) (inlist:byte list)`;`SUB_LIST(0,16*i+12) (inlist:byte list)`] SUBITER_FOLD_STEP) + (CONJ lr (CONJ prefix_store rej_store2)) in + let split = REWRITE_RULE[ADD_CLAUSES] (ISPECL[`inlist:byte list`;`16*i+12`;`4`;`0`] SUB_LIST_SPLIT) in + let clean = REWRITE_RULE[GSYM split; ARITH_RULE `(16*i+12)+4 = 16*i+16`] fold in + ASSUME_TAC clean) THEN + X86_STEPS_TAC EXEC (54--57);; + ALL_TAC;; + +let mk_si2_mg2_taken (memsafe:bool) : tactic = + W(fun (asl,w) -> + let asms = map snd asl in + let find_a p = find p asms in + let m8b_def = find_a (fun th -> match concl th with Comb(Comb(Const("=",_),_),r) -> r = `mask8b:int64` | _ -> false) in + let pinst = `\k. bit 7 (word_subword (f1bnd:int256) (8*k,8):byte)` in + let popcnt2 = REWRITE_RULE[m8b_def] + (CONV_RULE(DEPTH_CONV BETA_CONV THENC ONCE_DEPTH_CONV NUM_REDUCE_CONV) (SPEC pinst POPCNT_BYTE1)) in + let lanesum8 = rand(concl popcnt2) in + let mb2 = find_a (fun th -> let c=concl th in is_forall c && + can(find_term(fun u->u=`f1bnd:int256`))c && + can(find_term(fun u-> match u with Comb(Comb(Const("+",_),Var("k",_)),_) -> true | _ -> false))c) in + let mb2_tm = concl mb2 in + let i_le = find_a (fun th -> concl th = `16 * i <= 256`) in + let leninl = find_a (fun th -> concl th = `LENGTH(inlist:byte list) = 272`) in + let blk16 = find_a (fun th -> is_eq(concl th) && + (try fst(dest_const(fst(strip_comb(lhand(concl th)))))="SUB_LIST" && + length(dest_list(rand(concl th)))=16 with _->false)) in + let bb = MP (ISPECL [`inlist:byte list`; `i:num`; `chunk0:int128`] SUBITER_BLOCK_BYTES) + (CONJ (REWRITE_RULE[GSYM leninl] (MP (ARITH_RULE `16*i<=256 ==> 16*i+16<=272`) i_le)) blk16) in + let blk1_eq = el 1 (CONJUNCTS bb) in + let block1 = `[word_subword (chunk0:int128) (32,8); word_subword chunk0 (40,8); + word_subword chunk0 (48,8); word_subword chunk0 (56,8)]:byte list` in + let block1len_x = mk_comb(`LENGTH:(int16)list->num`, mk_comb(`REJ_NIBBLES_ETA4`, block1)) in + let bsum2_raw = prove(mk_imp(mb2_tm, mk_eq(lanesum8, block1len_x)), + DISCH_THEN(fun mbthm -> + let mbs = map (fun k -> let th=SPEC(mk_small_numeral k) mbthm in + CONV_RULE (NUM_REDUCE_CONV THENC ONCE_DEPTH_CONV EL_CONV) + (MP th (EQT_ELIM(NUM_REDUCE_CONV(lhand(concl th)))))) [0;1;2;3;4;5;6;7] in + REWRITE_TAC mbs) THEN + GEN_REWRITE_TAC RAND_CONV [GSYM LENGTH_FILTER_BYTE_NIBBLES_4_BYTES] THEN + REWRITE_TAC[GSYM BITVAL_SUM_8_EQ_LENGTH_FILTER] THEN + SIMP_TAC[VAL_WORD_BYTE_LT256; BYTE_DIV16_LT; BYTE_MOD16_LT]) in + let pop_len2 = REWRITE_RULE[GSYM blk1_eq] (TRANS popcnt2 (MP bsum2_raw mb2)) in + ASSUME_TAC pop_len2) THEN + SUBGOAL_THEN `acc1 + LENGTH(REJ_NIBBLES_ETA4 (SUB_LIST(16*i+4,4) inlist):int16 list) = LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+8) inlist):int32 list)` ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`;`16*i+4`] SUBITER_BRIDGE_ETA4) THEN + ANTS_TAC THENL [UNDISCH_TAC `16 * (i+1) <= 272` THEN UNDISCH_TAC `LENGTH(inlist:byte list)=272` THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(CONJUNCTS_THEN2 (K ALL_TAC) (CONJUNCTS_THEN2 MP_TAC (K ALL_TAC))) THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES; ARITH_RULE `(16*i+4)+4 = 16*i+8`] THEN + FIRST_X_ASSUM(fun th -> if concl th = `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+4) inlist):int32 list) = acc1` then MP_TAC th else NO_TAC) THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES] THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+8) inlist):int32 list) < 2 EXP 32` ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`;`16*i+4`] OUTLEN0_LE_256_FROM_SUBITER) THEN + ANTS_TAC THENL + [CONJ_TAC THENL + [UNDISCH_TAC `16 * (i+1) <= 272` THEN UNDISCH_TAC `LENGTH(inlist:byte list)=272` THEN ARITH_TAC; + FIRST_X_ASSUM(fun th -> if concl th = `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+4) inlist):int32 list) = acc1` then SUBST1_TAC th else NO_TAC) THEN FIRST_ASSUM ACCEPT_TAC]; ALL_TAC] THEN + REWRITE_TAC[ARITH_RULE `(16*i+4)+4 = 16*i+8`] THEN ARITH_TAC; ALL_TAC] THEN + W(fun (asl,w) -> + let block1len = `LENGTH(REJ_NIBBLES_ETA4 (SUB_LIST(16*i+4,4) inlist):int16 list)` in + let sum = mk_binop `(+):num->num->num` `acc1:num` block1len in + let bridge2 = snd(find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("+",_),Var("acc1",_)),_)),_) -> true | _ -> false) asl) in + let lt32 = REWRITE_RULE[SYM bridge2] (snd(find (fun (_,th) -> concl th = `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+8) inlist):int32 list) < 2 EXP 32`) asl)) in + let pop_len2 = snd(find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_popcount",_),_)),_) -> true | _ -> false) asl) in + let rax_red0 = MATCH_MP RAX_NEST_REDUCE lt32 in + let gt248 = REWRITE_RULE[SYM bridge2] (snd(find (fun (_,th) -> concl th = `248 < LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+8) inlist):int32 list)`) asl)) in + let ja_taken = MP (ISPECL [sum; `248`] JA_TAKEN_GT) (CONJ gt248 lt32) in + ASSUME_TAC pop_len2 THEN ASSUME_TAC rax_red0 THEN ASSUME_TAC ja_taken) THEN + X86_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (34--35) THEN + SUBGOAL_THEN `read RIP s35 = word (pc + 314):int64` ASSUME_TAC THENL + [W(fun (asl,w) -> + let pop_len2_old = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_popcount",_),_)),_) -> true | _ -> false) asl in + let zbe = MP (SPEC `val (mask8b:int64) MOD 256` zxbyte_eq) (ARITH_RULE `val (mask8b:int64) MOD 256 < 256`) in + let pop_len2_typed = TRANS (AP_TERM `word_popcount:int32->num` zbe) (snd pop_len2_old) in + let rax_red0 = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_zx",_),Comb(Comb(Const("word_add",_),_),_))),_) -> true | _ -> false) asl in + let ja = find (fun (_,th) -> is_neg(concl th) && + can(find_term(fun u->match u with Const("word_sub",_)->true|_->false))(concl th) && + can(find_term(fun u->u=`acc1:num`))(concl th)) asl in + rip_mp memsafe 314 35 THEN + REWRITE_TAC[pop_len2_typed] THEN REWRITE_TAC[snd rax_red0] THEN + REWRITE_TAC[snd ja] THEN DISCH_THEN SUBST1_TAC THEN REFL_TAC); + ALL_TAC];; + +let mk_si3_mg3_taken (memsafe:bool) : tactic = + W(fun (asl,w) -> + let asms = map snd asl in + let find_a p = find p asms in + let m8c_def = find_a (fun th -> match concl th with Comb(Comb(Const("=",_),_),r) -> r = `mask8c:int64` | _ -> false) in + let m8b_def = find_a (fun th -> match concl th with Comb(Comb(Const("=",_),_),r) -> r = `mask8b:int64` | _ -> false) in + let pinst = `\k. bit 7 (word_subword (f1bnd:int256) (8*k,8):byte)` in + let popcnt3 = REWRITE_RULE[m8b_def; m8c_def] + (CONV_RULE(DEPTH_CONV BETA_CONV THENC ONCE_DEPTH_CONV NUM_REDUCE_CONV) (SPEC pinst POPCNT_BYTE2)) in + let lanesum = rand(concl popcnt3) in + let mb3 = find_a (fun th -> let c=concl th in is_forall c && + can(find_term(fun u->u=`f1bnd:int256`))c && + can(find_term(fun u-> match u with Comb(Comb(Const("+",_),Var("k",_)),n) -> n=`16` | _ -> false))c) in + let mb3_tm = concl mb3 in + let i_le = find_a (fun th -> concl th = `16 * i <= 256`) in + let leninl = find_a (fun th -> concl th = `LENGTH(inlist:byte list) = 272`) in + let blk16 = find_a (fun th -> is_eq(concl th) && + (try fst(dest_const(fst(strip_comb(lhand(concl th)))))="SUB_LIST" && + length(dest_list(rand(concl th)))=16 with _->false)) in + let bb = MP (ISPECL [`inlist:byte list`; `i:num`; `chunk0:int128`] SUBITER_BLOCK_BYTES) + (CONJ (REWRITE_RULE[GSYM leninl] (MP (ARITH_RULE `16*i<=256 ==> 16*i+16<=272`) i_le)) blk16) in + let blk2_eq = el 2 (CONJUNCTS bb) in + let block2 = `[word_subword (chunk0:int128) (64,8); word_subword chunk0 (72,8); + word_subword chunk0 (80,8); word_subword chunk0 (88,8)]:byte list` in + let block2len_x = mk_comb(`LENGTH:(int16)list->num`, mk_comb(`REJ_NIBBLES_ETA4`, block2)) in + let bsum3_raw = prove(mk_imp(mb3_tm, mk_eq(lanesum, block2len_x)), + DISCH_THEN(fun mbthm -> + let mbs = map (fun k -> let th=SPEC(mk_small_numeral k) mbthm in + CONV_RULE (NUM_REDUCE_CONV THENC ONCE_DEPTH_CONV EL_CONV) + (MP th (EQT_ELIM(NUM_REDUCE_CONV(lhand(concl th)))))) [0;1;2;3;4;5;6;7] in + REWRITE_TAC mbs) THEN + GEN_REWRITE_TAC RAND_CONV [GSYM LENGTH_FILTER_BYTE_NIBBLES_4_BYTES] THEN + REWRITE_TAC[GSYM BITVAL_SUM_8_EQ_LENGTH_FILTER] THEN + SIMP_TAC[VAL_WORD_BYTE_LT256; BYTE_DIV16_LT; BYTE_MOD16_LT]) in + let pop_len3 = REWRITE_RULE[GSYM blk2_eq] (TRANS popcnt3 (MP bsum3_raw mb3)) in + ASSUME_TAC pop_len3) THEN + (* bridge3: acc2 + niblen(SUB(16i+8,4)) = niblen_sample(16i+12) *) + SUBGOAL_THEN `acc2 + LENGTH(REJ_NIBBLES_ETA4 (SUB_LIST(16*i+8,4) inlist):int16 list) = LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+12) inlist):int32 list)` ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`;`16*i+8`] SUBITER_BRIDGE_ETA4) THEN + ANTS_TAC THENL [UNDISCH_TAC `16 * (i+1) <= 272` THEN UNDISCH_TAC `LENGTH(inlist:byte list)=272` THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(CONJUNCTS_THEN2 (K ALL_TAC) (CONJUNCTS_THEN2 MP_TAC (K ALL_TAC))) THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES; ARITH_RULE `(16*i+8)+4 = 16*i+12`] THEN + FIRST_X_ASSUM(fun th -> if concl th = `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+8) inlist):int32 list) = acc2` then MP_TAC th else NO_TAC) THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES] THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+12) inlist):int32 list) < 2 EXP 32` ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`;`16*i+8`] OUTLEN0_LE_256_FROM_SUBITER) THEN + ANTS_TAC THENL + [CONJ_TAC THENL + [UNDISCH_TAC `16 * (i+1) <= 272` THEN UNDISCH_TAC `LENGTH(inlist:byte list)=272` THEN ARITH_TAC; + FIRST_X_ASSUM(fun th -> if concl th = `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+8) inlist):int32 list) = acc2` then SUBST1_TAC th else NO_TAC) THEN FIRST_ASSUM ACCEPT_TAC]; ALL_TAC] THEN + REWRITE_TAC[ARITH_RULE `(16*i+8)+4 = 16*i+12`] THEN ARITH_TAC; ALL_TAC] THEN + W(fun (asl,w) -> + let block2len = `LENGTH(REJ_NIBBLES_ETA4 (SUB_LIST(16*i+8,4) inlist):int16 list)` in + let sum = mk_binop `(+):num->num->num` `acc2:num` block2len in + let bridge3 = snd(find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("+",_),Var("acc2",_)),_)),_) -> true | _ -> false) asl) in + let lt32 = REWRITE_RULE[SYM bridge3] (snd(find (fun (_,th) -> concl th = `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+12) inlist):int32 list) < 2 EXP 32`) asl)) in + let pop_len3 = snd(find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_popcount",_),_)),_) -> true | _ -> false) asl) in + let rax_red0 = MATCH_MP RAX_NEST_REDUCE lt32 in + let gt248 = REWRITE_RULE[SYM bridge3] (snd(find (fun (_,th) -> concl th = `248 < LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+12) inlist):int32 list)`) asl)) in + let ja_taken = MP (ISPECL [sum; `248`] JA_TAKEN_GT) (CONJ gt248 lt32) in + ASSUME_TAC pop_len3 THEN ASSUME_TAC rax_red0 THEN ASSUME_TAC ja_taken) THEN + X86_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (46--47) THEN + SUBGOAL_THEN `read RIP s47 = word (pc + 314):int64` ASSUME_TAC THENL + [W(fun (asl,w) -> + let asms = map snd asl in + let find_a p = find p asms in + let i_le = find_a (fun th -> concl th = `16 * i <= 256`) in + let leninl = find_a (fun th -> concl th = `LENGTH(inlist:byte list) = 272`) in + let blk16 = find_a (fun th -> is_eq(concl th) && + (try fst(dest_const(fst(strip_comb(lhand(concl th)))))="SUB_LIST" && length(dest_list(rand(concl th)))=16 with _->false)) in + let bb = MP (ISPECL [`inlist:byte list`; `i:num`; `chunk0:int128`] SUBITER_BLOCK_BYTES) + (CONJ (REWRITE_RULE[GSYM leninl] (MP (ARITH_RULE `16*i<=256 ==> 16*i+16<=272`) i_le)) blk16) in + let blk2_eq = el 2 (CONJUNCTS bb) in + let rax_red0 = find_a (fun th -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_zx",_),Comb(Comb(Const("word_add",_),_),_))),_) -> + can(find_term(fun u->u=`acc2:num`))(concl th) | _ -> false) in + let ja = find_a (fun th -> is_neg(concl th) && + can(find_term(fun u->match u with Const("word_sub",_)->true|_->false))(concl th) && + can(find_term(fun u->u=`acc2:num`))(concl th)) in + rip_mp memsafe 314 47 THEN + REWRITE_TAC[GSYM blk2_eq] THEN REWRITE_TAC[rax_red0] THEN + REWRITE_TAC[ja] THEN DISCH_THEN SUBST1_TAC THEN REFL_TAC); + ALL_TAC];; + + +let mk_midexit2 (memsafe:bool) (disch:tactic) : tactic = +(mk_prefix_to_s21 memsafe) THEN + SUBGOAL_THEN `16 * i + 4 <= LENGTH(inlist:byte list)` ASSUME_TAC THENL + [UNDISCH_TAC `16 * (i+1) <= 272` THEN UNDISCH_TAC `LENGTH(inlist:byte list)=272` THEN ARITH_TAC; ALL_TAC] THEN + (mk_mg1_nt memsafe) THEN SI1_FOLD_V2 THEN + FIRST_X_ASSUM(fun th -> match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("read",_),Const("RIP",_)),Var("s23",_))),r) when + (match r with Comb(Comb(Comb(Const("COND",_),_),_),_)->true|_->false) -> ALL_TAC | _ -> NO_TAC) THEN + SI2_BODY_TAC THEN + (mk_si2_mg2_taken memsafe) THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN + (* discharge if-guard (taken), RAX collapse, RCX collapse *) + W(fun (asl,w) -> + let pop_len2 = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_popcount",_),_)),_) -> true | _ -> false) asl in + let zbe = MP (SPEC `val (mask8b:int64) MOD 256` zxbyte_eq) (ARITH_RULE `val (mask8b:int64) MOD 256 < 256`) in + let pop_len2_typed = TRANS (AP_TERM `word_popcount:int32->num` zbe) (snd pop_len2) in + let rax_red0 = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Const("word_zx",_),Comb(Comb(Const("word_add",_),_),_))),_) -> true | _ -> false) asl in + let bridge2 = find (fun (_,th) -> match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("+",_),Var("acc1",_)),_)),_) -> true | _ -> false) asl in + REWRITE_TAC[pop_len2_typed; snd rax_red0; snd bridge2]) THEN + W(fun (asl,w) -> + let ntake = MP (ISPECL [`LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+8) inlist):int32 list)`;`248`] JA_TAKEN_GT) + (CONJ (ASSUME `248 < LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+8) inlist):int32 list)`) + (ASSUME `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+8) inlist):int32 list) < 2 EXP 32`)) in + REWRITE_TAC[ntake]) THEN + (* RCX collapse: double +4 nest *) + MP_TAC(SPEC `16*i` RCX4_COLLAPSE) THEN ANTS_TAC THENL [UNDISCH_TAC `16*i<=256` THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(fun th -> REWRITE_TAC[th]) THEN + MP_TAC(SPEC `16*i+4` RCX4_COLLAPSE) THEN ANTS_TAC THENL [UNDISCH_TAC `16*i<=256` THEN ARITH_TAC; ALL_TAC] THEN + REWRITE_TAC[ARITH_RULE `16*i+4+4 = 16*i+8`] THEN DISCH_THEN(fun th -> REWRITE_TAC[th]) THEN + CONJ_TAC THENL [AP_TERM_TAC THEN ARITH_TAC; disch];; + + +(* --- SAFE clean-block step/closer + ETA4_CLEAN_BLOCK_SAFE --- *) +let PREFIX_G_FULL_SAFE_TAC : tactic = mk_prefix_g_full false;; + +(* ---- clean_block_safe_eta4_tm (port of the eta2 clean-block scaffold) ---- *) +let clean_block_safe_eta4_tm = + let qvars, body = strip_forall clean_block_tm in + let hyps_tm, ens = dest_imp body in + let ensc, ppf = strip_comb ens in + let pre = el 1 ppf and post = el 2 ppf and frame = el 3 ppf in + let sv, preb = dest_abs pre in + let sv2, postb = dest_abs post in + let pretempl = `read events (s:x86state) = (e:(uarch_event)list)` in + let posttempl = + `read events (s:x86state) = + APPEND (f_ev_loop_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) i) + (e:(uarch_event)list) /\ + memaccess_inbounds + (f_ev_loop_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) i) + [(buf:int64),272; (table:int64),2048] [(res:int64),1024]` in + let pre' = mk_abs(sv, mk_conj(preb, vsubst[sv,`s:x86state`] pretempl)) in + let post' = mk_abs(sv2, mk_conj(postb, vsubst[sv2,`s:x86state`] posttempl)) in + let ens' = list_mk_comb(ensc,[el 0 ppf; pre'; post'; frame]) in + list_mk_forall(qvars @ [`e:(uarch_event)list`], mk_imp(hyps_tm, ens'));; + +(* ---- eta4 SAFE step: plain body (via events-robust prefix) + split finals ---- *) +let ETA4_SAFE_STEP_TAC : tactic = + PREFIX_G_FULL_SAFE_TAC THEN SI1_FOLD_V2 THEN SI2_INTEGRATED THEN + SI3_INTEGRATED THEN SI4_INTEGRATED THEN + RULE_ASSUM_TAC(REWRITE_RULE[ARITH_RULE `16*i+16 = 16*(i+1)`]) THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN + CONJ_TAC THENL [RAX_FINAL_TAC; ALL_TAC] THEN + CONJ_TAC THENL [RCX_FINAL_TAC; ALL_TAC];; + +let ETA4_SAFE_CLOSER : tactic = + MP_TAC ETA4_EVENTS_BRIDGE THEN + ANTS_TAC THENL + [ REPEAT CONJ_TAC THEN FIRST_ASSUM ACCEPT_TAC; + DISCH_THEN(fun bridge -> + CONJ_TAC THENL + [ REWRITE_TAC[GSYM bridge; APPEND] THEN + (REFL_TAC ORELSE FIRST_ASSUM ACCEPT_TAC ORELSE ASM_REWRITE_TAC[APPEND]); + REWRITE_TAC[GSYM bridge] THEN + REWRITE_TAC[memaccess_inbounds; ALL; EX; FST; SND] THEN + REPEAT CONJ_TAC THEN + TRY(REPEAT ((DISJ1_TAC THEN CONTAINED_ASM_TAC) ORELSE DISJ2_TAC ORELSE + CONTAINED_ASM_TAC) THEN NO_TAC) THEN + GATHER_BOUND_TAC ]) ];; + +let ETA4_CLEAN_BLOCK_SAFE = + prove(clean_block_safe_eta4_tm, ETA4_SAFE_STEP_TAC THEN ETA4_SAFE_CLOSER);; + +(* --- SAFE loop scaffold + ETA4_LOOP_SAFE --- *) +let ev_concrete_eta4 = + `read events (s:x86state) = + APPEND (ENUMERATEL i (f_ev_loop_eta4 res buf table pc + (REJ_MASK_ETA4 (inlist:byte list)))) (e:(uarch_event)list)`;; + +let SAFE_LOOPINV_ETA4 = + let iv,rest = dest_abs CORRECT_LOOPINV in + let sv,body = dest_abs rest in + mk_abs(iv, mk_abs(sv, + conj_append_right body (vsubst[sv,`s:x86state`; iv,`i:num`] ev_concrete_eta4)));; + +let loop_safe_eta4_tm = + let qvars,body = strip_forall core_ms_tm in + let hyps_tm,ens = dest_imp body in + let ensc,ppf = strip_comb ens in + let pre = el 1 ppf and frame = el 3 ppf in + let wop = `!m. m < N ==> 16 * m <= 256 /\ + LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(0,16*m) inlist):int16 list) <= 248` in + let hyps' = list_mk_conj (conjuncts hyps_tm @ [`~(N = 0)`; `~(N = 1)`; wop]) in + let sv = `s:x86state` in + let svp,preb = dest_abs pre in + let pre' = mk_abs(svp, conj_append_right preb + (vsubst[svp,sv] `read RSP (s:x86state) = stackpointer`)) in + let iv2,rest2 = dest_abs SAFE_LOOPINV_ETA4 in + let sv2,invbody = dest_abs rest2 in + let inv_body = vsubst[`N-1`,iv2; sv,sv2] invbody in + let post = mk_abs(sv, list_mk_conj + [ `bytes_loaded s (word pc) (BUTLAST mldsa_rej_uniform_eta4_tmc)`; + `read RIP s = word(pc + 52)`; + inv_body ]) in + let ens' = list_mk_comb(ensc,[el 0 ppf; pre'; post; frame]) in + list_mk_forall(qvars @ [`N:num`; `stackpointer:int64`], mk_imp(hyps', ens'));; + +let G2_SAFE_BODY_BRIDGE_ETA4_TAC : tactic = + REPEAT STRIP_TAC THEN + MP_TAC(SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`N:num`;`i:num`;`stackpointer:int64`; + `APPEND (ENUMERATEL i (f_ev_loop_eta4 res buf table pc (REJ_MASK_ETA4 inlist))) (e:(uarch_event)list)`] + ETA4_CLEAN_BLOCK_SAFE) THEN + ANTS_TAC THENL + [SUBGOAL_THEN `i + 1 < N` ASSUME_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN + FIRST_X_ASSUM(MP_TAC o SPEC `i+1` o check(is_forall o concl)) THEN + ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES] THEN STRIP_TAC THEN + REPEAT CONJ_TAC THEN + (FIRST [FIRST_ASSUM ACCEPT_TAC; ASM_ARITH_TAC; ASM_REWRITE_TAC[]]); ALL_TAC] THEN + DISCH_THEN(fun bth -> + W(fun (asl,gl) -> + let lframe = rand(concl bth) in + let lpost = rand(rator(concl bth)) in + let lpre = rand(rator(rator(concl bth))) in + let gframe = rand gl in + let subsumed_tm = mk_binop `(subsumed):(x86state->x86state->bool)->(x86state->x86state->bool)->bool` lframe gframe in + let subsumed_th = prove(subsumed_tm, + REPEAT(MATCH_MP_TAC SUBSUMED_SEQ THEN REWRITE_TAC[SUBSUMED_REFL]) THEN SUBSUMED_MAYCHANGE_TAC) in + let bth' = MATCH_MP ENSURES_FRAME_SUBSUMED (CONJ subsumed_th bth) in + MATCH_MP_TAC ENSURES_PRECONDITION_THM THEN EXISTS_TAC lpre THEN + CONJ_TAC THENL + [GEN_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN TRY(ASM_MESON_TAC[]); + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN EXISTS_TAC lpost THEN + CONJ_TAC THENL + [GEN_TAC THEN STRIP_TAC THEN + ASM_REWRITE_TAC[GSYM SAFE_THREAD_EVENTS_STEP] THEN TRY(ASM_MESON_TAC[]); + ACCEPT_TAC bth']]));; + +let SAFE_LOOP_SCAFFOLD_ETA4_TAC : tactic = + MAP_EVERY X_GEN_TAC [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`; + `e:(uarch_event)list`;`pc:num`;`N:num`;`stackpointer:int64`] THEN + REWRITE_TAC[C_ARGUMENTS; C_RETURN; SOME_FLAGS; NONOVERLAPPING_CLAUSES; + LENGTH_MLDSA_REJ_UNIFORM_ETA4_TMC] THEN + STRIP_TAC THEN + ENSURES_WHILE_UP_TAC `N - 1` `pc + 52` `pc + 52` SAFE_LOOPINV_ETA4 THEN + REPEAT CONJ_TAC THENL + [REPEAT(FIRST_X_ASSUM(MP_TAC o check(fun th->concl th=`~(N=0)`||concl th=`~(N=1)`))) THEN ARITH_TAC; + ENSURES_INIT_TAC "s0" THEN + X86_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (1--11) THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN + REWRITE_TAC[MULT_CLAUSES; ADD_CLAUSES; SUB_LIST_CLAUSES; REJ_SAMPLE_ETA4_BYTES; + REJ_NIBBLES_ETA4; NIBBLES_OF_BYTES; FILTER; MAP; LENGTH; num_of_wordlist] THEN + CONV_TAC NUM_REDUCE_CONV THEN + REWRITE_TAC[READ_COMPONENT_COMPOSE; READ_MEMORY_BYTES_TRIVIAL] THEN + CONV_TAC WORD_REDUCE_CONV THEN + ASM_REWRITE_TAC[ENUMERATEL; APPEND]; + G2_SAFE_BODY_BRIDGE_ETA4_TAC; + REPEAT STRIP_TAC THEN ENSURES_INIT_TAC "s0" THEN ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[]; + ENSURES_INIT_TAC "s0" THEN ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[]];; + +let ETA4_LOOP_SAFE = prove(loop_safe_eta4_tm, SAFE_LOOP_SCAFFOLD_ETA4_TAC);; + +(* --- EXIT_OFFSET_SAFE_ETA4 (+ bridges) --- *) +let ev_append_op = `APPEND:(uarch_event)list->(uarch_event)list->(uarch_event)list`;; +let tail_events_e1 = + `APPEND (f_ev_loop_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) (N-1)) + (e:(uarch_event)list)`;; +let tail_events_e2 = mk_comb(mk_comb(ev_append_op,`f_ev_headguard_eta4 pc`), tail_events_e1);; +let scalar_tail_events = `f_ev_scalar_tail_eta4 (272 - 272) res buf pc (inlist:byte list) 272`;; +let exit_events_offset = mk_comb(mk_comb(ev_append_op, scalar_tail_events), tail_events_e2);; + +(* ---- the two SAFE intermediate predicates (concrete events), rebuilt inline + exactly as LEG1B_HEADGUARD_SAFE_ETA4 builds q52_safe/q314_safe; then + specialise ec := tail_events_e1. *) +let q52_pred_e1, q314_pred_e1 = + let sv56,body56 = dest_abs q56_ms in + let sv318,body318 = dest_abs q318_ms in + let q52_safe = mk_abs(sv56, + mk_conj(subst[`272`,`16 * N`] (lhand body56), `read events (s:x86state) = ec`)) in + let q314_safe = mk_abs(sv318, + mk_conj(subst[`272`,`16 * N`] (lhand body318), + `read events (s:x86state) = APPEND (f_ev_headguard_eta4 pc) ec`)) in + vsubst[tail_events_e1,`ec:(uarch_event)list`] q52_safe, + vsubst[tail_events_e1,`ec:(uarch_event)list`] q314_safe;; + +(* ---- statement: mirror eta2 exit_offset_safe_eta2_tm (L10986-11001) off the + eta4 exit_offset_ms_tm; add `read events s = e` to pre and + `read events s = exit_events_offset` to post (events conjuncts). *) +let exit_offset_safe_eta4_tm = + let exoff_ms = snd(strip_forall exit_offset_ms_tm) in + let hyps_tm, ens = dest_imp exoff_ms in + let ensc, ppf = strip_comb ens in + let pre = el 1 ppf and post = el 2 ppf and frame = el 3 ppf in + let sv, preb = dest_abs pre in + let pre_val = lhand preb in + let pre' = mk_abs(sv, mk_conj(pre_val, vsubst[sv,`s:x86state`] `read events (s:x86state) = e`)) in + let sv2, postb = dest_abs post in + let post_rip = lhand postb in + let post_ev = vsubst[sv2,`s:x86state`] (mk_eq(`read events (s:x86state)`, exit_events_offset)) in + let post' = mk_abs(sv2, mk_conj(post_rip, post_ev)) in + list_mk_forall + ([`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`; + `N:num`;`stackpointer:int64`;`e:(uarch_event)list`], + mk_imp(hyps_tm, list_mk_comb(ensc,[el 0 ppf; pre'; post'; frame])));; + +(* ---- bridge tactics (eta4 clones of eta2 EXIT_BRIDGE_CLOSE_TAC / SAFE_BRIDGE_FROM + / SCALAR_TAIL_LEG2_SAFE, with 16*N=272). The 16*N=272 rewrite is CORRECT on + the OFFSET arm (buflen constraint genuinely holds); the clean-closer caveat + is for the MIDEXIT/core arms (steps d/e), not this one. *) +let EXIT_BRIDGE_CLOSE_TAC_ETA4 : tactic = + GEN_TAC THEN STRIP_TAC THEN RULE_ASSUM_TAC BETA_RULE THEN + RULE_ASSUM_TAC(REWRITE_RULE[ASSUME `16 * N = 272`]) THEN ASM_REWRITE_TAC[];; + +let SAFE_BRIDGE_FROM_ETA4 (bth:thm) : tactic = + W(fun (asl,gl) -> + let lframe = rand(concl bth) in + let lpost = rand(rator(concl bth)) in + let lpre = rand(rator(rator(concl bth))) in + let gframe = rand gl in + let subsumed_tm = mk_binop `(subsumed):(x86state->x86state->bool)->(x86state->x86state->bool)->bool` lframe gframe in + let subsumed_th = prove(subsumed_tm, + REPEAT(MATCH_MP_TAC SUBSUMED_SEQ THEN REWRITE_TAC[SUBSUMED_REFL]) THEN SUBSUMED_MAYCHANGE_TAC) in + let bth' = MATCH_MP ENSURES_FRAME_SUBSUMED (CONJ subsumed_th bth) in + MATCH_MP_TAC ENSURES_PRECONDITION_THM THEN EXISTS_TAC lpre THEN + CONJ_TAC THENL + [EXIT_BRIDGE_CLOSE_TAC_ETA4; + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN EXISTS_TAC lpost THEN + CONJ_TAC THENL [EXIT_BRIDGE_CLOSE_TAC_ETA4; ACCEPT_TAC bth']]);; + +let SCALAR_TAIL_LEG2_SAFE_ETA4 (p:term) (etail:term) : tactic = + W(fun (asl,gl) -> + let atp = SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;p;`stackpointer:int64`;etail] + MLDSA_REJ_UNIFORM_ETA4_SCALAR_TAIL_AT_P_SAFE in + let atp_ens = snd(dest_imp(concl atp)) in + let _,ppf = strip_comb atp_ens in + let atp_pre = el 1 ppf and atp_post = el 2 ppf in + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN EXISTS_TAC atp_post THEN + CONJ_TAC THENL + [EXIT_BRIDGE_CLOSE_TAC_ETA4; + MATCH_MP_TAC ENSURES_PRECONDITION_THM THEN EXISTS_TAC atp_pre THEN + CONJ_TAC THENL + [EXIT_BRIDGE_CLOSE_TAC_ETA4; + MP_TAC atp THEN + ANTS_TAC THENL + [REPEAT CONJ_TAC THEN + (FIRST [FIRST_ASSUM ACCEPT_TAC; ASM_ARITH_TAC; + (FIRST_X_ASSUM(fun th -> if concl th = `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248` then MP_TAC th else NO_TAC) THEN ARITH_TAC)]); + MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] ENSURES_FRAME_SUBSUMED) THEN + REPEAT(MATCH_MP_TAC SUBSUMED_SEQ THEN REWRITE_TAC[SUBSUMED_REFL]) THEN + SUBSUMED_MAYCHANGE_TAC]]]);; + + +let EXIT_OFFSET_SAFE_ETA4 = prove(exit_offset_safe_eta4_tm, + REPEAT GEN_TAC THEN STRIP_TAC THEN + SUBGOAL_THEN `~(N = 0)` ASSUME_TAC THENL + [UNDISCH_TAC `16 * N = 272` THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248` ASSUME_TAC THENL + [REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES] THEN + FIRST_X_ASSUM(fun th -> if concl th = `LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(0,16*N) inlist):int16 list) <= 248` then ACCEPT_TAC th else NO_TAC); ALL_TAC] THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,272) inlist):int32 list) <= 248` ASSUME_TAC THENL + [UNDISCH_TAC `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248` THEN + SUBST1_TAC(ASSUME `16 * N = 272`) THEN REWRITE_TAC[]; ALL_TAC] THEN + MATCH_MP_TAC ENSURES_TRANS_SIMPLE THEN EXISTS_TAC q314_pred_e1 THEN + CONJ_TAC THENL [MAYCHANGE_IDEMPOT_TAC; ALL_TAC] THEN CONJ_TAC THENL + [MATCH_MP_TAC ENSURES_TRANS_SIMPLE THEN EXISTS_TAC q52_pred_e1 THEN + CONJ_TAC THENL [MAYCHANGE_IDEMPOT_TAC; ALL_TAC] THEN CONJ_TAC THENL + [MP_TAC(SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`N:num`;`N-1`;`stackpointer:int64`;`e:(uarch_event)list`] ETA4_CLEAN_BLOCK_SAFE) THEN + SUBGOAL_THEN `N - 1 + 1 = N` (fun th -> REWRITE_TAC[th]) THENL [ASM_ARITH_TAC; ALL_TAC] THEN + ANTS_TAC THENL + [REPEAT CONJ_TAC THEN (FIRST [FIRST_ASSUM ACCEPT_TAC; ASM_ARITH_TAC]); ALL_TAC] THEN + DISCH_THEN(fun bth -> SAFE_BRIDGE_FROM_ETA4 bth); + MP_TAC(SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`N:num`;`stackpointer:int64`;`e:(uarch_event)list`; tail_events_e1] LEG1B_HEADGUARD_SAFE_ETA4) THEN + ANTS_TAC THENL [ASM_REWRITE_TAC[]; ALL_TAC] THEN + DISCH_THEN ACCEPT_TAC]; + SCALAR_TAIL_LEG2_SAFE_ETA4 `272` tail_events_e2]);; + +(* --- MID_EXIT_SUBITER1_SAFE_ETA4 (arm 1) --- *) +let midexit_safe_eta4_tm value_tm fev_tm = + let qvars, body = strip_forall value_tm in + let hyps_tm, ens = dest_imp body in + let ensc, ppf = strip_comb ens in + let pre = el 1 ppf and post = el 2 ppf and frame = el 3 ppf in + let sv, preb = dest_abs pre in + let sv2, postb = dest_abs post in + let pretempl = `read events (s:x86state) = (e:(uarch_event)list)` in + let posttempl = + mk_conj(`read events (s:x86state) = APPEND FEV (e:(uarch_event)list)`, + `memaccess_inbounds FEV [(buf:int64),272; (table:int64),2048] [(res:int64),1024]`) in + let posttempl = subst [fev_tm, `FEV:(uarch_event)list`] posttempl in + let pre' = mk_abs(sv, mk_conj(preb, vsubst[sv,`s:x86state`] pretempl)) in + let post' = mk_abs(sv2, mk_conj(postb, vsubst[sv2,`s:x86state`] posttempl)) in + let ens' = list_mk_comb(ensc,[el 0 ppf; pre'; post'; frame]) in + list_mk_forall(qvars @ [`e:(uarch_event)list`], mk_imp(hyps_tm, ens'));; + +let midexit1_safe_eta4_tm = + midexit_safe_eta4_tm midexit1_tm + `f_ev_midexit_subiter1_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) i`;; + +(* ---- closer: port of eta2 MID_EXIT_SUBITER1_SAFE_CLOSER (L11389); ETA2->ETA4, 136->272 ---- *) +let MID_EXIT_SUBITER1_SAFE_CLOSER_ETA4 : tactic = + CONJ_TAC THENL + [FIRST_ASSUM(fun a1 -> FIRST_ASSUM(fun a2 -> ASSUME_TAC(MP (MP P0_BRIDGE_ETA4 a1) a2))) THEN + SUBGOAL_THEN `outlen0 = NUM_ACCEPTED(SUB_LIST(0,32*i)(REJ_MASK_ETA4 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,16 * i) inlist):int32 list) = outlen0` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i) = 32 * i`](ISPECL[`inlist:byte list`;`16*i`] STORE_BRIDGE_ETA4)); + ALL_TAC] THEN + ASM_REWRITE_TAC[f_ev_midexit_subiter1_eta4; APPEND]; + MATCH_MP_TAC MEMACCESS_F_EV_MIDEXIT_SUBITER1_ETA4 THEN + CONJ_TAC THENL + [UNDISCH_TAC `16 * (i + 1) <= 272` THEN ARITH_TAC; + MP_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i) = 32 * i`] + (ISPECL[`inlist:byte list`;`16*i`] STORE_BRIDGE_ETA4)) THEN + DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_REWRITE_TAC[]]];; + +let MID_EXIT_SUBITER1_SAFE_ETA4 = + prove(midexit1_safe_eta4_tm, mk_midexit1 false MID_EXIT_SUBITER1_SAFE_CLOSER_ETA4);; + +(* --- MID_EXIT_SUBITER2_SAFE_ETA4 (arm 2) --- *) +let MP_BRIDGE_FROM_ASL (bridge:thm) : tactic = + W(fun (asl,w) -> + let asms = map snd asl in + let rec go th = + if is_imp (concl th) then + let ante = lhand (concl th) in + let a = try find (fun a -> aconv (concl a) ante) asms + with Failure _ -> + failwith ("MP_BRIDGE_FROM_ASL: unmatched antecedent: " ^ + string_of_term ante) in + go (MP th a) + else th in + ASSUME_TAC (go bridge));; + +let midexit2_safe_eta4_tm = + midexit_safe_eta4_tm midexit2_tm + `f_ev_midexit_subiter2_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) i`;; +let SUBITER2_SAFE_DISCH_ETA4 : tactic = + CONJ_TAC THENL + [MP_BRIDGE_FROM_ASL P0_BRIDGE_ETA4 THEN + MP_BRIDGE_FROM_ASL GATHER_BRIDGE1_ETA4 THEN + SUBGOAL_THEN `outlen0 = NUM_ACCEPTED(SUB_LIST(0,32*i)(REJ_MASK_ETA4 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,16 * i) inlist):int32 list) = outlen0` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i) = 32 * i`](ISPECL[`inlist:byte list`;`16*i`] STORE_BRIDGE_ETA4)); ALL_TAC] THEN + SUBGOAL_THEN `acc1 = NUM_ACCEPTED(SUB_LIST(0,32*i+8)(REJ_MASK_ETA4 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,16 * i + 4) inlist):int32 list) = acc1` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 4) = 32 * i + 8`](ISPECL[`inlist:byte list`;`16*i+4`] STORE_BRIDGE_ETA4)); ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_NIBBLES_ETA4 [word_subword (chunk0:int128) (0,8); word_subword chunk0 (8,8); + word_subword chunk0 (16,8); word_subword chunk0 (24,8)]:int16 list) = + NUM_ACCEPTED(SUB_LIST(32*i,8)(REJ_MASK_ETA4 (inlist:byte list)))` + ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if (match concl th with + Comb(Comb(Const("=",_),l),_) -> l = `SUB_LIST (16 * i,4) (inlist:byte list)` | _ -> false) + then SUBST1_TAC(SYM th) else NO_TAC) THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA4_EQ_MASK; GSYM NUM_ACCEPTED; REJ_MASK_ETA4_SUB_LIST] THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * i) = 32 * i`; ARITH_RULE `2 * 4 = 8`]; ALL_TAC] THEN + ASM_REWRITE_TAC[f_ev_midexit_subiter2_eta4; APPEND]; + MATCH_MP_TAC MEMACCESS_F_EV_MIDEXIT_SUBITER2_ETA4 THEN + CONJ_TAC THENL + [UNDISCH_TAC `16 * (i + 1) <= 272` THEN ARITH_TAC; + MP_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 4) = 32 * i + 8`] + (ISPECL[`inlist:byte list`;`16*i+4`] STORE_BRIDGE_ETA4)) THEN + DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_REWRITE_TAC[]]];; + +let MID_EXIT_SUBITER2_SAFE_ETA4 = + prove(midexit2_safe_eta4_tm, mk_midexit2 false SUBITER2_SAFE_DISCH_ETA4);; + +(* --- MID_EXIT_SUBITER3_SAFE_ETA4 (arm 3; RCX4_COLLAPSE tail) --- *) +let ASSUME_MASK_TOWERS : tactic = + W(fun (asl,w) -> + let asms = map snd asl in + let fnd p = find (fun th -> p (concl th)) asms in + let tower8_mask8b = fnd (fun c -> is_eq c && rand c = `mask8b:int64` && + can (find_term (fun u -> match u with Const("word_ushr",_)->true|_->false)) c) in + let mask8c_def = fnd (fun c -> is_eq c && rand c = `mask8c:int64`) in + let t16m8c = REWRITE_RULE[SYM tower8_mask8b] mask8c_def in + let t24opt = + try let mask8d_def = fnd (fun c -> is_eq c && rand c = `mask8d:int64` && + can (find_term (fun u -> match u with Const("word_ushr",_)->true|_->false)) c) in + [REWRITE_RULE[SYM t16m8c] mask8d_def] + with Failure _ -> [] in + EVERY (map ASSUME_TAC (t16m8c :: t24opt)));; + +let midexit3_safe_eta4_tm = + midexit_safe_eta4_tm midexit3_tm + `f_ev_midexit_subiter3_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) i`;; + +let SUBITER3_SAFE_DISCH_ETA4 : tactic = + CONJ_TAC THENL + [ASSUME_MASK_TOWERS THEN + MP_BRIDGE_FROM_ASL P0_BRIDGE_ETA4 THEN + MP_BRIDGE_FROM_ASL GATHER_BRIDGE1_ETA4 THEN + MP_BRIDGE_FROM_ASL GATHER_BRIDGE2_ETA4 THEN + SUBGOAL_THEN `outlen0 = NUM_ACCEPTED(SUB_LIST(0,32*i)(REJ_MASK_ETA4 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,16 * i) inlist):int32 list) = outlen0` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i) = 32 * i`](ISPECL[`inlist:byte list`;`16*i`] STORE_BRIDGE_ETA4)); ALL_TAC] THEN + SUBGOAL_THEN `acc1 = NUM_ACCEPTED(SUB_LIST(0,32*i+8)(REJ_MASK_ETA4 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,16 * i + 4) inlist):int32 list) = acc1` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 4) = 32 * i + 8`](ISPECL[`inlist:byte list`;`16*i+4`] STORE_BRIDGE_ETA4)); ALL_TAC] THEN + SUBGOAL_THEN `acc2 = NUM_ACCEPTED(SUB_LIST(0,32*i+16)(REJ_MASK_ETA4 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,16 * i + 8) inlist):int32 list) = acc2` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 8) = 32 * i + 16`](ISPECL[`inlist:byte list`;`16*i+8`] STORE_BRIDGE_ETA4)); ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_NIBBLES_ETA4 [word_subword (chunk0:int128) (0,8); word_subword chunk0 (8,8); + word_subword chunk0 (16,8); word_subword chunk0 (24,8)]:int16 list) = + NUM_ACCEPTED(SUB_LIST(32*i,8)(REJ_MASK_ETA4 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if (match concl th with Comb(Comb(Const("=",_),l),_) -> l = `SUB_LIST (16 * i,4) (inlist:byte list)` | _ -> false) then SUBST1_TAC(SYM th) else NO_TAC) THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA4_EQ_MASK; GSYM NUM_ACCEPTED; REJ_MASK_ETA4_SUB_LIST] THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * i) = 32 * i`; ARITH_RULE `2 * 4 = 8`]; ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_NIBBLES_ETA4 [word_subword (chunk0:int128) (32,8); word_subword chunk0 (40,8); + word_subword chunk0 (48,8); word_subword chunk0 (56,8)]:int16 list) = + NUM_ACCEPTED(SUB_LIST(32*i+8,8)(REJ_MASK_ETA4 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if (match concl th with Comb(Comb(Const("=",_),l),_) -> l = `SUB_LIST (16 * i + 4,4) (inlist:byte list)` | _ -> false) then SUBST1_TAC(SYM th) else NO_TAC) THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA4_EQ_MASK; GSYM NUM_ACCEPTED; REJ_MASK_ETA4_SUB_LIST] THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * i + 4) = 32 * i + 8`; ARITH_RULE `2 * 4 = 8`]; ALL_TAC] THEN + ASM_REWRITE_TAC[f_ev_midexit_subiter3_eta4; APPEND]; + MATCH_MP_TAC MEMACCESS_F_EV_MIDEXIT_SUBITER3_ETA4 THEN + CONJ_TAC THENL + [UNDISCH_TAC `16 * (i + 1) <= 272` THEN ARITH_TAC; + MP_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 8) = 32 * i + 16`] + (ISPECL[`inlist:byte list`;`16*i+8`] STORE_BRIDGE_ETA4)) THEN + DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_REWRITE_TAC[]]];; + +(* ---- mk_midexit3_fix: eta4 mk_midexit3 body, tail = eta2 RCX4_COLLAPSE x3 ---- *) +let mk_midexit3_fix (memsafe:bool) (disch:tactic) : tactic = +(mk_prefix_to_s21 memsafe) THEN + SUBGOAL_THEN `16 * i + 4 <= LENGTH(inlist:byte list)` ASSUME_TAC THENL + [UNDISCH_TAC `16 * (i+1) <= 272` THEN UNDISCH_TAC `LENGTH(inlist:byte list)=272` THEN ARITH_TAC; ALL_TAC] THEN + (mk_mg1_nt memsafe) THEN SI1_FOLD_V2 THEN + FIRST_X_ASSUM(fun th -> match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("read",_),Const("RIP",_)),Var("s23",_))),r) when + (match r with Comb(Comb(Comb(Const("COND",_),_),_),_)->true|_->false) -> ALL_TAC | _ -> NO_TAC) THEN + SI2_BODY_TAC THEN (mk_mg2_nt memsafe) THEN + FIRST_X_ASSUM(fun th -> match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("read",_),Const("RIP",_)),Var("s35",_))),r) when + (match r with Comb(Comb(Comb(Const("COND",_),_),_),_)->true|_->false) -> ALL_TAC | _ -> NO_TAC) THEN + SI3_BODY3_TAC THEN (mk_si3_mg3_taken memsafe) THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN + W(fun (asl,w) -> + let asms = map snd asl in + let find_a p = find p asms in + let i_le = find_a (fun th -> concl th = `16 * i <= 256`) in + let leninl = find_a (fun th -> concl th = `LENGTH(inlist:byte list) = 272`) in + let blk16 = find_a (fun th -> is_eq(concl th) && (try fst(dest_const(fst(strip_comb(lhand(concl th)))))="SUB_LIST" && length(dest_list(rand(concl th)))=16 with _->false)) in + let bb = MP (ISPECL [`inlist:byte list`; `i:num`; `chunk0:int128`] SUBITER_BLOCK_BYTES) + (CONJ (REWRITE_RULE[GSYM leninl] (MP (ARITH_RULE `16*i<=256 ==> 16*i+16<=272`) i_le)) blk16) in + let blk2_eq = el 2 (CONJUNCTS bb) in + let pop_len3 = find_a (fun th -> match concl th with Comb(Comb(Const("=",_),Comb(Const("word_popcount",_),_)),_) -> true | _ -> false) in + let rax_red0 = find_a (fun th -> match concl th with Comb(Comb(Const("=",_),Comb(Const("word_zx",_),Comb(Comb(Const("word_add",_),_),_))),_) -> can(find_term(fun u->u=`acc2:num`))(concl th) | _ -> false) in + let bridge3 = find_a (fun th -> match concl th with Comb(Comb(Const("=",_),Comb(Comb(Const("+",_),Var("acc2",_)),_)),_) -> can(find_term(fun u->match u with Comb(Const("LENGTH",_),Comb(Const("REJ_SAMPLE_ETA4_BYTES",_),_))->true|_->false))(concl th) | _ -> false) in + REWRITE_TAC[GSYM blk2_eq] THEN REWRITE_TAC[pop_len3] THEN REWRITE_TAC[rax_red0; bridge3]) THEN + W(fun (asl,w) -> + let ntake = MP (ISPECL [`LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+12) inlist):int32 list)`;`248`] JA_TAKEN_GT) + (CONJ (ASSUME `248 < LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+12) inlist):int32 list)`) + (ASSUME `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+12) inlist):int32 list) < 2 EXP 32`)) in + REWRITE_TAC[ntake]) THEN + (* --- eta2 tail (mk_midexit3_eta2): RCX4_COLLAPSE x3, no val-expansion --- *) + MP_TAC(SPEC `16*i` RCX4_COLLAPSE) THEN ANTS_TAC THENL [UNDISCH_TAC `16*i<=256` THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(fun th -> REWRITE_TAC[th]) THEN + MP_TAC(SPEC `16*i+4` RCX4_COLLAPSE) THEN ANTS_TAC THENL [UNDISCH_TAC `16*i<=256` THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(fun th -> REWRITE_TAC[th]) THEN REWRITE_TAC[ARITH_RULE `(16*i+4)+4 = 16*i+8`] THEN + MP_TAC(SPEC `16*i+8` RCX4_COLLAPSE) THEN ANTS_TAC THENL [UNDISCH_TAC `16*i<=256` THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(fun th -> REWRITE_TAC[th]) THEN + TRY(AP_TERM_TAC THEN ARITH_TAC) THEN REWRITE_TAC[ARITH_RULE `(16*i+8)+4 = 16*i+12`] THEN disch;; + +let MID_EXIT_SUBITER3_SAFE_ETA4 = + prove(midexit3_safe_eta4_tm, mk_midexit3_fix false SUBITER3_SAFE_DISCH_ETA4);; + +(* --- MID_EXIT_SUBITER4_SAFE_ETA4 (arm 4; RCX4_COLLAPSE x4 tail) --- *) +let midexit4_safe_eta4_tm = + midexit_safe_eta4_tm midexit4_tm + `f_ev_midexit_subiter4_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) i`;; + +(* ---- SUB4_MG3_REDUCE_ETA4 (port of eta2) ---- *) +let SUB4_MG3_REDUCE_ETA4 : tactic = + W(fun (asl,w) -> + let asms = map snd asl in + let find_a p = find p asms in + let i_le = find_a (fun th -> concl th = `16 * i <= 256`) in + let leninl = find_a (fun th -> concl th = `LENGTH(inlist:byte list) = 272`) in + let blk16 = find_a (fun th -> is_eq(concl th) && + (try fst(dest_const(fst(strip_comb(lhand(concl th)))))="SUB_LIST" && + length(dest_list(rand(concl th)))=16 with _->false)) in + let bb = MP (ISPECL [`inlist:byte list`; `i:num`; `chunk0:int128`] SUBITER_BLOCK_BYTES) + (CONJ (REWRITE_RULE[GSYM leninl] (MP (ARITH_RULE `16*i<=256 ==> 16*i+16<=272`) i_le)) blk16) in + let blk2_eq = el 2 (CONJUNCTS bb) in + let ident = find_a (fun th -> match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("+",_),Var("acc2",_)),_)),Var("acc3",_)) -> true + | _ -> false) in + let acc3_le = find_a (fun th -> concl th = `acc3 <= 248`) in + let bnd_sublist = REWRITE_RULE[SYM ident] acc3_le in + let bnd_chunk = REWRITE_RULE[blk2_eq] bnd_sublist in + let sum = lhand(concl bnd_chunk) in + let lt32 = MATCH_MP (ARITH_RULE `a + b <= 248 ==> a + b < 2 EXP 32`) bnd_chunk in + let rax_red = MATCH_MP RAX_NEST_REDUCE lt32 in + let ja = MP (ISPECL [sum; `248`] JA_NOT_TAKEN_LE) (CONJ bnd_chunk (ARITH_RULE `248 < 2 EXP 32`)) in + REWRITE_TAC[rax_red; ja]);; + +(* ---- SUB4_EVENTS_CLOSER_ETA4 (port of eta2) ---- *) +let SUB4_EVENTS_CLOSER_ETA4 : tactic = + ASSUME_MASK_TOWERS THEN + MP_BRIDGE_FROM_ASL P0_BRIDGE_ETA4 THEN + MP_BRIDGE_FROM_ASL GATHER_BRIDGE1_ETA4 THEN + MP_BRIDGE_FROM_ASL GATHER_BRIDGE2_ETA4 THEN + MP_BRIDGE_FROM_ASL GATHER_BRIDGE3_ETA4 THEN + SUBGOAL_THEN `outlen0 = NUM_ACCEPTED(SUB_LIST(0,32*i)(REJ_MASK_ETA4 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,16 * i) inlist):int32 list) = outlen0` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i) = 32 * i`](ISPECL[`inlist:byte list`;`16*i`] STORE_BRIDGE_ETA4)); ALL_TAC] THEN + SUBGOAL_THEN `acc1 = NUM_ACCEPTED(SUB_LIST(0,32*i+8)(REJ_MASK_ETA4 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,16 * i + 4) inlist):int32 list) = acc1` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 4) = 32 * i + 8`](ISPECL[`inlist:byte list`;`16*i+4`] STORE_BRIDGE_ETA4)); ALL_TAC] THEN + SUBGOAL_THEN `acc2 = NUM_ACCEPTED(SUB_LIST(0,32*i+16)(REJ_MASK_ETA4 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,16 * i + 8) inlist):int32 list) = acc2` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 8) = 32 * i + 16`](ISPECL[`inlist:byte list`;`16*i+8`] STORE_BRIDGE_ETA4)); ALL_TAC] THEN + SUBGOAL_THEN `acc3 = NUM_ACCEPTED(SUB_LIST(0,32*i+24)(REJ_MASK_ETA4 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if concl th = `LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,16 * i + 12) inlist):int32 list) = acc3` then SUBST1_TAC(SYM th) else NO_TAC) THEN + MATCH_ACCEPT_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 12) = 32 * i + 24`](ISPECL[`inlist:byte list`;`16*i+12`] STORE_BRIDGE_ETA4)); ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_NIBBLES_ETA4 [word_subword (chunk0:int128) (0,8); word_subword chunk0 (8,8); + word_subword chunk0 (16,8); word_subword chunk0 (24,8)]:int16 list) = + NUM_ACCEPTED(SUB_LIST(32*i,8)(REJ_MASK_ETA4 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if (match concl th with Comb(Comb(Const("=",_),l),_) -> l = `SUB_LIST (16 * i,4) (inlist:byte list)` | _ -> false) then SUBST1_TAC(SYM th) else NO_TAC) THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA4_EQ_MASK; GSYM NUM_ACCEPTED; REJ_MASK_ETA4_SUB_LIST] THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * i) = 32 * i`; ARITH_RULE `2 * 4 = 8`]; ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_NIBBLES_ETA4 [word_subword (chunk0:int128) (32,8); word_subword chunk0 (40,8); + word_subword chunk0 (48,8); word_subword chunk0 (56,8)]:int16 list) = + NUM_ACCEPTED(SUB_LIST(32*i+8,8)(REJ_MASK_ETA4 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if (match concl th with Comb(Comb(Const("=",_),l),_) -> l = `SUB_LIST (16 * i + 4,4) (inlist:byte list)` | _ -> false) then SUBST1_TAC(SYM th) else NO_TAC) THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA4_EQ_MASK; GSYM NUM_ACCEPTED; REJ_MASK_ETA4_SUB_LIST] THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * i + 4) = 32 * i + 8`; ARITH_RULE `2 * 4 = 8`]; ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_NIBBLES_ETA4 [word_subword (chunk0:int128) (64,8); word_subword chunk0 (72,8); + word_subword chunk0 (80,8); word_subword chunk0 (88,8)]:int16 list) = + NUM_ACCEPTED(SUB_LIST(32*i+16,8)(REJ_MASK_ETA4 (inlist:byte list)))` ASSUME_TAC THENL + [FIRST_ASSUM(fun th -> if (match concl th with Comb(Comb(Const("=",_),l),_) -> l = `SUB_LIST (16 * i + 8,4) (inlist:byte list)` | _ -> false) then SUBST1_TAC(SYM th) else NO_TAC) THEN + REWRITE_TAC[LENGTH_REJ_NIBBLES_ETA4_EQ_MASK; GSYM NUM_ACCEPTED; REJ_MASK_ETA4_SUB_LIST] THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * i + 8) = 32 * i + 16`; ARITH_RULE `2 * 4 = 8`]; ALL_TAC] THEN + (* NOTE: eta4 def f_ev_midexit_subiter4_eta4 keeps mg3 (pc+268) SYMBOLIC (unlike eta2, + which resolves it via SUB4_MG3_REDUCE). So DO NOT resolve — the acc2/block2 SUBGOALs + fold the raw COND operands (acc2, LENGTH(REJ_NIBBLES block2)) to NUM_ACCEPTED, matching + the symbolic def. This is the eta2->eta4 def-shape difference. *) + ASM_REWRITE_TAC[f_ev_midexit_subiter4_eta4; APPEND];; + +(* ---- SUB4_MEMACCESS_CLOSER_ETA4 (port of eta2) ---- *) +let SUB4_MEMACCESS_CLOSER_ETA4 : tactic = + MATCH_MP_TAC MEMACCESS_F_EV_MIDEXIT_SUBITER4_ETA4 THEN + CONJ_TAC THENL + [UNDISCH_TAC `16 * (i + 1) <= 272` THEN ARITH_TAC; + MP_TAC(REWRITE_RULE[ARITH_RULE `2 * (16 * i + 12) = 32 * i + 24`] + (ISPECL[`inlist:byte list`;`16*i+12`] STORE_BRIDGE_ETA4)) THEN + DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_REWRITE_TAC[]];; + +let SUBITER4_SAFE_DISCH_ETA4 : tactic = + W(fun (asl,w) -> if is_eq w then SUB4_EVENTS_CLOSER_ETA4 else SUB4_MEMACCESS_CLOSER_ETA4);; + +(* ---- mk_midexit4_fix: eta4 mk_midexit4 body, tail = eta2 RCX4_COLLAPSE x4 ---- *) +let mk_midexit4_fix (memsafe:bool) (disch:tactic) : tactic = +(mk_prefix_to_s21 memsafe) THEN + SUBGOAL_THEN `16 * i + 4 <= LENGTH(inlist:byte list)` ASSUME_TAC THENL + [UNDISCH_TAC `16 * (i+1) <= 272` THEN UNDISCH_TAC `LENGTH(inlist:byte list)=272` THEN ARITH_TAC; ALL_TAC] THEN + (mk_mg1_nt memsafe) THEN SI1_FOLD_V2 THEN + FIRST_X_ASSUM(fun th -> match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("read",_),Const("RIP",_)),Var("s23",_))),r) when + (match r with Comb(Comb(Comb(Const("COND",_),_),_),_)->true|_->false) -> ALL_TAC | _ -> NO_TAC) THEN + SI2_BODY_TAC THEN (mk_mg2_nt memsafe) THEN + FIRST_X_ASSUM(fun th -> match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("read",_),Const("RIP",_)),Var("s35",_))),r) when + (match r with Comb(Comb(Comb(Const("COND",_),_),_),_)->true|_->false) -> ALL_TAC | _ -> NO_TAC) THEN + SI3_BODY3_TAC THEN (mk_mg3_nt memsafe) THEN + FIRST_X_ASSUM(fun th -> match concl th with + Comb(Comb(Const("=",_),Comb(Comb(Const("read",_),Const("RIP",_)),Var("s47",_))),r) when + (match r with Comb(Comb(Comb(Const("COND",_),_),_),_)->true|_->false) -> ALL_TAC | _ -> NO_TAC) THEN + SI4_BODY4_TAC THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(i+1)) inlist):int32 list) <= 256` ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`;`16*i+12`] OUTLEN0_LE_256_FROM_SUBITER) THEN + ANTS_TAC THENL + [CONJ_TAC THENL + [UNDISCH_TAC `16 * (i+1) <= 272` THEN UNDISCH_TAC `LENGTH(inlist:byte list)=272` THEN ARITH_TAC; + FIRST_X_ASSUM(fun th -> if (match concl th with Comb(Comb(Const("=",_),Comb(Const("LENGTH",_),Comb(Const("REJ_SAMPLE_ETA4_BYTES",_),_))),Var("acc3",_))->true|_->false) then SUBST1_TAC th else NO_TAC) THEN FIRST_ASSUM ACCEPT_TAC]; ALL_TAC] THEN + REWRITE_TAC[ARITH_RULE `(16*i+12)+4 = 16*(i+1)`; ARITH_RULE `16*i+16=16*(i+1)`]; ALL_TAC] THEN + SUBGOAL_THEN `acc3 + LENGTH(REJ_NIBBLES_ETA4 (SUB_LIST(16*i+12,4) inlist):int16 list) = LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(i+1)) inlist):int32 list)` ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`;`16*i+12`] SUBITER_BRIDGE_ETA4) THEN + ANTS_TAC THENL [UNDISCH_TAC `16 * (i+1) <= 272` THEN UNDISCH_TAC `LENGTH(inlist:byte list)=272` THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(CONJUNCTS_THEN2 (K ALL_TAC) (CONJUNCTS_THEN2 MP_TAC (K ALL_TAC))) THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES; ARITH_RULE `(16*i+12)+4 = 16*(i+1)`; ARITH_RULE `16*i+16 = 16*(i+1)`] THEN + FIRST_X_ASSUM(fun th -> if concl th = `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*i+12) inlist):int32 list) = acc3` then MP_TAC th else NO_TAC) THEN + REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES] THEN ARITH_TAC; ALL_TAC] THEN + W(fun (asl,w) -> + let asms = map snd asl in + let find_a p = find p asms in + let m8c_def = find_a (fun th -> match concl th with Comb(Comb(Const("=",_),_),r) -> r = `mask8c:int64` | _ -> false) in + let m8b_def = find_a (fun th -> match concl th with Comb(Comb(Const("=",_),_),r) -> r = `mask8b:int64` | _ -> false) in + let m8d_val = find_a (fun th -> match concl th with Comb(Comb(Const("=",_),_),r) -> r = `mask8d:int64` && can(find_term(fun u->match u with Const("word_ushr",_)->true|_->false))(concl th) | _ -> false) in + let pinst = `\k. bit 7 (word_subword (f1bnd:int256) (8*k,8):byte)` in + let popcnt4 = REWRITE_RULE[m8d_val] (REWRITE_RULE[m8b_def; m8c_def] + (CONV_RULE(DEPTH_CONV BETA_CONV THENC ONCE_DEPTH_CONV NUM_REDUCE_CONV) (SPEC pinst POPCNT_BYTE3))) in + let lanesum = rand(concl popcnt4) in + let mb4 = find_a (fun th -> let c=concl th in is_forall c && can(find_term(fun u->u=`f1bnd:int256`))c && + can(find_term(fun u-> match u with Comb(Comb(Const("+",_),Var("k",_)),n) -> n=`24` | _ -> false))c) in + let mb4_tm = concl mb4 in + let i_le = find_a (fun th -> concl th = `16 * i <= 256`) in + let leninl = find_a (fun th -> concl th = `LENGTH(inlist:byte list) = 272`) in + let blk16 = find_a (fun th -> is_eq(concl th) && (try fst(dest_const(fst(strip_comb(lhand(concl th)))))="SUB_LIST" && length(dest_list(rand(concl th)))=16 with _->false)) in + let bb = MP (ISPECL [`inlist:byte list`; `i:num`; `chunk0:int128`] SUBITER_BLOCK_BYTES) + (CONJ (REWRITE_RULE[GSYM leninl] (MP (ARITH_RULE `16*i<=256 ==> 16*i+16<=272`) i_le)) blk16) in + let blk3_eq = el 3 (CONJUNCTS bb) in + let block3 = `[word_subword (chunk0:int128) (96,8); word_subword chunk0 (104,8); word_subword chunk0 (112,8); word_subword chunk0 (120,8)]:byte list` in + let block3len_x = mk_comb(`LENGTH:(int16)list->num`, mk_comb(`REJ_NIBBLES_ETA4`, block3)) in + let bsum4_raw = prove(mk_imp(mb4_tm, mk_eq(lanesum, block3len_x)), + DISCH_THEN(fun mbthm -> + let mbs = map (fun k -> let th=SPEC(mk_small_numeral k) mbthm in + CONV_RULE (NUM_REDUCE_CONV THENC ONCE_DEPTH_CONV EL_CONV) (MP th (EQT_ELIM(NUM_REDUCE_CONV(lhand(concl th)))))) [0;1;2;3;4;5;6;7] in + REWRITE_TAC mbs) THEN + GEN_REWRITE_TAC RAND_CONV [GSYM LENGTH_FILTER_BYTE_NIBBLES_4_BYTES] THEN + REWRITE_TAC[GSYM BITVAL_SUM_8_EQ_LENGTH_FILTER] THEN + SIMP_TAC[VAL_WORD_BYTE_LT256; BYTE_DIV16_LT; BYTE_MOD16_LT]) in + let pop_len4 = REWRITE_RULE[GSYM blk3_eq] (TRANS popcnt4 (MP bsum4_raw mb4)) in + let bridge4 = find_a (fun th -> match concl th with Comb(Comb(Const("=",_),Comb(Comb(Const("+",_),Var("acc3",_)),_)),Comb(Const("LENGTH",_),Comb(Const("REJ_SAMPLE_ETA4_BYTES",_),_)))->true|_->false) in + let le256 = find_a (fun th -> concl th = `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(i+1)) inlist):int32 list) <= 256`) in + let lt32 = REWRITE_RULE[SYM bridge4] (MATCH_MP (ARITH_RULE `a<=256 ==> a < 2 EXP 32`) le256) in + let rax_red0 = MATCH_MP RAX_NEST_REDUCE lt32 in + ASSUME_TAC pop_len4 THEN ASSUME_TAC rax_red0) THEN + W(fun (asl,w) -> + let pl4 = find (fun (_,th) -> match concl th with Comb(Comb(Const("=",_),Comb(Const("word_popcount",_),_)),_) -> can(find_term(fun u->u=`mask8d:int64`))(concl th) | _ -> false) asl in + let rr = find (fun (_,th) -> match concl th with Comb(Comb(Const("=",_),Comb(Const("word_zx",_),Comb(Comb(Const("word_add",_),_),_))),_) -> can(find_term(fun u->u=`acc3:num`))(concl th) | _ -> false) asl in + let bridge4 = find (fun (_,th) -> match concl th with Comb(Comb(Const("=",_),Comb(Comb(Const("+",_),Var("acc3",_)),_)),Comb(Const("LENGTH",_),Comb(Const("REJ_SAMPLE_ETA4_BYTES",_),_)))->true|_->false) asl in + RULE_ASSUM_TAC(REWRITE_RULE[snd pl4]) THEN RULE_ASSUM_TAC(REWRITE_RULE[snd rr]) THEN RULE_ASSUM_TAC(REWRITE_RULE[snd bridge4])) THEN + SUBGOAL_THEN `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(i+1)) inlist):int32 list) < 2 EXP 32` ASSUME_TAC THENL + [UNDISCH_TAC `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(i+1)) inlist):int32 list) <= 256` THEN ARITH_TAC; ALL_TAC] THEN + W(fun (asl,w) -> + let gt248 = find (fun (_,th) -> concl th = `248 < LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(i+1)) inlist):int32 list)`) asl in + let lt32 = find (fun (_,th) -> concl th = `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(i+1)) inlist):int32 list) < 2 EXP 32`) asl in + let ja_taken = MP (ISPECL [`LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(i+1)) inlist):int32 list)`; `248`] JA_TAKEN_GT) (CONJ (snd gt248) (snd lt32)) in + ASSUME_TAC ja_taken) THEN + X86_STEPS_TAC MLDSA_REJ_UNIFORM_ETA4_EXEC (58--59) THEN + ENSURES_FINAL_STATE_TAC THEN ASM_REWRITE_TAC[] THEN + (* --- eta2 tail (mk_midexit4_eta2): RCX4_COLLAPSE x4, late normalize --- *) + MP_TAC(SPEC `16*i` RCX4_COLLAPSE) THEN ANTS_TAC THENL [UNDISCH_TAC `16*i<=256` THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(fun th -> REWRITE_TAC[th]) THEN + MP_TAC(SPEC `16*i+4` RCX4_COLLAPSE) THEN ANTS_TAC THENL [UNDISCH_TAC `16*i<=256` THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(fun th -> REWRITE_TAC[th]) THEN REWRITE_TAC[ARITH_RULE `(16*i+4)+4 = 16*i+8`] THEN + MP_TAC(SPEC `16*i+8` RCX4_COLLAPSE) THEN ANTS_TAC THENL [UNDISCH_TAC `16*i<=256` THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(fun th -> REWRITE_TAC[th]) THEN REWRITE_TAC[ARITH_RULE `(16*i+8)+4 = 16*i+12`] THEN + MP_TAC(SPEC `16*i+12` RCX4_COLLAPSE) THEN ANTS_TAC THENL [UNDISCH_TAC `16*i<=256` THEN ARITH_TAC; ALL_TAC] THEN + DISCH_THEN(fun th -> REWRITE_TAC[th]) THEN REWRITE_TAC[ARITH_RULE `(16*i+12)+4 = 16*i+16`] THEN + REWRITE_TAC[ARITH_RULE `16*(i+1) = 16*i+16`] THEN + ASM_REWRITE_TAC[] THEN TRY(CONJ_TAC) THEN TRY REFL_TAC THEN TRY(AP_TERM_TAC THEN ARITH_TAC) THEN disch;; + +let MID_EXIT_SUBITER4_SAFE_ETA4 = + prove(midexit4_safe_eta4_tm, mk_midexit4_fix false SUBITER4_SAFE_DISCH_ETA4);; + +(* --- SAFE dispatch machinery + 5 EXIT_BLOCK_SAFE arms + assembly --- *) +(* --- SAFE dispatch tactics --- *) +let midexit_qpost_safe_eta4 (midthm:thm) : term = + let post = rand(rator(snd(dest_imp(snd(strip_forall(concl midthm)))))) in + let post = vsubst [`N-1`,`i:num`] post in + let sv, body = dest_abs post in + let value_post = lhand body in + let ev_and_ma = rand body in + let ev_eq = lhand ev_and_ma in + mk_abs(sv, mk_conj(value_post, ev_eq));; + +let MIDEXIT_DISPATCH_SAFE_ETA4 (safearm:thm) (fev_tm:term) (pexpr:term) (prevpos:term) : tactic = + let qpost = midexit_qpost_safe_eta4 safearm in + let _, qbody = dest_abs qpost in + let etail = rand (rand qbody) in + MATCH_MP_TAC ENSURES_TRANS_SIMPLE THEN EXISTS_TAC qpost THEN + CONJ_TAC THENL [MAYCHANGE_IDEMPOT_TAC; ALL_TAC] THEN + CONJ_TAC THENL + [MP_TAC(SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`N-1`;`stackpointer:int64`;`e:(uarch_event)list`] safearm) THEN + ANTS_TAC THENL + [REPEAT CONJ_TAC THEN (FIRST [FIRST_ASSUM ACCEPT_TAC; ASM_ARITH_TAC]); ALL_TAC] THEN + DISCH_THEN(fun bth -> SAFE_BRIDGE_FROM_ETA4 bth); + SUBGOAL_THEN (mk_comb(mk_comb(`(<=):num->num->bool`, + mk_comb(`LENGTH:(int32)list->num`, mk_comb(`REJ_SAMPLE_ETA4_BYTES:byte list->int32 list`, + mk_comb(mk_comb(`SUB_LIST:num#num->byte list->byte list`,mk_pair(`0`,pexpr)),`inlist:byte list`)))), `256`)) ASSUME_TAC THENL + [SUBGOAL_THEN (mk_eq(pexpr, mk_binop `(+):num->num->num` prevpos `4`)) SUBST1_TAC THENL + [UNDISCH_TAC `~(N=0)` THEN UNDISCH_TAC `16 * N <= 272` THEN ARITH_TAC; ALL_TAC] THEN + MATCH_MP_TAC OUTLEN0_LE_256_FROM_SUBITER THEN CONJ_TAC THENL + [UNDISCH_TAC `16 * N <= 272` THEN UNDISCH_TAC `~(N=0)` THEN UNDISCH_TAC `LENGTH(inlist:byte list)=272` THEN ARITH_TAC; + FIRST_ASSUM ACCEPT_TAC]; ALL_TAC] THEN + SCALAR_TAIL_LEG2_SAFE_ETA4 pexpr etail];; + +let OFFSET_ARM_SAFE_ETA4_TAC : tactic = + SUBGOAL_THEN `16 * N = 272` ASSUME_TAC THENL + [SUBGOAL_THEN `256 < 16 * N` ASSUME_TAC THENL + [UNDISCH_TAC `256 < 16 * N \/ 248 < LENGTH (REJ_NIBBLES_ETA4 (SUB_LIST (0,16 * N) inlist):int16 list)` THEN + REWRITE_TAC[GSYM LENGTH_REJ_SAMPLE_ETA4_BYTES] THEN + UNDISCH_TAC `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248` THEN + ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `N = 17` (fun th -> REWRITE_TAC[th] THEN CONV_TAC NUM_REDUCE_CONV) THEN + SUBGOAL_THEN `16 * N <= 272` ASSUME_TAC THENL + [UNDISCH_TAC `16 * (N-1) <= 256` THEN UNDISCH_TAC `~(N=0)` THEN + SPEC_TAC(`N:num`,`N:num`) THEN INDUCT_TAC THEN ARITH_TAC; ALL_TAC] THEN + UNDISCH_TAC `256 < 16 * N` THEN UNDISCH_TAC `16 * N <= 272` THEN ARITH_TAC; ALL_TAC] THEN + MP_TAC(SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`N:num`;`stackpointer:int64`;`e:(uarch_event)list`] EXIT_OFFSET_SAFE_ETA4) THEN + ANTS_TAC THENL + [ASM_REWRITE_TAC[] THEN + REWRITE_TAC[GSYM LENGTH_REJ_SAMPLE_ETA4_BYTES] THEN ASM_REWRITE_TAC[] THEN + UNDISCH_TAC `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248` THEN + SUBST1_TAC(ASSUME `16 * N = 272`) THEN REWRITE_TAC[]; ALL_TAC] THEN + DISCH_THEN(fun bth -> SAFE_BRIDGE_FROM_ETA4 bth);; + +let MIDEXIT_ARM_SAFE_ETA4_TAC : tactic = + SUBGOAL_THEN `248 < LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*N) inlist):int32 list)` ASSUME_TAC THENL + [UNDISCH_TAC `~(LENGTH (REJ_SAMPLE_ETA4_BYTES (SUB_LIST (0,16 * N) inlist):int32 list) <= 248)` THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `16 * N <= 272` ASSUME_TAC THENL + [UNDISCH_TAC `16 * (N-1) <= 256` THEN UNDISCH_TAC `~(N=0)` THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN `16 * ((N-1)+1) <= 272` ASSUME_TAC THENL + [UNDISCH_TAC `16 * N <= 272` THEN UNDISCH_TAC `~(N=0)` THEN ARITH_TAC; ALL_TAC] THEN + ASM_CASES_TAC `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(N-1)+4) inlist):int32 list) <= 248` THENL + [ASM_CASES_TAC `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(N-1)+8) inlist):int32 list) <= 248` THENL + [ASM_CASES_TAC `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(N-1)+12) inlist):int32 list) <= 248` THENL + [SUBGOAL_THEN `248 < LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*((N-1)+1)) inlist):int32 list)` ASSUME_TAC THENL + [SUBGOAL_THEN `16*((N-1)+1) = 16*N` SUBST1_TAC THENL + [UNDISCH_TAC `~(N=0)` THEN ARITH_TAC; ALL_TAC] THEN FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN + MIDEXIT_DISPATCH_SAFE_ETA4 MID_EXIT_SUBITER4_SAFE_ETA4 + `f_ev_midexit_subiter4_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) (N-1)` + `16*((N-1)+1)` `16*(N-1)+12`; + MIDEXIT_DISPATCH_SAFE_ETA4 MID_EXIT_SUBITER3_SAFE_ETA4 + `f_ev_midexit_subiter3_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) (N-1)` + `16*(N-1)+12` `16*(N-1)+8`]; + MIDEXIT_DISPATCH_SAFE_ETA4 MID_EXIT_SUBITER2_SAFE_ETA4 + `f_ev_midexit_subiter2_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) (N-1)` + `16*(N-1)+8` `16*(N-1)+4`]; + MIDEXIT_DISPATCH_SAFE_ETA4 MID_EXIT_SUBITER1_SAFE_ETA4 + `f_ev_midexit_subiter1_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) (N-1)` + `16*(N-1)+4` `16*(N-1)`];; + +(* --- EXIT_BLOCK_SAFE arms 2/3/4 (defines shared builder) --- *) +let MASK_DBL_N1_ETA4 = ARITH_RULE `2 * (16 * (N - 1)) = 32 * (N - 1)`;; +let MASK_DBL_N_ETA4 = ARITH_RULE `2 * (16 * N) = 32 * N`;; +let MASK_DBL_N1_4_ETA4 = ARITH_RULE `2 * (16 * (N - 1) + 4) = 32 * (N - 1) + 8`;; +let MASK_DBL_N1_8_ETA4 = ARITH_RULE `2 * (16 * (N - 1) + 8) = 32 * (N - 1) + 16`;; +let MASK_DBL_N1_12_ETA4 = ARITH_RULE `2 * (16 * (N - 1) + 12) = 32 * (N - 1) + 24`;; + +let MASK_OF_ETA4 (maskgoal:term) (bexp:term) (redthm:thm) : tactic = + SUBGOAL_THEN maskgoal ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`; bexp] STORE_BRIDGE_ETA4) THEN + REWRITE_TAC[redthm] THEN + DISCH_THEN(fun th -> REWRITE_TAC[GSYM th]) THEN FIRST_ASSUM ACCEPT_TAC; + ALL_TAC];; + +let mk_midexit_safe_tm_eta4 (extraconds:term list) : term = + let body = snd(strip_forall(concl EXIT_OFFSET_SAFE_ETA4)) in + let hyps_off, ens = dest_imp body in + let ensc, ppf = strip_comb ens in + let step = el 0 ppf and pre = el 1 ppf and frame = el 3 ppf in + let shared = fst(chop_list 6 (conjuncts hyps_off)) in + let wopf = `!m. m < N ==> 16 * m <= 256 /\ + LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(0,16*m) inlist):int16 list) <= 248` in + let pN = `256 < 16 * N \/ + 248 < LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(0,16*N) inlist):int16 list)` in + let hyps' = list_mk_conj (shared @ [`~(N = 0)`; `~(N = 1)`; wopf; pN] @ extraconds) in + let sv = `s:x86state` in + let ctpost = mk_abs(sv, + `read RIP s = word(pc + LENGTH(BUTLAST mldsa_rej_uniform_eta4_tmc)) /\ + (?e2. read events s = APPEND e2 (e:(uarch_event)list) /\ + e2 = f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) N /\ + memaccess_inbounds e2 [(buf:int64),272; (table:int64),2048] + [(res:int64),1024])`) in + let ens' = list_mk_comb(ensc,[step; pre; ctpost; frame]) in + list_mk_forall + ([`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`; + `N:num`;`stackpointer:int64`;`e:(uarch_event)list`], + mk_imp(hyps', ens'));; + +let MIDEXIT_SETUP_TAC_ETA4 : tactic = + REPEAT GEN_TAC THEN DISCH_THEN(MAP_EVERY ASSUME_TAC o CONJUNCTS) THEN + SUBGOAL_THEN + `16 * (N-1) <= 256 /\ + LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(0,16*(N-1)) inlist):int16 list) <= 248` + STRIP_ASSUME_TAC THENL + [FIRST_X_ASSUM(MP_TAC o SPEC `N-1` o check(is_forall o concl)) THEN + ANTS_TAC THENL [UNDISCH_TAC `~(N = 0)` THEN ARITH_TAC; REWRITE_TAC[]]; + ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(N-1)) inlist):int32 list) <= 248` + ASSUME_TAC THENL + [ASM_REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES]; ALL_TAC] THEN + SUBGOAL_THEN `16 * N <= 272` ASSUME_TAC THENL + [UNDISCH_TAC `16 * (N-1) <= 256` THEN UNDISCH_TAC `~(N = 0)` THEN + SPEC_TAC(`N:num`,`N:num`) THEN INDUCT_TAC THEN ARITH_TAC; + ALL_TAC];; + +let exit_block_midexit2_safe_tm_eta4 = mk_midexit_safe_tm_eta4 + [`~(LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248)`; + `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(N-1)+4) inlist):int32 list) <= 248`; + `~(LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(N-1)+8) inlist):int32 list) <= 248)`];; + +let midexit2_concrete_post_eta4 = + `\s. read RIP s = word(pc + LENGTH(BUTLAST mldsa_rej_uniform_eta4_tmc)) /\ + read events s = + APPEND (f_ev_scalar_tail_eta4 (272 - (16 * (N-1) + 8)) res buf pc inlist (16 * (N-1) + 8)) + (APPEND (f_ev_midexit_subiter2_eta4 res buf table pc (REJ_MASK_ETA4 inlist) (N-1)) + (e:(uarch_event)list))`;; + +let EXIT_BLOCK_SAFE_MIDEXIT2_ETA4 = prove + (exit_block_midexit2_safe_tm_eta4, + MIDEXIT_SETUP_TAC_ETA4 THEN + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN + EXISTS_TAC midexit2_concrete_post_eta4 THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN + CONJ_TAC THENL [FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN + MASK_OF_ETA4 `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1))(REJ_MASK_ETA4 inlist)) <= 248` + `16 * (N-1)` MASK_DBL_N1_ETA4 THEN + MASK_OF_ETA4 `~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA4 inlist)) <= 248)` + `16 * N` MASK_DBL_N_ETA4 THEN + MASK_OF_ETA4 `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA4 inlist)) <= 248` + `16 * (N-1) + 4` MASK_DBL_N1_4_ETA4 THEN + MASK_OF_ETA4 `~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA4 inlist)) <= 248)` + `16 * (N-1) + 8` MASK_DBL_N1_8_ETA4 THEN + MATCH_MP_TAC MIDEXIT2_EXISTS_ETA4 THEN ASM_REWRITE_TAC[]; + MIDEXIT_DISPATCH_SAFE_ETA4 MID_EXIT_SUBITER2_SAFE_ETA4 + `f_ev_midexit_subiter2_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) (N-1)` + `16*(N-1)+8` `16*(N-1)+4`]);; + +let exit_block_midexit3_safe_tm_eta4 = mk_midexit_safe_tm_eta4 + [`~(LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248)`; + `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(N-1)+4) inlist):int32 list) <= 248`; + `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(N-1)+8) inlist):int32 list) <= 248`; + `~(LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(N-1)+12) inlist):int32 list) <= 248)`];; + +let midexit3_concrete_post_eta4 = + `\s. read RIP s = word(pc + LENGTH(BUTLAST mldsa_rej_uniform_eta4_tmc)) /\ + read events s = + APPEND (f_ev_scalar_tail_eta4 (272 - (16 * (N-1) + 12)) res buf pc inlist (16 * (N-1) + 12)) + (APPEND (f_ev_midexit_subiter3_eta4 res buf table pc (REJ_MASK_ETA4 inlist) (N-1)) + (e:(uarch_event)list))`;; + +let EXIT_BLOCK_SAFE_MIDEXIT3_ETA4 = prove + (exit_block_midexit3_safe_tm_eta4, + MIDEXIT_SETUP_TAC_ETA4 THEN + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN + EXISTS_TAC midexit3_concrete_post_eta4 THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN + CONJ_TAC THENL [FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN + MASK_OF_ETA4 `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1))(REJ_MASK_ETA4 inlist)) <= 248` + `16 * (N-1)` MASK_DBL_N1_ETA4 THEN + MASK_OF_ETA4 `~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA4 inlist)) <= 248)` + `16 * N` MASK_DBL_N_ETA4 THEN + MASK_OF_ETA4 `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA4 inlist)) <= 248` + `16 * (N-1) + 4` MASK_DBL_N1_4_ETA4 THEN + MASK_OF_ETA4 `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA4 inlist)) <= 248` + `16 * (N-1) + 8` MASK_DBL_N1_8_ETA4 THEN + MASK_OF_ETA4 `~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 24)(REJ_MASK_ETA4 inlist)) <= 248)` + `16 * (N-1) + 12` MASK_DBL_N1_12_ETA4 THEN + MATCH_MP_TAC MIDEXIT3_EXISTS_ETA4 THEN ASM_REWRITE_TAC[]; + MIDEXIT_DISPATCH_SAFE_ETA4 MID_EXIT_SUBITER3_SAFE_ETA4 + `f_ev_midexit_subiter3_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) (N-1)` + `16*(N-1)+12` `16*(N-1)+8`]);; + +(* --- OFFSET arm --- *) +let exit_block_offset_safe_tm_eta4 = + let body = snd(strip_forall(concl EXIT_OFFSET_SAFE_ETA4)) in + let hyps_off, ens = dest_imp body in + let ensc, ppf = strip_comb ens in + let step = el 0 ppf and pre = el 1 ppf and frame = el 3 ppf in + let shared = fst(chop_list 6 (conjuncts hyps_off)) in + let wopf = `!m. m < N ==> 16 * m <= 256 /\ + LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(0,16*m) inlist):int16 list) <= 248` in + let pN = `256 < 16 * N \/ + 248 < LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(0,16*N) inlist):int16 list)` in + let offbyte = `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248` in + let hyps' = list_mk_conj (shared @ [`~(N = 0)`; `~(N = 1)`; wopf; pN; offbyte]) in + let sv = `s:x86state` in + let ctpost = mk_abs(sv, + `read RIP s = word(pc + LENGTH(BUTLAST mldsa_rej_uniform_eta4_tmc)) /\ + (?e2. read events s = APPEND e2 (e:(uarch_event)list) /\ + e2 = f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) N /\ + memaccess_inbounds e2 [(buf:int64),272; (table:int64),2048] + [(res:int64),1024])`) in + let ens' = list_mk_comb(ensc,[step; pre; ctpost; frame]) in + list_mk_forall + ([`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`; + `N:num`;`stackpointer:int64`;`e:(uarch_event)list`], + mk_imp(hyps', ens'));; + +let EXIT_BLOCK_SAFE_OFFSET_ETA4 = prove + (exit_block_offset_safe_tm_eta4, + REPEAT GEN_TAC THEN DISCH_THEN(MAP_EVERY ASSUME_TAC o CONJUNCTS) THEN + SUBGOAL_THEN + `16 * (N-1) <= 256 /\ + LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(0,16*(N-1)) inlist):int16 list) <= 248` + STRIP_ASSUME_TAC THENL + [FIRST_X_ASSUM(MP_TAC o SPEC `N-1` o check(is_forall o concl)) THEN + ANTS_TAC THENL [UNDISCH_TAC `~(N = 0)` THEN ARITH_TAC; REWRITE_TAC[]]; + ALL_TAC] THEN + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN + EXISTS_TAC (rand(rator(snd(dest_imp(snd(strip_forall(concl EXIT_OFFSET_SAFE_ETA4))))))) THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN + CONJ_TAC THENL [FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN + SUBGOAL_THEN `16 * N = 272` ASSUME_TAC THENL + [SUBGOAL_THEN `N = 17` (fun th -> REWRITE_TAC[th] THEN CONV_TAC NUM_REDUCE_CONV) THEN + SUBGOAL_THEN `256 < 16 * N` ASSUME_TAC THENL + [UNDISCH_TAC `256 < 16 * N \/ + 248 < LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(0,16*N) inlist):int16 list)` THEN + REWRITE_TAC[GSYM LENGTH_REJ_SAMPLE_ETA4_BYTES] THEN + UNDISCH_TAC `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248` THEN + ARITH_TAC; + ALL_TAC] THEN + SUBGOAL_THEN `16 * N <= 272` ASSUME_TAC THENL + [UNDISCH_TAC `16 * (N-1) <= 256` THEN UNDISCH_TAC `~(N = 0)` THEN + SPEC_TAC(`N:num`,`N:num`) THEN INDUCT_TAC THEN ARITH_TAC; + ALL_TAC] THEN + UNDISCH_TAC `256 < 16 * N` THEN UNDISCH_TAC `16 * N <= 272` THEN ARITH_TAC; + ALL_TAC] THEN + SUBGOAL_THEN + `NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA4 inlist)) <= 248` + ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`; `16 * N`] STORE_BRIDGE_ETA4) THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * N) = 32 * N`] THEN + DISCH_THEN(fun th -> REWRITE_TAC[GSYM th]) THEN FIRST_ASSUM ACCEPT_TAC; + ALL_TAC] THEN + MATCH_MP_TAC OFFSET_EXISTS_ETA4 THEN ASM_REWRITE_TAC[]; + OFFSET_ARM_SAFE_ETA4_TAC]);; + +(* --- MIDEXIT1 arm --- *) +let exit_block_midexit1_safe_tm_eta4 = + let body = snd(strip_forall(concl EXIT_OFFSET_SAFE_ETA4)) in + let hyps_off, ens = dest_imp body in + let ensc, ppf = strip_comb ens in + let step = el 0 ppf and pre = el 1 ppf and frame = el 3 ppf in + let shared = fst(chop_list 6 (conjuncts hyps_off)) in + let wopf = `!m. m < N ==> 16 * m <= 256 /\ + LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(0,16*m) inlist):int16 list) <= 248` in + let pN = `256 < 16 * N \/ + 248 < LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(0,16*N) inlist):int16 list)` in + let midcase = `~(LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248)` in + let sub1sel = `~(LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(N-1)+4) inlist):int32 list) <= 248)` in + let hyps' = list_mk_conj + (shared @ [`~(N = 0)`; `~(N = 1)`; wopf; pN; midcase; sub1sel]) in + let sv = `s:x86state` in + let ctpost = mk_abs(sv, + `read RIP s = word(pc + LENGTH(BUTLAST mldsa_rej_uniform_eta4_tmc)) /\ + (?e2. read events s = APPEND e2 (e:(uarch_event)list) /\ + e2 = f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) N /\ + memaccess_inbounds e2 [(buf:int64),272; (table:int64),2048] + [(res:int64),1024])`) in + let ens' = list_mk_comb(ensc,[step; pre; ctpost; frame]) in + list_mk_forall + ([`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`; + `N:num`;`stackpointer:int64`;`e:(uarch_event)list`], + mk_imp(hyps', ens'));; + +let midexit1_concrete_post_eta4 = + `\s. read RIP s = word(pc + LENGTH(BUTLAST mldsa_rej_uniform_eta4_tmc)) /\ + read events s = + APPEND (f_ev_scalar_tail_eta4 (272 - (16 * (N-1) + 4)) res buf pc inlist (16 * (N-1) + 4)) + (APPEND (f_ev_midexit_subiter1_eta4 res buf table pc (REJ_MASK_ETA4 inlist) (N-1)) + (e:(uarch_event)list))`;; + +let EXIT_BLOCK_SAFE_MIDEXIT1_ETA4 = prove + (exit_block_midexit1_safe_tm_eta4, + REPEAT GEN_TAC THEN DISCH_THEN(MAP_EVERY ASSUME_TAC o CONJUNCTS) THEN + SUBGOAL_THEN + `16 * (N-1) <= 256 /\ + LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(0,16*(N-1)) inlist):int16 list) <= 248` + STRIP_ASSUME_TAC THENL + [FIRST_X_ASSUM(MP_TAC o SPEC `N-1` o check(is_forall o concl)) THEN + ANTS_TAC THENL [UNDISCH_TAC `~(N = 0)` THEN ARITH_TAC; REWRITE_TAC[]]; + ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(N-1)) inlist):int32 list) <= 248` + ASSUME_TAC THENL + [ASM_REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES]; ALL_TAC] THEN + SUBGOAL_THEN `16 * N <= 272` ASSUME_TAC THENL + [UNDISCH_TAC `16 * (N-1) <= 256` THEN UNDISCH_TAC `~(N = 0)` THEN + SPEC_TAC(`N:num`,`N:num`) THEN INDUCT_TAC THEN ARITH_TAC; + ALL_TAC] THEN + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN + EXISTS_TAC midexit1_concrete_post_eta4 THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN + CONJ_TAC THENL [FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN + SUBGOAL_THEN `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1))(REJ_MASK_ETA4 inlist)) <= 248` + ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`; `16 * (N-1)`] STORE_BRIDGE_ETA4) THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * (N-1)) = 32 * (N-1)`] THEN + DISCH_THEN(fun th -> REWRITE_TAC[GSYM th]) THEN FIRST_ASSUM ACCEPT_TAC; + ALL_TAC] THEN + SUBGOAL_THEN `~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA4 inlist)) <= 248)` + ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`; `16 * N`] STORE_BRIDGE_ETA4) THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * N) = 32 * N`] THEN + DISCH_THEN(fun th -> REWRITE_TAC[GSYM th]) THEN FIRST_ASSUM ACCEPT_TAC; + ALL_TAC] THEN + SUBGOAL_THEN `~(NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA4 inlist)) <= 248)` + ASSUME_TAC THENL + [MP_TAC(SPECL [`inlist:byte list`; `16 * (N-1) + 4`] STORE_BRIDGE_ETA4) THEN + REWRITE_TAC[ARITH_RULE `2 * (16 * (N-1) + 4) = 32 * (N-1) + 8`] THEN + DISCH_THEN(fun th -> REWRITE_TAC[GSYM th]) THEN FIRST_ASSUM ACCEPT_TAC; + ALL_TAC] THEN + MATCH_MP_TAC MIDEXIT1_EXISTS_ETA4 THEN ASM_REWRITE_TAC[]; + MIDEXIT_DISPATCH_SAFE_ETA4 MID_EXIT_SUBITER1_SAFE_ETA4 + `f_ev_midexit_subiter1_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) (N-1)` + `16*(N-1)+4` `16*(N-1)`]);; + +(* --- MIDEXIT4 arm --- *) +let SAFE_BRIDGE_CLEAN_ETA4 (bth:thm) : tactic = + W(fun (asl,gl) -> + let lframe = rand(concl bth) in + let lpost = rand(rator(concl bth)) in + let lpre = rand(rator(rator(concl bth))) in + let gframe = rand gl in + let subsumed_tm = mk_binop + `(subsumed):(x86state->x86state->bool)->(x86state->x86state->bool)->bool` + lframe gframe in + let subsumed_th = prove(subsumed_tm, + REPEAT(MATCH_MP_TAC SUBSUMED_SEQ THEN REWRITE_TAC[SUBSUMED_REFL]) THEN + SUBSUMED_MAYCHANGE_TAC) in + let bth2 = MATCH_MP ENSURES_FRAME_SUBSUMED (CONJ subsumed_th bth) in + MATCH_MP_TAC ENSURES_PRECONDITION_THM THEN EXISTS_TAC lpre THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN EXISTS_TAC lpost THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + ACCEPT_TAC bth2]]);; + +let SCALAR_TAIL_LEG2_CLEAN_ETA4 (p:term) (etail:term) : tactic = + W(fun (asl,gl) -> + let atp = SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`; + `pc:num`;p;`stackpointer:int64`;etail] + MLDSA_REJ_UNIFORM_ETA4_SCALAR_TAIL_AT_P_SAFE in + let atp_ens = snd(dest_imp(concl atp)) in + let _,ppf = strip_comb atp_ens in + let atp_pre = el 1 ppf and atp_post = el 2 ppf in + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN EXISTS_TAC atp_post THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + MATCH_MP_TAC ENSURES_PRECONDITION_THM THEN EXISTS_TAC atp_pre THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + MP_TAC atp THEN ANTS_TAC THENL + [REPEAT CONJ_TAC THEN FIRST_ASSUM ACCEPT_TAC; + MATCH_MP_TAC(REWRITE_RULE[IMP_CONJ] ENSURES_FRAME_SUBSUMED) THEN + REPEAT(MATCH_MP_TAC SUBSUMED_SEQ THEN REWRITE_TAC[SUBSUMED_REFL]) THEN + SUBSUMED_MAYCHANGE_TAC]]]);; + +let exit_block_midexit4_safe_tm_eta4 = mk_midexit_safe_tm_eta4 + [`~(LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248)`; + `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(N-1)+4) inlist):int32 list) <= 248`; + `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(N-1)+8) inlist):int32 list) <= 248`; + `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(N-1)+12) inlist):int32 list) <= 248`];; + +let midexit4_concrete_post_eta4 = + `\s. read RIP s = word(pc + LENGTH(BUTLAST mldsa_rej_uniform_eta4_tmc)) /\ + read events s = + APPEND (f_ev_scalar_tail_eta4 (272 - (16 * ((N-1) + 1))) res buf pc inlist (16 * ((N-1) + 1))) + (APPEND (f_ev_midexit_subiter4_eta4 res buf table pc (REJ_MASK_ETA4 inlist) (N-1)) + (e:(uarch_event)list))`;; + +let EXIT_BLOCK_SAFE_MIDEXIT4_ETA4 = prove + (exit_block_midexit4_safe_tm_eta4, + MIDEXIT_SETUP_TAC_ETA4 THEN + SUBGOAL_THEN `16 * ((N-1) + 1) = 16 * N` ASSUME_TAC THENL + [UNDISCH_TAC `~(N = 0)` THEN ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN + `248 < LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*((N-1)+1)) inlist):int32 list)` + ASSUME_TAC THENL + [SUBST1_TAC(ASSUME `16 * ((N-1) + 1) = 16 * N`) THEN + UNDISCH_TAC `~(LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248)` THEN + ARITH_TAC; ALL_TAC] THEN + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN + EXISTS_TAC midexit4_concrete_post_eta4 THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN + CONJ_TAC THENL [FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN + RULE_ASSUM_TAC(REWRITE_RULE[ASSUME `16 * ((N-1) + 1) = 16 * N`]) THEN + MASK_OF_ETA4 `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1))(REJ_MASK_ETA4 inlist)) <= 248` + `16 * (N-1)` MASK_DBL_N1_ETA4 THEN + MASK_OF_ETA4 `~(NUM_ACCEPTED(SUB_LIST(0,32 * N)(REJ_MASK_ETA4 inlist)) <= 248)` + `16 * N` MASK_DBL_N_ETA4 THEN + MASK_OF_ETA4 `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 8)(REJ_MASK_ETA4 inlist)) <= 248` + `16 * (N-1) + 4` MASK_DBL_N1_4_ETA4 THEN + MASK_OF_ETA4 `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 16)(REJ_MASK_ETA4 inlist)) <= 248` + `16 * (N-1) + 8` MASK_DBL_N1_8_ETA4 THEN + MASK_OF_ETA4 `NUM_ACCEPTED(SUB_LIST(0,32 * (N-1) + 24)(REJ_MASK_ETA4 inlist)) <= 248` + `16 * (N-1) + 12` MASK_DBL_N1_12_ETA4 THEN + MATCH_MP_TAC MIDEXIT4_EXISTS_ETA4 THEN ASM_REWRITE_TAC[]; + MATCH_MP_TAC ENSURES_TRANS_SIMPLE THEN + EXISTS_TAC (midexit_qpost_safe_eta4 MID_EXIT_SUBITER4_SAFE_ETA4) THEN + CONJ_TAC THENL [MAYCHANGE_IDEMPOT_TAC; ALL_TAC] THEN + CONJ_TAC THENL + [MP_TAC(SPECL [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`; + `pc:num`;`N-1`;`stackpointer:int64`;`e:(uarch_event)list`] + MID_EXIT_SUBITER4_SAFE_ETA4) THEN + ANTS_TAC THENL + [REPEAT CONJ_TAC THEN (FIRST[FIRST_ASSUM ACCEPT_TAC; ASM_ARITH_TAC]); ALL_TAC] THEN + DISCH_THEN(fun bth -> SAFE_BRIDGE_CLEAN_ETA4 bth); + SUBGOAL_THEN `16 * ((N-1) + 1) <= 272` ASSUME_TAC THENL + [UNDISCH_TAC `16 * N <= 272` THEN UNDISCH_TAC `16 * ((N-1) + 1) = 16 * N` THEN + ARITH_TAC; ALL_TAC] THEN + SUBGOAL_THEN + `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*((N-1)+1)) inlist):int32 list) <= 256` + ASSUME_TAC THENL + [SUBGOAL_THEN `16 * ((N-1) + 1) = (16 * (N-1) + 12) + 4` SUBST1_TAC THENL + [UNDISCH_TAC `~(N = 0)` THEN ARITH_TAC; ALL_TAC] THEN + MATCH_MP_TAC OUTLEN0_LE_256_FROM_SUBITER THEN CONJ_TAC THENL + [UNDISCH_TAC `16 * N <= 272` THEN UNDISCH_TAC `16 * ((N-1) + 1) = 16 * N` THEN + UNDISCH_TAC `LENGTH(inlist:byte list) = 272` THEN ARITH_TAC; + FIRST_ASSUM ACCEPT_TAC]; ALL_TAC] THEN + SCALAR_TAIL_LEG2_CLEAN_ETA4 `16 * ((N-1) + 1)` + `APPEND (f_ev_midexit_subiter4_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) (N-1)) + (e:(uarch_event)list)`]]);; + +(* --- EXIT_BLOCK_SAFE_ETA4 (assembled) --- *) +let exit_block_safe_eta4_tm = mk_midexit_safe_tm_eta4 [];; + +let EXIT_BLOCK_SAFE_ETA4 = prove + (exit_block_safe_eta4_tm, + MIDEXIT_SETUP_TAC_ETA4 THEN + ASM_CASES_TAC + `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*N) inlist):int32 list) <= 248` THENL + [MATCH_MP_TAC EXIT_BLOCK_SAFE_OFFSET_ETA4 THEN ASM_REWRITE_TAC[]; + ASM_CASES_TAC + `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(N-1)+4) inlist):int32 list) <= 248` THENL + [ASM_CASES_TAC + `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(N-1)+8) inlist):int32 list) <= 248` THENL + [ASM_CASES_TAC + `LENGTH(REJ_SAMPLE_ETA4_BYTES(SUB_LIST(0,16*(N-1)+12) inlist):int32 list) <= 248` THENL + [MATCH_MP_TAC EXIT_BLOCK_SAFE_MIDEXIT4_ETA4 THEN ASM_REWRITE_TAC[]; + MATCH_MP_TAC EXIT_BLOCK_SAFE_MIDEXIT3_ETA4 THEN ASM_REWRITE_TAC[]]; + MATCH_MP_TAC EXIT_BLOCK_SAFE_MIDEXIT2_ETA4 THEN ASM_REWRITE_TAC[]]; + MATCH_MP_TAC EXIT_BLOCK_SAFE_MIDEXIT1_ETA4 THEN ASM_REWRITE_TAC[]]]);; + + +(* --- CORE_SAFE_FREEN_ETA4 --- *) +let core_safe_freeN_tm_eta4 = + let bod = snd(strip_forall(concl ETA4_LOOP_SAFE)) in + let hyps,ens = dest_imp bod in + let comb,args = strip_comb ens in + let step = el 0 args and pre = el 1 args and frame = el 3 args in + let pN = `256 < 16 * N \/ + 248 < LENGTH(REJ_NIBBLES_ETA4(SUB_LIST(0,16*N) inlist):int16 list)` in + let hyps' = list_mk_conj (conjuncts hyps @ [pN]) in + let sv = `s:x86state` in + let post = mk_abs(sv, + `read RIP s = word (pc + LENGTH (BUTLAST mldsa_rej_uniform_eta4_tmc)) /\ + (?e2. read events s = APPEND e2 (e:(uarch_event)list) /\ + e2 = APPEND (f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 (inlist:byte list)) N) + (ENUMERATEL (N - 1) + (f_ev_loop_eta4 res buf table pc (REJ_MASK_ETA4 inlist))) /\ + memaccess_inbounds e2 [(buf:int64),272; (table:int64),2048] + [(res:int64),1024])`) in + let ens' = list_mk_comb(comb, [step; pre; post; frame]) in + list_mk_forall(fst(strip_forall(concl ETA4_LOOP_SAFE)), mk_imp(hyps', ens'));; + +let LOOPP_ETA4 = REWRITE_RULE[SOME_FLAGS] ETA4_LOOP_SAFE;; +let loop_post_tm_eta4 = el 2 (snd(strip_comb(snd(dest_imp(snd(strip_forall(concl ETA4_LOOP_SAFE)))))));; +let EXIT_INST_ETA4 = SPECL + [`res:int64`;`buf:int64`;`table:int64`;`inlist:byte list`;`pc:num`;`N:num`; + `stackpointer:int64`; + `APPEND (ENUMERATEL (N-1) (f_ev_loop_eta4 res buf table pc (REJ_MASK_ETA4 inlist))) + (e:(uarch_event)list)`] + EXIT_BLOCK_SAFE_ETA4;; +let q_inter_eta4 = el 1 (snd(strip_comb(snd(dest_imp(concl EXIT_INST_ETA4)))));; +let exit_post_tm_eta4 = el 2 (snd(strip_comb(snd(dest_imp(concl EXIT_INST_ETA4)))));; + +let CORE_SAFE_FREEN_ETA4 = prove + (core_safe_freeN_tm_eta4, + REPEAT GEN_TAC THEN + REWRITE_TAC[SOME_FLAGS] THEN + DISCH_THEN(MAP_EVERY ASSUME_TAC o CONJUNCTS) THEN + MATCH_MP_TAC ENSURES_TRANS_SIMPLE THEN + EXISTS_TAC q_inter_eta4 THEN + CONJ_TAC THENL [MAYCHANGE_IDEMPOT_TAC; ALL_TAC] THEN + CONJ_TAC THENL + [MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN + EXISTS_TAC loop_post_tm_eta4 THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[]; + MATCH_MP_TAC LOOPP_ETA4 THEN ASM_REWRITE_TAC[]]; + SUBGOAL_THEN `16 * (N - 1) <= 256` ASSUME_TAC THENL + [FIRST_ASSUM(MP_TAC o SPEC `N-1` o check(is_forall o concl)) THEN + ANTS_TAC THENL + [UNDISCH_TAC `~(N=0)` THEN ARITH_TAC; + DISCH_THEN(ACCEPT_TAC o CONJUNCT1)]; + ALL_TAC] THEN + MP_TAC EXIT_INST_ETA4 THEN ANTS_TAC THENL + [RULE_ASSUM_TAC(REWRITE_RULE[NONOVERLAPPING_CLAUSES; + LENGTH_MLDSA_REJ_UNIFORM_ETA4_TMC]) THEN + ASM_REWRITE_TAC[]; + DISCH_THEN(fun exitth -> + MATCH_MP_TAC ENSURES_POSTCONDITION_THM THEN + EXISTS_TAC exit_post_tm_eta4 THEN + CONJ_TAC THENL + [GEN_TAC THEN BETA_TAC THEN STRIP_TAC THEN + FIRST_X_ASSUM(SUBST_ALL_TAC o + check (fun th -> is_eq(concl th) && is_var(lhs(concl th)))) THEN + CONJ_TAC THENL + [ASM_REWRITE_TAC[]; + EXISTS_TAC + `APPEND (f_ev_exit_eta4 res buf table pc (REJ_MASK_ETA4 inlist) N) + (ENUMERATEL (N-1) + (f_ev_loop_eta4 res buf table pc (REJ_MASK_ETA4 inlist)))` THEN + REPEAT CONJ_TAC THENL + [ASM_REWRITE_TAC[APPEND_ASSOC]; + REFL_TAC; + REWRITE_TAC[MEMACCESS_INBOUNDS_APPEND] THEN CONJ_TAC THENL + [FIRST_ASSUM ACCEPT_TAC; + MATCH_MP_TAC MEMACCESS_ENUM_LOOP_ETA4 THEN ASM_REWRITE_TAC[]]]]; + ACCEPT_TAC exitth])]]);; + + +(* --- CORE_SAFE / NOIBT_SUBROUTINE_SAFE / SUBROUTINE_SAFE --- *) +let f_ev_core_eta4 = + `\(res:int64) (buf:int64) (table:int64) (pc:num) (mask:(bool)list). + APPEND (f_ev_exit_eta4 res buf table pc mask (N_OF_MASK_ETA4 mask)) + (ENUMERATEL (N_OF_MASK_ETA4 mask - 1) + (f_ev_loop_eta4 res buf table pc mask)) + :(uarch_event)list`;; + +let core_safe_eta4_tm = + `?f_events:int64->int64->int64->num->(bool)list->(uarch_event)list. + !res buf table (inlist:byte list) e pc. + LENGTH inlist = 272 /\ + nonoverlapping (word pc,LENGTH mldsa_rej_uniform_eta4_tmc) (res,1024) /\ + nonoverlapping (word pc,LENGTH mldsa_rej_uniform_eta4_tmc) (buf,272) /\ + nonoverlapping (word pc,LENGTH mldsa_rej_uniform_eta4_tmc) (table,2048) /\ + nonoverlapping (res,1024) (buf,272) /\ + nonoverlapping (res,1024) (table,2048) + ==> ensures x86 + (\s. bytes_loaded s (word pc) (BUTLAST mldsa_rej_uniform_eta4_tmc) /\ + read RIP s = word pc /\ + C_ARGUMENTS [res; buf; table] s /\ + read (memory :> bytes (buf,272)) s = num_of_wordlist inlist /\ + read (memory :> bytes (table,2048)) s = + num_of_wordlist mldsa_rej_uniform_table /\ + read events s = e) + (\s. read RIP s = + word (pc + LENGTH (BUTLAST mldsa_rej_uniform_eta4_tmc)) /\ + (?e2. read events s = APPEND e2 e /\ + e2 = f_events res buf table pc (REJ_MASK_ETA4 inlist) /\ + memaccess_inbounds e2 [buf,272; table,2048] [res,1024])) + (MAYCHANGE [RIP; RAX; RCX; R8; R9; R10; R11] ,, + MAYCHANGE + [ZMM0; ZMM1; ZMM2; ZMM3; ZMM4; ZMM5; ZMM6] ,, + MAYCHANGE SOME_FLAGS ,, + MAYCHANGE [events] ,, + MAYCHANGE [memory :> bytes (res,1024)])`;; + +let MLDSA_REJ_UNIFORM_ETA4_CORE_SAFE = prove + (core_safe_eta4_tm, + EXISTS_TAC f_ev_core_eta4 THEN + REPEAT GEN_TAC THEN STRIP_TAC THEN + GHOST_INTRO_TAC `stackpointer:int64` `read RSP` THEN + CONV_TAC(TOP_DEPTH_CONV BETA_CONV) THEN + MATCH_MP_TAC CORE_SAFE_FREEN_ETA4 THEN + ASM_REWRITE_TAC[] THEN + MP_TAC(SPEC `REJ_MASK_ETA4 (inlist:byte list)` N_OF_MASK_ETA4_MINIMAL) THEN + REWRITE_TAC[GSYM NIBLEN_EQ_NUMACC_ETA4] THEN + ABBREV_TAC `NN = N_OF_MASK_ETA4 (REJ_MASK_ETA4 (inlist:byte list))` THEN + DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC ASSUME_TAC) THEN + REPEAT CONJ_TAC THENL + [DISCH_TAC THEN + FIRST_X_ASSUM(MP_TAC o check(is_disj o concl)) THEN + ASM_REWRITE_TAC[MULT_CLAUSES; ADD_CLAUSES; SUB_LIST_CLAUSES; + REJ_NIBBLES_ETA4_EMPTY; LENGTH] THEN + ARITH_TAC; + DISCH_TAC THEN + FIRST_X_ASSUM(MP_TAC o check(is_disj o concl)) THEN + ASM_REWRITE_TAC[ARITH_RULE `16 * 1 = 16`; ARITH_RULE `~(256 < 16)`] THEN + MP_TAC(ISPECL [`inlist:byte list`; `16`] + LENGTH_REJ_SAMPLE_ETA4_BYTES_SUB_LIST_BOUND) THEN + ASM_REWRITE_TAC[LENGTH_REJ_SAMPLE_ETA4_BYTES] THEN ARITH_TAC; + X_GEN_TAC `m:num` THEN DISCH_TAC THEN + FIRST_X_ASSUM(MP_TAC o SPEC `m:num` o check(is_forall o concl)) THEN + ASM_REWRITE_TAC[] THEN REWRITE_TAC[NOT_LT] THEN DISCH_THEN ACCEPT_TAC; + FIRST_ASSUM ACCEPT_TAC]);; + +let MLDSA_REJ_UNIFORM_ETA4_CORE_SAFE_CONCRETE = + CONV_RULE(REWRITE_CONV[LENGTH_MLDSA_REJ_UNIFORM_ETA4_TMC; + fst MLDSA_REJ_UNIFORM_ETA4_EXEC]) + MLDSA_REJ_UNIFORM_ETA4_CORE_SAFE;; + +let MLDSA_REJ_UNIFORM_ETA4_NOIBT_SUBROUTINE_SAFE = + let saved_tic = !type_invention_error in + type_invention_error := false; + let th = prove + (`?f_events:int64->int64->int64->num->(bool)list->int64->int64-> + (uarch_event)list. + !res buf table (inlist:byte list) e pc stackpointer returnaddress. + LENGTH inlist = 272 /\ + nonoverlapping (word pc, LENGTH mldsa_rej_uniform_eta4_tmc) (res, 1024) /\ + nonoverlapping (word pc, LENGTH mldsa_rej_uniform_eta4_tmc) (buf, 272) /\ + nonoverlapping (word pc, LENGTH mldsa_rej_uniform_eta4_tmc) (table, 2048) /\ + nonoverlapping (res, 1024) (buf, 272) /\ + nonoverlapping (res, 1024) (table, 2048) /\ + nonoverlapping (stackpointer, 8) (res, 1024) /\ + nonoverlapping (stackpointer, 8) (buf, 272) /\ + nonoverlapping (stackpointer, 8) (table, 2048) /\ + nonoverlapping (stackpointer, 8) (word pc, LENGTH mldsa_rej_uniform_eta4_tmc) + ==> ensures x86 + (\s. bytes_loaded s (word pc) mldsa_rej_uniform_eta4_tmc /\ + read RIP s = word pc /\ + read RSP s = stackpointer /\ + read (memory :> bytes64 stackpointer) s = returnaddress /\ + C_ARGUMENTS [res; buf; table] s /\ + read(memory :> bytes(buf, 272)) s = num_of_wordlist inlist /\ + read(memory :> bytes(table,2048)) s = + num_of_wordlist mldsa_rej_uniform_table /\ + read events s = e) + (\s. read RIP s = returnaddress /\ + read RSP s = word_add stackpointer (word 8) /\ + (?e2. read events s = APPEND e2 e /\ + e2 = f_events res buf table pc (REJ_MASK_ETA4 inlist) + stackpointer returnaddress /\ + memaccess_inbounds e2 + [buf,272; table,2048; stackpointer,8] + [res,1024])) + (MAYCHANGE [RSP] ,, MAYCHANGE_REGS_AND_FLAGS_PERMITTED_BY_ABI ,, + MAYCHANGE [memory :> bytes(res,1024)])`, + REWRITE_TAC[LENGTH_MLDSA_REJ_UNIFORM_ETA4_TMC] THEN + X86_PROMOTE_RETURN_NOSTACK_TAC mldsa_rej_uniform_eta4_tmc + MLDSA_REJ_UNIFORM_ETA4_CORE_SAFE_CONCRETE THEN + ABBREV_TAC `mask:(bool)list = REJ_MASK_ETA4 (inlist:byte list)` THEN + DISCHARGE_SAFETY_PROPERTY_TAC) in + type_invention_error := saved_tic; + th;; + +let MLDSA_REJ_UNIFORM_ETA4_SUBROUTINE_SAFE = + ADD_IBT_RULE MLDSA_REJ_UNIFORM_ETA4_NOIBT_SUBROUTINE_SAFE;;