Skip to content

Releases: privkeyio/shrike

Shrike 2.5.5-blake2b.11 - every signer can sign

Choose a tag to compare

@kwsantiago kwsantiago released this 01 Sep 13:09
v2.5.5-blake2b.11
1446067

Shrike signing with the unified opt-in signature hash as Bitcoin Knots v29.4.1.knots20260508rc4 defines it, on upstream Sparrow 2.5.5.

Every signer can sign

A device that cannot opt in is no longer turned away. It is handed the hash type it can produce, and its signature combines with the opted-in ones. The previous release said this was out of reach because a PSBT carries one hash type per input and so cannot ask one cosigner for the opt-in and another for the legacy type. That is a limit of the container rather than of consensus: each device gets its own PSBT declaring what it can sign, and the partial signatures combine.

One marked signer is now enough, where the previous release wanted enough of them to meet the wallet's threshold. Replay protection belongs to the transaction rather than to each signature in it, and a transaction carrying a single opted-in signature is invalid under the pre-fork rules whatever the rest carry.

So a 2-of-3 with one signer on firmware that implements the opt-in is protected, and all three can still sign. Mark two and no quorum exists without a marked signer, so every transaction the wallet can make opts in. Mark one and the other two could meet the threshold between them, so the protection depends on the marked signer taking part. The wallet says which of those two it is rather than claiming the guarantee in advance.

What the send screen now separates

Replay protection and the commitment to spent amounts are two properties with two thresholds, and the previous release reported only the first. The transaction is unreplayable on one opted-in signature; committing to every amount it spends, which is what closes CVE-2020-14199, belongs to each signature and takes that signature opting in. Over a mixed set the send screen now says how many opted in, and that the others were shown the amounts by this computer rather than committing to them.

It also says when one of those signatures can be lifted out. A legacy SIGHASH_ALL signature commits to every input, so it is useless in any other transaction. A legacy ANYONECANPAY one commits only to its own input and to the outputs, so that input alone can be lifted into another transaction and spent on the chain that kept SHA256d, paying the same outputs. The transaction is still protected; that one input is not, and reporting only the first would have hidden it. Choosing Anyone Can Pay is what reaches this, and the wallet never selects it on its own account.

Verified

The replay protection of a mixed transaction is demonstrated rather than argued. Both chains are built from one shared history so the same coins exist on each, then:

1. post-fork node accepts and mines the mixed transaction (one input 0x21, one 0x81)
2. node that never scheduled the fork refuses it:
     mempool-script-verify-flag-failed (Signature opts in to the hardfork, which is not active here)
3. the same spend signed entirely the old way is accepted there
4. the ANYONECANPAY signature, copied out byte for byte, is mined on the pre-fork chain

Step 3 is what makes step 2 mean something: without it a refusal could be about a fee or a missing input rather than the opt-in. Step 4 is the caveat above, made real. Two mutations confirm it is not vacuous: signing that leg SIGHASH_ALL instead, or altering one output, both make the lift fail, so the lift is real but bounded to the same output set.

A 2-of-2 with one patched signer is proven too, which is the case most people are asking about. Both cosigners sign the same input, one producing 0x21 and the other 0x01 in a single witness. Consensus allows this because each signature carries its own hash type byte, so CHECKMULTISIG verifies each against the message that signature names. A post-fork node mines it, a node that never scheduled the fork refuses it, and the same 2-of-2 signed entirely the old way is accepted there.

Neither device has to be lied to about its firmware. Leave the unpatched one unmarked and it is handed the type it can produce. Marking a device whose firmware does not implement the opt-in is the one way to reach a device that will not sign, which is why the dialog says to leave it unmarked if you are unsure.

Each behavior above was checked by reverting the code that implements it and confirming the test covering it fails, then restoring.

343 wallet and 611 drongo unit tests, and seven node-driven end to end tests against a Knots regtest node.

