@forestrie/receipt-verify 1.1.0 → 2.0.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/dist/attach-transparent-statement-receipt.d.ts +5 -1
- package/dist/attach-transparent-statement-receipt.d.ts.map +1 -1
- package/dist/attach-transparent-statement-receipt.js +7 -3
- package/dist/build-receipt-offline.d.ts +8 -1
- package/dist/build-receipt-offline.d.ts.map +1 -1
- package/dist/build-receipt-offline.js +31 -24
- package/dist/checkpoint-chain.d.ts +130 -17
- package/dist/checkpoint-chain.d.ts.map +1 -1
- package/dist/checkpoint-chain.js +216 -117
- package/dist/decode-checkpoint-consistency-proof.d.ts +38 -0
- package/dist/decode-checkpoint-consistency-proof.d.ts.map +1 -0
- package/dist/decode-checkpoint-consistency-proof.js +108 -0
- package/dist/freshen-receipt.d.ts +23 -6
- package/dist/freshen-receipt.d.ts.map +1 -1
- package/dist/freshen-receipt.js +29 -17
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/parse-receipt.d.ts.map +1 -1
- package/dist/parse-receipt.js +2 -3
- package/package.json +3 -3
- package/src/attach-transparent-statement-receipt.ts +10 -3
- package/src/build-receipt-offline.ts +41 -22
- package/src/checkpoint-chain.ts +279 -136
- package/src/decode-checkpoint-consistency-proof.ts +136 -0
- package/src/freshen-receipt.ts +56 -25
- package/src/index.ts +2 -0
- package/src/parse-receipt.ts +2 -4
package/dist/freshen-receipt.js
CHANGED
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
* tested go-merklelog port); this module only assembles node values by index
|
|
46
46
|
* from the old receipt path + the consistency proofs.
|
|
47
47
|
*/
|
|
48
|
-
import { calculateRoot, inclusionProofPath, peakIndexForLeafProof, peakMMRIndexes, } from "@forestrie/merklelog";
|
|
48
|
+
import { calculateRoot, inclusionProofPath, mmrSizeForLeafCount, peakIndexForLeafProof, peakMMRIndexes, peaksBitmap, } from "@forestrie/merklelog";
|
|
49
49
|
import { assembleReceiptFromProof, parseCheckpoint, } from "./build-receipt-offline.js";
|
|
50
50
|
import { computeCheckpointAccumulator, } from "./checkpoint-chain.js";
|
|
51
51
|
import { parseReceipt } from "./parse-receipt.js";
|
|
@@ -90,19 +90,26 @@ export async function freshenReceipt(input) {
|
|
|
90
90
|
throw new Error("freshen requires at least one consistency proof linking the receipt's era to the checkpoint");
|
|
91
91
|
}
|
|
92
92
|
const firstLink = links[0];
|
|
93
|
-
// Base:
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
93
|
+
// Base: the CALLER's trusted size and its accumulator (size 0 and an empty
|
|
94
|
+
// accumulator for a whole-log chain). The size has to be a size an MMR can
|
|
95
|
+
// have — `peaksBitmap` rounds an incomplete one DOWN, so a size of 5 would
|
|
96
|
+
// fold the 4 -> N shape — and the accumulator has to hold that size's
|
|
97
|
+
// peaks, which is the check the proof's own declared base used to stand in
|
|
98
|
+
// for.
|
|
99
|
+
const baseSize = input.trustedBase?.size ?? 0n;
|
|
100
|
+
const baseAccumulator = input.trustedBase?.accumulator ?? [];
|
|
101
|
+
if (baseSize < 0n ||
|
|
102
|
+
mmrSizeForLeafCount(peaksBitmap(baseSize)) !== baseSize) {
|
|
103
|
+
throw new Error(`trusted base size ${baseSize} is not a complete MMR size`);
|
|
104
|
+
}
|
|
105
|
+
const basePeaks = baseSize === 0n ? 0 : peakMMRIndexes(baseSize - 1n).length;
|
|
106
|
+
if (baseAccumulator.length !== basePeaks) {
|
|
107
|
+
throw new Error(`base accumulator has ${baseAccumulator.length} peaks; trusted base size ${baseSize} has ${basePeaks}`);
|
|
108
|
+
}
|
|
109
|
+
// The first link must continue from that size, not from a size it names
|
|
110
|
+
// itself (ADR-0066 D5.4).
|
|
111
|
+
if (firstLink.treeSize1 !== baseSize) {
|
|
112
|
+
throw new Error(`first consistency proof declares tree-size-1 ${firstLink.treeSize1}; the trusted base size is ${baseSize}`);
|
|
106
113
|
}
|
|
107
114
|
// Contiguity: each link continues where the previous one sealed.
|
|
108
115
|
for (let i = 1; i < links.length; i++) {
|
|
@@ -115,10 +122,15 @@ export async function freshenReceipt(input) {
|
|
|
115
122
|
if (lastLink.treeSize2 !== sealedSize) {
|
|
116
123
|
throw new Error(`consistency chain ends at size ${lastLink.treeSize2} but the checkpoint sealed size ${sealedSize}`);
|
|
117
124
|
}
|
|
118
|
-
// Fold the chain to the latest accumulator (self-check target).
|
|
119
|
-
|
|
125
|
+
// Fold the chain to the latest accumulator (self-check target). Each step
|
|
126
|
+
// runs against a size the caller trusts, never one read off the link being
|
|
127
|
+
// folded: the trusted base for the first link, and the size the previous
|
|
128
|
+
// link was just folded TO for every link after it.
|
|
129
|
+
let accumulator = baseAccumulator;
|
|
130
|
+
let sizeFrom = baseSize;
|
|
120
131
|
for (const p of links) {
|
|
121
|
-
accumulator = await computeCheckpointAccumulator(p, accumulator);
|
|
132
|
+
accumulator = await computeCheckpointAccumulator(p, accumulator, sizeFrom);
|
|
133
|
+
sizeFrom = p.treeSize2;
|
|
122
134
|
}
|
|
123
135
|
const aLatest = accumulator;
|
|
124
136
|
// Cross-check the fold against the checkpoint we are borrowing from (F1): the
|
package/dist/index.d.ts
CHANGED
|
@@ -76,7 +76,7 @@ export { findGrantLeafInMassif } from "./find-grant-leaf.js";
|
|
|
76
76
|
export type { LocatedLeaf } from "./find-grant-leaf.js";
|
|
77
77
|
/** Re-exported so callers of findGrantLeafInMassif can catch it (FOR-344). */
|
|
78
78
|
export { MissingIndexError } from "@forestrie/merklelog";
|
|
79
|
-
export { accumulatorPayload, checkpointConsistencyProof, computeCheckpointAccumulator, verifyCheckpointChain, type CheckpointChainLink, type CheckpointChainResult, type CheckpointConsistencyProof, } from "./checkpoint-chain.js";
|
|
79
|
+
export { accumulatorPayload, checkpointConsistencyProof, computeCheckpointAccumulator, verifyCheckpointChain, CheckpointHighSSignatureError, CheckpointSignedSizeMismatchError, type CheckpointChainLink, type CheckpointChainResult, type CheckpointConsistencyProof, } from "./checkpoint-chain.js";
|
|
80
80
|
/**
|
|
81
81
|
* Univocity leaf commitment hash. Was CLI-private (forestrie-cli's own
|
|
82
82
|
* mirror, "hoist to the library when the FOR-297 multi-hop resolver lands");
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -61,7 +61,7 @@ export { grantCommitmentHashFromGrant } from "./grant-commitment.js";
|
|
|
61
61
|
export { findGrantLeafInMassif } from "./find-grant-leaf.js";
|
|
62
62
|
/** Re-exported so callers of findGrantLeafInMassif can catch it (FOR-344). */
|
|
63
63
|
export { MissingIndexError } from "@forestrie/merklelog";
|
|
64
|
-
export { accumulatorPayload, checkpointConsistencyProof, computeCheckpointAccumulator, verifyCheckpointChain, } from "./checkpoint-chain.js";
|
|
64
|
+
export { accumulatorPayload, checkpointConsistencyProof, computeCheckpointAccumulator, verifyCheckpointChain, CheckpointHighSSignatureError, CheckpointSignedSizeMismatchError, } from "./checkpoint-chain.js";
|
|
65
65
|
/**
|
|
66
66
|
* Univocity leaf commitment hash. Was CLI-private (forestrie-cli's own
|
|
67
67
|
* mirror, "hoist to the library when the FOR-297 multi-hop resolver lands");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-receipt.d.ts","sourceRoot":"","sources":["../src/parse-receipt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"parse-receipt.d.ts","sourceRoot":"","sources":["../src/parse-receipt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAElD,MAAM,MAAM,SAAS,GAAG;IACtB,eAAe,EAAE,UAAU;IAC3B,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACjE,OAAO,EAAE,UAAU,GAAG,IAAI;IAC1B,SAAS,EAAE,UAAU;CACtB,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAW1D;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,CAiB1D;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACpD,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAUtB;AAED,wBAAgB,YAAY,CAAC,YAAY,EAAE,UAAU,GAAG;IACtD,YAAY,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,EAAE,UAAU,CAAC;IACxB,SAAS,EAAE,SAAS,CAAC;CACtB,CAwDA"}
|
package/dist/parse-receipt.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { decodeCborDeterministic } from "@forestrie/encoding";
|
|
2
|
-
const VDS_COSE_RECEIPT_PROOFS_TAG = 396;
|
|
1
|
+
import { COSE_LABEL_VDP, decodeCborDeterministic } from "@forestrie/encoding";
|
|
3
2
|
export function unwrapCoseSign1Tag(value) {
|
|
4
3
|
if (value && typeof value === "object" && !(value instanceof Map)) {
|
|
5
4
|
const tagged = value;
|
|
@@ -58,7 +57,7 @@ export function parseReceipt(receiptBytes) {
|
|
|
58
57
|
throw new Error("Receipt payload must be nil (detached) or 32-byte peak hash");
|
|
59
58
|
}
|
|
60
59
|
const unprotected = toHeaderMap(coseSign1[1]);
|
|
61
|
-
const proofsRaw = unprotected.get(
|
|
60
|
+
const proofsRaw = unprotected.get(COSE_LABEL_VDP);
|
|
62
61
|
if (!proofsRaw || typeof proofsRaw !== "object") {
|
|
63
62
|
throw new Error("Receipt missing header 396 (inclusion proof)");
|
|
64
63
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forestrie/receipt-verify",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Offline SCITT grant receipt verification (ADR-0045)",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@noble/hashes": "^1.7.1",
|
|
31
31
|
"@forestrie/chain-rpc": "0.3.0",
|
|
32
|
-
"@forestrie/
|
|
33
|
-
"@forestrie/
|
|
32
|
+
"@forestrie/encoding": "0.8.0",
|
|
33
|
+
"@forestrie/merklelog": "0.4.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"esbuild": "^0.24.0",
|
|
@@ -6,11 +6,18 @@
|
|
|
6
6
|
* Golden vectors for receipt construction/verification are tracked by
|
|
7
7
|
* FOR-289.
|
|
8
8
|
*/
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
COSE_LABEL_VDP,
|
|
11
|
+
mergeUnprotectedIntoCoseSign1,
|
|
12
|
+
} from "@forestrie/encoding";
|
|
10
13
|
import { HEADER_IDTIMESTAMP } from "./forest-genesis-labels.js";
|
|
11
14
|
|
|
12
|
-
/**
|
|
13
|
-
|
|
15
|
+
/**
|
|
16
|
+
* SCITT transparent statement unprotected receipt label (grants.md §3.2).
|
|
17
|
+
* Alias of {@link COSE_LABEL_VDP} — kept exported under this name for
|
|
18
|
+
* existing callers.
|
|
19
|
+
*/
|
|
20
|
+
export const HEADER_RECEIPT = COSE_LABEL_VDP;
|
|
14
21
|
|
|
15
22
|
export function attachReceiptAndIdtimestampToTransparentStatement(
|
|
16
23
|
statementBytes: Uint8Array,
|
|
@@ -16,8 +16,11 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import {
|
|
19
|
+
COSE_LABEL_PEAK_RECEIPTS,
|
|
20
|
+
COSE_LABEL_VDP,
|
|
19
21
|
decodeCborDeterministic,
|
|
20
22
|
encodeCborDeterministic,
|
|
23
|
+
readProtectedTreeSize2,
|
|
21
24
|
} from "@forestrie/encoding";
|
|
22
25
|
import {
|
|
23
26
|
calculateRoot,
|
|
@@ -34,12 +37,11 @@ import {
|
|
|
34
37
|
unwrapCoseSign1Tag,
|
|
35
38
|
type CoseSign1,
|
|
36
39
|
} from "./parse-receipt.js";
|
|
40
|
+
import { decodeConsistencyProofFromUnprotected } from "./decode-checkpoint-consistency-proof.js";
|
|
37
41
|
import { SubtleHasher } from "./subtle-hasher.js";
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
const SEAL_PEAK_RECEIPTS_LABEL = -65931;
|
|
43
|
+
/** Not in scope for the shared cose-labels module (FOR-568 §4.1). */
|
|
41
44
|
const DELEGATION_CERT_LABEL = 1000;
|
|
42
|
-
const VDP_CONSISTENCY_PROOF_KEY = -2;
|
|
43
45
|
|
|
44
46
|
/**
|
|
45
47
|
* Re-exported for compatibility. The MMR proof math and massif node store now
|
|
@@ -54,7 +56,14 @@ export type ParsedCheckpoint = {
|
|
|
54
56
|
unprotected: Map<number, unknown>;
|
|
55
57
|
/** Pre-signed peak receipts (label -65931), or null when absent. */
|
|
56
58
|
peakReceipts: unknown[] | null;
|
|
57
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* Sealed tree size: the SIGNED `tree-size-2` from the checkpoint's
|
|
61
|
+
* PROTECTED header (ADR-0066 D1 as amended, label -65933), not the
|
|
62
|
+
* unprotected consistency proof's declared value. `null` when the
|
|
63
|
+
* checkpoint carries no embedded consistency proof or no signed
|
|
64
|
+
* tree-size-2 — such a checkpoint is not verifiable and callers must
|
|
65
|
+
* treat it exactly as they would a checkpoint with no proof at all.
|
|
66
|
+
*/
|
|
58
67
|
mmrSize: bigint | null;
|
|
59
68
|
delegationCert: Uint8Array | null;
|
|
60
69
|
};
|
|
@@ -65,7 +74,7 @@ export function parseCheckpoint(checkpointBytes: Uint8Array): ParsedCheckpoint {
|
|
|
65
74
|
const coseSign1 = requireCoseSign1(unwrapCoseSign1Tag(decoded));
|
|
66
75
|
const unprotected = toHeaderMap(coseSign1[1]);
|
|
67
76
|
|
|
68
|
-
const peakReceiptsRaw = unprotected.get(
|
|
77
|
+
const peakReceiptsRaw = unprotected.get(COSE_LABEL_PEAK_RECEIPTS);
|
|
69
78
|
const peakReceipts = Array.isArray(peakReceiptsRaw) ? peakReceiptsRaw : null;
|
|
70
79
|
|
|
71
80
|
const delegationCertRaw = unprotected.get(DELEGATION_CERT_LABEL);
|
|
@@ -78,7 +87,7 @@ export function parseCheckpoint(checkpointBytes: Uint8Array): ParsedCheckpoint {
|
|
|
78
87
|
coseSign1,
|
|
79
88
|
unprotected,
|
|
80
89
|
peakReceipts,
|
|
81
|
-
mmrSize: sealedSizeFromCheckpoint(unprotected),
|
|
90
|
+
mmrSize: sealedSizeFromCheckpoint(coseSign1, unprotected),
|
|
82
91
|
delegationCert,
|
|
83
92
|
};
|
|
84
93
|
}
|
|
@@ -186,7 +195,7 @@ export function assembleReceiptFromProof(
|
|
|
186
195
|
const verifiableProofs = new Map<number, unknown>([
|
|
187
196
|
[-1, [inclusionProofEntry]],
|
|
188
197
|
]);
|
|
189
|
-
receiptUnprotected.set(
|
|
198
|
+
receiptUnprotected.set(COSE_LABEL_VDP, verifiableProofs);
|
|
190
199
|
|
|
191
200
|
// Peak receipts are signed with detached payload; emit nil so verify uses
|
|
192
201
|
// the peak derived from the inclusion proof.
|
|
@@ -252,24 +261,34 @@ function cborBytes(value: unknown): Uint8Array {
|
|
|
252
261
|
}
|
|
253
262
|
|
|
254
263
|
/**
|
|
255
|
-
* Sealed mmr size from a format-v3 checkpoint: tree-size-2
|
|
256
|
-
*
|
|
257
|
-
*
|
|
264
|
+
* Sealed mmr size from a format-v3 checkpoint: the SIGNED `tree-size-2`
|
|
265
|
+
* (ADR-0066 D1 as amended, label -65933) from the PROTECTED header — not the
|
|
266
|
+
* unprotected consistency proof's declared value, which a checkpoint without
|
|
267
|
+
* a signing key could freely restate (ADR-0066's "keyless first checkpoint"
|
|
268
|
+
* case). A consistency proof must still be present (an unsigned checkpoint
|
|
269
|
+
* with no proof is not sealed at all); its declared sizes are not otherwise
|
|
270
|
+
* used here — {@link checkpointConsistencyProof} in `checkpoint-chain.ts`
|
|
271
|
+
* is the validating decode that requires the two to agree.
|
|
272
|
+
*
|
|
273
|
+
* Lenient by design: an absent proof, a malformed proof, or an absent or
|
|
274
|
+
* malformed signed tree-size-2 all yield `null` rather than a throw, so a
|
|
275
|
+
* caller of {@link parseCheckpoint} sees exactly the same "not verifiable"
|
|
276
|
+
* outcome either way.
|
|
258
277
|
*/
|
|
259
278
|
function sealedSizeFromCheckpoint(
|
|
279
|
+
coseSign1: CoseSign1,
|
|
260
280
|
unprotected: Map<number, unknown>,
|
|
261
281
|
): bigint | null {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
if (
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
return
|
|
282
|
+
let declared;
|
|
283
|
+
try {
|
|
284
|
+
declared = decodeConsistencyProofFromUnprotected(unprotected);
|
|
285
|
+
} catch {
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
if (declared === null) return null;
|
|
289
|
+
try {
|
|
290
|
+
return readProtectedTreeSize2(coseSign1[0]);
|
|
291
|
+
} catch {
|
|
292
|
+
return null;
|
|
273
293
|
}
|
|
274
|
-
return null;
|
|
275
294
|
}
|