sidestr-core 0.2.1

sidestr user-activated sidechains beside a Bitcoin-family parent: the chain document, the parents table, signed blocks generic over the header family (BIP-325 challenge, no subsidy), the peg-in claim and peg-out burn rules, Knots' unified sighash, the block file and an in-memory validating chain. A port of siding by Melvin Carvalho.
Documentation
# sidestr-core

[sidestr](https://github.com/sidestr/spec) user-activated sidechains beside a
Bitcoin-family parent, in Rust: the chain document, the parents table, signed
blocks in either header family (a BIP 325 challenge, no subsidy), the peg-in
claim and peg-out burn rules, the block file, and an in-memory validating
chain with a producer's mempool.

A sidestr chain runs beside a Bitcoin-family chain with Bitcoin's transaction
rules, blocks that are valid because they are *signed* rather than mined, no
subsidy, and every coin on it a coin locked on the parent. Signers decide the
order of blocks; they do not decide the rules.

```toml
[dependencies]
sidestr-core = "0.2"
# and, for a chain beside a BLAKE2b parent (xbt, txbt4):
sidestr-header = "0.2"
```

The rules, state and chain are generic over the header family
(`sidestr_core::block::HeaderFamily`): `State` / `Chain` are the stock
instantiation (`btc`, `tbtc4`), and `StateOf<Blake2bV2>` / `ChainOf<Blake2bV2>`
with `sidestr_header::Blake2bV2` validate a chain beside Knots' BLAKE2b fork.
The dependency edge runs from `sidestr-header` to this crate, never back.

## Attribution

This crate is a port of **siding**, the reference implementation of sidestr by
Melvin Carvalho — [github.com/sidestr/spec](https://github.com/sidestr/spec),
AGPL-3.0 — ported from commit `2de40bdac4cba01be0864156a553d8287c22e279`
(`siding/lib/{parents,block,chain,overlay,marker,records,address,checkpoint}.mjs`,
`bin/siding.mjs`, and the tests in `siding/test/`). Two parts come from the
engine siding loads, by the same author and under the same licence:

- the block, header and spending checks, and Knots' unified sighash, from
  [bitcoin-desktop/schema]https://github.com/bitcoin-desktop/schema
  (`codec/blocks.js`, `codec/headers.js`, `codec/interpreter.js`
  `sighashUnified`, `schema/validate.jsonld`);
- the block file format and the chain state machine from
  [bitcoin-blake/blaketestnode]https://github.com/bitcoin-blake/blaketestnode
  (`lib/blockfile.mjs`, `lib/node.mjs`).

`SPEC.md` in the sidestr repository is the design; the crate documentation
cites its sections, and every ported function names its original.

## What changed in the port

- Bitcoin's consensus serialisation, hashes, merkle roots, the taproot sighash
  and BIP-340 Schnorr come from [`rust-bitcoin`]https://crates.io/crates/bitcoin
  and its `secp256k1`; bech32 from the [`bech32`]https://crates.io/crates/bech32
  crate. Nothing cryptographic is hand-rolled.
- Script verification fails closed: taproot key-path spends are verified, every
  other script type is refused rather than skipped. The reference lets a witness
  version it cannot verify through.
- The solution's witness decoder refuses truncation, trailing bytes, non-minimal
  sizes and more than 256 items; the reference reads what it can.
- The mempool judges a spend's sighash type by the family's block rule (unified
  only beside a BLAKE2b parent); the reference mempool accepts unified on every
  family while its block rule does not.
- Claim and burn records commit only when a block is applied, not while it is
  being judged.
- Blocks are a pure function of their inputs and the key: BIP 340 auxiliary
  randomness is zero for every block, as siding sets it for the genesis.
- A document naming the `assets`, `pool` or `evm` rules is refused, because
  this version does not carry them.
- Level 2 carries the pure parts of `federation.mjs` and not the round: the
  script path is verified for exactly the `multi_a(k, …)` leaf, an unknown
  leaf version is refused rather than skipped, and `template_id` names what
  signers authorise separately from the sealed hash (ADR-2101 review).
- No I/O in the rules: the filesystem and the clock are behind the `std`
  feature (`blockfile`, `chain`).
- The genesis is judged, not trusted: `from_genesis` runs every rule that
  applies at height 0 (the family's header rules, the signature against the
  challenge, the pegs as the one subsidy, `sidestr:rule-genesis-document`)
  before the hash is held to the document's `genesisHash`; siding applies
  block 0 on the hash alone. There is no trusted import.
- A stock header with version bit 31 set is refused at decode and, on the
  typed path, by `btc:rule-header-version` — the rule the kernel names, which
  reads a stock version as `i32le`.
- A mirror's `blocks.dat` record framing (`[u32 height][u32 size]`) is held to
  `blocks.json` and to the file's length on every read (`Error::BlockFile`).
- Markers are written with a canonical push (`OP_PUSHDATA1` above 75 bytes)
  and read exactly as siding's `opReturnData` reads them — a bare length byte
  or an `OP_PUSHDATA1` prefix, minimal or not — because that is the burn
  rule's grammar and a burn a reference wallet wrote must be paid. Their
  text is decoded as siding's `TextDecoder` decodes it, one leading UTF-8
  byte-order mark dropped, at exactly the readers that text-decode there
  (burns, claims, the peg-in remainder's hex-form decision, records) and
  not at the two compared as bytes (the parent peg-out record, the
  checkpoint) — so a BOM-led burn is recorded, or refused, alike.
  `tests/audit_regressions_records.rs` holds every marker case and every
  block of an audit corpus to identical derived lists in both engines.

## Status — 0.2.1

Level 1 (one signer), both header families, end to end: genesis from the
document, block production, validation, the mempool policy, the block file.
Proven against the reference:

- the genesis of a throwaway chain rebuilt from its document and key is
  byte-identical to the one siding wrote (`tests/oracle.rs`);
- the estate's sealed `sidestr:dreamlab` genesis replays to its documented hash;
- blocks produced here are accepted by siding and blocks siding produces are
  accepted here (`tests/interop.rs`, needs the reference checkouts);
- with `sidestr-header`'s `Blake2bV2`, Melvin Carvalho's live
  `sidestr:txbt4-siding` chain replays from its genesis to its tip with every
  rule on, spends signed with Knots' unified sighash included
  (`sidestr-header/tests/core_family.rs`);
- a 2-of-3 federation's challenge, its genesis and two blocks sealed by three
  different pairs are byte-identical to siding's (`tests/federation.rs`,
  `fixtures/fedtest`), every subset and both parities are property-tested
  (`tests/federation_prop.rs`), and Bitcoin Core's interpreter agrees with the
  `multi_a` verifier on 161 differential cases
  (`cargo test --features consensus-oracle`);
- the five counter-examples of the independent 0.2 audit (an unsigned genesis
  accepted on its hash, a stock block with version bit 31 replayed, a corrupt
  record prefix replayed, a `u32` overflow in `claimable`, and the typed v2
  genesis bypassing the family rules) are fixed and pinned as regressions
  (`tests/audit_regressions.rs`, both crates).

0.2 made the rules, state and chain generic over `HeaderFamily` (with an
associated header and block type), added Knots' unified sighash and the
family's own rules, tightened the witness decoder, and added level 2's pure
parts (`federation`: NUMS key, leaf, partial signatures, witness assembly,
sealing, the `multi_a` verifier, `template_id`, `Chain::open_sealed`).
`State`, `Chain` and every 0.1 name keep their meaning as the stock
instantiation. The parent view (`parent`) is behind two traits — the chain
read-only, the peg wallet — with every decision pure (peg-ins found in
decoded blocks, what to claim and lock, the burn payment and the checkpoint
as `send` outputs, reconciliation) and Bitcoin Core's JSON-RPC as the one
implementation behind the `rpc` feature; `tests/parent_live.rs` (ignored,
`SIDESTR_PARENT_RPC`) finds the estate's peg-wallet funding on a testnet4
node without sending anything.

Not yet: the level-2 consensus round (a separate crate, per the ADR-2101
review), the assets and pool rules, tips and transactions over Nostr
(`sidestr-nostr`), a full script interpreter.

## Running the checks

```sh
cargo test                                   # unit, ported siding suites, fixtures, doctests
cargo test --features consensus-oracle       # plus Bitcoin Core's interpreter as a differential oracle (needs a C++ toolchain)
SIDESTR_PARENT_RPC=http://<node>:48332/ cargo test --features rpc --test parent_live -- --ignored   # a testnet4 node, read-only
cargo run --example siding -- replay --chain fixtures/dreamlab/chain.json --dir <dir with blocks.dat>
cargo run --example siding -- genesis --chain chain.json --dir state --key-file signer.key
# the JS interop test, with the reference checkouts:
SIDESTR_SIDING=<sidestr/spec>/siding SCHEMA=<bitcoin-desktop/schema> BLAKETESTNODE=<bitcoin-blake/blaketestnode> \
  cargo test --test interop
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps
cargo clippy --all-targets -- -D warnings && cargo fmt --check
```

`fixtures/trial` is a throwaway chain with its disposable signer key, carried
for the byte-for-byte test. `fixtures/dreamlab` is a sealed genesis without its
key. Keys are files, never arguments; nothing here prints one.

## Licence

AGPL-3.0-only, as a derivative work of siding. See [LICENSE](LICENSE). This
crate is **not dual-licensed**: a crate that links it is AGPL-3.0 in effect and
should say so.