Reproducible: this commit built locally with Eclipse Temurin 25.0.2 produces an application tree whose 171 paths, every file and symlink, hash identically to the tree CI published in shrike-2.5.5-x86_64.tar.gz. That archive is the one listed in SHA256SUMS as ec5a9cea885a14df14f44dca201884c34844f7dae21c98eea14cf1f664900b38, so the check is anchored to the file published here rather than to a build step. Only the Linux x86_64 build was reproduced; the archive contents are compared rather than the installers.

Also in this release

The Replay protection dialog is legible. Its height follows the number of keystores rather than being fixed, the content lines up with the header, and it reports which of the three states the wallet is in as devices are marked, instead of only whether the threshold was met.

A device that cannot produce the declared hash type is told why before it refuses, rather than surfacing raw firmware text.

The send screen names the signers that can opt in, rather than saying "the marked signers" and leaving you to work out which.

Downloads

Platform File
Windows Shrike-2.5.5.msi, or .zip for a portable copy
macOS Shrike-2.5.5-arm64-unsigned.dmg, or -x86_64-unsigned.dmg for Intel
Linux x86_64 shrike_2.5.5-1_amd64.deb, or -x86_64.tar.gz
Linux aarch64 shrike_2.5.5-1_arm64.deb, or -aarch64.tar.gz
Headless the shrikeserver-* files

Verify before running:

gpg --import privkeyio-signing-key.asc
gpg --verify SHA256SUMS.asc SHA256SUMS
sha256sum --ignore-missing -c SHA256SUMS

Signed by Kyle Santiago kyle@privkey.io, key A47D99B6DB0D715D40C59A2023AE8A8EA7E24E38.

The macOS builds are not code signed or notarized, so macOS reports the app as damaged or from an unidentified developer on first launch. That means it is unsigned, not that the download is bad:

xattr -dr com.apple.quarantine /Applications/Shrike.app

Verify SHA256SUMS first, because clearing quarantine removes the check that would otherwise stop a tampered download. The Windows installer is not Authenticode signed either, and SmartScreen will warn accordingly.

Shrike 2.5.5-blake2b.10 - multisig opts in on a quorum

Choose a tag to compare

@kwsantiago kwsantiago released this 01 Sep 00:35
v2.5.5-blake2b.10
2205e0f

Shrike signing with the unified opt-in signature hash as Bitcoin Knots v29.4.1.knots20260508rc4 defines it, on upstream Sparrow 2.5.5.

Multisig

A multisig opts in once enough signers are marked to meet its threshold, rather than requiring every keystore. A 2-of-3 holding one signer whose firmware cannot opt in now works with the other two, where before it declined on every transaction and signed the legacy way.

The previous release needed every keystore marked, so the only way to get protection from a lagging cosigner's wallet was to mark it anyway, which told the wallet something false about it. That is no longer necessary.

Where some keystore is left out, the send screen says the transaction has to be signed by the marked signers. The others cannot produce the hash type it asks for, and a device that is marked but does not implement the opt-in signs nothing rather than falling back.

The protocol is more permissive still. SIGHASH_UNIFIED is opted into per signature, so one opted-in signature in a transaction is enough to make it unreplayable. Matching that would mean mixed hash types within an input, which a PSBT cannot express: it carries one hash type per input, and omitting it makes capable signers fall back to legacy.

Verified

Replay protection is now demonstrated rather than argued. A 2-of-2 spend this wallet signed with the opt-in, submitted to a node running the pre-fork rules:

allowed: False
reject-reason: mempool-script-verify-flag-failed (Signature opts in to the hardfork, which is not active here)

The same spend, same input and output, signed the legacy way, is accepted by the same node. So the refusal is caused by the opt-in and not by anything else about the transaction.

Reproducible: this commit built locally with Eclipse Temurin 25.0.2 produces an application tree in which all 171 paths hash identically to CI's, covering the .tar.gz and .zip contents rather than the installers.

Each behaviour above was checked by reverting the code that implements it and confirming the test covering it fails, then restoring.

335 wallet and 610 drongo unit tests, including a 2-of-3 that signs and finalises on two signatures with every signature carrying the opt-in.

Also fixed

A threshold that cannot be read no longer decides anything. The policy may be absent on a wallet still being built and throws on one it cannot parse, and this runs on the send path. Both cases now require every keystore rather than throwing or opting in on fewer signers than the wallet might need.

