@forestrie/forestrie-cli 0.9.1 → 0.11.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 CHANGED
@@ -17,6 +17,7 @@ deploy, sign, register, and verify against a forestrie log:
17
17
  | `decode-receipt` | Decode a COSE receipt — it is just COSE: Sign1 + MMR inclusion |
18
18
  | `verify` | Verify a receipt offline — the same closer for every other subcommand |
19
19
  | `fetch-accumulator` | Cache the on-chain accumulator as a `--known-accumulator` snapshot |
20
+ | `fetch-ks256-attestation` | Cache an ERC-1271 attestation for a KS256 contract root as a `--ks256-attestation` file |
20
21
 
21
22
  **Status:** subcommands not yet implemented declare their real argument
22
23
  surface and parse it, then exit non-zero with a structured `not_implemented`
@@ -334,9 +335,13 @@ signature — no operator trust required.
334
335
 
335
336
  `verify` takes four named trust anchors — pass whichever you hold:
336
337
 
337
- - **`--known-log-key`** — a caller-known log owner key (base64 `x||y`, env
338
- `KNOWN_LOG_KEY`); fully offline, checks the signature under a key you trust
339
- out of band (the SCITT / SSH-known-hosts posture).
338
+ - **`--known-log-key`** — a caller-known log owner key (env `KNOWN_LOG_KEY`):
339
+ base64 `x||y` (a 64-byte ES256 key) or a 20-byte KS256 address (`0x` + 40
340
+ hex, or base64); fully offline, checks the signature under a key you trust
341
+ out of band (the SCITT / SSH-known-hosts posture). A KS256 address asserts,
342
+ and does not prove, the key-to-log binding, and cannot root
343
+ `--checkpoint-chain` (which needs ES256). `--genesis` may accompany it: it
344
+ then supplies only the forest chain id an attestation must match.
340
345
  - **`--genesis`** — a cached `genesis.cbor` (the univocity-instance root
341
346
  registration). Roots a receipt whose signer chains to that root owner; for a
342
347
  child log deeper in the hierarchy, reaching genesis is the grant-chain walk
@@ -362,6 +367,19 @@ and collapsing it into split-view is the specific confusion the trust model
362
367
  warns against. Split-view is the load-bearing property; currency is at most the
363
368
  `--rpc-url` "as of now" delta.
364
369
 
370
+ #### KS256 roots and `--ks256-attestation`
371
+
372
+ A genesis (or known-key) root that is a KS256 address verifies the receipt's
373
+ delegation certificate by ecrecover when the root is an EOA — pure, offline,
374
+ no chain call. A contract root (a Safe) cannot be recovered offline and fails
375
+ `ks256_root_not_recovered`; give `--ks256-attestation <file>` (from
376
+ `fetch-ks256-attestation`) and the certificate verifies as *valid under the
377
+ contract's signers at the attested block* — a narrower guarantee than a
378
+ signature by one key, reported as such. The attestation must bind the root
379
+ address, the certificate digest and signature, and the forest's genesis chain
380
+ id (`--genesis`; under `--known-log-key` without it the result is
381
+ `ks256_attestation_chain_unbound`). `verify` never calls the chain.
382
+
365
383
  ### `fetch-accumulator`
366
384
 
367
385
  ```bash
@@ -375,6 +393,34 @@ Reads `logState(logId)` pinned to a block and writes the
375
393
  `(chainId, univocity, logId, size, blockNumber, blockHash)` — anyone with
376
394
  RPC can re-run the read at that block and confirm or disprove it.
377
395
 
396
+ ### `fetch-ks256-attestation`
397
+
398
+ ```bash
399
+ forestrie fetch-ks256-attestation \
400
+ --receipt receipt.cbor --genesis genesis.cbor --rpc-url "$RPC_URL" \
401
+ --out attestation.cbor # [--root 0x… ] [--block <n>|latest]
402
+
403
+ forestrie verify --genesis genesis.cbor --ks256-attestation attestation.cbor …
404
+ ```
405
+
406
+ Resolves one block (`--block`, default latest; a block whose number differs
407
+ from an explicit `--block` is refused), then reads the contract's code and calls
408
+ its ERC-1271 `isValidSignature(digest, signature)` with the receipt's delegation
409
+ certificate, both pinned by that block's **hash** (EIP-1898,
410
+ `requireCanonical`), so the recorded `blockHash` is the state actually read.
411
+ The call must return exactly one 32-byte word equal to the ERC-1271 magic
412
+ value, `0x1626ba7e` followed by 28 zero bytes: extra data, non-zero padding or a
413
+ short result (including a fallback that echoes the calldata, whose selector is
414
+ that same magic) is refused, as is a revert; other RPC errors are reported as
415
+ RPC failures, not as the contract refusing. It writes canonical CBOR binding
416
+ `(chainId, address, digest, signature hash, blockNumber, blockHash, magic)` —
417
+ anyone with RPC can re-run the call at that block. `--root` overrides the
418
+ genesis root; `--genesis` also supplies the chain the RPC must match. It
419
+ refuses, writing nothing, an EOA root (no code: `verify` recovers it), a chain
420
+ differing from the genesis, a receipt with no delegation certificate or a
421
+ non-KS256 genesis root, and any result other than that magic word.
422
+ Use an archive node for an old `--block`.
423
+
378
424
  ## Use as a library: `decode-receipt`
379
425
 
380
426
  The receipt decoder behind `forestrie decode-receipt` is exported as a