json_atomic/
cycle.rs

1#[cfg(not(feature = "std"))]
2use alloc::vec::Vec;
3
4use ed25519_dalek::{Signer, SigningKey};
5use logline_core::LogLine;
6
7use crate::errors::{SealError, VerifyError};
8use crate::{
9    canonize,
10    version::{CANON_VERSION, FORMAT_ID},
11    SignedFact,
12};
13
14pub fn seal_value<T: serde::Serialize>(
15    value: &T,
16    sk: &SigningKey,
17) -> Result<SignedFact, SealError> {
18    let canonical = canonize(value)?;
19    let cid = blake3::hash(&canonical);
20    let sig = sk.sign(cid.as_bytes());
21    let vk = sk.verifying_key();
22
23    Ok(SignedFact {
24        canonical,
25        cid: *cid.as_bytes(),
26        signature: sig.to_bytes(),
27        public_key: vk.to_bytes(),
28        hash_alg: "blake3",
29        sig_alg: "ed25519",
30        canon_ver: CANON_VERSION,
31        format_id: FORMAT_ID,
32    })
33}
34
35pub fn verify_seal(f: &SignedFact) -> Result<(), VerifyError> {
36    // Recalcula CID do canonical e compara
37    let recomputed = blake3::hash(&f.canonical);
38    if recomputed.as_bytes() != &f.cid {
39        return Err(VerifyError::CanonicalMismatch);
40    }
41    let vk = f.verifying_key();
42    vk.verify_strict(recomputed.as_bytes(), &f.signature_obj())
43        .map_err(|_| VerifyError::BadSignature)
44}
45
46/// Sela um LogLine completo como Signed Fact (Paper II: Signed Fact de ação verificada)
47pub fn seal_logline(line: &LogLine, sk: &SigningKey) -> Result<SignedFact, SealError> {
48    // Reaproveita `serde` derivado do logline-core
49    seal_value(line, sk)
50}