@@ -85,3 +85,52 @@ code, all proofs must automatically ensure the absence of the following undefine
8585
8686Note: All solutions to verification challenges need to satisfy the criteria established in the [ challenge book] ( ../general-rules.md )
8787in addition to the ones listed above.
88+
89+ ## Verification
90+
91+ This challenge is addressed with Kani contracts and proof harnesses in
92+ ` library/core/src/num/nonzero.rs ` (module ` num::nonzero::verify ` ). All Part 1 and Part 2
93+ functions are verified across all twelve ` NonZero ` integer types.
94+
95+ ### Approach
96+
97+ - ** Inherent methods** carry ` #[safety::requires] ` / ` #[safety::ensures] ` contracts verified
98+ with ` #[kani::proof_for_contract] ` . Postconditions tie each result to the corresponding
99+ primitive operation (e.g. ` result.get() == old(self).get().swap_bytes() ` ), going beyond mere
100+ absence of UB.
101+ - ** ` abs ` ** is a safe method that overflows-and-panics at ` MIN ` ; following the rule that safe
102+ functions carry no real precondition, it keeps only an ` #[ensures] ` (no ` #[requires] ` ). The
103+ non-` MIN ` value is verified with ` #[kani::proof_for_contract] ` , and the ` MIN ` -input panic with a
104+ paired ` #[kani::should_panic] ` harness.
105+ - ** ` new_unchecked ` ** (Part 1) uses a byte-slice contract (generic over ` ZeroablePrimitive ` )
106+ asserting the stored value equals the input. ** ` new ` ** is verified by per-type proof harnesses
107+ asserting the full Part-1 property -- a ` NonZero ` is created if and only if the input is
108+ nonzero, and the value is preserved. A contract on ` new ` itself is deliberately avoided:
109+ because ` new ` is widely called, contract instrumentation is applied at every call site and
110+ regresses unrelated 128-bit harnesses under ` -Z loop-contracts ` ; a per-type proof verifies the
111+ same property without that side effect.
112+ - ** Operator-trait impls** (` BitOr ` x3, ` Neg ` ) are verified with ` #[kani::proof] ` plus a
113+ functional assertion, because the ` #[safety] ` contract proc-macro cannot annotate trait-impl
114+ methods (it parses ` ItemFn ` , not ` ImplItemFn ` ).
115+
116+ ### Bounded verification
117+
118+ Challenge 12 permits bounded verification. A few operations are intractable for CBMC at full
119+ 64/128-bit width and are verified over representative bounded domains:
120+
121+ - ** ` checked_mul ` / ` saturating_mul ` ** -- small types full-range; larger types via narrow value
122+ windows (small values, plus windows near MIN/MAX to exercise overflow), mirroring the existing
123+ ` unchecked_mul ` interval harnesses.
124+ - ** ` isqrt ` ** -- small types full-range; larger types with the input bounded (the internal
125+ candidate-square is the cost driver).
126+ - ** ` checked_pow ` / ` saturating_pow ` ** -- Part 2 requires * safety* ; the harnesses verify that the
127+ ` unsafe { new_unchecked(...) } ` is sound (the result is nonzero) over full-range base and
128+ exponent.
129+
130+ ### One supporting change outside ` nonzero.rs `
131+
132+ The primitive ` checked_pow ` loop invariant in ` int_macros.rs ` and ` uint_macros.rs ` was
133+ strengthened from ` true ` to ` self == 0 || (acc != 0 && base != 0) ` (signed) /
134+ ` self == 0 || (acc > 0 && base > 0) ` (unsigned). This is required so that, under
135+ ` -Z loop-contracts ` , the loop abstraction preserves the nonzero property that the ` NonZero `
136+ wrappers rely on. It does not change runtime behavior.
0 commit comments