@forestrie/receipt-verify 2.2.0 → 3.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/build-receipt-offline.js +14 -10
- package/dist/checkpoint-chain.d.ts +105 -43
- package/dist/checkpoint-chain.d.ts.map +1 -1
- package/dist/checkpoint-chain.js +141 -53
- package/dist/decode-checkpoint-consistency-proof.d.ts +47 -15
- package/dist/decode-checkpoint-consistency-proof.d.ts.map +1 -1
- package/dist/decode-checkpoint-consistency-proof.js +105 -33
- package/dist/freshen-receipt.d.ts +7 -5
- package/dist/freshen-receipt.d.ts.map +1 -1
- package/dist/freshen-receipt.js +16 -10
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +4 -4
- package/src/build-receipt-offline.ts +14 -10
- package/src/checkpoint-chain.ts +182 -72
- package/src/decode-checkpoint-consistency-proof.ts +118 -34
- package/src/freshen-receipt.ts +23 -15
- package/src/index.ts +5 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decode-checkpoint-consistency-proof.d.ts","sourceRoot":"","sources":["../src/decode-checkpoint-consistency-proof.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"decode-checkpoint-consistency-proof.d.ts","sourceRoot":"","sources":["../src/decode-checkpoint-consistency-proof.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAQH,8EAA8E;AAC9E,MAAM,MAAM,uBAAuB,GAAG;IACpC,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;AAEF;;;;;;;GAOG;AACH,qBAAa,2BAA4B,SAAQ,KAAK;gBACxC,OAAO,EAAE,MAAM;CAI5B;AA8GD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,sCAAsC,CACpD,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,uBAAuB,EAAE,GAAG,IAAI,CA6BlC"}
|
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Decode the draft-bryce consistency
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Decode the draft-bryce consistency proofs carried under a checkpoint's
|
|
3
|
+
* verifiable-proofs UNPROTECTED header (draft-bryce label 396, key -2 =
|
|
4
|
+
* `VDP_CONSISTENCY_PROOF_KEY`).
|
|
5
|
+
*
|
|
6
|
+
* The draft's CDDL is
|
|
7
|
+
* `consistency-proofs = [ + consistency-proof ]`, with each
|
|
8
|
+
* `consistency-proof = bstr .cbor [tree-size-1, tree-size-2, paths,
|
|
9
|
+
* right-peaks]` — one or more proofs, relayed in chain order under a single
|
|
10
|
+
* signature (ADR-0066 D2). Both shapes are accepted under the -2 key:
|
|
11
|
+
*
|
|
12
|
+
* - an ARRAY of one or more proof bstrs — the draft's wire form, and the
|
|
13
|
+
* only form that can carry a relayed chain;
|
|
14
|
+
* - a BARE proof bstr — the shape every checkpoint sealed before the array
|
|
15
|
+
* form carries, and the shape the pinned `checkpoint-receipt-kat39.json`
|
|
16
|
+
* vector's `conventions.receipt` still states. It decodes to the array of
|
|
17
|
+
* one, so nothing downstream distinguishes it.
|
|
5
18
|
*
|
|
6
19
|
* Single source of truth for this decode, shared by `parseCheckpoint`
|
|
7
20
|
* (build-receipt-offline.ts, lenient: an absent or malformed proof yields a
|
|
@@ -9,10 +22,25 @@
|
|
|
9
22
|
* (checkpoint-chain.ts, full validation: an absent proof or a malformed
|
|
10
23
|
* shape throws, and the SIGNED `tree-size-2` from the protected header —
|
|
11
24
|
* read separately via `readProtectedTreeSize2`, ADR-0066 D1 as amended —
|
|
12
|
-
* must match the `tree-size-2` decoded here;
|
|
13
|
-
* prover context and is not cross-checked against
|
|
25
|
+
* must match the `tree-size-2` of the LAST proof decoded here;
|
|
26
|
+
* `tree-size-1` is unsigned prover context and is not cross-checked against
|
|
27
|
+
* a signed value).
|
|
14
28
|
*/
|
|
15
29
|
import { COSE_LABEL_VDP, VDP_CONSISTENCY_PROOF_KEY, decodeCborDeterministic, } from "@forestrie/encoding";
|
|
30
|
+
/**
|
|
31
|
+
* The verifiable-proofs header carries the consistency-proof key with an
|
|
32
|
+
* EMPTY array. Distinct from an absent proof (no -2 key at all, which
|
|
33
|
+
* decodes to `null`): the key is present and claims to relay a chain, but
|
|
34
|
+
* the chain has no links, so there is nothing to fold and no last proof for
|
|
35
|
+
* the signed `tree-size-2` to equal. `consistency-proofs = [ + ... ]`
|
|
36
|
+
* requires at least one.
|
|
37
|
+
*/
|
|
38
|
+
export class EmptyConsistencyProofsError extends Error {
|
|
39
|
+
constructor(message) {
|
|
40
|
+
super(message);
|
|
41
|
+
this.name = "EmptyConsistencyProofsError";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
16
44
|
function asBigint(v, what) {
|
|
17
45
|
// Unsigned only: a negative size flows into peakMMRIndexes /
|
|
18
46
|
// consistentRootsForSizes, which reject or spin on a non-positive
|
|
@@ -36,35 +64,15 @@ function asBytesArray(v, what) {
|
|
|
36
64
|
}
|
|
37
65
|
return v;
|
|
38
66
|
}
|
|
39
|
-
/**
|
|
40
|
-
|
|
41
|
-
* header map. Returns `null` when the checkpoint carries no verifiable-proofs
|
|
42
|
-
* header (396) or no consistency-proof bstr there (key -2) — an ABSENT
|
|
43
|
-
* proof, not a malformed one.
|
|
44
|
-
*
|
|
45
|
-
* @throws When a consistency-proof bstr IS present but its contents are not
|
|
46
|
-
* the shape `[tree-size-1, tree-size-2, paths, right-peaks]`, either size
|
|
47
|
-
* is not an unsigned integer, the proof does not grow the tree
|
|
48
|
-
* (`tree-size-2 <= tree-size-1`), a path element or a right-peak is not a
|
|
49
|
-
* 32-byte string — or when header 396 is present but is not map-valued,
|
|
50
|
-
* or its `-2` entry is present but not a byte string.
|
|
51
|
-
*/
|
|
52
|
-
export function decodeConsistencyProofFromUnprotected(unprotected) {
|
|
53
|
-
const vdpRaw = unprotected.get(COSE_LABEL_VDP);
|
|
54
|
-
if (vdpRaw === undefined || vdpRaw === null)
|
|
55
|
-
return null;
|
|
56
|
-
if (!(vdpRaw instanceof Map)) {
|
|
57
|
-
throw new Error("checkpoint carries no verifiable-proofs header (396)");
|
|
58
|
-
}
|
|
59
|
-
const proofBstr = vdpRaw.get(VDP_CONSISTENCY_PROOF_KEY);
|
|
60
|
-
if (proofBstr === undefined || proofBstr === null)
|
|
61
|
-
return null;
|
|
62
|
-
if (!(proofBstr instanceof Uint8Array)) {
|
|
63
|
-
throw new Error("checkpoint carries no consistency proof (vdp key -2)");
|
|
64
|
-
}
|
|
67
|
+
/** Decode one `bstr .cbor [tree-size-1, tree-size-2, paths, right-peaks]`. */
|
|
68
|
+
function decodeOneProof(proofBstr) {
|
|
65
69
|
const proof = decodeCborDeterministic(proofBstr);
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
// Exactly 4 — the draft's CDDL names a fixed-arity array, and
|
|
71
|
+
// go-merklelog's decoder rejects any other length (F2). A 5th element
|
|
72
|
+
// (e.g. another proof tuple, mistaken for a chain of two) is as malformed
|
|
73
|
+
// as a 3rd missing.
|
|
74
|
+
if (!Array.isArray(proof) || proof.length !== 4) {
|
|
75
|
+
throw new Error(`consistency proof must be [tree-size-1, tree-size-2, paths, right-peaks] (4 elements), got ${Array.isArray(proof) ? proof.length : typeof proof}`);
|
|
68
76
|
}
|
|
69
77
|
const pathsRaw = proof[2];
|
|
70
78
|
if (!Array.isArray(pathsRaw)) {
|
|
@@ -106,3 +114,67 @@ export function decodeConsistencyProofFromUnprotected(unprotected) {
|
|
|
106
114
|
rightPeaks: asBytesArray(proof[3], "right-peaks"),
|
|
107
115
|
};
|
|
108
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Decode proof `at` of a relayed chain, naming its position in the message
|
|
119
|
+
* so a chain of several says which link is malformed. A header carrying a
|
|
120
|
+
* single proof names no position: its message is the one a single-proof
|
|
121
|
+
* checkpoint has always produced.
|
|
122
|
+
*/
|
|
123
|
+
function decodeProofAt(proofBstr, at) {
|
|
124
|
+
if (at === null)
|
|
125
|
+
return decodeOneProof(proofBstr);
|
|
126
|
+
try {
|
|
127
|
+
return decodeOneProof(proofBstr);
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
throw new Error(`consistency-proofs entry ${at}: ${err instanceof Error ? err.message : String(err)}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Decode the embedded consistency proofs from a checkpoint's UNPROTECTED
|
|
135
|
+
* header map, in the order they are relayed. Returns `null` when the
|
|
136
|
+
* checkpoint carries no verifiable-proofs header (396) or no
|
|
137
|
+
* consistency-proof entry there (key -2) — an ABSENT proof, not a malformed
|
|
138
|
+
* one. A returned array always holds at least one proof.
|
|
139
|
+
*
|
|
140
|
+
* This decode establishes each proof's shape only. Nothing here relates one
|
|
141
|
+
* proof to the next, or to a signed size: the chain has to be checked
|
|
142
|
+
* against state the CALLER trusts, which is `computeCheckpointAccumulator`
|
|
143
|
+
* and `checkpointConsistencyProof` (ADR-0066 D5.4).
|
|
144
|
+
*
|
|
145
|
+
* @throws {EmptyConsistencyProofsError} when the -2 entry is an empty array
|
|
146
|
+
* @throws When a consistency proof IS present but its contents are not the
|
|
147
|
+
* shape `[tree-size-1, tree-size-2, paths, right-peaks]`, either size is
|
|
148
|
+
* not an unsigned integer, a proof does not grow the tree
|
|
149
|
+
* (`tree-size-2 <= tree-size-1`), a path element or a right-peak is not a
|
|
150
|
+
* 32-byte string — or when header 396 is present but is not map-valued,
|
|
151
|
+
* or its `-2` entry is neither a byte string nor an array of byte strings.
|
|
152
|
+
*/
|
|
153
|
+
export function decodeConsistencyProofsFromUnprotected(unprotected) {
|
|
154
|
+
const vdpRaw = unprotected.get(COSE_LABEL_VDP);
|
|
155
|
+
if (vdpRaw === undefined || vdpRaw === null)
|
|
156
|
+
return null;
|
|
157
|
+
if (!(vdpRaw instanceof Map)) {
|
|
158
|
+
throw new Error("checkpoint carries no verifiable-proofs header (396)");
|
|
159
|
+
}
|
|
160
|
+
const entry = vdpRaw.get(VDP_CONSISTENCY_PROOF_KEY);
|
|
161
|
+
if (entry === undefined || entry === null)
|
|
162
|
+
return null;
|
|
163
|
+
if (entry instanceof Uint8Array) {
|
|
164
|
+
// The pre-array shape: a single proof written straight under -2. It is
|
|
165
|
+
// the array of one, and is reported as such.
|
|
166
|
+
return [decodeOneProof(entry)];
|
|
167
|
+
}
|
|
168
|
+
if (!Array.isArray(entry)) {
|
|
169
|
+
throw new Error("checkpoint carries no consistency proof (vdp key -2)");
|
|
170
|
+
}
|
|
171
|
+
if (entry.length === 0) {
|
|
172
|
+
throw new EmptyConsistencyProofsError("consistency-proofs (vdp key -2) is empty; at least one proof is required");
|
|
173
|
+
}
|
|
174
|
+
return entry.map((proofBstr, i) => {
|
|
175
|
+
if (!(proofBstr instanceof Uint8Array)) {
|
|
176
|
+
throw new Error(`consistency-proofs entry ${i} is not a byte string (vdp key -2)`);
|
|
177
|
+
}
|
|
178
|
+
return decodeProofAt(proofBstr, entry.length === 1 ? null : i);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
@@ -15,11 +15,13 @@ export type FreshenReceiptInput = {
|
|
|
15
15
|
* value `verify` recomputes from the entry (caller derives it). */
|
|
16
16
|
leafValue: Uint8Array;
|
|
17
17
|
/** Consistency-proof chain covering [0 or the trusted base] → the latest
|
|
18
|
-
* sealed size, in ascending contiguous order
|
|
19
|
-
* proofs
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* checkpoint
|
|
18
|
+
* sealed size, in ascending contiguous order: one entry per checkpoint,
|
|
19
|
+
* each holding the proofs that checkpoint relays (`proofs`, one or more —
|
|
20
|
+
* ADR-0066 D2). Every link's `signedTreeSize2` must equal its
|
|
21
|
+
* `treeSize2` — the size its LAST relayed proof reaches — as
|
|
22
|
+
* `checkpointConsistencyProof` requires of the checkpoint it decoded each
|
|
23
|
+
* link from. The chain's last link must end at the checkpoint's sealed
|
|
24
|
+
* size. */
|
|
23
25
|
consistencyProofs: readonly CheckpointConsistencyProof[];
|
|
24
26
|
/** Trusted base for a suffix chain — the size the caller already trusts
|
|
25
27
|
* and that size's accumulator; omit for a chain from base 0 (size 0, an
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"freshen-receipt.d.ts","sourceRoot":"","sources":["../src/freshen-receipt.ts"],"names":[],"mappings":"AA2DA,OAAO,EAGL,KAAK,0BAA0B,EAChC,MAAM,uBAAuB,CAAC;AAI/B;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,iEAAiE;IACjE,eAAe,EAAE,UAAU,CAAC;IAC5B;uEACmE;IACnE,SAAS,EAAE,UAAU,CAAC;IACtB
|
|
1
|
+
{"version":3,"file":"freshen-receipt.d.ts","sourceRoot":"","sources":["../src/freshen-receipt.ts"],"names":[],"mappings":"AA2DA,OAAO,EAGL,KAAK,0BAA0B,EAChC,MAAM,uBAAuB,CAAC;AAI/B;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,iEAAiE;IACjE,eAAe,EAAE,UAAU,CAAC;IAC5B;uEACmE;IACnE,SAAS,EAAE,UAAU,CAAC;IACtB;;;;;;;eAOW;IACX,iBAAiB,EAAE,SAAS,0BAA0B,EAAE,CAAC;IACzD;;;;;kDAK8C;IAC9C,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC;IAC1D;wDACoD;IACpD,qBAAqB,EAAE,UAAU,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,wEAAwE;IACxE,OAAO,EAAE,UAAU,CAAC;IACpB,wDAAwD;IACxD,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AASF;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAAC,oBAAoB,CAAC,CA4L/B"}
|
package/dist/freshen-receipt.js
CHANGED
|
@@ -125,7 +125,9 @@ export async function freshenReceipt(input) {
|
|
|
125
125
|
if (firstLink.treeSize1 !== baseSize) {
|
|
126
126
|
throw new Error(`first consistency proof declares tree-size-1 ${firstLink.treeSize1}; the trusted base size is ${baseSize}`);
|
|
127
127
|
}
|
|
128
|
-
// Contiguity: each link continues where the previous
|
|
128
|
+
// Contiguity BETWEEN checkpoints: each link continues where the previous
|
|
129
|
+
// one sealed. Contiguity WITHIN a link — between the proofs one
|
|
130
|
+
// checkpoint relays — is `computeCheckpointAccumulator`'s, below.
|
|
129
131
|
for (let i = 1; i < links.length; i++) {
|
|
130
132
|
if (links[i].treeSize1 !== links[i - 1].treeSize2) {
|
|
131
133
|
throw new Error(`consistency chain is not contiguous at link ${i}: base ${links[i].treeSize1} != previous sealed size ${links[i - 1].treeSize2}`);
|
|
@@ -136,10 +138,11 @@ export async function freshenReceipt(input) {
|
|
|
136
138
|
if (lastLink.treeSize2 !== sealedSize) {
|
|
137
139
|
throw new Error(`consistency chain ends at size ${lastLink.treeSize2} but the checkpoint sealed size ${sealedSize}`);
|
|
138
140
|
}
|
|
139
|
-
// Fold the chain to the latest accumulator (self-check target). Each
|
|
141
|
+
// Fold the chain to the latest accumulator (self-check target). Each link
|
|
140
142
|
// runs against a size the caller trusts, never one read off the link being
|
|
141
143
|
// folded: the trusted base for the first link, and the size the previous
|
|
142
|
-
// link was just folded TO for every link after it.
|
|
144
|
+
// link was just folded TO for every link after it. A link relaying several
|
|
145
|
+
// proofs folds them all, in order, and ends at its last one.
|
|
143
146
|
let accumulator = baseAccumulator;
|
|
144
147
|
let sizeFrom = baseSize;
|
|
145
148
|
for (const p of links) {
|
|
@@ -173,20 +176,23 @@ export async function freshenReceipt(input) {
|
|
|
173
176
|
for (let k = 0; k < oldPath.length; k++) {
|
|
174
177
|
store.set(fullIndices[k], oldPath[k]);
|
|
175
178
|
}
|
|
176
|
-
|
|
177
|
-
|
|
179
|
+
// Every relayed proof contributes, not just one per checkpoint: a link
|
|
180
|
+
// that relays several sealed steps (ADR-0066 D2) carries one set of paths
|
|
181
|
+
// per step, each addressed by that step's own two sizes.
|
|
182
|
+
for (const step of links.flatMap((link) => link.proofs)) {
|
|
183
|
+
// A base-0 step (treeSize1 === 0) has no from-peaks to climb — a 0→N
|
|
178
184
|
// consistency proof carries `paths: []` (the whole accumulator is its
|
|
179
185
|
// right-peaks). Skip it: it contributes no store nodes, and calling
|
|
180
186
|
// `peakMMRIndexes(-1n)` would throw (`posHeight(0)`, FOR-414). A genesis-
|
|
181
|
-
// rooted `.sth` chain always starts with such a
|
|
182
|
-
if (
|
|
187
|
+
// rooted `.sth` chain always starts with such a step.
|
|
188
|
+
if (step.treeSize1 === 0n)
|
|
183
189
|
continue;
|
|
184
|
-
const fromPeaks = peakMMRIndexes(
|
|
190
|
+
const fromPeaks = peakMMRIndexes(step.treeSize1 - 1n);
|
|
185
191
|
fromPeaks.forEach((peakIndex, j) => {
|
|
186
|
-
const climb =
|
|
192
|
+
const climb = step.paths[j];
|
|
187
193
|
if (climb === undefined)
|
|
188
194
|
return;
|
|
189
|
-
const climbIndices = inclusionProofPath(
|
|
195
|
+
const climbIndices = inclusionProofPath(step.treeSize2 - 1n, peakIndex);
|
|
190
196
|
climbIndices.forEach((ix, e) => {
|
|
191
197
|
const v = climb[e];
|
|
192
198
|
if (v !== undefined)
|
package/dist/index.d.ts
CHANGED
|
@@ -76,7 +76,10 @@ 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, CheckpointHighSSignatureError, CheckpointProtectedHeaderAlgError, CheckpointSignedSizeMismatchError, type CheckpointChainLink, type CheckpointChainResult, type CheckpointConsistencyProof, } from "./checkpoint-chain.js";
|
|
79
|
+
export { accumulatorPayload, checkpointConsistencyProof, computeCheckpointAccumulator, verifyCheckpointChain, CheckpointHighSSignatureError, CheckpointProtectedHeaderAlgError, CheckpointSignedSizeMismatchError, ConsistencyChainNotContiguousError, EmptyConsistencyProofsError, type CheckpointChainLink, type CheckpointChainResult, type CheckpointConsistencyProof, } from "./checkpoint-chain.js";
|
|
80
|
+
/** One relayed consistency proof; `CheckpointConsistencyProof.proofs` holds
|
|
81
|
+
* the chain of them a checkpoint carries (ADR-0066 D2). */
|
|
82
|
+
export type { DecodedConsistencyProof } from "./decode-checkpoint-consistency-proof.js";
|
|
80
83
|
/**
|
|
81
84
|
* Univocity leaf commitment hash. Was CLI-private (forestrie-cli's own
|
|
82
85
|
* 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, CheckpointHighSSignatureError, CheckpointProtectedHeaderAlgError, CheckpointSignedSizeMismatchError, } from "./checkpoint-chain.js";
|
|
64
|
+
export { accumulatorPayload, checkpointConsistencyProof, computeCheckpointAccumulator, verifyCheckpointChain, CheckpointHighSSignatureError, CheckpointProtectedHeaderAlgError, CheckpointSignedSizeMismatchError, ConsistencyChainNotContiguousError, EmptyConsistencyProofsError, } 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");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forestrie/receipt-verify",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Offline SCITT grant receipt verification (ADR-0045)",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@noble/hashes": "^1.7.1",
|
|
31
|
-
"@forestrie/
|
|
32
|
-
"@forestrie/
|
|
33
|
-
"@forestrie/
|
|
31
|
+
"@forestrie/encoding": "0.9.1",
|
|
32
|
+
"@forestrie/merklelog": "0.5.0",
|
|
33
|
+
"@forestrie/chain-rpc": "0.3.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"esbuild": "^0.24.0",
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
unwrapCoseSign1Tag,
|
|
38
38
|
type CoseSign1,
|
|
39
39
|
} from "./parse-receipt.js";
|
|
40
|
-
import {
|
|
40
|
+
import { decodeConsistencyProofsFromUnprotected } from "./decode-checkpoint-consistency-proof.js";
|
|
41
41
|
import { SubtleHasher } from "./subtle-hasher.js";
|
|
42
42
|
|
|
43
43
|
/** Not in scope for the shared cose-labels module (FOR-568 §4.1). */
|
|
@@ -265,15 +265,19 @@ function cborBytes(value: unknown): Uint8Array {
|
|
|
265
265
|
* (ADR-0066 D1 as amended, label -65933) from the PROTECTED header — not the
|
|
266
266
|
* unprotected consistency proof's declared value, which a checkpoint without
|
|
267
267
|
* a signing key could freely restate (ADR-0066's "keyless first checkpoint"
|
|
268
|
-
* case).
|
|
269
|
-
* with no proof is not sealed at all)
|
|
270
|
-
*
|
|
271
|
-
*
|
|
268
|
+
* case). At least one consistency proof must still be present (an unsigned
|
|
269
|
+
* checkpoint with no proof is not sealed at all) — one or more, since a
|
|
270
|
+
* checkpoint may relay a chain of sealed steps under one signature
|
|
271
|
+
* (ADR-0066 D2). Their declared sizes are not otherwise used here;
|
|
272
|
+
* {@link checkpointConsistencyProof} in `checkpoint-chain.ts` is the
|
|
273
|
+
* validating decode that requires the signed size and the last relayed
|
|
274
|
+
* proof's to agree.
|
|
272
275
|
*
|
|
273
|
-
* Lenient by design: an absent proof,
|
|
274
|
-
* malformed signed tree-size-2
|
|
275
|
-
*
|
|
276
|
-
*
|
|
276
|
+
* Lenient by design: an absent proof, an empty or malformed
|
|
277
|
+
* consistency-proofs array, or an absent or malformed signed tree-size-2
|
|
278
|
+
* all yield `null` rather than a throw, so a caller of
|
|
279
|
+
* {@link parseCheckpoint} sees exactly the same "not verifiable" outcome
|
|
280
|
+
* either way.
|
|
277
281
|
*/
|
|
278
282
|
function sealedSizeFromCheckpoint(
|
|
279
283
|
coseSign1: CoseSign1,
|
|
@@ -281,7 +285,7 @@ function sealedSizeFromCheckpoint(
|
|
|
281
285
|
): bigint | null {
|
|
282
286
|
let declared;
|
|
283
287
|
try {
|
|
284
|
-
declared =
|
|
288
|
+
declared = decodeConsistencyProofsFromUnprotected(unprotected);
|
|
285
289
|
} catch {
|
|
286
290
|
return null;
|
|
287
291
|
}
|