Downloads

Platform File
Windows Shrike-2.5.5.msi, or .zip for a portable copy
macOS Shrike-2.5.5-arm64-unsigned.dmg, or -x86_64-unsigned.dmg for Intel
Linux x86_64 shrike_2.5.5-1_amd64.deb, or -x86_64.tar.gz
Linux aarch64 shrike_2.5.5-1_arm64.deb, or -aarch64.tar.gz
Headless the shrikeserver-* files

Verify before running:

gpg --import privkeyio-signing-key.asc
gpg --verify SHA256SUMS.asc SHA256SUMS
sha256sum --ignore-missing -c SHA256SUMS

Signed by Kyle Santiago kyle@privkey.io, key A47D99B6DB0D715D40C59A2023AE8A8EA7E24E38.

The macOS builds are not code signed or notarized, so macOS reports the app as damaged or from an unidentified developer on first launch. That means it is unsigned, not that the download is bad:

xattr -dr com.apple.quarantine /Applications/Shrike.app

Verify SHA256SUMS first, because clearing quarantine removes the check that would otherwise stop a tampered download. The Windows installer is not Authenticode signed either, and SmartScreen will warn accordingly.

Shrike 2.5.5-blake2b.9 - replay protection status and taproot fee estimates

Choose a tag to compare

@kwsantiago kwsantiago released this 31 Aug 17:59
v2.5.5-blake2b.9
8d078e6

Shrike signing with the unified opt-in signature hash as Bitcoin Knots v29.4.1.knots20260508rc4 defines it, on upstream Sparrow 2.5.5. First build published as a release rather than a prerelease.

Fixed

A watch only wallet is told something it can act on. It reported that a signer was not marked as supporting the opt-in, and sent the reader to a Replay protection control the keystore tab only draws for hardware sources. A watch only keystore has no device to mark, so it now says that and points at re-importing with the signing device as an airgapped hardware wallet.

Signatures are attributed to the keystores that made them. Signed keystores were determined against an assumed SIGHASH_ALL, so a finalized transaction signed with the unified hash type showed no signing keystore. From upstream Sparrow.

An opt-in with nothing to corroborate it says so. An Electrum server reports no activation height, so the cross check against the connected node cannot run and the opt-in rests on the height compiled into this build alone. That read identically to a confirmed one. It is now distinguishable in the send screen tooltip and logged once per connection. Signing is unchanged: an Electrum connection still opts in, because declining when a server cannot answer would forgo the protection on every Electrum setup.

Taproot fee estimates cover the signature actually made. There is no opted-in form of SIGHASH_DEFAULT, so an opted-in taproot signature is 65 bytes rather than 64 and the estimate was one weight unit an input short. Unrelated to a node refusing a transaction for insufficient relay fee: that is the node's mempoolminfee, which rises above minrelaytxfee as the mempool fills.

Bitcoin Knots is named where Bitcoin Core was, in the Taproot backend message and the descriptor export text.

Known limitation: multisig

The opt-in is all or nothing across a wallet's keystores. A 2-of-3 holding one signer that cannot opt in declines on every transaction, even where the other two would have been enough.

The protocol is more permissive. SIGHASH_UNIFIED is opted into per signature, so one opted-in signature is enough to make a transaction unreplayable: it does not verify under the pre-fork rules, which drops the input below its threshold.

Until the wallet matches that, mark every keystore and sign with the capable ones. The wallet then holds something false about the lagging signer, so a later transaction that needs it fails to sign rather than falling back. Upgrading its firmware is the better fix.

Verified

Reproducible: this commit built locally with Eclipse Temurin 25.0.2 produces an application tree in which all 171 paths hash identically to CI's, covering the .tar.gz and .zip contents rather than the installers.

Each fix above was checked by reverting it and confirming the test covering it fails, then restoring.

328 wallet and 610 drongo unit tests. Activation heights and the target shift are unchanged and still match the rc4 tag.

Downloads

