/**
 * remote/proof-export — turn an attestation Trace into a publicly shareable
 * proof claim (T6e).
 *
 * The full Trace is verbose and may carry redacted payloads — it is not a
 * great thing to drop into a tweet or a pitch deck. A ProofClaim is the
 * compact, self-contained extract: who, what, when, how many steps, and
 * the Merkle root that anchors the claim to the underlying trace. It is
 * Ed25519-signed by the exporter (typically the agent's own attestation
 * key) so a verifier with the exporter's public key can recompute and
 * confirm without ever seeing the Trace.
 *
 * Cross-check is optional but encouraged: when both the claim and the
 * source trace bytes are available, the verifier should also confirm that
 * `sha256(traceBytes) === claim.traceSha256` so the claim cannot be reused
 * to vouch for a different run.
 *
 * @public @since 2.16.0 — preste remote-control T6e (attested proof export)
 */
import { createHash } from "node:crypto";
import { canonicalize } from "json-canonicalize";
/** Stable schema version of the proof-claim format. */
export const PROOF_CLAIM_VERSION = "1";
/** Compute the hex SHA-256 of a UTF-8 string — used for `traceSha256`. */
export function sha256Hex(s) {
    return createHash("sha256").update(s, "utf-8").digest("hex");
}
/** The bytes that get signed. Same shape as the claim, sans `claimSignature`. */
export function canonicalClaimString(claim) {
    const { claimSignature: _omitted, ...rest } = claim;
    return canonicalize(rest);
}
/**
 * Build a ProofClaim from a Trace and the exact bytes the Trace was loaded
 * from. Pass `signClaim` to seal the claim with the exporter's Ed25519 key.
 *
 * `opts.paymentReceipt` embeds a settlement receipt — when present, the
 * resulting claim is a single signed artefact that links the agent's work
 * to its payment transaction. The receipt is part of the signed surface,
 * so any tampering post-sign invalidates the claim.
 */
export function exportProofClaim(trace, traceBytes, signClaim, opts = {}) {
    const task = typeof trace.config["task"] === "string" && trace.config["task"].trim()
        ? trace.config["task"].trim()
        : undefined;
    const base = {
        type: "preste-proof-claim",
        version: PROOF_CLAIM_VERSION,
        runId: trace.runId,
        agent: { id: trace.agentId, version: trace.agentVersion },
        ...(task ? { task } : {}),
        status: trace.status,
        stepCount: trace.totalSteps,
        startedAt: new Date(trace.startedAt).toISOString(),
        completedAt: new Date(trace.completedAt).toISOString(),
        rootHash: trace.rootHash,
        ...(trace.agentSignature ? { agentSignature: trace.agentSignature } : {}),
        ...(trace.receipt
            ? {
                receipt: {
                    tsa: trace.receipt.tsa,
                    timestamp: trace.receipt.timestamp,
                    signature: trace.receipt.signature,
                    algorithm: trace.receipt.algorithm,
                    hashedMessage: trace.receipt.hashedMessage,
                },
            }
            : {}),
        traceSha256: sha256Hex(traceBytes),
        exportedAt: new Date().toISOString(),
        ...(opts.paymentReceipt ? { paymentReceipt: opts.paymentReceipt } : {}),
    };
    if (!signClaim)
        return base;
    const sig = signClaim(canonicalClaimString(base));
    return { ...base, claimSignature: sig };
}
/**
 * Late-bind a `paymentReceipt` to an existing claim and re-sign. Use this
 * when settlement happens AFTER the agent run finishes — the original
 * claim was exported unpaid, payment lands later, and the verifier wants
 * both the run attestation AND the settlement receipt in one artefact.
 *
 * @param claim       The original (signed or unsigned) claim.
 * @param receipt     The settlement receipt to embed.
 * @param signClaim   Optional re-sign function ; omit to leave the claim
 *                    unsigned (the verifier can still cross-check the
 *                    receipt against the chain itself).
 *
 * @public @since 2.23.0 — preste P10 settlement receipt embedding
 */
export function withPaymentReceipt(claim, receipt, signClaim) {
    // Drop the prior signature ; the surface is changing.
    const { claimSignature: _omit, ...rest } = claim;
    const updated = { ...rest, paymentReceipt: receipt };
    if (!signClaim)
        return updated;
    const sig = signClaim(canonicalClaimString(updated));
    return { ...updated, claimSignature: sig };
}
/**
 * Verify a ProofClaim. Required: the exporter's verify function. Optional:
 * the source trace bytes — when provided, the verifier also recomputes
 * `sha256(traceBytes)` and compares against `claim.traceSha256`, so a claim
 * cannot be reused to vouch for a different Trace.
 *
 * Returns `{valid, reasons[]}`; every failure is recorded so the caller can
 * surface a useful error rather than a binary yes/no.
 */
export function verifyProofClaim(claim, verifyClaim, traceBytes) {
    const reasons = [];
    if (claim.type !== "preste-proof-claim") {
        reasons.push(`unknown type: ${String(claim.type)}`);
    }
    if (claim.version !== PROOF_CLAIM_VERSION) {
        reasons.push(`unsupported version: ${String(claim.version)}`);
    }
    if (!claim.claimSignature) {
        reasons.push("missing claimSignature");
    }
    else {
        let signatureOk = false;
        try {
            signatureOk = verifyClaim(canonicalClaimString(claim), claim.claimSignature);
        }
        catch (err) {
            reasons.push(`signature check threw: ${err instanceof Error ? err.message : String(err)}`);
        }
        if (!signatureOk)
            reasons.push("claim signature does not verify");
    }
    if (traceBytes !== undefined) {
        const recomputed = sha256Hex(traceBytes);
        if (recomputed !== claim.traceSha256) {
            reasons.push(`traceSha256 mismatch: claim=${claim.traceSha256} actual=${recomputed}`);
        }
    }
    return { valid: reasons.length === 0, reasons };
}
//# sourceMappingURL=proof-export.js.map