← index

zkPoH: Zero-Knowledge Proof-of-Hodl

An archive of delvingbitcoin.org · view original topic →

· 40230 · #1 ·

I’m sharing a small proof-of-concept for zkPoH, a Zero-Knowledge Proof of Hodl system for Bitcoin.

The idea is simple: prove that you control a set of Bitcoin UTXOs whose combined value is at least 1 BTC, without revealing the UTXOs, addresses, exact balance, tx history, or private keys.

How it works in the current prototype:

  1. A Bitcoin UTXO snapshot is generated off-chain.

  2. The snapshot is committed into a Merkle tree.

  3. The Merkle root becomes the public commitment.

  4. The prover privately selects up to four UTXOs from that snapshot.

  5. Rust generates the witness inputs for Noir.

  6. The Noir circuit checks:

    • each selected UTXO belongs to the committed snapshot;

    • the Merkle paths are valid;

    • the sum of the selected UTXO values is at least 100,000,000 sats.

  7. If the constraints pass, the verifier only learns: this prover satisfies the 1 BTC threshold against this snapshot.

For the prototype, the Merkle tree uses Blake2s over fixed encodings, and Bitcoin ownership is checked off-circuit with signed WIF ownership proofs. Future work could move ownership verification into the circuit, add Schnorr/Taproot support, snapshot epochs, nullifiers, Utreexo commitments, and arbitrary thresholds.

This is experimental and educational, not production-ready, but it shows a concrete path for private Bitcoin proof-of-hold primitives.

Repo: GitHub - fabohax/zkPoH: Zero Knowledge Proof of Hodl · GitHub

· Murch · #2 ·

(post deleted by author)

· treeforest · #3 ·

Wow. This is some rad innovation. I haven’t been keeping up much with zk happenings in Bitcoin and am happy to see this.

· 40230 · #4 ·

Without an ownership/signing step, the current construction would only prove that some UTXOs exist in the snapshot and that their sum passes the threshold. A malicious prover could otherwise pick arbitrary UTXOs from the chain.

So the design needs an explicit ownership binding step.

The intended flow is:

  1. The verifier gives the prover a fresh challenge:
challenge = H(
  "zkPoH-v1",
  merkle_root,
  threshold,
  verifier_nonce,
  expiry,
  context
)

  1. The prover privately selects UTXOs from the committed snapshot.

  2. For each selected UTXO, the prover signs that challenge with the key controlling the output.

For example, for a P2WPKH output:

sig_i = Sign(privkey_i, challenge)

Then the proof checks:

MerkleVerify(utxo_i, merkle_path_i, merkle_root) == true
HASH160(pubkey_i) == scriptPubKey_pubkeyhash_i
VerifySignature(pubkey_i, challenge, sig_i) == true
sum(values_i) >= threshold

So the proof is not just:

“These UTXOs exist and sum to >= 1 BTC”

but:

“I know the keys that control hidden UTXOs in this snapshot, and their hidden values sum to >= 1 BTC.”

In the current PoC, this ownership step is not yet cleanly integrated into the Noir circuit. That should be clarified in the README. Right now, the circuit mainly demonstrates the Merkle inclusion + private threshold logic. The next step is to bind ownership signatures to the same challenge, snapshot root, and threshold.

There are two possible versions:

v0 — off-circuit ownership check Simpler to implement. The prover signs a challenge for each selected UTXO and the verifier checks those signatures separately. The downside is that this may reveal the UTXOs/pubkeys to the verifier, so it weakens the privacy model.

v1 — in-circuit ownership check Better version. The prover keeps the selected UTXOs, pubkeys, signatures, and Merkle paths private. The circuit verifies internally that:

The verifier only sees the public result:

valid proof
snapshot root = X
threshold >= 1 BTC
challenge/context = Y

but not which UTXOs were used.

For Taproot, this should ideally use Schnorr verification against the x-only output key. For broader Bitcoin script support, BIP-322-style message signing is probably the right direction, although proving arbitrary script satisfaction inside a ZK circuit is more complex.

The Lightning use case is very interesting, but it also needs care. A channel funding output is usually not equivalent to a simple single-key UTXO. Depending on whether it is 2-of-2 multisig, MuSig2, Taproot key-path, etc., the proof may need to show either unilateral participation, cooperative control, or some channel-specific ownership condition without revealing the actual funding output.