Platform File
Windows Shrike-2.5.5.msi, or .zip for a portable copy
macOS Shrike-2.5.5-arm64-unsigned.dmg, or -x86_64-unsigned.dmg for Intel
Linux x86_64 shrike_2.5.5-1_amd64.deb, or -x86_64.tar.gz
Linux aarch64 shrike_2.5.5-1_arm64.deb, or -aarch64.tar.gz
Headless the shrikeserver-* files

Verify before running:

gpg --import privkeyio-signing-key.asc
gpg --verify SHA256SUMS.asc SHA256SUMS
sha256sum --ignore-missing -c SHA256SUMS

Signed by Kyle Santiago kyle@privkey.io, key A47D99B6DB0D715D40C59A2023AE8A8EA7E24E38.

The macOS builds are not code signed or notarized, so macOS will report the app as damaged or from an unidentified developer on first launch. That means it is unsigned, not that the download is bad:

xattr -dr com.apple.quarantine /Applications/Shrike.app

Verify SHA256SUMS first, because clearing quarantine removes the check that would otherwise stop a tampered download. The Windows installer is not Authenticode signed either, and SmartScreen will warn accordingly.

Shrike 2.5.5-blake2b.7 - connecting to a node behind a TLS proxy

Choose a tag to compare

@kwsantiago kwsantiago released this 31 Aug 01:24
v2.5.5-blake2b.7
e6bbb25

Shrike signing with the unified opt-in signature hash as Bitcoin Knots v29.4.1.knots20260508rc4 defines it, on upstream Sparrow 2.5.5.

Fixes connecting to a node behind a TLS terminating proxy, which covers most self hosted setups and failed with an unreadable error.

Fixed

An entered https scheme is kept. It was decided by the port, so anything but 443 became http, and a proxy answered a redirect the wallet could not follow. Connection failed whatever the credentials were.

A reply that is not JSON-RPC says so, naming the host, scheme and HTTP status, instead of Cannot invoke ErrorMessage.toString() because <parameter1> is null. A refused connection points at rpcallowip.

Both from upstream Sparrow 2.5.5.

The replay protection status refreshes when what decides it changes. Upgrading a node mid session left the send screen reporting a schedule disagreement that had already cleared, while the transaction it built was correctly opted in.

Offline, the wallet says the chain was not seen rather than that it did not activate. There is no tip to read, and those are different claims.

Verified

Reproducible: this commit built locally with Eclipse Temurin 25.0.2+10 produces an application tree byte-identical to CI's, covering the .tar.gz and .zip contents rather than the installers.

The request that produced the null pointer now returns did not return a JSON-RPC response to the http request (HTTP 307), against a live node behind a proxy.

Heights and the target shift are unchanged from 2.5.4-blake2b.6 and still match the rc4 tag. The signature hash message is unchanged from rc3, and the vectors in drongo and embit match it.

322 wallet and 601 drongo unit tests.

Downloads

Platform File
Windows Shrike-2.5.5.msi, or .zip for a portable copy
macOS Shrike-2.5.5-arm64-unsigned.dmg, or -x86_64-unsigned.dmg for Intel
Linux x86_64 shrike_2.5.5-1_amd64.deb, or -x86_64.tar.gz
Linux aarch64 shrike_2.5.5-1_arm64.deb, or -aarch64.tar.gz
Headless the shrikeserver-* files

The macOS builds are not code signed or notarized, so macOS will report the app as damaged or from an unidentified developer on first launch. That means it is unsigned, not that the download is bad:

xattr -dr com.apple.quarantine /Applications/Shrike.app

Verify SHA256SUMS before doing that. Clearing quarantine removes the check that would stop a tampered download.

The Windows installer is not Authenticode signed either, as upstream Sparrow's is not.

Installs to /opt/shrike, config in ~/.shrike, alongside an existing Sparrow. Reports its version as 2.5.5-blake2b.7.

gpg --import privkeyio-signing-key.asc
gpg --verify SHA256SUMS.asc SHA256SUMS
sha256sum --ignore-missing -c SHA256SUMS

