1use serde::{Deserialize, Serialize};
2use std::collections::BTreeMap;
3
4pub use super::composition::{ShapeContract, ShapeExpr};
5pub use super::kind::ContractKind;
6
7#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12pub struct Contract {
13 pub metadata: Metadata,
14 #[serde(default)]
17 pub equations: BTreeMap<String, Equation>,
18 #[serde(default)]
19 pub proof_obligations: Vec<ProofObligation>,
20 #[serde(default)]
21 pub kernel_structure: Option<KernelStructure>,
22 #[serde(default)]
23 pub simd_dispatch: BTreeMap<String, BTreeMap<String, String>>,
24 #[serde(default)]
25 pub enforcement: BTreeMap<String, EnforcementRule>,
26 #[serde(default)]
27 pub falsification_tests: Vec<FalsificationTest>,
28 #[serde(default)]
29 pub kani_harnesses: Vec<KaniHarness>,
30 #[serde(default)]
31 pub qa_gate: Option<QaGate>,
32 #[serde(default)]
34 pub verification_summary: Option<VerificationSummary>,
35 #[serde(default)]
37 pub type_invariants: Vec<TypeInvariant>,
38 #[serde(default)]
40 pub coq_spec: Option<CoqSpec>,
41}
42
43impl Contract {
44 pub fn is_registry(&self) -> bool {
46 self.metadata.registry || self.metadata.kind == ContractKind::Registry
47 }
48
49 pub fn kind(&self) -> ContractKind {
51 if self.metadata.registry && self.metadata.kind == ContractKind::Kernel {
52 ContractKind::Registry
53 } else {
54 self.metadata.kind
55 }
56 }
57
58 pub fn requires_proofs(&self) -> bool {
60 self.kind() == ContractKind::Kernel
61 }
62
63 pub fn provability_violations(&self) -> Vec<String> {
67 if !self.requires_proofs() {
68 return vec![];
69 }
70 let mut violations = Vec::new();
71 if self.proof_obligations.is_empty() {
72 violations.push("Kernel contract has no proof_obligations".into());
73 }
74 if self.falsification_tests.is_empty() {
75 violations.push("Kernel contract has no falsification_tests".into());
76 }
77 if self.kani_harnesses.is_empty() {
78 violations.push("Kernel contract has no kani_harnesses".into());
79 }
80 if self.falsification_tests.len() < self.proof_obligations.len() {
81 violations.push(format!(
82 "falsification_tests ({}) < proof_obligations ({})",
83 self.falsification_tests.len(),
84 self.proof_obligations.len(),
85 ));
86 }
87 violations
88 }
89}
90
91#[derive(Debug, Clone, Default, Serialize, Deserialize)]
93pub struct Metadata {
94 pub version: String,
95 #[serde(default)]
96 pub created: Option<String>,
97 #[serde(default)]
98 pub author: Option<String>,
99 pub description: String,
100 #[serde(default)]
101 pub references: Vec<String>,
102 #[serde(default)]
105 pub depends_on: Vec<String>,
106 #[serde(default)]
108 pub registry: bool,
109 #[serde(default)]
111 pub kind: ContractKind,
112 #[serde(default)]
116 pub enforcement_level: Option<EnforcementLevel>,
117 #[serde(default)]
120 pub locked_level: Option<String>,
121}
122
123#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
125#[serde(rename_all = "lowercase")]
126pub enum EnforcementLevel {
127 Basic,
129 Standard,
131 Strict,
133 Proven,
135}
136
137#[derive(Debug, Clone, Default, Serialize, Deserialize)]
139pub struct Equation {
140 pub formula: String,
141 #[serde(default)]
142 pub domain: Option<String>,
143 #[serde(default)]
144 pub codomain: Option<String>,
145 #[serde(default)]
146 pub invariants: Vec<String>,
147 #[serde(default)]
149 pub preconditions: Vec<String>,
150 #[serde(default)]
152 pub postconditions: Vec<String>,
153 #[serde(default)]
156 pub lean_theorem: Option<String>,
157 #[serde(default)]
159 pub float_tolerance: Option<f64>,
160 #[serde(default)]
163 pub assumes: Option<ShapeContract>,
164 #[serde(default)]
167 pub guarantees: Option<ShapeContract>,
168}
169
170#[derive(Debug, Clone, Default, Serialize, Deserialize)]
176pub struct ProofObligation {
177 #[serde(rename = "type")]
178 pub obligation_type: ObligationType,
179 pub property: String,
180 #[serde(default)]
181 pub formal: Option<String>,
182 #[serde(default)]
183 pub tolerance: Option<f64>,
184 #[serde(default)]
185 pub applies_to: Option<AppliesTo>,
186 #[serde(default)]
188 pub lean: Option<LeanProof>,
189 #[serde(default)]
191 pub requires: Option<String>,
192 #[serde(default)]
194 pub applies_to_phase: Option<String>,
195 #[serde(default)]
197 pub parent_contract: Option<String>,
198}
199
200#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
201#[serde(rename_all = "lowercase")]
202pub enum ObligationType {
203 #[default]
204 Invariant,
205 Equivalence,
206 Bound,
207 Monotonicity,
208 Idempotency,
209 Linearity,
210 Symmetry,
211 Associativity,
212 Conservation,
213 Ordering,
214 Completeness,
215 Soundness,
216 Involution,
217 Determinism,
218 Roundtrip,
219 #[serde(rename = "state_machine")]
220 StateMachine,
221 Classification,
222 Independence,
223 Termination,
224 Precondition,
226 Postcondition,
227 Frame,
228 #[serde(rename = "loop_invariant")]
229 LoopInvariant,
230 #[serde(rename = "loop_variant")]
231 LoopVariant,
232 #[serde(rename = "old_state")]
233 OldState,
234 Subcontract,
235}
236
237impl std::fmt::Display for ObligationType {
238 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
239 let s = match self {
240 Self::Invariant => "invariant",
241 Self::Equivalence => "equivalence",
242 Self::Bound => "bound",
243 Self::Monotonicity => "monotonicity",
244 Self::Idempotency => "idempotency",
245 Self::Linearity => "linearity",
246 Self::Symmetry => "symmetry",
247 Self::Associativity => "associativity",
248 Self::Conservation => "conservation",
249 Self::Ordering => "ordering",
250 Self::Completeness => "completeness",
251 Self::Soundness => "soundness",
252 Self::Involution => "involution",
253 Self::Determinism => "determinism",
254 Self::Roundtrip => "roundtrip",
255 Self::StateMachine => "state_machine",
256 Self::Classification => "classification",
257 Self::Independence => "independence",
258 Self::Termination => "termination",
259 Self::Precondition => "precondition",
260 Self::Postcondition => "postcondition",
261 Self::Frame => "frame",
262 Self::LoopInvariant => "loop_invariant",
263 Self::LoopVariant => "loop_variant",
264 Self::OldState => "old_state",
265 Self::Subcontract => "subcontract",
266 };
267 write!(f, "{s}")
268 }
269}
270
271#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
272#[serde(rename_all = "lowercase")]
273pub enum AppliesTo {
274 All,
275 Scalar,
276 Simd,
277 Converter,
278 #[serde(other)]
280 Other,
281}
282
283#[derive(Debug, Clone, Serialize, Deserialize)]
285pub struct KernelStructure {
286 pub phases: Vec<KernelPhase>,
287}
288
289#[derive(Debug, Clone, Serialize, Deserialize)]
290pub struct KernelPhase {
291 pub name: String,
292 pub description: String,
293 #[serde(default)]
294 pub invariant: Option<String>,
295}
296
297#[derive(Debug, Clone, Serialize, Deserialize)]
299pub struct EnforcementRule {
300 pub description: String,
301 #[serde(default)]
302 pub check: Option<String>,
303 #[serde(default)]
304 pub severity: Option<String>,
305 #[serde(default)]
306 pub reference: Option<String>,
307}
308
309#[derive(Debug, Clone, Default, Serialize, Deserialize)]
314pub struct FalsificationTest {
315 pub id: String,
316 pub rule: String,
317 pub prediction: String,
318 #[serde(default)]
319 pub test: Option<String>,
320 pub if_fails: String,
321}
322
323#[derive(Debug, Clone, Default, Serialize, Deserialize)]
327pub struct KaniHarness {
328 pub id: String,
329 pub obligation: String,
330 #[serde(default)]
331 pub property: Option<String>,
332 #[serde(default)]
333 pub bound: Option<u32>,
334 #[serde(default)]
335 pub strategy: Option<KaniStrategy>,
336 #[serde(default)]
337 pub solver: Option<String>,
338 #[serde(default)]
339 pub harness: Option<String>,
340}
341
342#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
343#[serde(rename_all = "snake_case")]
344pub enum KaniStrategy {
345 Exhaustive,
346 StubFloat,
347 Compositional,
348 BoundedInt,
349}
350
351impl std::fmt::Display for KaniStrategy {
352 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
353 let s = match self {
354 Self::Exhaustive => "exhaustive",
355 Self::StubFloat => "stub_float",
356 Self::Compositional => "compositional",
357 Self::BoundedInt => "bounded_int",
358 };
359 write!(f, "{s}")
360 }
361}
362
363#[derive(Debug, Clone, Serialize, Deserialize)]
365pub struct LeanProof {
366 pub theorem: String,
368 #[serde(default)]
370 pub module: Option<String>,
371 #[serde(default)]
373 pub status: LeanStatus,
374 #[serde(default)]
376 pub depends_on: Vec<String>,
377 #[serde(default)]
379 pub mathlib_imports: Vec<String>,
380 #[serde(default)]
382 pub notes: Option<String>,
383}
384
385#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
387#[serde(rename_all = "kebab-case")]
388pub enum LeanStatus {
389 Proved,
391 #[default]
393 Sorry,
394 Wip,
396 NotApplicable,
398}
399
400impl std::fmt::Display for LeanStatus {
401 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
402 let s = match self {
403 Self::Proved => "proved",
404 Self::Sorry => "sorry",
405 Self::Wip => "wip",
406 Self::NotApplicable => "not-applicable",
407 };
408 write!(f, "{s}")
409 }
410}
411
412#[derive(Debug, Clone, Serialize, Deserialize)]
414pub struct VerificationSummary {
415 pub total_obligations: u32,
416 #[serde(default)]
417 pub l2_property_tested: u32,
418 #[serde(default)]
419 pub l3_kani_proved: u32,
420 #[serde(default)]
421 pub l4_lean_proved: u32,
422 #[serde(default)]
423 pub l4_sorry_count: u32,
424 #[serde(default)]
425 pub l4_not_applicable: u32,
426}
427
428#[derive(Debug, Clone, Serialize, Deserialize)]
430pub struct QaGate {
431 pub id: String,
432 pub name: String,
433 #[serde(default)]
434 pub description: Option<String>,
435 #[serde(default)]
436 pub checks: Vec<String>,
437 #[serde(default)]
438 pub pass_criteria: Option<String>,
439 #[serde(default)]
440 pub falsification: Option<String>,
441}
442
443#[derive(Debug, Clone, Serialize, Deserialize)]
448pub struct TypeInvariant {
449 pub name: String,
450 #[serde(rename = "type")]
452 pub type_name: String,
453 pub predicate: String,
455 #[serde(default)]
456 pub description: Option<String>,
457}
458
459#[derive(Debug, Clone, Serialize, Deserialize)]
461pub struct CoqSpec {
462 pub module: String,
464 #[serde(default)]
466 pub imports: Vec<String>,
467 #[serde(default)]
469 pub definitions: Vec<CoqDefinition>,
470 #[serde(default)]
472 pub obligations: Vec<CoqObligation>,
473}
474
475#[derive(Debug, Clone, Serialize, Deserialize)]
477pub struct CoqDefinition {
478 pub name: String,
479 pub statement: String,
480}
481
482#[derive(Debug, Clone, Serialize, Deserialize)]
484pub struct CoqObligation {
485 pub links_to: String,
487 pub coq_lemma: String,
489 #[serde(default = "coq_status_default")]
491 pub status: String,
492}
493
494fn coq_status_default() -> String {
495 "stub".to_string()
496}
497
498#[cfg(test)]
499#[path = "types_tests.rs"]
500mod tests;