Repository navigation
Releases: codenlighten/scriptmin
Release list
@smartledger/scriptmin 0.1.3
Data and standard templates are kept
A script can be shorter without being the same output. Earlier versions made that mistake on real mainnet scripts, so both protections below are on by default:
- Data that nothing uses is kept byte for byte. A push no operation takes as an operand, and that is not left on the stack, is a data carrier:
<document> OP_DROP <pubkey> OP_CHECKSIG(121 B → 35 B in 0.1.2), signed protocol fields dropped in pairs, a Boost puzzle's content hash. Removing them leaves the script doing the same thing, but the output no longer carries what it was made to carry. Where a region carries data, its one-byte fields and empty pushes are kept too.--drop-unused-data(keepData: false) allows the old behaviour. - Standard output templates come back unchanged: P2PKH, P2PK, P2SH, bare multisig and
OP_RETURNdata outputs. A bare multisig listing the same key twice could reuse it withOP_OVERand save 65 bytes, and stop being a bare multisig, which wallets, indexers and relay policy recognise by its exact bytes.--rewrite-templates(templates: false) optimizes them anyway.
Generated contract code is unaffected: across 72 mainnet script templates the savings are the same as with the protections off, and the Miller loop, the final exponentiation and 19 other module scripts come out byte for byte as before.
--effort high no longer wastes minutes
The superoptimizer's A* search costs more the deeper the stack a window starts from, while its wins do not: on real scripts every replacement it found started from a stack of at most 15 items, and the searches on stacks of 20 or more found nothing while taking most of the time. Those windows now go to the lookup table.
| script | bytes | before | after |
|---|---|---|---|
field-300.hex |
2,607 | 45 s | 8.9 s |
| a 934 B mainnet contract | 694 | 155 s | 51 s |
Output is byte for byte what it was.
Also
- The reason ASM output is refused now names the real cause for data after a top-level
OP_RETURNtoo. - New:
docs/mainnet-survey.mdandexamples/mainnet-survey.js— what mainnet locking scripts are made of, and what this saves. Half of outputs are P2PKH holding under 3% of the bytes; most bytes are data; the saving is concentrated in contracts that check their own transaction (a fifth to a third of compiled contract bytes, under 1% of all locking-script bytes).
Install
npm install @smartledger/scriptmin @smartledger/bsv
@smartledger/scriptmin 0.1.2
Fixes
--no-chronicleresults are tested under the rules before and after Chronicle. Interpreter tests used to run under current consensus flags only, so a change that broke a script only under the older rules could pass them. TheOP_VERIFdead-block bug fixed in 0.1.1 was one.differential()accepts a list of flag sets, anderaFlags({ chronicle })gives them. (#3)- ASM output reads back as the same script, or is refused.
--asm -owrote<tail N bytes>in place of the data afterOP_RETURN, andOP_PUSHDATA1:<hex>for pushes of 76 bytes or more, and neither reads back. Output now uses the ASM that@smartledger/bsvreads, with theOP_RETURNdata included, and is checked by reading it back. When ASM cannot hold the script exactly, the CLI exits with the reason and suggests hex. Those cases are a non-minimal or truncated push kept verbatim, or data pushes alone.exactAsm()is exported. (#3) - Unnamed opcodes (
0xba–0xfc) are written in ASM as0xba, which@smartledger/bsv9.11.1 and later reads back. With an older version such scripts are refused. (#4) - Tested against
@smartledger/bsv9.11.2, which writes empty pushes in text form correctly.OP_RETURNdata such asbuildDataOut('')now round-trips through ASM. (#5)
Install
npm install @smartledger/scriptmin @smartledger/bsv
@smartledger/scriptmin 0.1.1
Fixes
- Data envelopes are kept byte for byte. An
OP_0 OP_IF … OP_ENDIFblock never runs, so the optimizer could rewrite what is inside it and still pass its equivalence checks. That is where inscription envelopes (1Sat Ordinals, BSV-21 and similar) carry their data, and 0.1.0 could change it, for example turning a repeated field intoOP_OVER. Such blocks are now kept verbatim, and code around them is still optimized. Blocks containingOP_VERIF/OP_VERNOTIFare left to ordinary branch handling, because where they end depends on whether Chronicle rules apply. (#1) - No quadratic slowdown on very deep stacks. A constant
ROLL/PICKindex in the tens of thousands made stack scheduling quadratic: a 6-op script took 75 s. The scheduler now abandons schedules far larger than the code they would replace, and the script takes 3.8 s. The Miller loop, final exponentiation and other real module scripts optimize to the same bytes as before. (#2) - Wider fuzz test: every modelled opcode, unusual push encodings, boundary numbers, and computed
PICK/ROLLindices.
Install
npm install @smartledger/scriptmin @smartledger/bsv
@smartledger/scriptmin 0.1.0
A Bitcoin Script minimizer. It takes a working locking script, returns a smaller one that does exactly the same thing, and proves the two are equivalent.
What's in it
scriptmin <script>: minimizes a script and reports where the savings came from. It uses:- a liveness-driven stack scheduler, with an optional beam search over its choices;
- an exhaustive table plus A* superoptimizer for short stack sequences;
- peephole rules and constant folding.
scriptmin --profile: shows where a script's bytes go (stack moves, arithmetic, constants, hashing), how deep its PICKs and ROLLs reach, and its most expensive repeated patterns.scriptmin compile: compiles a prime-field circuit (JSON) to Script with lazy modular reduction.scriptmin relax: lifts existing field-arithmetic Script back to its circuit and re-decides where it reduces.
Correctness
- Symbolic proof: every result is proven equivalent region by region. It fails on exactly the stacks the original fails on, leaves identical main and alt stacks, and evaluates the same set of checks.
- Interpreter tests: results are also run against the original on
@smartledger/bsv's interpreter. relax: its results are checked on the interpreter against the original, on canonical inputs and out-of-range ones.
Measured on real code
On script-high-level-modules, a library of BSV Script modules up to a full BLS12-381 pairing:
- Miller loop: the 333 KB loop that ran on mainnet drops 40%, to 199 KB, and every test case of the library still passes.
- Mainnet redeployment: the library's two-transaction pairing chain was redeployed to mainnet with minimized stage scripts.
Details are in docs/real-world.md.
Install
npm install @smartledger/scriptmin @smartledger/bsvRequires Node 20.19+.