Structural diff between two ratchet trees (D-02): the pure input
validateCommitAccountIdentityProofs (./integrity.js) diffs to find
every changed leaf a commit must re-validate the 0x8009 proof of, without
relying on ts-mls exposing a StagedCommit/proposal-derived changed-leaf
list.
Walks even node indices (leaf positions) from 0 up to the greater of the
two trees' lengths (tree width grows on Add). For each resulting node:
a blank or absent node (removed, or beyond either tree's width) is
skipped — blanked leaves are never validated (D-02);
a leaf whose signature bytes are byte-identical to the parent leaf at
the same node index is skipped — unchanged leaves are trusted, validated
at join or when they last changed (D-01), so re-verifying the whole tree
on every commit is unnecessary;
every other resulting leaf (new via Add, or re-signed via an Update
proposal or the committer's own update-path leaf) is returned.
Comparing leaf.signature byte-inequality (via bytesEqual, which
already treats two undefined values as equal) is a safe, zero-dependency
proxy for "this leaf's content changed": every LeafNode (all three
leafNodeSource variants — key_package/update/commit) signs over its own
full TBS content, so any content change forces a new signature (Assumption
A1, 08-RESEARCH.md). ts-mls's own leafNodeEncoder/leafNodeEqual helpers
are not exported from its package root and leafNodeEqual itself only
compares signaturePublicKey (insufficient — it would miss an extensions
change with an unchanged signature key) — do not use either.
leafIndex is the true MLS tree leaf index (nodeIndex / 2) — this is
NOT the same numbering validateGroupMemberAccountIdentityProofs uses
internally (./account-identity-proof.js, a tree-walk-skipping-blanks
member enumeration that differs from the tree index once any leaf is
blank). Callers that need to report a MLS leaf position MUST use this
function's leafIndex, never that helper's enumeration index.
Structural diff between two ratchet trees (D-02): the pure input validateCommitAccountIdentityProofs (
./integrity.js) diffs to find every changed leaf a commit must re-validate the0x8009proof of, without relying on ts-mls exposing aStagedCommit/proposal-derived changed-leaf list.Walks even node indices (leaf positions) from
0up to the greater of the two trees' lengths (tree width grows on Add). For each resulting node:signaturebytes are byte-identical to the parent leaf at the same node index is skipped — unchanged leaves are trusted, validated at join or when they last changed (D-01), so re-verifying the whole tree on every commit is unnecessary;Comparing
leaf.signaturebyte-inequality (via bytesEqual, which already treats twoundefinedvalues as equal) is a safe, zero-dependency proxy for "this leaf's content changed": everyLeafNode(all threeleafNodeSourcevariants — key_package/update/commit) signs over its own full TBS content, so any content change forces a new signature (Assumption A1, 08-RESEARCH.md). ts-mls's ownleafNodeEncoder/leafNodeEqualhelpers are not exported from its package root andleafNodeEqualitself only comparessignaturePublicKey(insufficient — it would miss anextensionschange with an unchanged signature key) — do not use either.leafIndexis the true MLS tree leaf index (nodeIndex / 2) — this is NOT the same numberingvalidateGroupMemberAccountIdentityProofsuses internally (./account-identity-proof.js, a tree-walk-skipping-blanks member enumeration that differs from the tree index once any leaf is blank). Callers that need to report a MLS leaf position MUST use this function'sleafIndex, never that helper's enumeration index.