docs: pin the JCS nesting bound with a jcs_depth_v1 vector corpus - #2246
astrogilda wants to merge 2 commits into
Conversation
RFC 8785 specifies byte production and no limit on input nesting, so two canonicalizers that agree on every byte of the jcs_edge_v1 corpus can still disagree on whether a deeply nested artifact canonicalizes at all. One returns bytes, one returns an error, and one exhausts its call stack. The profile has to state the bound itself. This corpus pins the boundary at 128 open containers, counted so that an empty container is charged its own level. Four accept vectors sit at the bound in objects, arrays, alternating containers and with an empty-container leaf; three reject vectors sit one level past each of those; and one holds ten million levels, which separates an implementation that refuses from one that dies. Four pair invariants state the relations no single vector can. Expected canonical bytes come from canonicalizing each materialized preimage with rfc8785 0.1.4, the reference implementation jcs_edge_v1 also names, and were reproduced with a second serializer before being pinned. Preimages are given as nesting rules rather than literal JSON so the corpus file stays shallow enough to be read by a parser enforcing the bound it describes.
|
Thanks, Sankalp. The empty-container boundary pair is a useful addition to the discussion. For the TSC, I would keep the distinction explicit: #2219 checks canonical output bytes; #2246 proposes an input-admission rule with a 128-container limit. Could the README label that limit as a proposed profile choice, rather than a requirement of RFC 8785 or an already-adopted A2A rule? The provenance file already makes the status of the in-toto proposal clear. It would also help to link the second serializer and its pinned run results so others can reproduce the independent cross-check. I haven’t run these vectors against Concordia yet. |
The README now says 128 is a proposed profile choice, required by neither RFC 8785 nor an adopted A2A rule, and states the grounds the in-toto proposal gives for it. The unsourced second-serializer claim is withdrawn from both the README and PROVENANCE.json, and replaced by the third-party run against the a2a-go canonicalizer reported on a2aproject#2219, including its finding that the jcs-depth-104 refusal there came from the encoding/json decoder rather than from the canonicalizer. The gowebpki/jcs measurement now names its version, and notes that v1.0.2 adds a limit of 10,000. PROVENANCE.json pins the new README digest and names the source corpus by its current repository path.
|
Erik, thank you for the label catch: the README now calls 128 a proposed profile choice, required by neither RFC 8785 nor A2A. The second-serializer line is withdrawn, because it named nothing a reader could repeat. @kuangmi-bit, thank you for the run that replaced it, and for finding that jcs-depth-104's refusal came from the decoder's cap. The corpus does not depend on the number, so whichever bound the TSC settles, the counting rule from agent-evidence-vectors carries over unchanged. |
jcs_depth_v1goes in beside the jcs_edge_v1 appendix from #2219. It holds 8 vectors: 4 accept at a bound of 128 open containers, 4 reject one level past it, 4 pair invariants.jcs_edge_v1 pins the output a canonicalizer must produce, and this pins the input it must refuse, which RFC 8785 leaves open. So 2 implementations agreeing on its 10 vectors can still disagree over whether a deep artifact canonicalizes at all. Canonicalization runs before signature verification, and I read that as putting the recursive walk in reach of anyone holding an artifact.
That bound is the rule in-toto/attestation#570 proposes, in a pull request that has not merged. The 2 boundary cases come from agent-evidence-vectors, which runs with
uvx agent-evidence-vectors, ahead of the 22 September TSC slot.Closes #2255.