@@ -15,10 +15,14 @@ module VerisimCore
1515
1616using SHA
1717
18+ # Crypto module is loaded by the including script before VerisimCore
19+ # (flat-include scaffold). Reached via Main namespace.
20+
1821export OctadId, Timestamp, Signature, SemanticBlob,
1922 ProvenanceEntry, ProvenanceChain, TemporalHistory,
2023 CoreOctad, Store,
21- get_core, enrich!, attest, verify_attest, now_ts
24+ get_core, enrich!, attest, verify_attest, now_ts,
25+ ed25519_sign, ed25519_verify
2226
2327# -----------------------------------------------------------------------
2428# Primitive types (mirror Idris2 ABI)
@@ -52,12 +56,14 @@ Base.:(==)(a::Timestamp, b::Timestamp) = a.epoch_nanos == b.epoch_nanos
5256now_ts () = Timestamp (Int64 (time_ns ()))
5357
5458"""
55- Signature placeholder. TODO(Phase 3 defaults validation): replace with
56- Ed25519 via Nettle.jl or similar. For scaffold, using SHA-256 as a
57- stand-in 'signature' (signer_id || payload). This is NOT cryptographic
58- signing — it is a placeholder so the ABI shapes compile and test paths
59- work. Cryptographic fidelity is not required for Phase 3's correctness
60- experiment; it IS required before any production consideration.
59+ Ed25519 detached signature. Matches Idris2 ABI
60+ `Signature { keyId, sigBytes }`. In this implementation `key_id` holds
61+ the signer's Ed25519 **public key** (32 bytes); pubkeys are both
62+ compact and self-identifying, so no separate key_id registry is
63+ needed.
64+
65+ - `key_id` : 32 bytes (Ed25519 public key)
66+ - `sig_bytes`: 64 bytes (Ed25519 detached signature)
6167"""
6268struct Signature
6369 key_id:: Vector{UInt8}
@@ -108,18 +114,18 @@ end
108114# Store
109115# -----------------------------------------------------------------------
110116
111- " In-memory ephemeral Core store. Dict-backed, no persistence."
117+ " In-memory ephemeral Core store. Dict-backed, no persistence. Holds
118+ a fresh Ed25519 keypair for signing attestations and provenance entries."
112119struct Store
113120 octads:: Dict{OctadId, CoreOctad}
114- # For placeholder signing — real impl would hold an Ed25519 keypair
115- signing_key_id:: Vector{UInt8}
121+ keypair:: Any # Main.Crypto.Ed25519KeyPair (duck-typed to avoid load order)
116122 # Attestation freshness window, in nanoseconds (default: 60s)
117123 freshness_window_ns:: Int64
118124end
119125
120126Store (; freshness_window_ns:: Int64 = Int64 (60_000_000_000 )) = Store (
121127 Dict {OctadId, CoreOctad} (),
122- collect ( codeunits ( " verisim-core-test-key " ) ),
128+ Main . Crypto . generate_keypair ( ),
123129 freshness_window_ns,
124130)
125131
@@ -196,8 +202,8 @@ function enrich!(store::Store,
196202 )
197203 this_hash = sha256 (to_hash)
198204
199- # Placeholder signature — see Signature docstring .
200- sig = placeholder_sign (store. signing_key_id , this_hash)
205+ # Real Ed25519 signature over this_hash .
206+ sig = ed25519_sign (store. keypair , this_hash)
201207
202208 push! (octad. provenance. entries, ProvenanceEntry (
203209 prev, this_hash, actor, t, sig,
@@ -215,27 +221,25 @@ function bytes2hex_summary(blob::SemanticBlob)::Vector{UInt8}
215221end
216222
217223"""
218- placeholder_sign(key_id , payload) -> Signature
224+ ed25519_sign(keypair , payload) -> Signature
219225
220- Placeholder for Ed25519 signing. Current impl: SHA-256 of
221- (key_id || payload). NOT cryptographically sound. See Signature docstring.
226+ Produce an Ed25519 detached signature over `payload`. Returns a
227+ Signature whose `key_id` field carries the public key (32 bytes) and
228+ `sig_bytes` carries the 64-byte signature.
222229"""
223- function placeholder_sign (key_id:: Vector{UInt8} ,
224- payload:: Vector{UInt8} ):: Signature
225- sig = sha256 (vcat (key_id, payload))
226- Signature (key_id, sig)
230+ function ed25519_sign (keypair, payload:: Vector{UInt8} ):: Signature
231+ sig_bytes = Main. Crypto. sign_detached (keypair, payload)
232+ Signature (copy (keypair. pk), sig_bytes)
227233end
228234
229235"""
230- placeholder_verify (sig, payload) -> Bool
236+ ed25519_verify (sig, payload) -> Bool
231237
232- Placeholder verification matching placeholder_sign. Recomputes the
233- expected SHA-256 and compares. This provides the ABI shape; real
234- Ed25519 verification is a Phase 4+ task.
238+ Verify an Ed25519 signature. Uses `sig.key_id` as the public key.
239+ Returns true iff the signature is valid for the given payload.
235240"""
236- function placeholder_verify (sig:: Signature , payload:: Vector{UInt8} ):: Bool
237- expected = sha256 (vcat (sig. key_id, payload))
238- expected == sig. sig_bytes
241+ function ed25519_verify (sig:: Signature , payload:: Vector{UInt8} ):: Bool
242+ Main. Crypto. verify_detached (sig. key_id, sig. sig_bytes, payload)
239243end
240244
241245# -----------------------------------------------------------------------
@@ -256,7 +260,7 @@ function attest(store::Store, id::OctadId)
256260 # Sign a digest of (id || t || semantic summary).
257261 sem_summary = octad. semantic === nothing ? UInt8[] : bytes2hex_summary (octad. semantic)
258262 payload = vcat (octad. id. bytes, reinterpret (UInt8, [t. epoch_nanos]), sem_summary)
259- sig = placeholder_sign (store. signing_key_id , payload)
263+ sig = ed25519_sign (store. keypair , payload)
260264 (octad, sig, t)
261265end
262266
@@ -280,7 +284,7 @@ function verify_attest(store::Store,
280284 # Recompute expected payload and verify.
281285 sem_summary = octad. semantic === nothing ? UInt8[] : bytes2hex_summary (octad. semantic)
282286 payload = vcat (octad. id. bytes, reinterpret (UInt8, [t. epoch_nanos]), sem_summary)
283- placeholder_verify (sig, payload)
287+ ed25519_verify (sig, payload)
284288end
285289
286290end # module
0 commit comments