Signed by Kyle Santiago kyle@privkey.io, key A47D99B6DB0D715D40C59A2023AE8A8EA7E24E38. All files come from one workflow run and one manifest.

Mainnet

Activation is at 961640, and the wallet opts in once the chain has reached it and the connected node agrees. A node reporting the rc3 schedule or none is a disagreement, and the wallet signs the legacy way instead. Upgrade the node first.

A signature that does not opt in is valid under the pre-fork rules as well as the new ones, so it can be replayed against nodes that have not adopted the fork.

No warranty

This is an unofficial, unaudited build provided as is, with no warranty and no liability, under the same Apache 2.0 terms as the LICENSE it inherits. It is not a Sparrow release and is neither affiliated with nor supported by Sparrow Wallet. Running it is entirely at your own risk, and you alone bear any loss of funds.

This is a fork built to exercise a consensus change. Do not point it at a wallet holding funds you cannot afford to lose.

Built from privkeyio/sparrow@e6bbb252 with privkeyio/drongo@634fdb67, on upstream Sparrow 2.5.5.

Shrike 2.5.4-blake2b.6 - the rc4 schedule and mainnet activation

Choose a tag to compare

@kwsantiago kwsantiago released this 30 Aug 06:14
v2.5.4-blake2b.6
cbcc0e9

Superseded by v2.5.5-blake2b.7. This build cannot connect to a node behind a TLS terminating proxy, which covers most self hosted setups: an entered https scheme is overwritten based on the port, and the resulting failure reports Cannot invoke ErrorMessage.toString() because <parameter1> is null rather than the cause. Its replay protection status can also go stale after a node upgrade. Kept here so the files already downloaded can still be verified against its signed manifest.

Shrike signing with the unified opt-in signature hash as Bitcoin Knots v29.4.1.knots20260508rc4 defines it, on upstream Sparrow 2.5.4.

Builds published before this one carry the rc3 schedule and must be replaced. testnet4 activation moved from 150027 to 150308, so an earlier build and an rc4 node disagree about the height and the wallet declines to opt in on every connection. The chain above the old height was replaced along with it.

The schedule

  • testnet4 activates at 150308, moved from 150027.
  • Mainnet activates at 961640. No previous build carried a mainnet height, so none of them opted in there. This one does, once the chain reaches it and the connected node agrees.

Upgrade the node before the wallet. While a node still reports the rc3 height the cross-check reads a disagreement and signs the legacy way, which is correct but looks like a fault.

Header verification across the fork

The one-off difficulty shift is applied. At the activation height the required target moves left by Blake2bTargetShift, which mainnet pins at 22, capped at the proof of work limit. Without it the header at that block is refused and the sync stops there, leaving every height above it unprovable, which shows as confirmed transactions with no confirmations.

A pinned header above the activation height has been removed. The checkpoints are inherited from upstream, which follows the chain that kept the old proof of work, so above the fork its hashes are not the ones this wallet verifies against. Mainnet pinned 961631 and 963647; the second is 2007 blocks past activation and carries an ordinary pre-fork target where the shift puts the forked chain three exponents easier. Anchoring there would have linked every mainnet height to a block a Knots node does not have. The last pin is now nine blocks below activation, on history that predates the fork, so the store syncs forward across it.

Hardware signers can opt in

A device is no longer refused outright. Mark it under Replay protection in the keystore tab, or from the send screen where the wallet says it is not replay protected. Off by default: nothing a device sends says which firmware it runs, and one asked for a hash type it does not implement adds no signature at all and reports a failure of its own, which an airgapped device gives the wallet no way to notice.

Measured against stock embit, a PSBT this build produces for a marked device is signed with hash type 0x21 by firmware that implements the opt-in, and skipped entirely by firmware that does not.

Also

  • The server settings and connection errors name Bitcoin Knots, which is the only node this build can use: it reads the schedule from getdeploymentinfo, which Bitcoin Core does not report.
  • The udev rules dialog names the directory this build installs to. It named /opt/sparrowwallet, which no build here creates, so the install failed and USB devices did not connect.
  • New application artwork throughout, and the About dialog describes this wallet rather than Sparrow.

Verified

