agent-toolprint 0.1.0

Double-signed receipts for AI-agent tool invocations — DSSE + JCS + Ed25519, verifiable offline (Rust port of @p-vbordei/agent-toolprint)
Documentation
//! DSSE PAE + envelope helpers.

use base64::{engine::general_purpose::STANDARD, Engine};
use serde_json::{json, Value};

use crate::error::Error;
use crate::types::PAYLOAD_TYPE;

pub fn pae_encode(payload_type: &str, body: &[u8]) -> Vec<u8> {
    let head = format!(
        "DSSEv1 {} {} {} ",
        payload_type.len(),
        payload_type,
        body.len()
    );
    let mut out = Vec::with_capacity(head.len() + body.len());
    out.extend_from_slice(head.as_bytes());
    out.extend_from_slice(body);
    out
}

pub fn new_envelope(body: &[u8]) -> Value {
    json!({
        "payloadType": PAYLOAD_TYPE,
        "payload": STANDARD.encode(body),
        "signatures": [],
    })
}

pub fn envelope_payload_bytes(env: &Value) -> Result<Vec<u8>, Error> {
    let s = env
        .get("payload")
        .and_then(Value::as_str)
        .ok_or_else(|| Error::Invalid("envelope.payload missing".into()))?;
    STANDARD
        .decode(s)
        .map_err(|e| Error::Invalid(format!("envelope.payload base64: {e}")))
}

pub fn envelope_pae_bytes(env: &Value) -> Result<Vec<u8>, Error> {
    let ptype = env
        .get("payloadType")
        .and_then(Value::as_str)
        .ok_or_else(|| Error::Invalid("envelope.payloadType missing".into()))?;
    let body = envelope_payload_bytes(env)?;
    Ok(pae_encode(ptype, &body))
}