@forestrie/receipt-verify 0.7.0 → 0.7.1
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkpoint-chain.d.ts","sourceRoot":"","sources":["../src/checkpoint-chain.ts"],"names":[],"mappings":"AA6BA,iEAAiE;AACjE,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,KAAK,EAAE,UAAU,EAAE,EAAE,CAAC;IACtB,uEAAuE;IACvE,UAAU,EAAE,UAAU,EAAE,CAAC;CAC1B,CAAC;
|
|
1
|
+
{"version":3,"file":"checkpoint-chain.d.ts","sourceRoot":"","sources":["../src/checkpoint-chain.ts"],"names":[],"mappings":"AA6BA,iEAAiE;AACjE,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,KAAK,EAAE,UAAU,EAAE,EAAE,CAAC;IACtB,uEAAuE;IACvE,UAAU,EAAE,UAAU,EAAE,CAAC;CAC1B,CAAC;AA2BF,gEAAgE;AAChE,wBAAgB,0BAA0B,CACxC,eAAe,EAAE,UAAU,GAC1B,0BAA0B,CA6C5B;AAED;;;;;GAKG;AACH,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,0BAA0B,EACjC,eAAe,EAAE,UAAU,EAAE,GAC5B,OAAO,CAAC,UAAU,EAAE,CAAC,CAmBvB;AAED;+DAC+D;AAC/D,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,UAAU,CAQxE;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAC7B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAAC,WAAW,EAAE,UAAU,EAAE,CAAA;CAAE,GACrE;IACE,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EACF,aAAa,GACb,oBAAoB,GACpB,WAAW,GACX,iBAAiB,CAAC;IACtB,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,mBAAmB,EAAE,CAAC;CAC9B,CAAC;AAEN;;;;;;;;;;;;;GAaG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,eAAe,EAAE,CACf,eAAe,EAAE,UAAU,EAC3B,eAAe,EAAE,UAAU,KACxB,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB,4EAA4E;IAC5E,eAAe,CAAC,EAAE,UAAU,EAAE,CAAC;CAChC,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAiGjC"}
|
package/dist/checkpoint-chain.js
CHANGED
|
@@ -26,15 +26,23 @@ import { parseCheckpoint } from "./build-receipt-offline.js";
|
|
|
26
26
|
const VDS_COSE_RECEIPT_PROOFS_TAG = 396;
|
|
27
27
|
const VDP_CONSISTENCY_PROOF_KEY = -2;
|
|
28
28
|
function asBigint(v, what) {
|
|
29
|
-
|
|
29
|
+
// Unsigned only: a negative size flows into `peakMMRIndexes`, whose
|
|
30
|
+
// `posHeight` spins forever on a non-positive argument — a malformed `.sth`
|
|
31
|
+
// must be rejected in bounded time, before any such call (FOR-414).
|
|
32
|
+
if (typeof v === "bigint") {
|
|
33
|
+
if (v < 0n)
|
|
34
|
+
throw new Error(`${what}: must be an unsigned integer, got ${v}`);
|
|
30
35
|
return v;
|
|
31
|
-
|
|
36
|
+
}
|
|
37
|
+
if (typeof v === "number" && Number.isSafeInteger(v) && v >= 0) {
|
|
32
38
|
return BigInt(v);
|
|
39
|
+
}
|
|
33
40
|
throw new Error(`${what}: expected an unsigned integer`);
|
|
34
41
|
}
|
|
35
42
|
function asBytesArray(v, what) {
|
|
36
|
-
if (!Array.isArray(v) ||
|
|
37
|
-
|
|
43
|
+
if (!Array.isArray(v) ||
|
|
44
|
+
v.some((e) => !(e instanceof Uint8Array) || e.length !== 32)) {
|
|
45
|
+
throw new Error(`${what}: expected an array of 32-byte strings`);
|
|
38
46
|
}
|
|
39
47
|
return v;
|
|
40
48
|
}
|
|
@@ -58,9 +66,19 @@ export function checkpointConsistencyProof(checkpointBytes) {
|
|
|
58
66
|
pathsRaw.some((p) => !Array.isArray(p) || p.some((n) => !(n instanceof Uint8Array)))) {
|
|
59
67
|
throw new Error("consistency paths must be arrays of byte strings");
|
|
60
68
|
}
|
|
69
|
+
const treeSize1 = asBigint(proof[0], "tree-size-1");
|
|
70
|
+
const treeSize2 = asBigint(proof[1], "tree-size-2");
|
|
71
|
+
// A consistency proof strictly grows the tree; enforce `0 <= ts1 < ts2`
|
|
72
|
+
// (ts1 == 0 is a legitimate base-0 first link). This is the primary guard
|
|
73
|
+
// that keeps `treeSize2 - 1` / `treeSize1 - 1` non-negative before they
|
|
74
|
+
// reach `peakMMRIndexes` (FOR-414); the unsigned check in `asBigint` and
|
|
75
|
+
// the `posHeight` guard in @forestrie/merklelog are defence-in-depth.
|
|
76
|
+
if (treeSize2 <= treeSize1) {
|
|
77
|
+
throw new Error(`consistency proof must grow the tree: tree-size-1 ${treeSize1} < tree-size-2 ${treeSize2}`);
|
|
78
|
+
}
|
|
61
79
|
return {
|
|
62
|
-
treeSize1
|
|
63
|
-
treeSize2
|
|
80
|
+
treeSize1,
|
|
81
|
+
treeSize2,
|
|
64
82
|
paths: pathsRaw,
|
|
65
83
|
rightPeaks: asBytesArray(proof[3], "right-peaks"),
|
|
66
84
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forestrie/receipt-verify",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Offline SCITT grant receipt verification (ADR-0045)",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@noble/hashes": "^1.7.1",
|
|
31
31
|
"@forestrie/encoding": "0.5.0",
|
|
32
|
-
"@forestrie/merklelog": "0.2.
|
|
32
|
+
"@forestrie/merklelog": "0.2.1"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"esbuild": "^0.24.0",
|
package/src/checkpoint-chain.ts
CHANGED
|
@@ -38,14 +38,26 @@ export type CheckpointConsistencyProof = {
|
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
function asBigint(v: unknown, what: string): bigint {
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
// Unsigned only: a negative size flows into `peakMMRIndexes`, whose
|
|
42
|
+
// `posHeight` spins forever on a non-positive argument — a malformed `.sth`
|
|
43
|
+
// must be rejected in bounded time, before any such call (FOR-414).
|
|
44
|
+
if (typeof v === "bigint") {
|
|
45
|
+
if (v < 0n)
|
|
46
|
+
throw new Error(`${what}: must be an unsigned integer, got ${v}`);
|
|
47
|
+
return v;
|
|
48
|
+
}
|
|
49
|
+
if (typeof v === "number" && Number.isSafeInteger(v) && v >= 0) {
|
|
50
|
+
return BigInt(v);
|
|
51
|
+
}
|
|
43
52
|
throw new Error(`${what}: expected an unsigned integer`);
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
function asBytesArray(v: unknown, what: string): Uint8Array[] {
|
|
47
|
-
if (
|
|
48
|
-
|
|
56
|
+
if (
|
|
57
|
+
!Array.isArray(v) ||
|
|
58
|
+
v.some((e) => !(e instanceof Uint8Array) || e.length !== 32)
|
|
59
|
+
) {
|
|
60
|
+
throw new Error(`${what}: expected an array of 32-byte strings`);
|
|
49
61
|
}
|
|
50
62
|
return v as Uint8Array[];
|
|
51
63
|
}
|
|
@@ -80,9 +92,21 @@ export function checkpointConsistencyProof(
|
|
|
80
92
|
) {
|
|
81
93
|
throw new Error("consistency paths must be arrays of byte strings");
|
|
82
94
|
}
|
|
95
|
+
const treeSize1 = asBigint(proof[0], "tree-size-1");
|
|
96
|
+
const treeSize2 = asBigint(proof[1], "tree-size-2");
|
|
97
|
+
// A consistency proof strictly grows the tree; enforce `0 <= ts1 < ts2`
|
|
98
|
+
// (ts1 == 0 is a legitimate base-0 first link). This is the primary guard
|
|
99
|
+
// that keeps `treeSize2 - 1` / `treeSize1 - 1` non-negative before they
|
|
100
|
+
// reach `peakMMRIndexes` (FOR-414); the unsigned check in `asBigint` and
|
|
101
|
+
// the `posHeight` guard in @forestrie/merklelog are defence-in-depth.
|
|
102
|
+
if (treeSize2 <= treeSize1) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`consistency proof must grow the tree: tree-size-1 ${treeSize1} < tree-size-2 ${treeSize2}`,
|
|
105
|
+
);
|
|
106
|
+
}
|
|
83
107
|
return {
|
|
84
|
-
treeSize1
|
|
85
|
-
treeSize2
|
|
108
|
+
treeSize1,
|
|
109
|
+
treeSize2,
|
|
86
110
|
paths: pathsRaw as Uint8Array[][],
|
|
87
111
|
rightPeaks: asBytesArray(proof[3], "right-peaks"),
|
|
88
112
|
};
|