Reproducible. Building this commit locally with Eclipse Temurin 25.0.2+10 produces an application tree byte-identical to the one CI published. As upstream notes, this covers the .tar.gz and .zip contents, not the installers.

Against the rc4 tag. The mainnet height, the testnet4 height and the shift are read from v29.4.1.knots20260508rc4 rather than a branch. The signature hash message is unchanged from rc3: the vectors and the specification are byte-identical between the two tags, and the copies in drongo and embit match them.

320 wallet and 600 drongo unit tests.

Downloads

Platform File
Windows Shrike-2.5.4.msi, or .zip for a portable copy
macOS Shrike-2.5.4-arm64-unsigned.dmg, or -x86_64-unsigned.dmg for Intel
Linux x86_64 shrike_2.5.4-1_amd64.deb, or -x86_64.tar.gz
Linux aarch64 shrike_2.5.4-1_arm64.deb, or -aarch64.tar.gz
Headless the shrikeserver-* files

The macOS builds are not code signed or notarized. Notarization needs a paid Apple Developer account this project does not have. macOS will refuse to open the app on first launch, reporting it as damaged or from an unidentified developer; that means it is unsigned, not that the download is bad. To run it:

xattr -dr com.apple.quarantine /Applications/Shrike.app

Verify SHA256SUMS before doing that. Clearing quarantine removes the check that would otherwise stop a tampered download, so the signature is the only assurance left.

The Windows installer is not Authenticode signed either, and SmartScreen will warn. Upstream Sparrow does not sign its installer either.

Installs to /opt/shrike with its config in ~/.shrike, alongside an existing Sparrow rather than over it. The app reports its version as 2.5.4-blake2b.6.

gpg --import privkeyio-signing-key.asc
gpg --verify SHA256SUMS.asc SHA256SUMS
sha256sum --ignore-missing -c SHA256SUMS

Signed by Kyle Santiago kyle@privkey.io, key A47D99B6DB0D715D40C59A2023AE8A8EA7E24E38. All files come from one packaging workflow run and one manifest.

Still to check yourself

A signature that does not opt in is valid under the pre-fork rules as well as the new ones, so it can be replayed against nodes that have not adopted the fork. The wallet reports which it did, per transaction, and signs the legacy way wherever the chain, the node or a keystore does not allow the opt-in.

No warranty

This is an unofficial, unaudited build provided as is, with no warranty and no liability, under the same Apache 2.0 terms as the LICENSE it inherits. It is not a Sparrow release and is neither affiliated with nor supported by Sparrow Wallet. Running it is entirely at your own risk, and you alone bear any loss of funds.

This is a fork built to exercise a consensus change. Do not point it at a wallet holding funds you cannot afford to lose.

Built from privkeyio/sparrow@cbcc0e9a with privkeyio/drongo@96454e22, on upstream Sparrow 2.5.4.

Shrike 2.5.4-blake2b.5 - block headers past the BLAKE2b fork

Choose a tag to compare

@kwsantiago kwsantiago released this 29 Aug 16:20
v2.5.4-blake2b.5
fe6dfbf

Superseded by v2.5.4-blake2b.6. This build carries the rc3 schedule and cannot opt in against an rc4 node: testnet4 activation moved from 150027 to 150308, so this build and the node disagree about the height and the wallet signs the legacy way on every connection. It also carries no mainnet activation height, and pins a mainnet header from above the fork. Kept here so the files already downloaded can still be verified against its signed manifest.

Shrike signing with the unified opt-in signature hash as Bitcoin Knots v29.4.1.knots20260508rc3 defines it, on upstream Sparrow 2.5.4.

Builds published before this one cannot verify a confirmation above height 149183 on testnet4 and must be replaced. A transaction confirmed above the last compiled-in checkpoint is reported with no confirmations and raises a verification refused dialog naming the connected server, which is not at fault.

Changes since .4

Block headers are read at the length each one carries. A header is 164 bytes from the fork on, not 80. The response check rejected any range spanning activation outright, the chunk split read every header after the first from the middle of its predecessor, and the header store wrote 164 bytes into an 80 byte record. Since the forward sync asks for a full difficulty period at a time, a single chunk spanning the crossing left the store empty and every height above the last pin unprovable.

