@forestrie/receipt-verify 2.1.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 +130 -48
- package/dist/checkpoint-chain.d.ts.map +1 -1
- package/dist/checkpoint-chain.js +212 -60
- 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 +12 -6
- package/dist/freshen-receipt.d.ts.map +1 -1
- package/dist/freshen-receipt.js +34 -14
- 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 +254 -79
- package/src/decode-checkpoint-consistency-proof.ts +118 -34
- package/src/freshen-receipt.ts +43 -16
- package/src/index.ts +6 -0
package/src/freshen-receipt.ts
CHANGED
|
@@ -58,6 +58,7 @@ import {
|
|
|
58
58
|
parseCheckpoint,
|
|
59
59
|
} from "./build-receipt-offline.js";
|
|
60
60
|
import {
|
|
61
|
+
CheckpointSignedSizeMismatchError,
|
|
61
62
|
computeCheckpointAccumulator,
|
|
62
63
|
type CheckpointConsistencyProof,
|
|
63
64
|
} from "./checkpoint-chain.js";
|
|
@@ -80,9 +81,13 @@ export type FreshenReceiptInput = {
|
|
|
80
81
|
* value `verify` recomputes from the entry (caller derives it). */
|
|
81
82
|
leafValue: Uint8Array;
|
|
82
83
|
/** Consistency-proof chain covering [0 or the trusted base] → the latest
|
|
83
|
-
* sealed size, in ascending contiguous order
|
|
84
|
-
*
|
|
85
|
-
*
|
|
84
|
+
* sealed size, in ascending contiguous order: one entry per checkpoint,
|
|
85
|
+
* each holding the proofs that checkpoint relays (`proofs`, one or more —
|
|
86
|
+
* ADR-0066 D2). Every link's `signedTreeSize2` must equal its
|
|
87
|
+
* `treeSize2` — the size its LAST relayed proof reaches — as
|
|
88
|
+
* `checkpointConsistencyProof` requires of the checkpoint it decoded each
|
|
89
|
+
* link from. The chain's last link must end at the checkpoint's sealed
|
|
90
|
+
* size. */
|
|
86
91
|
consistencyProofs: readonly CheckpointConsistencyProof[];
|
|
87
92
|
/** Trusted base for a suffix chain — the size the caller already trusts
|
|
88
93
|
* and that size's accumulator; omit for a chain from base 0 (size 0, an
|
|
@@ -111,9 +116,11 @@ function bytesEqual(a: Uint8Array, b: Uint8Array): boolean {
|
|
|
111
116
|
}
|
|
112
117
|
|
|
113
118
|
/**
|
|
114
|
-
* Freshen a stale receipt to the latest sealed state. Throws if
|
|
115
|
-
*
|
|
116
|
-
*
|
|
119
|
+
* Freshen a stale receipt to the latest sealed state. Throws if a link's
|
|
120
|
+
* signed `tree-size-2` disagrees with its declared one
|
|
121
|
+
* ({@link CheckpointSignedSizeMismatchError}), if the chain is not a
|
|
122
|
+
* contiguous cover from the trusted base to the checkpoint's sealed size, if
|
|
123
|
+
* a climb node is missing from the supplied proofs, or if the recomputed
|
|
117
124
|
* peak does not match the folded latest accumulator.
|
|
118
125
|
*/
|
|
119
126
|
export async function freshenReceipt(
|
|
@@ -170,6 +177,20 @@ export async function freshenReceipt(
|
|
|
170
177
|
`base accumulator has ${baseAccumulator.length} peaks; trusted base size ${baseSize} has ${basePeaks}`,
|
|
171
178
|
);
|
|
172
179
|
}
|
|
180
|
+
// Every link's SIGNED tree-size-2 must equal its declared one — the same
|
|
181
|
+
// equality `checkpointConsistencyProof` enforces when it decodes a
|
|
182
|
+
// checkpoint (ADR-0066 D1 as amended, D5.5). These links arrive already
|
|
183
|
+
// decoded, so nothing here had re-read the field the type says was pinned
|
|
184
|
+
// to the signature, and a link carrying `signedTreeSize2: 999n` beside
|
|
185
|
+
// `treeSize2: 7n` freshened (review finding I5).
|
|
186
|
+
for (let i = 0; i < links.length; i++) {
|
|
187
|
+
const link = links[i]!;
|
|
188
|
+
if (link.signedTreeSize2 !== link.treeSize2) {
|
|
189
|
+
throw new CheckpointSignedSizeMismatchError(
|
|
190
|
+
`consistency proof ${i}: signed tree-size-2 (-65933) ${link.signedTreeSize2} != declared consistency-proof tree-size-2 ${link.treeSize2}`,
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
173
194
|
// The first link must continue from that size, not from a size it names
|
|
174
195
|
// itself (ADR-0066 D5.4).
|
|
175
196
|
if (firstLink.treeSize1 !== baseSize) {
|
|
@@ -177,7 +198,9 @@ export async function freshenReceipt(
|
|
|
177
198
|
`first consistency proof declares tree-size-1 ${firstLink.treeSize1}; the trusted base size is ${baseSize}`,
|
|
178
199
|
);
|
|
179
200
|
}
|
|
180
|
-
// Contiguity: each link continues where the previous
|
|
201
|
+
// Contiguity BETWEEN checkpoints: each link continues where the previous
|
|
202
|
+
// one sealed. Contiguity WITHIN a link — between the proofs one
|
|
203
|
+
// checkpoint relays — is `computeCheckpointAccumulator`'s, below.
|
|
181
204
|
for (let i = 1; i < links.length; i++) {
|
|
182
205
|
if (links[i]!.treeSize1 !== links[i - 1]!.treeSize2) {
|
|
183
206
|
throw new Error(
|
|
@@ -193,10 +216,11 @@ export async function freshenReceipt(
|
|
|
193
216
|
);
|
|
194
217
|
}
|
|
195
218
|
|
|
196
|
-
// Fold the chain to the latest accumulator (self-check target). Each
|
|
219
|
+
// Fold the chain to the latest accumulator (self-check target). Each link
|
|
197
220
|
// runs against a size the caller trusts, never one read off the link being
|
|
198
221
|
// folded: the trusted base for the first link, and the size the previous
|
|
199
|
-
// link was just folded TO for every link after it.
|
|
222
|
+
// link was just folded TO for every link after it. A link relaying several
|
|
223
|
+
// proofs folds them all, in order, and ends at its last one.
|
|
200
224
|
let accumulator = baseAccumulator;
|
|
201
225
|
let sizeFrom = baseSize;
|
|
202
226
|
for (const p of links) {
|
|
@@ -240,18 +264,21 @@ export async function freshenReceipt(
|
|
|
240
264
|
for (let k = 0; k < oldPath.length; k++) {
|
|
241
265
|
store.set(fullIndices[k]!, oldPath[k]!);
|
|
242
266
|
}
|
|
243
|
-
|
|
244
|
-
|
|
267
|
+
// Every relayed proof contributes, not just one per checkpoint: a link
|
|
268
|
+
// that relays several sealed steps (ADR-0066 D2) carries one set of paths
|
|
269
|
+
// per step, each addressed by that step's own two sizes.
|
|
270
|
+
for (const step of links.flatMap((link) => link.proofs)) {
|
|
271
|
+
// A base-0 step (treeSize1 === 0) has no from-peaks to climb — a 0→N
|
|
245
272
|
// consistency proof carries `paths: []` (the whole accumulator is its
|
|
246
273
|
// right-peaks). Skip it: it contributes no store nodes, and calling
|
|
247
274
|
// `peakMMRIndexes(-1n)` would throw (`posHeight(0)`, FOR-414). A genesis-
|
|
248
|
-
// rooted `.sth` chain always starts with such a
|
|
249
|
-
if (
|
|
250
|
-
const fromPeaks = peakMMRIndexes(
|
|
275
|
+
// rooted `.sth` chain always starts with such a step.
|
|
276
|
+
if (step.treeSize1 === 0n) continue;
|
|
277
|
+
const fromPeaks = peakMMRIndexes(step.treeSize1 - 1n);
|
|
251
278
|
fromPeaks.forEach((peakIndex, j) => {
|
|
252
|
-
const climb =
|
|
279
|
+
const climb = step.paths[j];
|
|
253
280
|
if (climb === undefined) return;
|
|
254
|
-
const climbIndices = inclusionProofPath(
|
|
281
|
+
const climbIndices = inclusionProofPath(step.treeSize2 - 1n, peakIndex);
|
|
255
282
|
climbIndices.forEach((ix, e) => {
|
|
256
283
|
const v = climb[e];
|
|
257
284
|
if (v !== undefined) store.set(ix, v);
|
package/src/index.ts
CHANGED
|
@@ -156,11 +156,17 @@ export {
|
|
|
156
156
|
computeCheckpointAccumulator,
|
|
157
157
|
verifyCheckpointChain,
|
|
158
158
|
CheckpointHighSSignatureError,
|
|
159
|
+
CheckpointProtectedHeaderAlgError,
|
|
159
160
|
CheckpointSignedSizeMismatchError,
|
|
161
|
+
ConsistencyChainNotContiguousError,
|
|
162
|
+
EmptyConsistencyProofsError,
|
|
160
163
|
type CheckpointChainLink,
|
|
161
164
|
type CheckpointChainResult,
|
|
162
165
|
type CheckpointConsistencyProof,
|
|
163
166
|
} from "./checkpoint-chain.js";
|
|
167
|
+
/** One relayed consistency proof; `CheckpointConsistencyProof.proofs` holds
|
|
168
|
+
* the chain of them a checkpoint carries (ADR-0066 D2). */
|
|
169
|
+
export type { DecodedConsistencyProof } from "./decode-checkpoint-consistency-proof.js";
|
|
164
170
|
/**
|
|
165
171
|
* Univocity leaf commitment hash. Was CLI-private (forestrie-cli's own
|
|
166
172
|
* mirror, "hoist to the library when the FOR-297 multi-hop resolver lands");
|