lllv-core 0.1.1

LLLV — Cryptographic capsules for verifiable retrieval.
Documentation

LLLV — The Retrieval Atom (lllv-core)

crates.io docs.rs license MSRV no_std

lllv-core define a Vector Capsule com cabeçalho binário assinado e manifesto canônico (Paper II), endereçada por BLAKE3 (CID) e selada com Ed25519. É a base do Retrieval Atom (Paper III).

  • Header (binário, fixo): MAGIC | VER | FLAGS | TS | CID | DIM | LEN | SIG
  • CID = blake3(payload) — endereçamento por conteúdo
  • Assinatura = Ed25519.sign(header_without_sig || payload)
  • Manifesto (JSON✯Atomic): canoniza → CID → DV25-Seal

Instalação

[dependencies]
lllv-core = "0.1.0"
# integrações recomendadas
logline-core = { version = "0.1.1", features = ["serde"] }
json_atomic  = "0.1.1" # já incluso via feature "manifest"
ed25519-dalek = "2"
rand = "0.8"

Quickstart

use ed25519_dalek::SigningKey;
use rand::rngs::OsRng;
use lllv_core::{Capsule, CapsuleHeader, CapsuleFlags, encrypt_chacha20poly1305, decrypt_chacha20poly1305};

fn main() {
    // Chave de assinatura (Ed25519)
    let sk = SigningKey::generate(&mut OsRng);

    // Payload vetorial (pode ser embedding quantizado)
    let dim: u16 = 3;
    let payload = vec![1u8, 2, 3, 4, 5, 6]; // exemplo

    // (Opcional) criptografia do payload com AAD=(vector_id||CID)
    let vector_id = "doc:1";
    let key = [7u8; 32];
    let nonce = [9u8; 12];
    let aad = [vector_id.as_bytes(), &[]].concat(); // simples; use CID real em prod.

    // Cria a cápsula (sem criptografia)
    let cap = Capsule::create(dim, &payload, CapsuleFlags::NONE, &sk).unwrap();
    cap.verify_cid().unwrap(); // verifica integridade
    cap.verify_with(&sk.verifying_key()).unwrap(); // verifica autenticidade

    // Cria a cápsula (criptografada) — payload = nonce || ciphertext
    let enc = encrypt_chacha20poly1305(&payload, &key, &nonce, &aad).unwrap();
    let cap_enc = Capsule::create(dim, &enc, CapsuleFlags::ENCRYPTED, &sk).unwrap();
    cap_enc.verify_with(&sk.verifying_key()).unwrap();

    // Decriptar depois
    let (nonce2, ct2) = enc.split_at(12);
    let pt = decrypt_chacha20poly1305(ct2, nonce2.try_into().unwrap(), &key, &aad).unwrap();
    assert_eq!(pt, payload);
}

API (essencial)

pub struct CapsuleHeader { /* MAGIC, VER, FLAGS, TS, CID, DIM, LEN, SIG */ }
pub struct Capsule { pub header: CapsuleHeader, pub payload: Vec<u8> }

impl Capsule {
  pub fn create(dim: u16, payload: &[u8], flags: CapsuleFlags, sk: &ed25519_dalek::SigningKey)
    -> Result<Self, LllvError>;
  pub fn to_bytes(&self) -> Vec<u8>;
  pub fn from_bytes(raw: &[u8]) -> Result<Self, LllvError>;
  pub fn verify_cid(&self) -> Result<(), LllvError>;  // integridade (CID)
  pub fn verify_with(&self, pk: &ed25519_dalek::VerifyingKey) -> Result<(), LllvError>;  // integridade + autenticidade
  #[deprecated] pub fn verify(&self) -> Result<(), LllvError>;  // use verify_cid() ou verify_with()
}

pub fn encrypt_chacha20poly1305(plain: &[u8], key: &[u8;32], nonce: &[u8;12], aad: &[u8])
  -> Result<Vec<u8>, LllvError>;
pub fn decrypt_chacha20poly1305(cipher: &[u8], nonce: &[u8;12], key: &[u8;32], aad: &[u8])
  -> Result<Vec<u8>, LllvError>;

Manifesto JSON✯Atomic (Paper II)

Se a feature manifest estiver ativa, use json_atomic para canonizar, hashear e selar o manifesto (DV25-Seal).

use lllv_core::{CapsuleManifest, seal_manifest};
let mf = CapsuleManifest::minimal("doc:1", "text/plain", dim, "q8");
let fact = seal_manifest(&mf, &sk)?; // SignedFact (json_atomic)

Segurança (como verificar corretamente)

  • Integridade do payload: capsule.verify_cid()? — verifica se o CID corresponde ao payload
  • Autenticidade (assinatura Ed25519): capsule.verify_with(&verifying_key)? — verifica integridade + assinatura

verify() está deprecated — use verify_with(pk) para checagem completa ou verify_cid() apenas para integridade.

Detalhes de implementação

  • Assinatura é calculada sobre header_without_sig || payload.
  • CID cobre o payload em repouso (cifrado ou não).
  • Use AAD com identidade forte (vector_id || CID) quando cifrar.

Supply-chain

  • CI roda cargo-audit e cargo-deny em PRs/merge.
  • Releases geram SBOM CycloneDX anexado no GitHub Release.

MIT • MSRV 1.75+ • pronto para evoluir para alloc/no_std no v0.1.1.