A v2 block is identified by the BLAKE2b hash the chain links on. The fork replaces the block identifier along with the proof of work, so a v2 header's SHA256d is not a block id at all. Computed the old way, no header past activation links to its parent.

An existing header store is re-verified from the pinned checkpoint on load and truncates at the first record that no longer links, so it repairs itself on first run at the cost of a re-download. Wallet files are not touched.

Verified

Reproducible. Building this commit locally with Eclipse Temurin 25.0.2+10 produces an application tree byte-identical to the one CI published: diff -r reports no differences. As upstream notes, this covers the .tar.gz and .zip contents, not the installers.

Against a live testnet4 server. The 1191 header response that was being refused now splits into its 843 v1 and 348 v2 headers, links from the pinned checkpoint at 149183 through to the tip, and reconstructs the merkle root of the block whose proof was refused. The first v2 header lands at height 150027, the activation height this build ships.

Against a node built from rc3. All 121 headers of a regtest chain crossing activation hash to the identifier getblockhash reports, where 11 of them did not before. On the 105 archived testnet4 v2 headers, every consecutive pair links.

Carried forward from .4, unchanged by this release: Knots' own feature_unified_sighash; 166 cross-implementation vectors across all four script types; an opted-in send accepted and mined; a pre-activation input spent after activation; an early opt-in refused where the fork is unscheduled; CVE-2020-14199 blocked under the opt-in and reproduced without it. A node at /Knots:20260508rc3/ reports blake2b {height: 150027, active: true}, matching the height this build ships.

309 wallet and 596 drongo unit tests.

Downloads

Platform File
Windows Shrike-2.5.4.msi, or .zip for a portable copy
macOS Shrike-2.5.4-arm64-unsigned.dmg, or -x86_64-unsigned.dmg for Intel
Linux x86_64 shrike_2.5.4-1_amd64.deb, or -x86_64.tar.gz
Linux aarch64 shrike_2.5.4-1_arm64.deb, or -aarch64.tar.gz
Headless the shrikeserver-* files

The macOS builds are not code signed or notarized. Notarization needs a paid Apple Developer account this project does not have. macOS will refuse to open the app on first launch, reporting it as damaged or from an unidentified developer; that means it is unsigned, not that the download is bad. To run it:

xattr -dr com.apple.quarantine /Applications/Shrike.app

Verify SHA256SUMS before doing that. Clearing quarantine removes the check that would otherwise stop a tampered download, so the signature is the only assurance left.

The Windows installer is not Authenticode signed either, and SmartScreen will warn. Upstream Sparrow does not sign its installer either.

Installs to /opt/shrike with its config in ~/.shrike, alongside an existing Sparrow rather than over it. The app reports its version as 2.5.4-blake2b.5.

gpg --import privkeyio-signing-key.asc
gpg --verify SHA256SUMS.asc SHA256SUMS
sha256sum --ignore-missing -c SHA256SUMS

Signed by Kyle Santiago kyle@privkey.io, key A47D99B6DB0D715D40C59A2023AE8A8EA7E24E38. All files come from one packaging workflow run and one manifest.

Do not use on mainnet

No build carries a mainnet activation height, so past activation the wallet declines to opt in and signs the legacy way, as it does anywhere if even one keystore is hardware-held. A signature that does not opt in is valid under the pre-fork rules as well as the new ones, so it can be replayed against nodes that have not adopted the fork. Opting in is what prevents that. The wallet says so in its status; it does not stop you.

Built from privkeyio/sparrow@fe6dfbff with privkeyio/drongo@69ecf14, on upstream Sparrow 2.5.4.

No warranty

This is an unofficial, unaudited build provided as is, with no warranty and no liability, under the same Apache 2.0 terms as the LICENSE it inherits. It is not a Sparrow release and is neither affiliated with nor supported by Sparrow Wallet. Running it is entirely at your own risk, and you alone bear any loss of funds.

Shrike 2.5.4-blake2b.4 - unified opt-in signature hash for Knots rc3

