Skip to content

Commit b0f71c3

Browse files
committed
Prove and consume the Unaligned alignment law
Declare Unaligned's alignment-one promise in its Rust documentation. Prove the extracted built-in u8 implementation and exercise generic callers, callee-proof reuse, a concrete caller, and an unused bound whose law must remain in the theorem domain. Use that law to prove a zero-free unsafe NonZeroUsize construction followed by ordinary division. The guarded standard-library interpretation rejects zero as forbidden execution, even when a caller discards the result or subsequently diverges. The concrete byte caller discharges the selected implementation's law. Interpret the byte carrier's ABI alignment explicitly as one, checked by the native compile-time layout fixture. Other carriers retain the abstract alignment data input. The compiled audit checks that complete interpretation, so the byte theorem cannot silently constrain every generic alignment. Agent-authored-by: AI agent acting on joshlf's behalf gherrit-pr-id: Gw5blxfy2ukqgizynv5tybeaa67xgzkmj
1 parent 227b724 commit b0f71c3

18 files changed

Lines changed: 608 additions & 37 deletions

‎verification/aeneas/ADMISSION_DESIGN.md‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ normalization must not lose a guarded call. Pinned builtin mapping and backend
4646
semantics remain trusted correspondence premises, rather than a translation
4747
certificate established by the report.
4848

49+
The `Unaligned` trial admits only the standard-library `NonZeroUsize`
50+
constructor boundary. Before and after lowering, admission checks its exact
51+
unsafe signature and original `usize` instantiation. The native model guards
52+
zero before constructing a wrapper and leaves it forbidden even if discarded.
53+
The generic caller's extracted alignment read and both checked divisions remain
54+
visible; its exact trait law establishes alignment one and the nonzero argument.
55+
Kernel controls reject zero under total and partial `True` contracts and show
56+
that an alignment-two model cannot establish either execution contract without
57+
the law. No body of the new Rust caller is made opaque.
58+
4959
The production `IntoBytes` methods delegate their write selection to
5060
`util::bytewrite::{exact,prefix,suffix}`. Their contracts prove exact byte
5161
contents, preservation of untouched destination regions, and unchanged

‎verification/aeneas/DESIGN.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,8 @@ the library already models every part of Rust's abstract machine.
329329
const generics, associated-type trait laws, higher-ranked bounds, bounded
330330
nominal models, and escaping borrow reconstruction remain unsupported with
331331
explicit errors. The first trait-law bridge supports `Self`-only traits and
332-
simple generic bounds, with a total byte codec as a checked example. Add semantics and admission checks before accepting
332+
simple generic bounds, with `Unaligned` and a total byte codec as checked
333+
examples. Add semantics and admission checks before accepting
333334
them. Stateful or nondeterministic APIs may need observable traces and
334335
effects, rather than only result contracts.
335336
- **Abstract storage and bit validity.** Check byte-to-value production before

‎verification/aeneas/SEMANTICS.md‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,14 @@ not to replace the universal algebra proof.
8282
## External inputs and trust
8383

8484
Aeneas erases ABI layout information from generic Rust type parameters.
85-
`Zerocopy.RustLayout.size` and `Zerocopy.RustLayout.align` are therefore
85+
`Zerocopy.RustLayout.size` and `Zerocopy.RustLayout.alignInput` are
8686
uninterpreted **data inputs**, each of type `Type → Usize`. No proposition
87-
about their values is an axiom. The constructors' contracts explicitly
87+
about their values is an axiom. `RustLayout.align` uses alignment one for the
88+
concrete byte carrier `U8` and the abstract alignment input for every other
89+
carrier. That byte interpretation is an explicit compiler-correspondence
90+
premise, checked by a Rust compile-time assertion. It allows the concrete
91+
`u8: Unaligned` dictionary to discharge its trait law without assuming that
92+
all types have alignment one. The constructors' contracts explicitly
8893
require the relevant primitive reads and alignment properties. The audit
8994
admits exactly these two names and verifies their signatures. Changing an
9095
input to a proposition, or adding another axiom, fails the audit.