PoC needs to make ownership binding explicit, and the strongest version should verify that binding inside the ZK proof.

· Murch · #5 · · in reply to #4

@fabohax I should probably reintroduce the context. I had originally asked after reading your comment whether the UTXOs had to be owned by the prover (or similar), but then had taken another look at your repository, and saw the sections on signing UTXOs. That made me think that I had misconstrued what you had written and I deleted my comment. Thanks for taking the time to answer my question anyway.

Your proposal reminded me of the discussion by Lightning protocol developers about whether it would be possible to have channels based on a proof of UTXO existence without revealing which UTXOs fund the channel. This was intended as a means to improve privacy of lightning channel owners. IIRC, the requirements were somewhat longer, but I don’t remember the details of the discussion. Presumably it would be nice if UTXOs couldn’t be used to prove multiple channels.

· Adam Gibson · #6 ·

I had implemented basically the same primitive (proof of ownership of X funds at N utxos) here and more specifically in this blog post.

You’ll notice I deliberately included a range proof to avoid the obvious footgun of “my balance is exactly X” and then people enumerating 4 utxos that add up to X. I see you’ve also done that with your “at least” clause.

The taproot limitation there is specifically related to attempts to create spontaneous anon sets (i.e. no cooperation) over public keys that are already on the blockchain, plus the fact that this allows pure EC-based ZKP techniques (think: Bulletproofs), specifically building algebraic Merkle trees using the secp/secq 2-cycle (all of that is “Curve Trees”). It can be very cheap when well optimized, including in proving time.

Another closely related project with more a focus on utxo ownership for Lightning gossip applications, as @murch alluded to, was by @halseth here: ZK-gossip for lightning channel announcements

@halseth 's work is more closely aligned with what I gather you’re describing here, since it was also using the more generalized ZKP techniques, which are certainly heavier than Curve Trees, but that’s probably just necessary.

At the very least I guess we can say all these ideas are closely related :smiley:

I’d earlier done work on ring-signature based proofs of ownership but that’s much more limited because of the linear scaling. See “RIDDLE”.

· 40230 · #7 · · in reply to #6

Thanks for reaching out. These ideas are certainly closely related.

I’m still exploring the primitive and the prior research around it. I initially started experimenting simply to understand whether this type of proof was feasible, but I hadn’t come across the concepts and projects you mentioned. They give me a much broader understanding of the current state of the work.

I also hadn’t considered the Lightning application, but I’ll look more closely at Halseth’s proposal and see whether there is any useful contribution I could make.

My current understanding is that AUT-CT uses a highly optimized Taproot and Curve Trees construction, while zkPoH explores a heavier general-purpose circuit that could compose more application-specific conditions—for example, proving that a user holds at least a certain amount of sats to access a club or service, or something along those lines.

I’m glad there is substantial prior work in this area. My focus now is to identify useful proof-of-UTXO-ownership processes and application cases that could justify the generalized approach. Halseth’s work looks especially relevant here.

Thanks again—the comparison really helps clarify screen.

· Adam Gibson · #8 · · in reply to #7

Well no, as I specifically said and also linked the blog post that described it, I did exactly what you describe here - proof of ownership of N utxos adding to an amount in a range, from a chosen utxo snapshot - using a bulletproofs circuit in aut-ct.

Halseth was also surprised about this, but I don’t think you should be! The original bulletproofs paper describes specifically how you can do this. Bulletproofs is a general purpose proving system, it’s just that it buys proof compactness in exchange for poor verification scaling/performance (so not technically SNARK) - which is going to matter in a very large range of scenarios, but not all - here, if you have a utxo snapshot of taproot utxos [1] then you have a set of keys, so all the circuit has to do is prove that "I own N of these curve-tree-leaves, the sum of the attached amounts is k < X < k + 2^n or whatever); that being sufficiently simple, bulletproofs’ drawback is not exposed. Try to do the same thing with hashed outputs, and, well, you can, but I presume it’ll have extremely poor verification performance.

[1] of course the requirement is not literally taproot, it’s ‘outputs for which you know the key’, so other scenarios might exist, taproot is just the most natural one