Choose a tag to compare

@kwsantiago kwsantiago released this 28 Aug 16:56
v2.5.4-blake2b.4
6e9acc9

Superseded by v2.5.4-blake2b.5. This build cannot verify a confirmation above height 149183 on testnet4: it reads every block header as 80 bytes, where a header is 164 from the fork on, and identifies a v2 block by its SHA256d rather than the BLAKE2b hash the chain links on. A transaction confirmed above that height shows no confirmations and raises a verification refused dialog naming the connected server, which is not at fault. Kept here so the files already downloaded can still be verified against its signed manifest.

Shrike signing with the unified opt-in signature hash as Bitcoin Knots v29.4.1.knots20260508rc3 defines it, on upstream Sparrow 2.5.4.

Builds published before rc3 do not work and must be replaced. The signature message changed, so an older build's opted-in spends are rejected with mempool-script-verify-flag-failed. Every opted-in spend, not just some.

Verified

Reproducible: building this commit locally with Eclipse Temurin 25.0.2+10 produces an application tree byte-identical to the one CI published. As upstream notes, this covers the .tar.gz and .zip contents, not the installers.

On live testnet4: a node at /Knots:20260508rc3/ reports blake2b {height: 150027, active: true}, matching the height this build ships, and a mined transaction carries hash type 0x21.

Against a node built from rc3 on regtest: Knots' own feature_unified_sighash; 166 cross-implementation vectors across all four script types; an opted-in send accepted and mined; a pre-activation input spent after activation; an early opt-in refused where the fork is unscheduled; CVE-2020-14199 blocked under the opt-in and reproduced without it. The published x86_64 deb itself was run against rc3, not just the source tree. 306 wallet and 595 drongo unit tests.

Downloads

Platform File
Windows Shrike-2.5.4.msi, or .zip for a portable copy
macOS Shrike-2.5.4-arm64-unsigned.dmg, or -x86_64-unsigned.dmg for Intel
Linux x86_64 shrike_2.5.4-1_amd64.deb, or -x86_64.tar.gz
Linux aarch64 shrike_2.5.4-1_arm64.deb, or -aarch64.tar.gz
Headless the shrikeserver-* files

The macOS builds are not code signed or notarized. Notarization needs a paid Apple Developer account this project does not have. macOS will refuse to open the app on first launch, reporting it as damaged or from an unidentified developer; that means it is unsigned, not that the download is bad. To run it:

xattr -dr com.apple.quarantine /Applications/Shrike.app

Verify SHA256SUMS before doing that. Clearing quarantine removes the check that would otherwise stop a tampered download, so the signature is the only assurance left.

The Windows installer is not Authenticode signed either, and SmartScreen will warn. Upstream Sparrow does not sign its installer either.

Installs to /opt/shrike with its config in ~/.shrike, alongside an existing Sparrow rather than over it. The app reports its version as 2.5.4-blake2b.4.

gpg --import privkeyio-signing-key.asc
gpg --verify SHA256SUMS.asc SHA256SUMS
sha256sum --ignore-missing -c SHA256SUMS

Signed by Kyle Santiago kyle@privkey.io, key A47D99B6DB0D715D40C59A2023AE8A8EA7E24E38. All files come from one packaging workflow run and one manifest.

Do not use on mainnet

No build carries a mainnet activation height, so past activation the wallet declines to opt in and signs the legacy way, as it does anywhere if even one keystore is hardware-held. A signature that does not opt in is valid under the pre-fork rules as well as the new ones, so it can be replayed against nodes that have not adopted the fork. Opting in is what prevents that. The wallet says so in its status; it does not stop you.

Built from privkeyio/sparrow@6e9acc9c with privkeyio/drongo@2829907, on upstream Sparrow 2.5.4.

No warranty

This is an unofficial, unaudited build provided as is, with no warranty and no liability, under the same Apache 2.0 terms as the LICENSE it inherits. It is not a Sparrow release and is neither affiliated with nor supported by Sparrow Wallet. Running it is entirely at your own risk, and you alone bear any loss of funds.