‎verification/aeneas/external.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
{"rust": "core::num::{usize}::checked_mul", "signature": {"unsafe": false, "inputs": ["usize", "usize"], "output": "core::option::Option<usize>", "types": 0, "consts": 0}, "lean": "Usize.checked_mul"},
66
{"rust": "core::num::nonzero::{core::num::nonzero::NonZero<T0,T1>}::get", "signature": {"unsafe": false, "inputs": ["core::num::nonzero::NonZero<T0,T1>"], "output": "T0", "types": 2, "consts": 0}, "lean": "core.num.nonzero.NonZero.get", "before": {"rust": "core::num::nonzero::{core::num::nonzero::NonZero<T0>}::get", "signature": {"unsafe": false, "inputs": ["core::num::nonzero::NonZero<T0>"], "output": "T0", "types": 1, "consts": 0}}},
77
{"rust": "core::num::nonzero::{core::num::nonzero::NonZero<T0,T1>}::new", "signature": {"unsafe": false, "inputs": ["T0"], "output": "core::option::Option<core::num::nonzero::NonZero<T0,T1>>", "types": 2, "consts": 0}, "lean": "core.num.nonzero.NonZero.new", "before": {"rust": "core::num::nonzero::{core::num::nonzero::NonZero<T0>}::new", "signature": {"unsafe": false, "inputs": ["T0"], "output": "core::option::Option<core::num::nonzero::NonZero<T0>>", "types": 1, "consts": 0}}},
8+
{"rust": "core::num::nonzero::{core::num::nonzero::NonZero<T0,T1>}::new_unchecked", "signature": {"unsafe": true, "inputs": ["T0"], "output": "core::num::nonzero::NonZero<T0,T1>", "types": 2, "consts": 0}, "lean": "core.num.nonzero.NonZero.new_unchecked", "before": {"rust": "core::num::nonzero::{core::num::nonzero::NonZero<T0>}::new_unchecked", "signature": {"unsafe": true, "inputs": ["T0"], "output": "core::num::nonzero::NonZero<T0>", "types": 1, "consts": 0}}},
89
{"rust": "core::num::{usize}::checked_sub", "signature": {"unsafe": false, "inputs": ["usize", "usize"], "output": "core::option::Option<usize>", "types": 0, "consts": 0}, "lean": "Usize.checked_sub"},
910
{"rust": "core::fmt::{core::fmt::Arguments}::from_str", "signature": {"unsafe": false, "inputs": ["&str"], "output": "core::fmt::Arguments", "types": 0, "consts": 0}, "lean": "core.fmt.Arguments.from_str"},
1011
{"rust": "core::slice::{[T0]}::len", "signature": {"unsafe": false, "inputs": ["&[T0]"], "output": "usize", "types": 1, "consts": 0}, "lean": "Slice.len"},

