Zero knowledge. Zero custody. Zero lock-in. Zero leakage.
Sigbash is a policy-bound key agent for Bitcoin. It joins your existing quorum as an independent co-signer seat, with the same building blocks your custody stack already uses, or stands outside the signing path as a policy verification service that issues a signed, offline-verifiable receipt for every transaction.
Policy enforcement is a proof, not a promise. If a transaction violates your rules, our co-signer's signature mathematically cannot complete, no matter what any interface, insider, or compromised vendor claims. Not even we can override it.
Institutional-grade controls. None of the institutional surface area.
What only Sigbash can do
Every other signing platform enforces your policy with software the vendor operates and asks you to trust. Sigbash enforces it with math: the co-signer cannot produce a signature for a transaction your policy forbids.
We never see your policy.
Other policy engines must evaluate your approval rules in cleartext on their infrastructure. Ours evaluates a zero-knowledge circuit compiled from your policy. We learn nothing about your rules, only whether your transaction passes them.
We never see your transactions.
Your transaction never leaves your browser. The co-signer receives a proof, not a payload. Breach our servers and you find nothing. No transaction history, no addresses, no counterparties. No institutional signing platform that holds or sees transactions can say the same.
Built for Bitcoin from the ground up.
No MPC ceremonies. No TEE attestations. No technical debt from trying to accommodate every chain in existence. Just Taproot and Schnorr. The same xpubs and PSBTs your custody stack already speaks.
How a transaction gets signed
End to end, the only thing that crosses the wire is a proof and a partial signature.
1. Define policy
Define a policy in the builder or programmatically via the SDK: signers, limits, locks, quorums.
2. Compile to POET + SMT
Your rules become a Policy Operand Expression Tree and a Sparse Merkle Tree of clauses. The server only ever sees a commitment to it.
3. Browser proves satisfaction
On every transaction, your browser generates a zero-knowledge proof that some clause of your policy is satisfied.
4. Server verifies & co-signs
The co-signer verifies the proof and contributes its partial signature. It never sees the transaction, the counterparty, or which clause fired. No valid proof, no signature: there is no override path, for an attacker or for us.
Two roles, one integration
The same SDK deploys Sigbash in either role. The cryptographic guarantees are identical.
Join the signing path
Sigbash becomes an independent co-signer seat in your existing quorum, one more signature share alongside the signers you already run. It contributes its share only when a valid zero-knowledge proof of policy satisfaction is present. No migration, no displacement, no change to how your other signers work.
Integrate the SDKVerify policies before signing
Sigbash runs as a policy verification service. It never joins your quorum: it checks each transaction against your policy, however you sign it, and issues a signed, offline-verifiable receipt for every transaction. Auditors get proof; your signing stack stays untouched.
Integrate the SDKEvaluate both roles in the hosted demo at sigbash.com, free on signet.
Try the demoBook a Consultation
See Sigbash in action: schedule a 30-minute walkthrough with the team.
Frequently Asked Questions
Sigbash is a policy-bound key agent for Bitcoin: an independent co-signer seat and policy verification service that enforces spending controls with zero-knowledge proofs, while remaining blind to transaction and policy details.
You define spending policies (approval workflows, vendor whitelists, rate limits, etc.), and we cryptographically verify policy satisfaction while remaining blind to transaction amounts, recipients, or policy details. Institutional-grade policy enforcement, with none of the institutional surface area.
Our system uses zero-knowledge cryptography to separate policy enforcement from policy knowledge:
- Policy Definition: Define spending policies using our policy builder.
- Policy Generation: We convert policies to a Policy Operand Expression Tree (POET), a custom data structure meant to efficiently describe signing policies. We then walk the tree and break the policy down into discrete clauses which are converted into a Sparse Merkle Tree.
- Proof Generation: On transaction upload, the browser automatically generates a mathematical proof that the transaction matches at least one of the policy clauses, along with a Merkle proof showing that clause fits into the policy.
- Proof Verification: Our server verifies the proof cryptographically, blind to transaction details and satisfied policy rules, then provides a signature only if the proof is valid.
You use Sigbash through the SDK (@sigbash/sdk), a TypeScript library or a dedicated single-tenant HTTP service callable from any language. It runs in either deployment role: the signing role joins your quorum as an independent co-signer seat that contributes a signature share only against a valid zero-knowledge proof, and the verification role stays outside the signing path, checking each transaction against your policy and issuing a signed, offline-verifiable receipt. Provision keys for your users, run either role from your backend, and ship under your own brand. See Build on Sigbash.
To evaluate the engine before integrating, the hosted demo at sigbash.com runs the same flow in your browser, free on signet.
Either way, the entire process maintains privacy: we never see policy details, transaction amounts, or recipients.
Sigbash is designed for organizations requiring institutional-grade policy controls without sacrificing transaction privacy:
- Custody platforms and qualified custodians adding an independent policy-bound co-signer seat alongside their existing quorum
- Institutions running collaborative multisig who want a signed policy-verification receipt for every transaction without changing how they sign
- Corporate treasuries needing vendor whitelisting and approval workflows
- Financial institutions with regulatory policy requirements
- Family offices, funds, and trading firms with proprietary risk management requirements
- Developers and platforms integrating Bitcoin co-signing. See our SDK (
@sigbash/sdk)
POET stands for Policy Operand Expression Tree. It's the data structure we use to efficiently describe complex signing policies. It's a boolean logic tree: each leaf represents a specific constraint about the transaction (spending limits, allowed recipients, time windows), and each branch represents how those constraints combine using logical operators like AND, OR, and NOT.
A policy definition like "allow transactions under 1 BTC to approved vendors OR allow any amount with two factor authentication" gets captured as POET structure, convertible to cryptographic proofs. The server never sees the actual tree structure or policy rules. Instead, we walk the tree to find all valid paths through the policy logic. These satisfying clauses are then committed into a Sparse Merkle Tree, and the root hash becomes the policy commitment. At signing time, the browser generates a proof showing the transaction satisfies at least one valid path; exactly which path was satisfied remains unknown, as does the content of other paths.
POET v1.1 supports fourteen logical operators for combining conditions: AND, OR, NOT, XOR, NAND, NOR, THRESHOLD, EXACTLY, AT_MOST, IMPLIES, IFF, VETO, WEIGHTED_THRESHOLD, and MAJORITY. These let you express everything from simple "require all three conditions" logic to sophisticated weighted voting schemes.
For conditions themselves, we support comprehensive Bitcoin transaction introspection across four categories. Transaction level conditions include TX_VERSION, TX_LOCKTIME, TX_INPUT_COUNT, TX_OUTPUT_COUNT, TX_FEE_ABSOLUTE. Input level conditions cover INPUT_VALUE (amount constraints on specific inputs), INPUT_SEQUENCE (for relative timelocks), INPUT_SCRIPT_TYPE (requiring certain address types), and INPUT_SIGHASH_TYPE (signature flags). Output level conditions include OUTPUT_VALUE, OUTPUT_SCRIPT_TYPE, OUTPUT_DEST_IS_IN_SETS (recipient allowlists/denylists), and OUTPUT_OP_RETURN for matching specific data patterns in OP_RETURN outputs.
Beyond basic constraints, we support relationship conditions like NO_SCRIPT_REUSE, INPUT_SET_IS_HOMOGENEOUS, and OUTPUT_SET_IS_HOMOGENEOUS for enforcing transaction structure patterns. For stateful constraints across multiple transactions, COUNT_BASED_CONSTRAINT enables "5 uses per week" type limits while TIME_BASED_CONSTRAINT supports WALLCLOCK, AFTER, BEFORE, and WITHIN time windows. We also support SIGNATURE_PRESENT for requiring additional signatures, REQKEY for signer universe checks, and PSBT_TXID plus INPUT_TXID for transaction identification. Finally, derived conditions computed at signing time include DERIVED_FEE_RATE_CATEGORY, DERIVED_SIGHASH_TYPE, DERIVED_RBF_ENABLED, DERIVED_IS_CONSOLIDATION, DERIVED_IS_COINJOIN_LIKE, DERIVED_IS_PAYJOIN_LIKE, and DERIVED_NO_NEW_OUTPUTS for detecting transaction patterns.
Each condition accepts parameters controlling how it evaluates. Selectors like ALL, ANY, or INDEX determine which inputs or outputs to check, while operators like EQ, NEQ, LTE, GTE specify numeric comparisons. Range conditions can specify minimum and maximum bounds. The system is designed for extensibility, so new conditions can be added as Bitcoin evolves.
It's not actually converted. The 32 byte hash is a cryptographic commitment, not a compressed version of the policy. During policy registration, the browser walks through the POET decision tree to find every distinct path that could satisfy the rules. Each path becomes a leaf in a Sparse Merkle Tree, with the root hash serving as an immutable fingerprint of the entire policy structure.
Upon PSBT upload for signing, Sigbash analyzes the transaction and identifies any matching policy path. It then generates a Merkle inclusion proof showing that path belongs to the committed tree. The server verifies the proof connects to the policy commitment while remaining blind to which path was satisfied or what other paths exist. Similar to password verification without password transmission, the cryptographic structure allows server verification of path compliance while keeping the policy logic, path count, and satisfied conditions hidden.
The proof generation happens entirely in the browser using WebAssembly. First, the browser commits to transaction data using cryptographic accumulators. These compress output addresses, input references, and derived transaction fields into single field elements that are information theoretically too small to reveal underlying values, yet cryptographically bound to Bitcoin's BIP 341 transaction hash components. These bindings use Fiat-Shamir challenges that prove the accumulator corresponds to real transaction data while keeping the underlying data hidden.
Next, for each constraint in the selected PathLeaf, specialized circuits generate zero knowledge proofs. Numeric range constraints use range proof circuits, address membership checks use set membership proofs, and time validations use timestamp circuits. These proofs reveal only that the constraint is satisfied, not the actual values. For example, a proof that an output value is less than 1 BTC reveals neither the actual amount nor the 1 BTC limit itself.
The system combines these individual constraint proofs into a single proof bundle along with the PathLeaf data, its Merkle inclusion proof showing it's part of the committed policy, and the transaction commitments. Critically, the bundle is bound to the signing session and to every input being signed: each proof carries a session-scoped binding, an accumulator chain ties all inputs of the transaction together, and the entire bundle is sealed under a single digest, preventing proof replay or substitution across sessions or inputs.
The server receives this complete package and verifies: the PathLeaf is part of the policy commitment, the zero knowledge proofs are mathematically valid, the cryptographic bindings are structurally consistent, and the session and cross-input bindings are correct. But at no point does the server see transaction outputs, input sources, amounts, or which specific constraints were satisfied. After verification passes, the server generates its MuSig2 partial signature blindly; it signs while remaining blind to the actual BIP 341 sighash of the transaction. The browser then aggregates the server's partial signature with its own, creates the final Bitcoin signature, and verifies it before broadcasting. If anything was wrong, if the proofs were fake or mismatched, the signature verification fails and the transaction never leaves the browser.
Nullifiers are cryptographic commitments that get "burned" or revoked to track state across multiple transactions. They enable constraints that traditional stateless zero knowledge proofs can't handle, things like "this signing path can only be used 5 times per week" or "transactions are only allowed between 9am and 5pm on weekdays".
Policy registration with stateful constraints stores those definitions (maximum use counts, time windows, reset intervals) in the policy commitment as static configuration that never changes. Separately, we maintain a global revocation tree that tracks consumed nullifiers across all users. When signing a transaction using a path with stateful constraints, the browser generates a unique cryptographic commitment binding together the constrained value (a counter index like 0, 1, 2, and so on, or a timestamp), the policy root, the constraint scope, the time epoch for automatic resets, and the transaction hash. This commitment is constructed using techniques that hide the actual counter value or timestamp. The server learns only that a valid, previously unused commitment was presented.
For count-based constraints like "5 uses per week", the browser queries the global revocation tree to find which counter slots are already consumed, picks the next available one, proves via zero knowledge that the counter is within the allowed range (0 to 4 for 5 uses), and burns that commitment. Next week, the epoch changes automatically and you get a fresh set of counters without needing to re-register. For time-based constraints, the timestamp gets revealed to enable server-side freshness validation (preventing old replays), but the cryptographic commitment still prevents forgery and maintains privacy since timestamps change constantly and can't be correlated to specific users.
The key privacy feature is that every signing operation burns exactly one nullifier commitment regardless of whether the policy actually uses stateful constraints. An observer watching the global revocation tree cannot distinguish between users with count limits, time limits, or no stateful constraints. Everything looks identical. The commitments are also unlinkable across different uses by the same user because each transaction hash is unique, so even though the system tracks state, it preserves transaction-level privacy while preventing double-spending of counter slots or violating time windows.
For comprehensive technical documentation on the implementation, architecture, and cryptographic protocols, check out our open-source repository:
The repository includes detailed documentation on POET architecture, zero-knowledge proof system implementation, MuSig2 signing protocol integration, Sparse Merkle Tree construction and verification, and WebAssembly client-side cryptography.
Found a bug or have a feature request? Please report issues on our GitHub repository:
When reporting issues, please include a clear description of the problem, steps to reproduce, expected vs. actual behavior, browser and OS information, and any relevant error messages or console logs.
For security-sensitive issues, please contact us directly at inquiries@sigbash.com instead of creating a public issue.
Sigbash uses two-factor authentication: a passkey (Face ID, fingerprint, or hardware key) plus a PIN you set during registration.
Click "Log In" in the navigation bar. Your browser will prompt for your passkey. After passkey verification, enter your PIN. That's it.
No passwords, no magic email codes, no SMS. Your passkey is bound to your device and can't be phished.
Your Recovery Kit is a QR code that lets you regain access if you lose your device or passkey. It contains encrypted account credentials that only work with your PIN.
Without it, a lost device means a lost account. We can't recover it for you because we don't have access to any of your data. You are entirely responsible for maintaining access to your account.
After registration, go to "Account Recovery Kit" in the menu. Print the QR code and store it somewhere safe (fireproof safe, bank deposit box, with your other important documents). You can also download it as a file, but paper backup is recommended.
Click "Recover Account" in the navigation bar. Upload or scan your Recovery Kit QR code. You will then be prompted to register a new passkey on your current device.
Your account migrates to the new device with your policies and signing keys intact. The old passkey is invalidated automatically.
Your Sigbash account is gone. We have no backdoor and no way to recover it.
Your bitcoin isn't necessarily lost; you should still have your other key(s) in your multisig setup. But you'll need to move funds to a new address with a new co-signing arrangement. We strongly recommend building multisignature wallets with either decaying timelocks or backup keys to avoid being dependent on any single signer.
This is why the Recovery Kit matters. Print it. Store it safely. Test the recovery process before you need it.
Book a consultation to see the key agent in action, or reach out to scope an integration.

