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)]
160 pub assumes: Option<ShapeContract>,
161 #[serde(default)]
164 pub guarantees: Option<ShapeContract>,
165}
166
167#[derive(Debug, Clone, Default, Serialize, Deserialize)]
173pub struct ProofObligation {
174 #[serde(rename = "type")]
175 pub obligation_type: ObligationType,
176 pub property: String,
177 #[serde(default)]
178 pub formal: Option<String>,
179 #[serde(default)]
180 pub tolerance: Option<f64>,
181 #[serde(default)]
182 pub applies_to: Option<AppliesTo>,
183 #[serde(default)]
185 pub lean: Option<LeanProof>,
186 #[serde(default)]
188 pub requires: Option<String>,
189 #[serde(default)]
191 pub applies_to_phase: Option<String>,
192 #[serde(default)]
194 pub parent_contract: Option<String>,
195}
196
197#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
198#[serde(rename_all = "lowercase")]
199pub enum ObligationType {
200 #[default]
201 Invariant,
202 Equivalence,
203 Bound,
204 Monotonicity,
205 Idempotency,
206 Linearity,
207 Symmetry,
208 Associativity,
209 Conservation,
210 Ordering,
211 Completeness,
212 Soundness,
213 Involution,
214 Determinism,
215 Roundtrip,
216 #[serde(rename = "state_machine")]
217 StateMachine,
218 Classification,
219 Independence,
220 Termination,
221 Precondition,
223 Postcondition,
224 Frame,
225 #[serde(rename = "loop_invariant")]
226 LoopInvariant,
227 #[serde(rename = "loop_variant")]
228 LoopVariant,
229 #[serde(rename = "old_state")]
230 OldState,
231 Subcontract,
232}
233
234impl std::fmt::Display for ObligationType {
235 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236 let s = match self {
237 Self::Invariant => "invariant",
238 Self::Equivalence => "equivalence",
239 Self::Bound => "bound",
240 Self::Monotonicity => "monotonicity",
241 Self::Idempotency => "idempotency",
242 Self::Linearity => "linearity",
243 Self::Symmetry => "symmetry",
244 Self::Associativity => "associativity",
245 Self::Conservation => "conservation",
246 Self::Ordering => "ordering",
247 Self::Completeness => "completeness",
248 Self::Soundness => "soundness",
249 Self::Involution => "involution",
250 Self::Determinism => "determinism",
251 Self::Roundtrip => "roundtrip",
252 Self::StateMachine => "state_machine",
253 Self::Classification => "classification",
254 Self::Independence => "independence",
255 Self::Termination => "termination",
256 Self::Precondition => "precondition",
257 Self::Postcondition => "postcondition",
258 Self::Frame => "frame",
259 Self::LoopInvariant => "loop_invariant",
260 Self::LoopVariant => "loop_variant",
261 Self::OldState => "old_state",
262 Self::Subcontract => "subcontract",
263 };
264 write!(f, "{s}")
265 }
266}
267
268#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
269#[serde(rename_all = "lowercase")]
270pub enum AppliesTo {
271 All,
272 Scalar,
273 Simd,
274 Converter,
275 #[serde(other)]
277 Other,
278}
279
280#[derive(Debug, Clone, Serialize, Deserialize)]
282pub struct KernelStructure {
283 pub phases: Vec<KernelPhase>,
284}
285
286#[derive(Debug, Clone, Serialize, Deserialize)]
287pub struct KernelPhase {
288 pub name: String,
289 pub description: String,
290 #[serde(default)]
291 pub invariant: Option<String>,
292}
293
294#[derive(Debug, Clone, Serialize, Deserialize)]
296pub struct EnforcementRule {
297 pub description: String,
298 #[serde(default)]
299 pub check: Option<String>,
300 #[serde(default)]
301 pub severity: Option<String>,
302 #[serde(default)]
303 pub reference: Option<String>,
304}
305
306#[derive(Debug, Clone, Default, Serialize, Deserialize)]
311pub struct FalsificationTest {
312 pub id: String,
313 pub rule: String,
314 pub prediction: String,
315 #[serde(default)]
316 pub test: Option<String>,
317 pub if_fails: String,
318}
319
320#[derive(Debug, Clone, Default, Serialize, Deserialize)]
324pub struct KaniHarness {
325 pub id: String,
326 pub obligation: String,
327 #[serde(default)]
328 pub property: Option<String>,
329 #[serde(default)]
330 pub bound: Option<u32>,
331 #[serde(default)]
332 pub strategy: Option<KaniStrategy>,
333 #[serde(default)]
334 pub solver: Option<String>,
335 #[serde(default)]
336 pub harness: Option<String>,
337}
338
339#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
340#[serde(rename_all = "snake_case")]
341pub enum KaniStrategy {
342 Exhaustive,
343 StubFloat,
344 Compositional,
345 BoundedInt,
346}
347
348impl std::fmt::Display for KaniStrategy {
349 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
350 let s = match self {
351 Self::Exhaustive => "exhaustive",
352 Self::StubFloat => "stub_float",
353 Self::Compositional => "compositional",
354 Self::BoundedInt => "bounded_int",
355 };
356 write!(f, "{s}")
357 }
358}
359
360#[derive(Debug, Clone, Serialize, Deserialize)]
362pub struct LeanProof {
363 pub theorem: String,
365 #[serde(default)]
367 pub module: Option<String>,
368 #[serde(default)]
370 pub status: LeanStatus,
371 #[serde(default)]
373 pub depends_on: Vec<String>,
374 #[serde(default)]
376 pub mathlib_imports: Vec<String>,
377 #[serde(default)]
379 pub notes: Option<String>,
380}
381
382#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
384#[serde(rename_all = "kebab-case")]
385pub enum LeanStatus {
386 Proved,
388 #[default]
390 Sorry,
391 Wip,
393 NotApplicable,
395}
396
397impl std::fmt::Display for LeanStatus {
398 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
399 let s = match self {
400 Self::Proved => "proved",
401 Self::Sorry => "sorry",
402 Self::Wip => "wip",
403 Self::NotApplicable => "not-applicable",
404 };
405 write!(f, "{s}")
406 }
407}
408
409#[derive(Debug, Clone, Serialize, Deserialize)]
411pub struct VerificationSummary {
412 pub total_obligations: u32,
413 #[serde(default)]
414 pub l2_property_tested: u32,
415 #[serde(default)]
416 pub l3_kani_proved: u32,
417 #[serde(default)]
418 pub l4_lean_proved: u32,
419 #[serde(default)]
420 pub l4_sorry_count: u32,
421 #[serde(default)]
422 pub l4_not_applicable: u32,
423}
424
425#[derive(Debug, Clone, Serialize, Deserialize)]
427pub struct QaGate {
428 pub id: String,
429 pub name: String,
430 #[serde(default)]
431 pub description: Option<String>,
432 #[serde(default)]
433 pub checks: Vec<String>,
434 #[serde(default)]
435 pub pass_criteria: Option<String>,
436 #[serde(default)]
437 pub falsification: Option<String>,
438}
439
440#[derive(Debug, Clone, Serialize, Deserialize)]
445pub struct TypeInvariant {
446 pub name: String,
447 #[serde(rename = "type")]
449 pub type_name: String,
450 pub predicate: String,
452 #[serde(default)]
453 pub description: Option<String>,
454}
455
456#[derive(Debug, Clone, Serialize, Deserialize)]
458pub struct CoqSpec {
459 pub module: String,
461 #[serde(default)]
463 pub imports: Vec<String>,
464 #[serde(default)]
466 pub definitions: Vec<CoqDefinition>,
467 #[serde(default)]
469 pub obligations: Vec<CoqObligation>,
470}
471
472#[derive(Debug, Clone, Serialize, Deserialize)]
474pub struct CoqDefinition {
475 pub name: String,
476 pub statement: String,
477}
478
479#[derive(Debug, Clone, Serialize, Deserialize)]
481pub struct CoqObligation {
482 pub links_to: String,
484 pub coq_lemma: String,
486 #[serde(default = "coq_status_default")]
488 pub status: String,
489}
490
491fn coq_status_default() -> String {
492 "stub".to_string()
493}
494
495#[cfg(test)]
496#[path = "types_tests.rs"]
497mod tests;