‎verification/aeneas/golden/Funs.lean‎

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,20 +1077,83 @@ def layout.primitive_checks.check_empty_layout
10771077
native_models def FromZeros.new_zeroed.default (Self : Type) : Result Self := do
10781078
core.mem.zeroed Self
10791079
1080+
/-- [zerocopy::trait_checks::unaligned_alignment]:
1081+
Source: 'src/trait_checks.rs', lines 25:0-27:1 -/
1082+
def trait_checks.unaligned_alignment
1083+
{T : Type} (UnalignedInst : Unaligned T) : Result Std.Usize := do
1084+
core.mem.align_of T
1085+
1086+
/-- [zerocopy::trait_checks::check_unaligned]:
1087+
Source: 'src/trait_checks.rs', lines 35:0-37:1 -/
1088+
def trait_checks.check_unaligned
1089+
{T : Type} (UnalignedInst : Unaligned T) : Result Unit := do
1090+
let i ← trait_checks.unaligned_alignment UnalignedInst
1091+
massert (i = 1#usize)
1092+
1093+
/-- [zerocopy::trait_checks::unused_unaligned_bound]:
1094+
Source: 'src/trait_checks.rs', lines 48:0-50:1 -/
1095+
def trait_checks.unused_unaligned_bound
1096+
{T : Type} (UnalignedInst : Unaligned T) (value : Std.Usize) :
1097+
Result Std.Usize
1098+
:= do
1099+
ok value
1100+
1101+
/-- [zerocopy::impls::_#1::{impl zerocopy::Unaligned for u8}::only_derive_is_allowed_to_implement_this_trait]:
1102+
Source: 'src/util/macros.rs', lines 165:8-165:62
1103+
Visibility: public -/
1104+
def U8.Insts.ZerocopyUnaligned.only_derive_is_allowed_to_implement_this_trait
1105+
: Result Unit := do
1106+
ok ()
1107+
1108+
/-- Trait implementation: [zerocopy::impls::_#1::{impl zerocopy::Unaligned for u8}]
1109+
Source: 'src/util/macros.rs', lines 30:8-32:9 -/
1110+
@[reducible]
1111+
def U8.Insts.ZerocopyUnaligned : Unaligned Std.U8 := {
1112+
only_derive_is_allowed_to_implement_this_trait :=
1113+
U8.Insts.ZerocopyUnaligned.only_derive_is_allowed_to_implement_this_trait
1114+
}
1115+
1116+
/-- [zerocopy::trait_checks::check_byte_unaligned]:
1117+
Source: 'src/trait_checks.rs', lines 58:0-60:1 -/
1118+
def trait_checks.check_byte_unaligned : Result Unit := do
1119+
trait_checks.check_unaligned U8.Insts.ZerocopyUnaligned
1120+
1121+
/-- [zerocopy::trait_checks::divide_by_unaligned]:
1122+
Source: 'src/trait_checks.rs', lines 71:0-78:1 -/
1123+
def trait_checks.divide_by_unaligned
1124+
{T : Type} (UnalignedInst : Unaligned T) (x : Std.Usize) :
1125+
Result Std.Usize
1126+
:= do
1127+
let i ← core.mem.align_of T
1128+
let divisor ← 1#usize / i
1129+
let divisor1 ←
1130+
core.num.nonzero.NonZero.new_unchecked
1131+
Usize.Insts.CoreNumNonzeroZeroablePrimitiveNonZeroUsizeInner divisor
1132+
let i1 ←
1133+
core.num.nonzero.NonZero.get
1134+
Usize.Insts.CoreNumNonzeroZeroablePrimitiveNonZeroUsizeInner divisor1
1135+
x / i1
1136+
1137+
/-- [zerocopy::trait_checks::divide_by_byte_alignment]:
1138+
Source: 'src/trait_checks.rs', lines 86:0-88:1 -/
1139+
def trait_checks.divide_by_byte_alignment
1140+
(x : Std.Usize) : Result Std.Usize := do
1141+
trait_checks.divide_by_unaligned U8.Insts.ZerocopyUnaligned x
1142+
10801143
/-- [zerocopy::trait_checks::{impl zerocopy::trait_checks::ByteCodec for zerocopy::trait_checks::XorCodec}::decode]:
1081-
Source: 'src/trait_checks.rs', lines 41:4-43:5 -/
1144+
Source: 'src/trait_checks.rs', lines 112:4-114:5 -/
10821145
def trait_checks.XorCodec.Insts.ZerocopyTrait_checksByteCodec.decode
10831146
(byte : Std.U8) : Result Std.U8 := do
10841147
ok (byte ^^^ 170#u8)
10851148
10861149
/-- [zerocopy::trait_checks::{impl zerocopy::trait_checks::ByteCodec for zerocopy::trait_checks::XorCodec}::encode]:
1087-
Source: 'src/trait_checks.rs', lines 37:4-39:5 -/
1150+
Source: 'src/trait_checks.rs', lines 108:4-110:5 -/
10881151
def trait_checks.XorCodec.Insts.ZerocopyTrait_checksByteCodec.encode
10891152
(byte : Std.U8) : Result Std.U8 := do
10901153
ok (byte ^^^ 170#u8)
10911154
10921155
/-- Trait implementation: [zerocopy::trait_checks::{impl zerocopy::trait_checks::ByteCodec for zerocopy::trait_checks::XorCodec}]
1093-
Source: 'src/trait_checks.rs', lines 36:0-44:1 -/
1156+
Source: 'src/trait_checks.rs', lines 107:0-115:1 -/
10941157
@[reducible]
10951158
def trait_checks.XorCodec.Insts.ZerocopyTrait_checksByteCodec :
10961159
trait_checks.ByteCodec trait_checks.XorCodec := {
@@ -1099,23 +1162,23 @@ def trait_checks.XorCodec.Insts.ZerocopyTrait_checksByteCodec :
10991162
}
11001163
11011164
/-- [zerocopy::trait_checks::{impl zerocopy::trait_checks::ByteCodec for zerocopy::trait_checks::Forward<C>}::decode]:
1102-
Source: 'src/trait_checks.rs', lines 54:4-56:5 -/
1165+
Source: 'src/trait_checks.rs', lines 125:4-127:5 -/
11031166
def trait_checks.Forward.Insts.ZerocopyTrait_checksByteCodec.decode
11041167
{C : Type} (ByteCodecInst : trait_checks.ByteCodec C) (byte : Std.U8) :
11051168
Result Std.U8
11061169
:= do
11071170
ByteCodecInst.decode byte
11081171
11091172
/-- [zerocopy::trait_checks::{impl zerocopy::trait_checks::ByteCodec for zerocopy::trait_checks::Forward<C>}::encode]:
1110-
Source: 'src/trait_checks.rs', lines 50:4-52:5 -/
1173+
Source: 'src/trait_checks.rs', lines 121:4-123:5 -/
11111174
def trait_checks.Forward.Insts.ZerocopyTrait_checksByteCodec.encode
11121175
{C : Type} (ByteCodecInst : trait_checks.ByteCodec C) (byte : Std.U8) :
11131176
Result Std.U8
11141177
:= do
11151178
ByteCodecInst.encode byte
11161179
11171180
/-- Trait implementation: [zerocopy::trait_checks::{impl zerocopy::trait_checks::ByteCodec for zerocopy::trait_checks::Forward<C>}]
1118-
Source: 'src/trait_checks.rs', lines 49:0-57:1 -/
1181+
Source: 'src/trait_checks.rs', lines 120:0-128:1 -/
11191182
@[reducible]
11201183
def trait_checks.Forward.Insts.ZerocopyTrait_checksByteCodec {C : Type}
11211184
(ByteCodecInst : trait_checks.ByteCodec C) : trait_checks.ByteCodec
@@ -1127,7 +1190,7 @@ def trait_checks.Forward.Insts.ZerocopyTrait_checksByteCodec {C : Type}
11271190
}
11281191
11291192
/-- [zerocopy::trait_checks::byte_codec_roundtrip]:
1130-
Source: 'src/trait_checks.rs', lines 63:0-65:1 -/
1193+
Source: 'src/trait_checks.rs', lines 134:0-136:1 -/
11311194
def trait_checks.byte_codec_roundtrip
11321195
{C : Type} (ByteCodecInst : trait_checks.ByteCodec C) (byte : Std.U8) :
11331196
Result Std.U8
@@ -1136,14 +1199,14 @@ def trait_checks.byte_codec_roundtrip
11361199
ByteCodecInst.decode i
11371200
11381201
/-- [zerocopy::trait_checks::forwarded_byte_codec]:
1139-
Source: 'src/trait_checks.rs', lines 73:0-75:1 -/
1202+
Source: 'src/trait_checks.rs', lines 144:0-146:1 -/
11401203
def trait_checks.forwarded_byte_codec (byte : Std.U8) : Result Std.U8 := do
11411204
trait_checks.byte_codec_roundtrip
11421205
(trait_checks.Forward.Insts.ZerocopyTrait_checksByteCodec
11431206
trait_checks.XorCodec.Insts.ZerocopyTrait_checksByteCodec) byte
11441207
11451208
/-- [zerocopy::trait_checks::require_into_bytes]:
1146-
Source: 'src/trait_checks.rs', lines 77:0-77:47 -/
1209+
Source: 'src/trait_checks.rs', lines 148:0-148:47 -/
11471210
def trait_checks.require_into_bytes
11481211
{T : Type} (IntoBytesInst : IntoBytes T) : Result Unit := do
11491212
ok ()
@@ -1213,7 +1276,7 @@ def Tuple.Insts.ZerocopyIntoBytes : IntoBytes Unit := {
12131276
}
12141277
12151278
/-- [zerocopy::trait_checks::check_array_into_bytes]:
1216-
Source: 'src/trait_checks.rs', lines 92:0-98:1 -/
1279+
Source: 'src/trait_checks.rs', lines 163:0-169:1 -/
12171280
def trait_checks.check_array_into_bytes : Result Unit := do
12181281
trait_checks.require_into_bytes (Array.Insts.ZerocopyIntoBytes 3#usize
12191282
Bool.Insts.ZerocopyIntoBytes)

‎verification/aeneas/golden/FunsExternal_Template.lean‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,17 @@ axiom core.num.nonzero.NonZero.new
7777
core.num.nonzero.ZeroablePrimitive T Clause0_NonZeroInner) :
7878
T → Result (Option (core.num.nonzero.NonZero T Clause0_NonZeroInner))
7979
80+
/-- [core::num::nonzero::{core::num::nonzero::NonZero<T, Clause0_NonZeroInner>}::new_unchecked]:
81+
Source: '/rustc/library/core/src/num/nonzero.rs', lines 405:4-405:51
82+
Name pattern: [core::num::nonzero::{core::num::nonzero::NonZero<@T, @Clause0_NonZeroInner>}::new_unchecked]
83+
Visibility: public -/
84+
@[rust_fun
85+
"core::num::nonzero::{core::num::nonzero::NonZero<@T, @Clause0_NonZeroInner>}::new_unchecked"]
86+
axiom core.num.nonzero.NonZero.new_unchecked
87+
{T : Type} {Clause0_NonZeroInner : Type} (ZeroablePrimitiveInst :
88+
core.num.nonzero.ZeroablePrimitive T Clause0_NonZeroInner) :
89+
T → Result (core.num.nonzero.NonZero T Clause0_NonZeroInner)
90+
8091
/-- [core::num::nonzero::{core::num::nonzero::NonZero<T, Clause0_NonZeroInner>}::get]:
8192
Source: '/rustc/library/core/src/num/nonzero.rs', lines 467:4-467:31
8293
Name pattern: [core::num::nonzero::{core::num::nonzero::NonZero<@T, @Clause0_NonZeroInner>}::get]

‎verification/aeneas/golden/Types.lean‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -303,18 +303,24 @@ structure FromBytes (Self : Type) where
303303
structure IntoBytes (Self : Type) where
304304
only_derive_is_allowed_to_implement_this_trait : Result Unit
305305
306+
/-- Trait declaration: [zerocopy::Unaligned]
307+
Source: 'src/lib.rs', lines 6564:0-6571:1
308+
Visibility: public -/
309+
structure Unaligned (Self : Type) where
310+
only_derive_is_allowed_to_implement_this_trait : Result Unit
311+
306312
/-- Trait declaration: [zerocopy::trait_checks::ByteCodec]
307-
Source: 'src/trait_checks.rs', lines 26:0-29:1 -/
313+
Source: 'src/trait_checks.rs', lines 97:0-100:1 -/
308314
structure trait_checks.ByteCodec (Self : Type) where
309315
encode : Std.U8 → Result Std.U8
310316
decode : Std.U8 → Result Std.U8
311317
312318
/-- [zerocopy::trait_checks::XorCodec]
313-
Source: 'src/trait_checks.rs', lines 31:0-31:16 -/
319+
Source: 'src/trait_checks.rs', lines 102:0-102:16 -/
314320
structure trait_checks.XorCodec where
315321
316322
/-- [zerocopy::trait_checks::Forward]
317-
Source: 'src/trait_checks.rs', lines 47:0-47:34 -/
323+
Source: 'src/trait_checks.rs', lines 118:0-118:34 -/
318324
structure trait_checks.Forward (C : Type) where
319325
_0 : core.marker.PhantomData C
320326
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/- Copyright 2026 The Fuchsia Authors
2+
3+
Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4+
<LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5+
license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6+
This file may not be copied, modified, or distributed except according to
7+
those terms. -/
8+
9+
module
10+
public import SpecsSyntax
11+
public import Zerocopy.Funs
12+
@[expose] public section
13+
open Aeneas Aeneas.Std AeneasSpecs Zerocopy
14+
namespace NonZeroSafetyTests
15+
16+
-- These are model executions, not attempts to execute undefined Rust.
17+
noncomputable def zeroConstructor :=
18+
core.num.nonzero.NonZero.new_unchecked
19+
Zerocopy.Usize.Insts.CoreNumNonzeroZeroablePrimitiveNonZeroUsizeInner (0#usize)
20+
21+
theorem zero_forbidden : zeroConstructor = .fail .undef := by
22+
simp [zeroConstructor, core.num.nonzero.NonZero.new_unchecked,
23+
Zerocopy.forbiddenExecution]
24+
25+
example : ¬ WP.spec zeroConstructor (fun _ => True) := by simp [zero_forbidden]
26+
example : ¬ WP.dspec zeroConstructor (fun _ => True) := by simp [zero_forbidden]
27+
28+
noncomputable def discardZero : Result Unit := do let _ ← zeroConstructor; .ok ()
29+
noncomputable def zeroBeforeDivergence : Result Unit := do let _ ← zeroConstructor; .div
30+
spec discarded for discardZero with 0 type parameters
31+
ensures _ => True
32+
partial spec beforeDivergence for zeroBeforeDivergence with 0 type parameters
33+
ensures _ => True
34+
35+
example : ¬discarded := by simp [discarded, discardZero, zero_forbidden]
36+
example : ¬beforeDivergence := by
37+
simp [beforeDivergence, zeroBeforeDivergence, zero_forbidden]
38+
39+
theorem unsupported_carrier_forbidden {T Inner : Type}
40+
(inst : core.num.nonzero.ZeroablePrimitive T Inner) (x : T) (unsupported : T ≠ Usize) :
41+
core.num.nonzero.NonZero.new_unchecked inst x = .fail .undef := by
42+
simp [core.num.nonzero.NonZero.new_unchecked, unsupported, Zerocopy.forbiddenExecution]
43+
44+
-- A native dictionary alone supplies no alignment proposition. Without its
45+
-- law, an alignment-two model reaches a forbidden zero constructor. The
46+
-- premise here is a counterfactual model value, not an extra Rust assumption.
47+
theorem missing_law_forbidden (T : Type) (dictionary : Zerocopy.Unaligned T) (x : Usize)
48+
(alignment : Zerocopy.RustLayout.align T = 2#usize) :
49+
Zerocopy.trait_checks.divide_by_unaligned dictionary x = .fail .undef := by
50+
have half : (1#usize / 2#usize : Result Usize) = .ok (0#usize) := by
51+
obtain ⟨result, call, numeric⟩ :=
52+
UScalar.div_spec (1#usize) (y := 2#usize) (by scalar_tac)
53+
have zero : result = 0#usize := by
54+
apply UScalar.eq_of_val_eq
55+
simpa using numeric
56+
simpa only [zero] using call
57+
simp [Zerocopy.trait_checks.divide_by_unaligned, core.mem.align_of, alignment,
58+
half, core.num.nonzero.NonZero.new_unchecked, Zerocopy.forbiddenExecution]
59+
60+
example (T : Type) (dictionary : Zerocopy.Unaligned T) (x : Usize)
61+
(alignment : Zerocopy.RustLayout.align T = 2#usize) :
62+
¬ WP.spec (Zerocopy.trait_checks.divide_by_unaligned dictionary x) (fun _ => True) := by
63+
simp [missing_law_forbidden T dictionary x alignment]
64+
65+
example (T : Type) (dictionary : Zerocopy.Unaligned T) (x : Usize)
66+
(alignment : Zerocopy.RustLayout.align T = 2#usize) :
67+
¬ WP.dspec (Zerocopy.trait_checks.divide_by_unaligned dictionary x) (fun _ => True) := by
68+
simp [missing_law_forbidden T dictionary x alignment]
69+
70+
end NonZeroSafetyTests

‎verification/aeneas/lean/Obligations/TraitChecks.lean‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,52 @@ def array_into_bytes_spec_contract (run : Result Unit) : Prop :=
4242
def array_into_bytes_spec : Prop :=
4343
array_into_bytes_spec_contract trait_checks.check_array_into_bytes
4444
45+
def unaligned_alignment_spec_contract (T : Type) (dictionary : Unaligned T)
46+
(run : Result Usize) : Prop :=
47+
TraitLaws.unaligned T dictionary → run ⦃ alignment => alignment = 1#usize ⦄
48+
49+
def unaligned_alignment_spec : Prop :=
50+
∀ (T : Type) (dictionary : Unaligned T),
51+
unaligned_alignment_spec_contract T dictionary (trait_checks.unaligned_alignment dictionary)
52+
53+
def unaligned_check_spec_contract (T : Type) (dictionary : Unaligned T)
54+
(run : Result Unit) : Prop :=
55+
TraitLaws.unaligned T dictionary → run ⦃ _ => True ⦄
56+
57+
def unaligned_check_spec : Prop :=
58+
∀ (T : Type) (dictionary : Unaligned T),
59+
unaligned_check_spec_contract T dictionary (trait_checks.check_unaligned dictionary)
60+
61+
def unused_unaligned_bound_spec_contract (T : Type) (dictionary : Unaligned T)
62+
(value : Usize) (run : Result Usize) : Prop :=
63+
TraitLaws.unaligned T dictionary → run ⦃ result => result = value ⦄
64+
65+
def unused_unaligned_bound_spec : Prop :=
66+
∀ (T : Type) (dictionary : Unaligned T) (value : Usize),
67+
unused_unaligned_bound_spec_contract T dictionary value
68+
(trait_checks.unused_unaligned_bound dictionary value)
69+
70+
def concrete_unaligned_check_spec_contract (run : Result Unit) : Prop :=
71+
run ⦃ _ => True ⦄
72+
73+
def concrete_unaligned_check_spec : Prop :=
74+
concrete_unaligned_check_spec_contract trait_checks.check_byte_unaligned
75+
76+
def divide_by_unaligned_spec_contract (T : Type) (dictionary : Unaligned T)
77+
(x : Usize) (run : Result Usize) : Prop :=
78+
TraitLaws.unaligned T dictionary → run ⦃ result => result = x ⦄
79+
80+
def divide_by_unaligned_spec : Prop :=
81+
∀ (T : Type) (dictionary : Unaligned T) (x : Usize),
82+
divide_by_unaligned_spec_contract T dictionary x
83+
(trait_checks.divide_by_unaligned dictionary x)
84+
85+
def divide_by_byte_alignment_spec_contract (x : Usize) (run : Result Usize) : Prop :=
86+
run ⦃ result => result = x ⦄
87+
88+
def divide_by_byte_alignment_spec : Prop :=
89+
∀ (x : Usize), divide_by_byte_alignment_spec_contract x
90+
(trait_checks.divide_by_byte_alignment x)
4591
4692
def byte_codec_roundtrip_spec_contract (C : Type) (dictionary : trait_checks.ByteCodec C)
4793
(byte : U8) (run : Result U8) : Prop :=

0 commit comments

Comments
 (0)