-
-
Notifications
You must be signed in to change notification settings - Fork 0
fix(idris2): cure seven build blockers — build goes VOID → RED, frontier 165 → 211/305 #206
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -55,7 +55,7 @@ import Data.Vect | |
| ||| (FFI-opaque Bits primitives). Discharge once a `Data.Bits` | ||
| ||| reflective tactic / Prelude lemma is available. | ||
| public export | ||
| postulate 0 constantTimeRefl : (d : ByteVector n) -> digestEq d d = True | ||
| 0 constantTimeRefl : (d : ByteVector n) -> digestEq d d = True | ||
|
|
||
| ||| OWED: constant-time `digestEq` is symmetric — | ||
| ||| `digestEq d1 d2 = digestEq d2 d1`. Reduces to showing that | ||
|
|
@@ -66,7 +66,7 @@ postulate 0 constantTimeRefl : (d : ByteVector n) -> digestEq d d = True | |
| ||| stdlib). Same blocker family as `constantTimeRefl`. Discharge | ||
| ||| once `Data.Bits` exposes `xorCommutative : (x, y : Bits8) -> x \`xor\` y = y \`xor\` x`. | ||
| public export | ||
| postulate 0 constantTimeSym : (d1, d2 : ByteVector n) -> | ||
| 0 constantTimeSym : (d1, d2 : ByteVector n) -> | ||
| digestEq d1 d2 = digestEq d2 d1 | ||
|
|
||
| -------------------------------------------------------------------------------- | ||
|
|
@@ -122,31 +122,53 @@ public export | |
| sha1NotSecure : isSecure SHA1_ALG = False | ||
| sha1NotSecure = Refl | ||
|
|
||
| ||| OWED: any algorithm whose `securityLevel` is `Modern` is `isSecure`. | ||
| ||| `isSecure` is defined as a `case securityLevel alg of` with a | ||
| ||| wildcard `_ => True` arm covering `Modern` (and `Standard`). With | ||
| ||| the hypothesis `securityLevel alg = Modern` in scope we need to | ||
| ||| rewrite the scrutinee under the `case`, but Idris2 0.8.0 will not | ||
| ||| reduce `isSecure alg` for an abstract `alg : HashAlg` even after | ||
| ||| `rewrite` substitutes `securityLevel alg`, because the `case` was | ||
| ||| not eta-expanded to a generalised motive at elaboration time. | ||
| ||| Discharge by either (a) refactoring `isSecure` to a top-level | ||
| ||| pattern-match dispatch on `securityLevel`, or (b) hand-proving via | ||
| ||| `with (securityLevel alg) proof prf` once the 0.8.0 `with`/`rewrite` | ||
| ||| interaction is improved. | ||
| ||| Any algorithm whose `securityLevel` is `Modern` is `isSecure`. | ||
| ||| | ||
| ||| DISCHARGED 2026-08-27 by case-split on the finite `HashAlg` enum. | ||
| ||| `securityLevel` is a top-level pattern match over 11 constructors, so | ||
| ||| for every CONCRETE `alg` both it and `isSecure` reduce and `Refl` | ||
| ||| closes the goal. The six non-`Modern` constructors are refuted by the | ||
| ||| hypothesis itself, not assumed away. | ||
| ||| | ||
| ||| Supersedes an earlier note claiming `isSecure alg` could not be | ||
| ||| reduced. That is true only while `alg` is ABSTRACT -- and `alg` does | ||
| ||| not have to stay abstract. No change to the public API was needed. | ||
| public export | ||
| modernIsSecure : (alg : HashAlg) -> | ||
| securityLevel alg = Modern -> | ||
| isSecure alg = True | ||
| modernIsSecure prf = unfold isSecure; rewrite prf; rfl | ||
|
|
||
| ||| OWED: any algorithm whose `securityLevel` is `Standard` is | ||
| ||| `isSecure`. Same shape as `modernIsSecure`. | ||
| modernIsSecure MD5_ALG Refl impossible | ||
| modernIsSecure SHA1_ALG Refl impossible | ||
| modernIsSecure SHA224_ALG Refl impossible | ||
| modernIsSecure SHA256_ALG Refl impossible | ||
| modernIsSecure SHA384_ALG Refl impossible | ||
| modernIsSecure SHA512_ALG Refl impossible | ||
| modernIsSecure SHA3_256_ALG _ = Refl | ||
| modernIsSecure SHA3_512_ALG _ = Refl | ||
| modernIsSecure BLAKE2b_ALG _ = Refl | ||
| modernIsSecure BLAKE2s_ALG _ = Refl | ||
| modernIsSecure BLAKE3_ALG _ = Refl | ||
|
|
||
| ||| Any algorithm whose `securityLevel` is `Standard` is `isSecure`. | ||
| ||| | ||
| ||| DISCHARGED 2026-08-27. Same shape as `modernIsSecure`: the four SHA-2 | ||
| ||| constructors reduce to `True`; the other seven are refuted by the | ||
| ||| hypothesis. | ||
| public export | ||
| standardIsSecure : (alg : HashAlg) -> | ||
| securityLevel alg = Standard -> | ||
| isSecure alg = True | ||
| standardIsSecure prf = unfold isSecure; rewrite prf; rfl | ||
| standardIsSecure MD5_ALG Refl impossible | ||
| standardIsSecure SHA1_ALG Refl impossible | ||
| standardIsSecure SHA3_256_ALG Refl impossible | ||
| standardIsSecure SHA3_512_ALG Refl impossible | ||
| standardIsSecure BLAKE2b_ALG Refl impossible | ||
| standardIsSecure BLAKE2s_ALG Refl impossible | ||
| standardIsSecure BLAKE3_ALG Refl impossible | ||
| standardIsSecure SHA224_ALG _ = Refl | ||
| standardIsSecure SHA256_ALG _ = Refl | ||
| standardIsSecure SHA384_ALG _ = Refl | ||
| standardIsSecure SHA512_ALG _ = Refl | ||
|
|
||
| -------------------------------------------------------------------------------- | ||
| -- Digest Comparison Properties | ||
|
|
@@ -158,13 +180,13 @@ standardIsSecure prf = unfold isSecure; rewrite prf; rfl | |
| ||| and inherits the same `Data.Bits` `xor x x = 0` reductive blocker. | ||
| ||| Discharge together with `constantTimeRefl`. | ||
| public export | ||
| postulate 0 digestEqRefl : (d : ByteVector n) -> digestEq d d = True | ||
| 0 digestEqRefl : (d : ByteVector n) -> digestEq d d = True | ||
|
|
||
| ||| OWED: digest equality is symmetric — `digestEq d1 d2 = digestEq d2 d1`. | ||
| ||| Same claim as `constantTimeSym` above; same `Data.Bits` `xor` | ||
| ||| commutativity blocker. Discharge together with `constantTimeSym`. | ||
| public export | ||
| postulate 0 digestEqSym : (d1, d2 : ByteVector n) -> digestEq d1 d2 = digestEq d2 d1 | ||
| 0 digestEqSym : (d1, d2 : ByteVector n) -> digestEq d1 d2 = digestEq d2 d1 | ||
|
|
||
| ||| OWED: distinct `ByteVector`s compare unequal under `digestEq`. | ||
| ||| Stated with `Not (d1 = d2)` (propositional inequality) because | ||
|
|
@@ -176,7 +198,7 @@ postulate 0 digestEqSym : (d1, d2 : ByteVector n) -> digestEq d1 d2 = digestEq d | |
| ||| Discharge once `Data.Bits` exposes the cancellation lemma OR once | ||
| ||| `digestEq` is refactored to recurse via `decEq` element-wise. | ||
| public export | ||
| postulate 0 differentDigestsUnequal : (d1, d2 : ByteVector n) -> | ||
| 0 differentDigestsUnequal : (d1, d2 : ByteVector n) -> | ||
| Not (d1 = d2) -> | ||
| digestEq d1 d2 = False | ||
|
|
||
|
|
@@ -198,7 +220,7 @@ postulate 0 differentDigestsUnequal : (d1, d2 : ByteVector n) -> | |
| ||| index, or (b) refactoring the return type so the length witness | ||
| ||| is exposed without case-pattern reduction. | ||
| public export | ||
| postulate 0 randomBytesLength : (n : Nat) -> | ||
| 0 randomBytesLength : (n : Nat) -> | ||
| case randomBytes n of | ||
| Right (MkByteVec v) => length v = n | ||
| Left _ => () | ||
|
|
@@ -213,7 +235,7 @@ postulate 0 randomBytesLength : (n : Nat) -> | |
| ||| modelled propositionally and `modLT : (a, b : Nat) -> IsSucc b -> LT (a \`mod\` b) b` | ||
| ||| is available in `Data.Nat`. | ||
| public export | ||
| postulate 0 randomNatBounded : (max : Nat) -> {auto ok : IsSucc max} -> | ||
| 0 randomNatBounded : (max : Nat) -> {auto ok : IsSucc max} -> | ||
| case randomNat max of | ||
| Right n => LT n max | ||
| Left _ => () | ||
|
|
@@ -225,7 +247,7 @@ postulate 0 randomNatBounded : (max : Nat) -> {auto ok : IsSucc max} -> | |
| ||| reasoning. Same FFI + `Data.Nat` blocker family. Discharge | ||
| ||| together with `randomNatBounded`. | ||
| public export | ||
| postulate 0 randomRangeBounded : (mn, mx : Nat) -> {auto ok : LTE mn mx} -> | ||
| 0 randomRangeBounded : (mn, mx : Nat) -> {auto ok : LTE mn mx} -> | ||
| case randomNatRange mn mx of | ||
| Right n => (LTE mn n, LTE n mx) | ||
| Left _ => () | ||
|
|
@@ -245,7 +267,7 @@ postulate 0 randomRangeBounded : (mn, mx : Nat) -> {auto ok : LTE mn mx} -> | |
| ||| `Not (c1 = c2)` for 0.8.0 (`/=` returns `Bool`). Discharge once | ||
| ||| `Data.Bits` exposes the requisite cast/shift round-trip lemmas. | ||
| public export | ||
| postulate 0 counterNonceUnique : (pfx : ByteVec 8) -> (c1, c2 : Bits64) -> | ||
| 0 counterNonceUnique : (pfx : ByteVec 8) -> (c1, c2 : Bits64) -> | ||
| Not (c1 = c2) -> | ||
| Not (counterNonce pfx c1 = counterNonce pfx c2) | ||
|
Comment on lines
+270
to
272
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift Restrict the counter domain or widen the nonce encoding.
Encode all eight counter bytes, or constrain the API and proof to a 32-bit counter domain before proving uniqueness. 🤖 Prompt for AI Agents |
||
|
|
||
|
|
@@ -254,7 +276,7 @@ postulate 0 counterNonceUnique : (pfx : ByteVec 8) -> (c1, c2 : Bits64) -> | |
| ||| `randomBytesLength` lifted through the rename. Same FFI entropy | ||
| ||| opacity blocker; discharge together with `randomBytesLength`. | ||
| public export | ||
| postulate 0 freshNonceSize : (n : Nat) -> | ||
| 0 freshNonceSize : (n : Nat) -> | ||
| case freshNonce n of | ||
| Right (MkByteVec v) => length v = n | ||
| Left _ => () | ||
|
|
@@ -275,7 +297,7 @@ postulate 0 freshNonceSize : (n : Nat) -> | |
| ||| once a `String`-FFI reflective tactic or pack/unpack length | ||
| ||| lemma is available. | ||
| public export | ||
| postulate 0 tokenLengthApprox : (bytes : Nat) -> | ||
| 0 tokenLengthApprox : (bytes : Nat) -> | ||
| case randomToken bytes of | ||
| Right s => LTE (length s) ((bytes * 4 `div` 3) + 3) | ||
| Left _ => () | ||
|
|
@@ -289,7 +311,7 @@ postulate 0 tokenLengthApprox : (bytes : Nat) -> | |
| ||| opacity blocker as `tokenLengthApprox`. Discharge together with | ||
| ||| `tokenLengthApprox` once the pack/unpack length lemma lands. | ||
| public export | ||
| postulate 0 uuidLength : case randomUUID of | ||
| 0 uuidLength : case randomUUID of | ||
| Right s => length s = 36 | ||
| Left _ => () | ||
|
|
||
|
|
@@ -331,5 +353,5 @@ hexEncodeDeterministic _ _ = Refl | |
| ||| concrete `bytesToHex`, AND (b) the `String`-FFI reflective | ||
| ||| tactic / pack-length lemma. | ||
| public export | ||
| postulate 0 hexEncodeEvenLength : (bytesToHex : List Bits8 -> String) -> (bs : List Bits8) -> | ||
| 0 hexEncodeEvenLength : (bytesToHex : List Bits8 -> String) -> (bs : List Bits8) -> | ||
| mod (length (bytesToHex bs)) 2 = 0 | ||
|
Comment on lines
+356
to
357
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift Do not quantify over an arbitrary encoder.
Specialise the theorem to the concrete 🤖 Prompt for AI Agents |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
🔎 Supported by static analysis
🏁 Script executed:
Repository: hyperpolymath/proven
Length of output: 198
🏁 Script executed:
Repository: hyperpolymath/proven
Length of output: 13879
🌐 Web query:
Idris2 0 multiplicity declaration without function body no definition for function💡 Result:
In Idris 2, a multiplicity declaration of
0before a parameter indicates that the argument is erased at run time [1][2]. This means the value is only available during compile time and cannot be accessed or used in the implementation of the function at run time [1][3]. If you receive an error regarding "no definition for function" or that an argument is "not accessible in this context" when using a0multiplicity, it is typically because your code attempts to use that parameter in a way that requires it to exist at run time [2][4]. Key points regarding this behavior: 1. Requirement for Run-time Access: If a function's implementation attempts to return the erased argument or use it in a computation that persists to run time, Idris will reject the code because the value is explicitly marked as unavailable [2][4]. 2. Resolution: To fix this, you must either change the multiplicity of the argument (e.g., to1or unrestricted) so it is available at run time [2][4], or change the function context—such as marking the entire function as erased—if the result itself is also meant to be compile-time only [2]. 3. Pattern Matching: It is also an error in Idris 2 to attempt to pattern match on an argument with multiplicity0unless its value can be inferred by the compiler from other available information [5]. If you are encountering a "no definition for function" error specifically in the context of interfaces or forward declarations, ensure that your function body actually provides a definition for the declared type signature, as Idris 2 expects implementations to match the declared multiplicities [6].Citations:
🏁 Script executed:
Repository: hyperpolymath/proven
Length of output: 50377
🌐 Web query:
site:idris2.readthedocs.io Idris 2 declarations must have definitions postulate erased function declaration💡 Result:
In Idris 2, there is no direct keyword or construct named "postulate" used for function declarations. Instead, Idris 2 enforces a "define before use" rule for all functions and data types, requiring a type declaration followed by a definition [1][2]. If you wish to declare a function without providing a definition (a common use case for "postulates" or forward declarations in other systems), there is no built-in "postulate" keyword to facilitate this directly in standard Idris 2 code. However, you can achieve similar functionality using specific techniques: 1. Mutual Blocks: If you need to declare functions or data types that depend on each other, you must use a mutual block [1][2]. In this block, Idris elaborates all type declarations first, followed by the function definitions, effectively allowing forward references [1][2]. 2. Erasure (Multiplicity 0): You mentioned "erased function declaration." In Idris 2, erasure is controlled via multiplicities [3][4][5]. Arguments marked with a multiplicity of 0 are guaranteed to be erased at runtime and are not available for inspection in case trees [3][4][5]. This is not a way to declare a function without a body, but rather a mechanism to specify that certain arguments to a defined function are strictly for compile-time purposes [3][6]. 3. Totality/Partiality: Idris 2 allows you to declare whether functions are total or partial using directives like %default total or %default partial, but this does not remove the requirement for a function definition [7]. In summary, all functions in Idris 2 must have a corresponding definition to be used [1]. If you are looking to define an interface or a set of required operations, Interfaces (type classes) are the standard way to declare a set of required function types without providing an immediate implementation [2].
Citations:
🌐 Web query:
site:github.com/idris-lang/Idris2 "No definition for" function declaration💡 Result:
The phrase "No definition for function declaration" is not a standard error message produced by common C, C++, or other major programming language compilers. Instead, it appears to be a descriptive way of identifying a common category of link-time or compile-time issues, most frequently encountered in C and C++ development [1][2][3]. This issue typically occurs when a program includes a header file that declares a function (providing the function's signature/prototype) but fails to provide the corresponding implementation (the actual function body) in the source code or a linked library [1][4]. Key Causes and Solutions: 1. Missing Implementation File: The function is declared in a header (.h) file, but the source (.c or.cpp) file containing the function's definition was not compiled or added to the project. Ensure the implementation file is included in your build system (e.g., Makefile, CMakeLists.txt, or IDE project settings). 2. Linker Errors: In C and C++, the compiler successfully checks the syntax of the declaration, but the linker cannot find the object code for the function during the final build step. This usually manifests as an "undefined reference to
function_name" error. Check that all necessary object files and libraries are being linked correctly. 3. Namespace or Scope Mismatch: In languages that support namespaces or modules, ensure that the definition is not incorrectly scoped (e.g., defined inside a different namespace than it was declared in). 4. Incorrect Visibility Modifiers: In languages like Idris (often associated with specific module visibility rules), declaring a function without properly exporting its definition—or having a mismatch between forward-declaration visibility and the actual definition—can lead to errors regarding missing or inaccessible definitions [1][2][3]. If you are seeing this exact phrase in a specific tool or compiler, it may be a custom error message or a user-facing explanation from an IDE or static analysis tool. If you are encountering a "symbol not found" or "undefined reference" error, focus on verifying that the function's implementation file is correctly compiled and linked into your executable.Citations:
Define each OWED export before merging.
Multiplicity
0only controls erasure. It does not provide a function body or proof term. Idris2 requires a definition for each function, so theProven.SafeCrypto.ProofsCI check will reject these declaration-only exports. Add total proof terms, or remove the exports until an explicit, audited assumption mechanism exists.🤖 Prompt for AI Agents
Source: MCP tools