@uuaid/pillar 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uuaid/pillar",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Pillar (Protocol for Inter-agent Linked Ledger And Relay) — the secure delivery layer of UACP, the Universal Agent Communication Protocol. UACP = UUAID (identity) + Envelope (signed, encrypted container) + Pillar (relay, mailbox, routing, store-and-forward). Reference implementation of the UACP delivery layer; includes VDA-1 (IAASO-3901, in ballot) delivery attestation and a blind escrow for the Zilligon ZGN / EVM rails.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -24,7 +24,7 @@
24
24
  */
25
25
  import { createHash, createCipheriv, createDecipheriv, hkdfSync, randomBytes } from "node:crypto";
26
26
  import { ed25519, x25519 } from "@noble/curves/ed25519.js";
27
- import { jcs } from "../identity/jcs.mjs";
27
+ import { jcsRfc8785 } from "../identity/jcs.mjs";
28
28
 
29
29
  export const E2E_ALG = "x25519-hkdf-sha256-aes256gcm";
30
30
  const HKDF_INFO = "uuaid-pillar-e2e/1";
@@ -58,7 +58,8 @@ export function sealPayload(recipientEdPubHex, payload, { aad }) {
58
58
  const iv = randomBytes(12);
59
59
  const cipher = createCipheriv("aes-256-gcm", key, iv);
60
60
  cipher.setAAD(Buffer.from(aad, "utf-8"));
61
- const plaintext = Buffer.from(jcs(payload), "utf-8");
61
+ // Sealed payloads carry full RFC 8785 numbers (2026-10-24); see identity/jcs.mjs.
62
+ const plaintext = Buffer.from(jcsRfc8785(payload), "utf-8");
62
63
  const ct = Buffer.concat([cipher.update(plaintext), cipher.final()]);
63
64
  const tag = cipher.getAuthTag();
64
65
  return {
@@ -2,16 +2,27 @@
2
2
  * RFC 8785 JCS canonicalization. Same implementation as the pillar-core reference,
3
3
  * kept independent so the pillar-node package has no upward dependency.
4
4
  *
5
- * Numbers: integers only (safe for the wire we design; enforce it). Floats
6
- * throw because deterministic ECMA-262 number serialization requires more code
7
- * than we want in a reference impl and this package's message payloads never
8
- * legitimately contain non-integer numbers.
5
+ * Numbers — two entry points with one byte rule for integers:
6
+ * jcs() INTEGERS ONLY; floats throw. Every transport document (envelopes,
7
+ * delegations, receipts, escrow terms, blobs, VDA) keeps using it, so
8
+ * what the carrier and escrow refuse is unchanged — escrow v1/v2 rely
9
+ * on that throw to reject a hostile offer (src/escrow/terms.mjs).
10
+ * jcsRfc8785() full RFC 8785 §3.2.2.3 numbers (ECMAScript Number::toString, i.e.
11
+ * JSON.stringify(n)); used only for the SEALED PAYLOAD (crypto/e2e.mjs
12
+ * sealPayload) and documents carried inside it (PAM-1, AinFi). Byte-
13
+ * identical to jcs() for every finite integer. Added 2026-10-24 so an
14
+ * agent can send a device a value such as 21.5; byte-matches
15
+ * @uuaid/pillar-client jcsRfc8785.
9
16
  */
10
17
  export function jcs(value) {
11
- return _ser(value);
18
+ return _ser(value, false);
12
19
  }
13
20
 
14
- function _ser(v) {
21
+ export function jcsRfc8785(value) {
22
+ return _ser(value, true);
23
+ }
24
+
25
+ function _ser(v, fractions) {
15
26
  if (v === null) return "null";
16
27
  if (v === true) return "true";
17
28
  if (v === false) return "false";
@@ -19,16 +30,17 @@ function _ser(v) {
19
30
  if (typeof v === "number") {
20
31
  if (!Number.isFinite(v)) throw new Error("JCS: NaN/Infinity not permitted");
21
32
  if (Number.isInteger(v)) return String(v);
33
+ if (fractions) return JSON.stringify(v); // RFC 8785 §3.2.2.3
22
34
  throw new Error("JCS: non-integer numbers not permitted; use string decimal encoding");
23
35
  }
24
36
  if (typeof v === "bigint") return v.toString();
25
- if (Array.isArray(v)) return "[" + v.map(_ser).join(",") + "]";
37
+ if (Array.isArray(v)) return "[" + v.map((x) => _ser(x, fractions)).join(",") + "]";
26
38
  if (typeof v === "object") {
27
39
  // RFC 8785 §3.2.3: keys sort by their UTF-16 code units, which is exactly
28
40
  // JavaScript's default string order. (Comparing UTF-16LE *bytes* is not: it
29
41
  // puts "Ā" (U+0100) before "a", and disagreed with @uuaid/pillar-client.)
30
42
  const keys = Object.keys(v).sort(); // @rule jcs.code-unit-order
31
- return "{" + keys.map(k => JSON.stringify(k) + ":" + _ser(v[k])).join(",") + "}";
43
+ return "{" + keys.map(k => JSON.stringify(k) + ":" + _ser(v[k], fractions)).join(",") + "}";
32
44
  }
33
45
  throw new Error("JCS: unsupported type " + typeof v);
34
46
  }
package/src/index.mjs CHANGED
@@ -8,7 +8,7 @@
8
8
  * lives at @uuaid/pillar-browser (later).
9
9
  */
10
10
  export { Keychain, localIdFromKey, SELF_CERTIFYING_NAMESPACES, NEW_IDENTITY_NAMESPACE, SERVICE_IDENTITY_NAMESPACE, mintNamespace, keyDerivedUuaidFor, keyDerivesUuaid } from "./identity/keychain.mjs";
11
- export { jcs } from "./identity/jcs.mjs";
11
+ export { jcs, jcsRfc8785 } from "./identity/jcs.mjs";
12
12
  export { seal, open, decrypt, envelopeSha, keychainSeed, ENVELOPE_VERSION, E2E_ALG } from "./net/envelope.mjs";
13
13
  export { DELEGATION_VERSION, verifyDelegationDoc, delegationCoversKind } from "./net/delegation.mjs";
14
14
  export { sealPayload, openPayload, edPubToX25519, edSeedToX25519 } from "./crypto/e2e.mjs";