@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/index.js
CHANGED
|
@@ -1735,7 +1735,7 @@ function decodeCanonicalCbor(bytes) {
|
|
|
1735
1735
|
...r,
|
|
1736
1736
|
rejectStreaming: true,
|
|
1737
1737
|
rejectDuplicateKeys: true,
|
|
1738
|
-
// A
|
|
1738
|
+
// A Label 309 record carries integers, byte/text strings, arrays, maps and
|
|
1739
1739
|
// `null` — and nothing else. Without these rejections the major-type-7
|
|
1740
1740
|
// surface leaks into the decoder: a float16/32/64 that happens to hold an
|
|
1741
1741
|
// integral value (e.g. 1.0) silently decodes to the integer 1 and passes
|
|
@@ -2281,7 +2281,7 @@ function decodeCanonicalCbor2(bytes) {
|
|
|
2281
2281
|
...r,
|
|
2282
2282
|
rejectStreaming: true,
|
|
2283
2283
|
rejectDuplicateKeys: true,
|
|
2284
|
-
// A
|
|
2284
|
+
// A Label 309 record carries integers, byte/text strings, arrays, maps and
|
|
2285
2285
|
// `null` — and nothing else. Without these rejections the major-type-7
|
|
2286
2286
|
// surface leaks into the decoder: a float16/32/64 that happens to hold an
|
|
2287
2287
|
// integral value (e.g. 1.0) silently decodes to the integer 1 and passes
|
|
@@ -2388,6 +2388,60 @@ function decodeCoseSign1(bytes) {
|
|
|
2388
2388
|
};
|
|
2389
2389
|
}
|
|
2390
2390
|
|
|
2391
|
+
// ../crypto-core/dist/sealed-poe.js
|
|
2392
|
+
var CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX = new TextEncoder().encode(
|
|
2393
|
+
"cardano-poe-slots-transcript-v1"
|
|
2394
|
+
);
|
|
2395
|
+
var CARDANO_POE_HKDF_INFO_PAYLOAD = new TextEncoder().encode(
|
|
2396
|
+
"cardano-poe-payload-v1"
|
|
2397
|
+
);
|
|
2398
|
+
var CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE = new TextEncoder().encode(
|
|
2399
|
+
"cardano-poe-payload-passphrase-v1"
|
|
2400
|
+
);
|
|
2401
|
+
var CARDANO_POE_XWING_KEK_SALT_PREFIX = new TextEncoder().encode(
|
|
2402
|
+
"cardano-poe-xwing-kek-salt-v1"
|
|
2403
|
+
);
|
|
2404
|
+
if (CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX.length !== 31) {
|
|
2405
|
+
throw new Error(
|
|
2406
|
+
"CARDANO_POE_SLOTS_TRANSCRIPT_PREFIX byte-length invariant violated (expected 31)"
|
|
2407
|
+
);
|
|
2408
|
+
}
|
|
2409
|
+
if (CARDANO_POE_HKDF_INFO_PAYLOAD.length !== 22) {
|
|
2410
|
+
throw new Error("CARDANO_POE_HKDF_INFO_PAYLOAD byte-length invariant violated (expected 22)");
|
|
2411
|
+
}
|
|
2412
|
+
if (CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE.length !== 33) {
|
|
2413
|
+
throw new Error(
|
|
2414
|
+
"CARDANO_POE_HKDF_INFO_PAYLOAD_PASSPHRASE byte-length invariant violated (expected 33)"
|
|
2415
|
+
);
|
|
2416
|
+
}
|
|
2417
|
+
if (CARDANO_POE_XWING_KEK_SALT_PREFIX.length !== 29) {
|
|
2418
|
+
throw new Error("CARDANO_POE_XWING_KEK_SALT_PREFIX byte-length invariant violated (expected 29)");
|
|
2419
|
+
}
|
|
2420
|
+
var MAX_SLOTS = 1024;
|
|
2421
|
+
var MAX_DECODED_ENVELOPE_BYTES = 65536;
|
|
2422
|
+
var CARDANO_POE_HKDF_INFO_KEK = new TextEncoder().encode("cardano-poe-kek-v1");
|
|
2423
|
+
var CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 = new TextEncoder().encode(
|
|
2424
|
+
"cardano-poe-kek-mlkem768x25519-v1"
|
|
2425
|
+
);
|
|
2426
|
+
var CARDANO_POE_HKDF_INFO_SLOTS_MAC = new TextEncoder().encode(
|
|
2427
|
+
"cardano-poe-slots-mac-v1"
|
|
2428
|
+
);
|
|
2429
|
+
var ZERO_NONCE_12 = new Uint8Array(12);
|
|
2430
|
+
if (CARDANO_POE_HKDF_INFO_KEK.length !== 18) {
|
|
2431
|
+
throw new Error("CARDANO_POE_HKDF_INFO_KEK byte-length invariant violated (expected 18)");
|
|
2432
|
+
}
|
|
2433
|
+
if (CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519.length !== 33) {
|
|
2434
|
+
throw new Error(
|
|
2435
|
+
"CARDANO_POE_HKDF_INFO_KEK_MLKEM768X25519 byte-length invariant violated (expected 33)"
|
|
2436
|
+
);
|
|
2437
|
+
}
|
|
2438
|
+
if (CARDANO_POE_HKDF_INFO_SLOTS_MAC.length !== 24) {
|
|
2439
|
+
throw new Error("CARDANO_POE_HKDF_INFO_SLOTS_MAC byte-length invariant violated (expected 24)");
|
|
2440
|
+
}
|
|
2441
|
+
if (ZERO_NONCE_12.length !== 12) {
|
|
2442
|
+
throw new Error("ZERO_NONCE_12 byte-length invariant violated (expected 12)");
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2391
2445
|
// src/chunked.ts
|
|
2392
2446
|
var CHUNK_MAX_BYTES = 64;
|
|
2393
2447
|
var UTF8_ENCODER2 = new TextEncoder();
|
|
@@ -2470,6 +2524,9 @@ var STRUCTURAL_ERROR_CODES = [
|
|
|
2470
2524
|
"UNSUPPORTED_ENVELOPE_SCHEME",
|
|
2471
2525
|
"ENC_SLOTS_EMPTY",
|
|
2472
2526
|
"ENC_SLOT_INVALID_SHAPE",
|
|
2527
|
+
"ENC_SLOTS_DUPLICATE_KEM_MATERIAL",
|
|
2528
|
+
"ENC_SLOTS_TOO_MANY",
|
|
2529
|
+
"ENC_ENVELOPE_TOO_LARGE",
|
|
2473
2530
|
"UNSUPPORTED_KEM_ALG",
|
|
2474
2531
|
"ENC_KEM_REQUIRED",
|
|
2475
2532
|
"KEM_EPK_LENGTH_MISMATCH",
|
|
@@ -2545,6 +2602,9 @@ var SEVERITY = Object.freeze({
|
|
|
2545
2602
|
UNSUPPORTED_ENVELOPE_SCHEME: "error",
|
|
2546
2603
|
ENC_SLOTS_EMPTY: "error",
|
|
2547
2604
|
ENC_SLOT_INVALID_SHAPE: "error",
|
|
2605
|
+
ENC_SLOTS_DUPLICATE_KEM_MATERIAL: "error",
|
|
2606
|
+
ENC_SLOTS_TOO_MANY: "error",
|
|
2607
|
+
ENC_ENVELOPE_TOO_LARGE: "error",
|
|
2548
2608
|
UNSUPPORTED_KEM_ALG: "error",
|
|
2549
2609
|
ENC_KEM_REQUIRED: "error",
|
|
2550
2610
|
KEM_EPK_LENGTH_MISMATCH: "error",
|
|
@@ -2625,6 +2685,8 @@ var KEM_FIELD_LENGTH_CODE = {
|
|
|
2625
2685
|
epk: "KEM_EPK_LENGTH_MISMATCH",
|
|
2626
2686
|
kem_ct: "KEM_CT_LENGTH_MISMATCH"
|
|
2627
2687
|
};
|
|
2688
|
+
var NONCE_LENGTH = 24;
|
|
2689
|
+
var SLOTS_MAC_LENGTH = 32;
|
|
2628
2690
|
var PASSPHRASE_KDF_ALGS = /* @__PURE__ */ new Set(["argon2id"]);
|
|
2629
2691
|
var KNOWN_SIG_ALG_IDS = /* @__PURE__ */ new Set([-8, -19]);
|
|
2630
2692
|
function validatePoeRecord(bytes) {
|
|
@@ -2838,7 +2900,7 @@ function validateOneUri(chunks, path, errors) {
|
|
|
2838
2900
|
const cid = slashIdx === -1 ? rest : rest.slice(0, slashIdx);
|
|
2839
2901
|
if (!validateCidProfile(cid)) {
|
|
2840
2902
|
errors.push(
|
|
2841
|
-
issue("INVALID_URI", path, "ipfs:// URI is not a valid CID under the
|
|
2903
|
+
issue("INVALID_URI", path, "ipfs:// URI is not a valid CID under the Label 309 profile")
|
|
2842
2904
|
);
|
|
2843
2905
|
}
|
|
2844
2906
|
return;
|
|
@@ -2886,7 +2948,7 @@ function checkItemEnc(item, idx, errors) {
|
|
|
2886
2948
|
issue(
|
|
2887
2949
|
"UNAUTHENTICATED_CIPHER_FORBIDDEN",
|
|
2888
2950
|
[...basePath, "aead"],
|
|
2889
|
-
`'${enc.aead}' is an unauthenticated cipher;
|
|
2951
|
+
`'${enc.aead}' is an unauthenticated cipher; Label 309 mandates an authenticated (AEAD) cipher`
|
|
2890
2952
|
)
|
|
2891
2953
|
);
|
|
2892
2954
|
return;
|
|
@@ -2941,24 +3003,62 @@ function checkItemEnc(item, idx, errors) {
|
|
|
2941
3003
|
);
|
|
2942
3004
|
}
|
|
2943
3005
|
if (hasSlots) {
|
|
2944
|
-
|
|
3006
|
+
const slotCount = enc.slots.length;
|
|
3007
|
+
if (slotCount < 1) {
|
|
2945
3008
|
errors.push(
|
|
2946
|
-
issue("ENC_SLOTS_EMPTY", [...basePath, "slots"], `slots length ${
|
|
3009
|
+
issue("ENC_SLOTS_EMPTY", [...basePath, "slots"], `slots length ${slotCount} < 1`)
|
|
2947
3010
|
);
|
|
2948
|
-
}
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
);
|
|
2961
|
-
|
|
3011
|
+
} else if (slotCount > MAX_SLOTS) {
|
|
3012
|
+
errors.push(
|
|
3013
|
+
issue(
|
|
3014
|
+
"ENC_SLOTS_TOO_MANY",
|
|
3015
|
+
[...basePath, "slots"],
|
|
3016
|
+
`slots length ${slotCount} exceeds MAX_SLOTS=${MAX_SLOTS}`
|
|
3017
|
+
)
|
|
3018
|
+
);
|
|
3019
|
+
} else {
|
|
3020
|
+
const descriptor = enc.kem !== void 0 ? KEM_SLOT_DESCRIPTORS[enc.kem] : void 0;
|
|
3021
|
+
if (descriptor !== void 0) {
|
|
3022
|
+
const rawSlotKeys = rawSlotKeySets(item.enc);
|
|
3023
|
+
const seenKemMaterial = /* @__PURE__ */ new Set();
|
|
3024
|
+
enc.slots.forEach((slot, si) => {
|
|
3025
|
+
const slotPath = [...basePath, "slots", si];
|
|
3026
|
+
checkSlotShape(
|
|
3027
|
+
slot,
|
|
3028
|
+
rawSlotKeys[si] ?? /* @__PURE__ */ new Set(),
|
|
3029
|
+
descriptor,
|
|
3030
|
+
enc.kem,
|
|
3031
|
+
slotPath,
|
|
3032
|
+
errors
|
|
3033
|
+
);
|
|
3034
|
+
const material = slotKemMaterial(slot, descriptor);
|
|
3035
|
+
if (material !== void 0) {
|
|
3036
|
+
const key = bytesToHex2(material);
|
|
3037
|
+
if (seenKemMaterial.has(key)) {
|
|
3038
|
+
errors.push(
|
|
3039
|
+
issue(
|
|
3040
|
+
"ENC_SLOTS_DUPLICATE_KEM_MATERIAL",
|
|
3041
|
+
[...slotPath, descriptor.field],
|
|
3042
|
+
`slot ${si} ${descriptor.field} duplicates an earlier slot \u2014 per-slot KEK uniqueness is violated`
|
|
3043
|
+
)
|
|
3044
|
+
);
|
|
3045
|
+
} else {
|
|
3046
|
+
seenKemMaterial.add(key);
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
});
|
|
3050
|
+
const perSlotBytes = descriptor.fieldLength + descriptor.wrapLength;
|
|
3051
|
+
const decodedEnvelopeBytes = NONCE_LENGTH + SLOTS_MAC_LENGTH + slotCount * perSlotBytes;
|
|
3052
|
+
if (decodedEnvelopeBytes > MAX_DECODED_ENVELOPE_BYTES) {
|
|
3053
|
+
errors.push(
|
|
3054
|
+
issue(
|
|
3055
|
+
"ENC_ENVELOPE_TOO_LARGE",
|
|
3056
|
+
[...basePath, "slots"],
|
|
3057
|
+
`decoded envelope size ${decodedEnvelopeBytes} exceeds MAX_DECODED_ENVELOPE_BYTES=${MAX_DECODED_ENVELOPE_BYTES}`
|
|
3058
|
+
)
|
|
3059
|
+
);
|
|
3060
|
+
}
|
|
3061
|
+
}
|
|
2962
3062
|
}
|
|
2963
3063
|
}
|
|
2964
3064
|
if (hasPassphrase) {
|
|
@@ -3115,6 +3215,20 @@ function checkSlotShape(slot, rawKeys, descriptor, kem, slotPath, errors) {
|
|
|
3115
3215
|
);
|
|
3116
3216
|
}
|
|
3117
3217
|
}
|
|
3218
|
+
function slotKemMaterial(slot, descriptor) {
|
|
3219
|
+
if (descriptor.field === "epk") {
|
|
3220
|
+
return slot.epk;
|
|
3221
|
+
}
|
|
3222
|
+
if (slot.kem_ct === void 0) return void 0;
|
|
3223
|
+
return bytesChunkArrayConcat(slot.kem_ct);
|
|
3224
|
+
}
|
|
3225
|
+
function bytesToHex2(bytes) {
|
|
3226
|
+
let hex = "";
|
|
3227
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
3228
|
+
hex += bytes[i].toString(16).padStart(2, "0");
|
|
3229
|
+
}
|
|
3230
|
+
return hex;
|
|
3231
|
+
}
|
|
3118
3232
|
function rawSlotKeySets(rawEnc) {
|
|
3119
3233
|
const slots = mapLikeGet(rawEnc, "slots");
|
|
3120
3234
|
if (!Array.isArray(slots)) return [];
|