Archived
rename crates/ to engrams/; add el-compiler el package with bootstrap artifact
- crates/ → engrams/ (Rust engrams live here)
- el-compiler/ added: el self-hosting compiler as an el package
- src/{compiler,lexer,parser,codegen}.el
- bootstrap/el-compiler.elc (114KB, Rust-compiled seed)
- el.toml Cargo.toml workspace paths updated
- neuron-rs cross-repo path deps fixed (were pointing to products/ instead of foundation/)
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
//! Sealed artifact format definition.
|
||||
//!
|
||||
//! Binary layout (big-endian):
|
||||
//!
|
||||
//! ```text
|
||||
//! Offset Size Field
|
||||
//! ────── ───── ─────────────────────────────────────────────────────────
|
||||
//! 0 8 magic: b"ENGRAM01"
|
||||
//! 8 2 version: u16 (currently 1)
|
||||
//! 10 * JSON-encoded SealedArtifact body (algorithm_id, nonce, …)
|
||||
//! ```
|
||||
//!
|
||||
//! The body is JSON so the format is self-describing and forward-compatible.
|
||||
//! Future versions can add new fields without breaking older parsers.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Magic header bytes — identify an Engram sealed artifact.
|
||||
pub const MAGIC: [u8; 8] = *b"ENGRAM01";
|
||||
|
||||
/// Current artifact format version.
|
||||
pub const FORMAT_VERSION: u16 = 1;
|
||||
|
||||
// ── Configuration ─────────────────────────────────────────────────────────────
|
||||
|
||||
/// Which algorithm was used to seal the artifact.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum SealAlgorithm {
|
||||
/// AES-256-GCM — current default, quantum-resistant at 256-bit.
|
||||
Aes256Gcm,
|
||||
/// CRYSTALS-Kyber 768 — when ml-kem crate stabilizes.
|
||||
MlKem768,
|
||||
/// CRYSTALS-Kyber 1024 — when ml-kem crate stabilizes.
|
||||
MlKem1024,
|
||||
}
|
||||
|
||||
impl SealAlgorithm {
|
||||
pub fn id(&self) -> &'static str {
|
||||
match self {
|
||||
SealAlgorithm::Aes256Gcm => "aes256gcm-v1",
|
||||
SealAlgorithm::MlKem768 => "mlkem768-v1",
|
||||
SealAlgorithm::MlKem1024 => "mlkem1024-v1",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// How the deployment key is derived / bound.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DeploymentBinding {
|
||||
/// Read the seal key from an environment variable (e.g. `ENGRAM_SEAL_KEY`).
|
||||
EnvironmentKey(String),
|
||||
/// Bind to this machine's hostname + OS + CPU model (BLAKE3 hash of all three).
|
||||
MachineFingerprint,
|
||||
/// No binding — key is the zero vector. For testing only; offers no security.
|
||||
None,
|
||||
}
|
||||
|
||||
/// Configuration for the sealing operation.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SealConfig {
|
||||
pub algorithm: SealAlgorithm,
|
||||
pub deployment_binding: DeploymentBinding,
|
||||
}
|
||||
|
||||
impl Default for SealConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
algorithm: SealAlgorithm::Aes256Gcm,
|
||||
deployment_binding: DeploymentBinding::EnvironmentKey("ENGRAM_SEAL_KEY".into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Artifact ──────────────────────────────────────────────────────────────────
|
||||
|
||||
/// A quantum-sealed bytecode artifact.
|
||||
///
|
||||
/// This is the output of `el seal` / the `prod` compilation target.
|
||||
/// It is serialized to disk as: `MAGIC || VERSION_u16_be || JSON(body)`.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SealedArtifact {
|
||||
/// Algorithm identifier — matches [`SealAlgorithm::id()`].
|
||||
pub algorithm_id: String,
|
||||
|
||||
/// BLAKE3-keyed MAC over `(algorithm_id || nonce || ciphertext)`.
|
||||
/// Used to detect tampering before attempting decryption.
|
||||
/// In the PQ upgrade path, this becomes an ML-DSA signature.
|
||||
pub signature: Vec<u8>,
|
||||
|
||||
/// The binding-protected symmetric key.
|
||||
///
|
||||
/// In the current scheme: `symmetric_key XOR BLAKE3(binding_material)`.
|
||||
/// Without the deployment key, the binding material cannot be derived,
|
||||
/// so the symmetric key cannot be recovered.
|
||||
///
|
||||
/// In the ML-KEM upgrade: this becomes the KEM-encapsulated key ciphertext.
|
||||
pub encapsulated_key: Vec<u8>,
|
||||
|
||||
/// 96-bit AES-GCM nonce.
|
||||
pub nonce: Vec<u8>,
|
||||
|
||||
/// Encrypted bytecode (AES-256-GCM ciphertext including the 128-bit auth tag).
|
||||
pub ciphertext: Vec<u8>,
|
||||
|
||||
/// BLAKE3 hash of the binding material. Allows the unsealer to verify
|
||||
/// it is running in the correct deployment environment before decryption.
|
||||
/// `None` if [`DeploymentBinding::None`] was used.
|
||||
pub deployment_fingerprint: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl SealedArtifact {
|
||||
/// Serialize to the on-disk wire format: `MAGIC || version_be16 || JSON`.
|
||||
pub fn to_bytes(&self) -> Result<Vec<u8>, serde_json::Error> {
|
||||
let mut out = Vec::with_capacity(256);
|
||||
out.extend_from_slice(&MAGIC);
|
||||
out.extend_from_slice(&FORMAT_VERSION.to_be_bytes());
|
||||
let json = serde_json::to_vec(self)?;
|
||||
out.extend_from_slice(&json);
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// Deserialize from the on-disk wire format.
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, crate::SealError> {
|
||||
if bytes.len() < 10 {
|
||||
return Err(crate::SealError::Serialization("artifact too short".into()));
|
||||
}
|
||||
let magic: [u8; 8] = bytes[..8].try_into().unwrap();
|
||||
if magic != MAGIC {
|
||||
return Err(crate::SealError::InvalidMagic(magic));
|
||||
}
|
||||
// Version check (bytes 8..10) — currently we only support v1
|
||||
let version = u16::from_be_bytes([bytes[8], bytes[9]]);
|
||||
if version != FORMAT_VERSION {
|
||||
return Err(crate::SealError::UnsupportedAlgorithm(format!("format v{version}")));
|
||||
}
|
||||
let body = &bytes[10..];
|
||||
serde_json::from_slice(body).map_err(|e| crate::SealError::Serialization(e.to_string()))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user