Skip to content

fix(evolution): look up COSE HeaderMap labels by structural equality (#482) - #638

Open
Kshot3000 wants to merge 1 commit into
IntersectMBO:mainfrom
Kshot3000:fix/cose-headermap-label-equality
Open

Kshot3000 wants to merge 1 commit into
IntersectMBO:mainfrom
Kshot3000:fix/cose-headermap-label-equality

Conversation

@Kshot3000

Copy link
Copy Markdown

Summary

Fixes #482: HeaderMap stored headers in a JS Map keyed by Label objects, but Label equality is structural while Map.get/Map.set compare by reference. Three consequences, all reproduced with failing tests on main first:

  • (a) the public header() accessor called this.headers.get(label) with a freshly built Label, so it always returned undefined;
  • (b) HeaderMap's [Equal.symbol] looked keys up in the other map by reference, so two structurally equal HeaderMaps never compared equal;
  • (c) setAlgorithmId followed by setHeader(labelFromInt(1n), ...) inserted two distinct Label objects for logical key 1, leaving duplicate entries in the map — the exact sequence EdDSA25519Key.build() performs.

Fix

In packages/evolution/src/cose/Header.ts, following the pattern the working accessors (algorithmId, keyId, …) already use:

  • a getLabel helper looks entries up by iterating with Equal.equals — header() and [Equal.symbol] now use it;
  • a setLabel helper removes any structurally equal key before inserting, and every mutator (setAlgorithmId, setCriticality, setKeyId, setContentType, setInitVector, setPartialInitVector, setHeader) goes through it, so setting an already-present label overwrites instead of duplicating.

The CBOR encoding is unchanged: encode already re-keyed by primitive label.value, where the later entry won, and that is the entry the overwrite now keeps.

One scope note: value comparison inside [Equal.symbol] still uses Equal.equals, which compares Uint8Array values by reference — that is the pre-existing value semantics across this codebase and is not changed here.

Tests

New file packages/evolution/test/HeaderMap.LabelEquality.test.ts (8 tests), each verified RED on main (run one at a time, since this repo's vitest bails a file after its first failure) and GREEN with the fix:

  • header() returns the value stored under an equal text label (the regression test from COSE HeaderMap: header() and equality use Map reference equality; build() creates duplicate label entries #482) and under an equal int label; returns undefined for a label never set and for a text label "7" vs int label 7;
  • two HeaderMaps built from distinct but equal labels compare equal in both directions; maps with different values under an equal label do not;
  • setHeader on an existing logical key leaves one entry holding the new value;
  • the setAlgorithmId → setHeader(label 1) sequence leaves a single label-1 entry, and EdDSA25519Key.build() produces no duplicate label-1 entries (header(label 1) is the key type, header(label -1) the curve).

Full suite: 1686 passed / 75 skipped / 0 failed, test files 102 passed / 1 skipped of 103 — exactly main's 1678 baseline + the 8 new tests. tsc --noEmit, eslint and prettier are clean on both touched files, and a patch changeset is included.


Independent builder — not affiliated with the Cardano Foundation, IOG or Intersect.

— @Kshot9000 (https://x.com/kshot9000) · Cardano (ADA) donations: addr1q8hnl6vl5a6k3rw3n5g3jtte696zcl76kfatzv7gpswa9r0dj7fma6klq55y4ffm7tf0em09udnyhuk4ah92pl5x9jpqjae44v

cc @cardano-foundation @IntersectMBO

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

COSE HeaderMap: header() and equality use Map reference equality; build() creates duplicate label entries

1 participant