@cardanowall/poe-standard 0.1.0 → 0.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/README.md +13 -13
- package/dist/encoder.cjs.map +1 -1
- package/dist/encoder.js.map +1 -1
- package/dist/error-codes.cjs +6 -0
- package/dist/error-codes.cjs.map +1 -1
- package/dist/error-codes.d.cts +2 -2
- package/dist/error-codes.d.ts +2 -2
- package/dist/error-codes.js +6 -0
- package/dist/error-codes.js.map +1 -1
- package/dist/index.cjs +134 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +134 -20
- package/dist/index.js.map +1 -1
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.js.map +1 -1
- package/dist/validator.cjs +131 -20
- package/dist/validator.cjs.map +1 -1
- package/dist/validator.js +131 -20
- package/dist/validator.js.map +1 -1
- package/package.json +6 -6
package/dist/validator.js
CHANGED
|
@@ -1625,7 +1625,7 @@ function decodeCanonicalCbor(bytes) {
|
|
|
1625
1625
|
...r,
|
|
1626
1626
|
rejectStreaming: true,
|
|
1627
1627
|
rejectDuplicateKeys: true,
|
|
1628
|
-
// A
|
|
1628
|
+
// A Label 309 record carries integers, byte/text strings, arrays, maps and
|
|
1629
1629
|
// `null` — and nothing else. Without these rejections the major-type-7
|
|
1630
1630
|
// surface leaks into the decoder: a float16/32/64 that happens to hold an
|
|
1631
1631
|
// integral value (e.g. 1.0) silently decodes to the integer 1 and passes
|
|
@@ -2076,7 +2076,7 @@ function decodeCanonicalCbor2(bytes) {
|
|
|
2076
2076
|
...r,
|
|
2077
2077
|
rejectStreaming: true,
|
|
2078
2078
|
rejectDuplicateKeys: true,
|
|
2079
|
-
// A
|
|
2079
|
+
// A Label 309 record carries integers, byte/text strings, arrays, maps and
|
|
2080
2080
|
// `null` — and nothing else. Without these rejections the major-type-7
|
|
2081
2081
|
// surface leaks into the decoder: a float16/32/64 that happens to hold an
|
|
2082
2082
|
// integral value (e.g. 1.0) silently decodes to the integer 1 and passes
|
|
@@ -2183,6 +2183,60 @@ function decodeCoseSign1(bytes) {
|
|
|
2183
2183
|
};
|
|
2184
2184
|
}
|
|
2185
2185
|
|
|
2186
|
+
// ../crypto-core/dist/sealed-poe.js
|
|
2187
|
+
var CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX = new TextEncoder().encode(
|
|
2188
|
+
"cardano-poe-slots-transcript-v1"
|
|
2189
|
+
);
|
|
2190
|
+
var CARDANO_POE_HKDF_INFO_PAYLOAD = new TextEncoder().encode(
|
|
2191
|
+
"cardano-poe-payload-v1"
|
|
2192
|
+
);
|
|
2193
|
+
var CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE = new TextEncoder().encode(
|
|
2194
|
+
"cardano-poe-payload-passphrase-v1"
|
|
2195
|
+
);
|
|
2196
|
+
var CARDANO_POE_XWING_KEK_SALT_PREFIX = new TextEncoder().encode(
|
|
2197
|
+
"cardano-poe-xwing-kek-salt-v1"
|
|
2198
|
+
);
|
|
2199
|
+
if (CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX.length !== 31) {
|
|
2200
|
+
throw new Error(
|
|
2201
|
+
"CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX byte-length invariant violated (expected 31)"
|
|
2202
|
+
);
|
|
2203
|
+
}
|
|
2204
|
+
if (CARDANO_POE_HKDF_INFO_PAYLOAD.length !== 22) {
|
|
2205
|
+
throw new Error("CARDANO_POE_HKDF_INFO_PAYLOAD byte-length invariant violated (expected 22)");
|
|
2206
|
+
}
|
|
2207
|
+
if (CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE.length !== 33) {
|
|
2208
|
+
throw new Error(
|
|
2209
|
+
"CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE byte-length invariant violated (expected 33)"
|
|
2210
|
+
);
|
|
2211
|
+
}
|
|
2212
|
+
if (CARDANO_POE_XWING_KEK_SALT_PREFIX.length !== 29) {
|
|
2213
|
+
throw new Error("CARDANO_POE_XWING_KEK_SALT_PREFIX byte-length invariant violated (expected 29)");
|
|
2214
|
+
}
|
|
2215
|
+
var MAX_SLOTS = 1024;
|
|
2216
|
+
var MAX_DECODED_ENVELOPE_BYTES = 65536;
|
|
2217
|
+
var CARDANO_POE_HKDF_INFO_KEK = new TextEncoder().encode("cardano-poe-kek-v1");
|
|
2218
|
+
var CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 = new TextEncoder().encode(
|
|
2219
|
+
"cardano-poe-kek-mlkem768x25519-v1"
|
|
2220
|
+
);
|
|
2221
|
+
var CARDANO_POE_HKDF_INFO_SLOTS_MAC = new TextEncoder().encode(
|
|
2222
|
+
"cardano-poe-slots-mac-v1"
|
|
2223
|
+
);
|
|
2224
|
+
var ZERO_NONCE_12 = new Uint8Array(12);
|
|
2225
|
+
if (CARDANO_POE_HKDF_INFO_KEK.length !== 18) {
|
|
2226
|
+
throw new Error("CARDANO_POE_HKDF_INFO_KEK byte-length invariant violated (expected 18)");
|
|
2227
|
+
}
|
|
2228
|
+
if (CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519.length !== 33) {
|
|
2229
|
+
throw new Error(
|
|
2230
|
+
"CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 byte-length invariant violated (expected 33)"
|
|
2231
|
+
);
|
|
2232
|
+
}
|
|
2233
|
+
if (CARDANO_POE_HKDF_INFO_SLOTS_MAC.length !== 24) {
|
|
2234
|
+
throw new Error("CARDANO_POE_HKDF_INFO_SLOTS_MAC byte-length invariant violated (expected 24)");
|
|
2235
|
+
}
|
|
2236
|
+
if (ZERO_NONCE_12.length !== 12) {
|
|
2237
|
+
throw new Error("ZERO_NONCE_12 byte-length invariant violated (expected 12)");
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2186
2240
|
// src/chunked.ts
|
|
2187
2241
|
var UTF8_ENCODER = new TextEncoder();
|
|
2188
2242
|
function bytesChunkArrayConcat(chunks) {
|
|
@@ -2228,6 +2282,9 @@ var SEVERITY = Object.freeze({
|
|
|
2228
2282
|
UNSUPPORTED_ENVELOPE_SCHEME: "error",
|
|
2229
2283
|
ENC_SLOTS_EMPTY: "error",
|
|
2230
2284
|
ENC_SLOT_INVALID_SHAPE: "error",
|
|
2285
|
+
ENC_SLOTS_DUPLICATE_KEM_MATERIAL: "error",
|
|
2286
|
+
ENC_SLOTS_TOO_MANY: "error",
|
|
2287
|
+
ENC_ENVELOPE_TOO_LARGE: "error",
|
|
2231
2288
|
UNSUPPORTED_KEM_ALG: "error",
|
|
2232
2289
|
ENC_KEM_REQUIRED: "error",
|
|
2233
2290
|
KEM_EPK_LENGTH_MISMATCH: "error",
|
|
@@ -2407,6 +2464,8 @@ var KEM_FIELD_LENGTH_CODE = {
|
|
|
2407
2464
|
epk: "KEM_EPK_LENGTH_MISMATCH",
|
|
2408
2465
|
kem_ct: "KEM_CT_LENGTH_MISMATCH"
|
|
2409
2466
|
};
|
|
2467
|
+
var NONCE_LENGTH = 24;
|
|
2468
|
+
var SLOTS_MAC_LENGTH = 32;
|
|
2410
2469
|
var PASSPHRASE_KDF_ALGS = /* @__PURE__ */ new Set(["argon2id"]);
|
|
2411
2470
|
var KNOWN_SIG_ALG_IDS = /* @__PURE__ */ new Set([-8, -19]);
|
|
2412
2471
|
function validatePoeRecord(bytes) {
|
|
@@ -2620,7 +2679,7 @@ function validateOneUri(chunks, path, errors) {
|
|
|
2620
2679
|
const cid = slashIdx === -1 ? rest : rest.slice(0, slashIdx);
|
|
2621
2680
|
if (!validateCidProfile(cid)) {
|
|
2622
2681
|
errors.push(
|
|
2623
|
-
issue("INVALID_URI", path, "ipfs:// URI is not a valid CID under the
|
|
2682
|
+
issue("INVALID_URI", path, "ipfs:// URI is not a valid CID under the Label 309 profile")
|
|
2624
2683
|
);
|
|
2625
2684
|
}
|
|
2626
2685
|
return;
|
|
@@ -2668,7 +2727,7 @@ function checkItemEnc(item, idx, errors) {
|
|
|
2668
2727
|
issue(
|
|
2669
2728
|
"UNAUTHENTICATED_CIPHER_FORBIDDEN",
|
|
2670
2729
|
[...basePath, "aead"],
|
|
2671
|
-
`'${enc.aead}' is an unauthenticated cipher;
|
|
2730
|
+
`'${enc.aead}' is an unauthenticated cipher; Label 309 mandates an authenticated (AEAD) cipher`
|
|
2672
2731
|
)
|
|
2673
2732
|
);
|
|
2674
2733
|
return;
|
|
@@ -2723,24 +2782,62 @@ function checkItemEnc(item, idx, errors) {
|
|
|
2723
2782
|
);
|
|
2724
2783
|
}
|
|
2725
2784
|
if (hasSlots) {
|
|
2726
|
-
|
|
2785
|
+
const slotCount = enc.slots.length;
|
|
2786
|
+
if (slotCount < 1) {
|
|
2727
2787
|
errors.push(
|
|
2728
|
-
issue("ENC_SLOTS_EMPTY", [...basePath, "slots"], `slots length ${
|
|
2788
|
+
issue("ENC_SLOTS_EMPTY", [...basePath, "slots"], `slots length ${slotCount} < 1`)
|
|
2729
2789
|
);
|
|
2730
|
-
}
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
);
|
|
2743
|
-
|
|
2790
|
+
} else if (slotCount > MAX_SLOTS) {
|
|
2791
|
+
errors.push(
|
|
2792
|
+
issue(
|
|
2793
|
+
"ENC_SLOTS_TOO_MANY",
|
|
2794
|
+
[...basePath, "slots"],
|
|
2795
|
+
`slots length ${slotCount} exceeds MAX_SLOTS=${MAX_SLOTS}`
|
|
2796
|
+
)
|
|
2797
|
+
);
|
|
2798
|
+
} else {
|
|
2799
|
+
const descriptor = enc.kem !== void 0 ? KEM_SLOT_DESCRIPTORS[enc.kem] : void 0;
|
|
2800
|
+
if (descriptor !== void 0) {
|
|
2801
|
+
const rawSlotKeys = rawSlotKeySets(item.enc);
|
|
2802
|
+
const seenKemMaterial = /* @__PURE__ */ new Set();
|
|
2803
|
+
enc.slots.forEach((slot, si) => {
|
|
2804
|
+
const slotPath = [...basePath, "slots", si];
|
|
2805
|
+
checkSlotShape(
|
|
2806
|
+
slot,
|
|
2807
|
+
rawSlotKeys[si] ?? /* @__PURE__ */ new Set(),
|
|
2808
|
+
descriptor,
|
|
2809
|
+
enc.kem,
|
|
2810
|
+
slotPath,
|
|
2811
|
+
errors
|
|
2812
|
+
);
|
|
2813
|
+
const material = slotKemMaterial(slot, descriptor);
|
|
2814
|
+
if (material !== void 0) {
|
|
2815
|
+
const key = bytesToHex2(material);
|
|
2816
|
+
if (seenKemMaterial.has(key)) {
|
|
2817
|
+
errors.push(
|
|
2818
|
+
issue(
|
|
2819
|
+
"ENC_SLOTS_DUPLICATE_KEM_MATERIAL",
|
|
2820
|
+
[...slotPath, descriptor.field],
|
|
2821
|
+
`slot ${si} ${descriptor.field} duplicates an earlier slot \u2014 per-slot KEK uniqueness is violated`
|
|
2822
|
+
)
|
|
2823
|
+
);
|
|
2824
|
+
} else {
|
|
2825
|
+
seenKemMaterial.add(key);
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
});
|
|
2829
|
+
const perSlotBytes = descriptor.fieldLength + descriptor.wrapLength;
|
|
2830
|
+
const decodedEnvelopeBytes = NONCE_LENGTH + SLOTS_MAC_LENGTH + slotCount * perSlotBytes;
|
|
2831
|
+
if (decodedEnvelopeBytes > MAX_DECODED_ENVELOPE_BYTES) {
|
|
2832
|
+
errors.push(
|
|
2833
|
+
issue(
|
|
2834
|
+
"ENC_ENVELOPE_TOO_LARGE",
|
|
2835
|
+
[...basePath, "slots"],
|
|
2836
|
+
`decoded envelope size ${decodedEnvelopeBytes} exceeds MAX_DECODED_ENVELOPE_BYTES=${MAX_DECODED_ENVELOPE_BYTES}`
|
|
2837
|
+
)
|
|
2838
|
+
);
|
|
2839
|
+
}
|
|
2840
|
+
}
|
|
2744
2841
|
}
|
|
2745
2842
|
}
|
|
2746
2843
|
if (hasPassphrase) {
|
|
@@ -2897,6 +2994,20 @@ function checkSlotShape(slot, rawKeys, descriptor, kem, slotPath, errors) {
|
|
|
2897
2994
|
);
|
|
2898
2995
|
}
|
|
2899
2996
|
}
|
|
2997
|
+
function slotKemMaterial(slot, descriptor) {
|
|
2998
|
+
if (descriptor.field === "epk") {
|
|
2999
|
+
return slot.epk;
|
|
3000
|
+
}
|
|
3001
|
+
if (slot.kem_ct === void 0) return void 0;
|
|
3002
|
+
return bytesChunkArrayConcat(slot.kem_ct);
|
|
3003
|
+
}
|
|
3004
|
+
function bytesToHex2(bytes) {
|
|
3005
|
+
let hex = "";
|
|
3006
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
3007
|
+
hex += bytes[i].toString(16).padStart(2, "0");
|
|
3008
|
+
}
|
|
3009
|
+
return hex;
|
|
3010
|
+
}
|
|
2900
3011
|
function rawSlotKeySets(rawEnc) {
|
|
2901
3012
|
const slots = mapLikeGet(rawEnc, "slots");
|
|
2902
3013
|
if (!Array.isArray(slots)) return [];
|