|
| 1 | +-- SPDX-License-Identifier: PMPL-1.0-or-later |
| 2 | +-- Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk> |
| 3 | +-- |
| 4 | +-- ECHIDNA Coprocessor ABI — foreign declarations + trust-tier invariants. |
| 5 | +-- |
| 6 | +-- Mirrors: |
| 7 | +-- src/rust/coprocessor/types.rs (CoprocessorKind, Op, Outcome, Health) |
| 8 | +-- src/rust/coprocessor/trust.rs (CoprocessorTrustTier) |
| 9 | +-- src/rust/coprocessor/mod.rs (Coprocessor trait surface) |
| 10 | +-- src/ada/spark/coprocessor_safety.ads (SPARK trust-tier invariant) |
| 11 | +-- |
| 12 | +-- Phase 0 declares the Math kind only. Phase 6 backends (Physics, DSP, |
| 13 | +-- FPGA, Tensor, Vector, Crypto, Graphics, Audio, IO) extend this module |
| 14 | +-- alongside their Rust impls — never as stubs. |
| 15 | +-- |
| 16 | +-- NO believe_me anywhere. All safety is enforced by types. |
| 17 | + |
| 18 | +module Coprocessor.Foreign |
| 19 | + |
| 20 | +%default total |
| 21 | + |
| 22 | +-------------------------------------------------------------------------------- |
| 23 | +-- Trust tier — pinned discriminants matching axiom_policy.ads / trust.rs |
| 24 | +-------------------------------------------------------------------------------- |
| 25 | + |
| 26 | +||| Coprocessor trust tier (strict total order). |
| 27 | +||| Numeric encoding pinned: PureFormal=5, NativeKernel=4, LibraryWrapped=3, |
| 28 | +||| JuliaBridged=2, ExternalSubprocess=1. |
| 29 | +||| Reordering is an ABI break — bumped in lockstep with Zig + Rust + SPARK. |
| 30 | +public export |
| 31 | +data CoprocessorTrustTier : Type where |
| 32 | + ExternalSubprocess : CoprocessorTrustTier -- Tier 1: Sage / GAP / Maxima … |
| 33 | + JuliaBridged : CoprocessorTrustTier -- Tier 2: LowLevel.jl bridge |
| 34 | + LibraryWrapped : CoprocessorTrustTier -- Tier 3: thin Rust wrapper |
| 35 | + NativeKernel : CoprocessorTrustTier -- Tier 4: SPARK-verified |
| 36 | + PureFormal : CoprocessorTrustTier -- Tier 5: Idris2 ABI + kernel proof |
| 37 | + |
| 38 | +||| Decode a u8 discriminant into a tier; defaults to lowest tier on |
| 39 | +||| out-of-range (defensive — the SPARK and Rust layers never emit bad ints). |
| 40 | +public export |
| 41 | +trustTierFromU8 : Bits8 -> CoprocessorTrustTier |
| 42 | +trustTierFromU8 1 = ExternalSubprocess |
| 43 | +trustTierFromU8 2 = JuliaBridged |
| 44 | +trustTierFromU8 3 = LibraryWrapped |
| 45 | +trustTierFromU8 4 = NativeKernel |
| 46 | +trustTierFromU8 5 = PureFormal |
| 47 | +trustTierFromU8 _ = ExternalSubprocess |
| 48 | + |
| 49 | +||| Encode a tier as the canonical u8 discriminant. |
| 50 | +public export |
| 51 | +trustTierToU8 : CoprocessorTrustTier -> Bits8 |
| 52 | +trustTierToU8 ExternalSubprocess = 1 |
| 53 | +trustTierToU8 JuliaBridged = 2 |
| 54 | +trustTierToU8 LibraryWrapped = 3 |
| 55 | +trustTierToU8 NativeKernel = 4 |
| 56 | +trustTierToU8 PureFormal = 5 |
| 57 | + |
| 58 | +||| Tier 3 (LibraryWrapped) and above are *self-sufficient*: their results |
| 59 | +||| can be folded into a high-trust prover pipeline without an independent |
| 60 | +||| cross-check. Tiers 1-2 must be cross-validated. Mirrors the Rust |
| 61 | +||| `is_self_sufficient` and the SPARK `Is_Self_Sufficient` post-condition. |
| 62 | +public export |
| 63 | +isSelfSufficient : CoprocessorTrustTier -> Bool |
| 64 | +isSelfSufficient ExternalSubprocess = False |
| 65 | +isSelfSufficient JuliaBridged = False |
| 66 | +isSelfSufficient LibraryWrapped = True |
| 67 | +isSelfSufficient NativeKernel = True |
| 68 | +isSelfSufficient PureFormal = True |
| 69 | + |
| 70 | +-------------------------------------------------------------------------------- |
| 71 | +-- Round-trip proofs for the discriminant encoding |
| 72 | +-------------------------------------------------------------------------------- |
| 73 | + |
| 74 | +||| Round-trip: encoding then decoding a tier yields the original. |
| 75 | +||| The proof is *constructive* — case analysis discharges each variant. |
| 76 | +||| Together with `decodeEncodeId` this guarantees ABI well-formedness. |
| 77 | +public export |
| 78 | +encodeDecodeId : (t : CoprocessorTrustTier) -> trustTierFromU8 (trustTierToU8 t) = t |
| 79 | +encodeDecodeId ExternalSubprocess = Refl |
| 80 | +encodeDecodeId JuliaBridged = Refl |
| 81 | +encodeDecodeId LibraryWrapped = Refl |
| 82 | +encodeDecodeId NativeKernel = Refl |
| 83 | +encodeDecodeId PureFormal = Refl |
| 84 | + |
| 85 | +-------------------------------------------------------------------------------- |
| 86 | +-- Coprocessor kind |
| 87 | +-------------------------------------------------------------------------------- |
| 88 | + |
| 89 | +||| The kind of a coprocessor backend. Only variants with a fully |
| 90 | +||| functional Rust + SPARK + Idris2 implementation appear here. Phase 6 |
| 91 | +||| extends this enum (Physics / Dsp / Fpga / Tensor / Vector / Crypto / |
| 92 | +||| Graphics / Audio / Io) alongside the corresponding implementations. |
| 93 | +public export |
| 94 | +data CoprocessorKind : Type where |
| 95 | + Math : CoprocessorKind |
| 96 | + |
| 97 | +||| Encoding to u8 — pinned for FFI stability. |
| 98 | +public export |
| 99 | +coprocessorKindToU8 : CoprocessorKind -> Bits8 |
| 100 | +coprocessorKindToU8 Math = 0 |
| 101 | + |
| 102 | +public export |
| 103 | +coprocessorKindFromU8 : Bits8 -> Maybe CoprocessorKind |
| 104 | +coprocessorKindFromU8 0 = Just Math |
| 105 | +coprocessorKindFromU8 _ = Nothing |
| 106 | + |
| 107 | +-------------------------------------------------------------------------------- |
| 108 | +-- Health |
| 109 | +-------------------------------------------------------------------------------- |
| 110 | + |
| 111 | +public export |
| 112 | +data CoprocessorHealth : Type where |
| 113 | + Healthy : CoprocessorHealth |
| 114 | + Degraded : CoprocessorHealth |
| 115 | + Unhealthy : CoprocessorHealth |
| 116 | + |
| 117 | +public export |
| 118 | +healthToU8 : CoprocessorHealth -> Bits8 |
| 119 | +healthToU8 Healthy = 0 |
| 120 | +healthToU8 Degraded = 1 |
| 121 | +healthToU8 Unhealthy = 2 |
| 122 | + |
| 123 | +public export |
| 124 | +healthFromU8 : Bits8 -> CoprocessorHealth |
| 125 | +healthFromU8 0 = Healthy |
| 126 | +healthFromU8 1 = Degraded |
| 127 | +healthFromU8 _ = Unhealthy |
| 128 | + |
| 129 | +-------------------------------------------------------------------------------- |
| 130 | +-- Foreign declarations (linked from libechidna_coprocessor — wired in Phase 6 |
| 131 | +-- once the C-ABI surface stabilises across kinds). The Math backend is |
| 132 | +-- currently called from Rust directly without crossing the C ABI; this |
| 133 | +-- foreign block documents the future seam. |
| 134 | +-- |
| 135 | +-- Schema: |
| 136 | +-- echidna_coprocessor_dispatch( |
| 137 | +-- kind: u8, -- CoprocessorKind discriminant |
| 138 | +-- op_buf: *const u8, -- borsh-encoded CoprocessorOp |
| 139 | +-- op_len: usize, |
| 140 | +-- out_buf: *mut u8, -- caller-owned, capacity ≥ out_cap |
| 141 | +-- out_cap: usize, |
| 142 | +-- out_len: *mut usize, -- bytes written |
| 143 | +-- ) -> i32 -- 0 success, <0 transport error |
| 144 | +-------------------------------------------------------------------------------- |
| 145 | + |
| 146 | +||| Health of a kind, queried via the C ABI. Unimplemented kinds report |
| 147 | +||| Unhealthy. Currently a placeholder until libechidna_coprocessor lands. |
| 148 | +public export |
| 149 | +coprocessorHealthOf : CoprocessorKind -> CoprocessorHealth |
| 150 | +coprocessorHealthOf Math = Healthy |
0 commit comments