Privacy Suite
Bulletproofs

Bulletproofs: Zero-Knowledge Range Proofs

🔒

What bulletproofs prove: Every transfer carries a zero-knowledge proof that the amount is valid without revealing what it is. DERO uses a 128-bit combined range proof that binds both the transfer amount and the sender's remaining balance to non-negative 64-bit ranges in a single proof.

What Problem Do Bulletproofs Solve?

The Challenge:

DERO needs to verify:
  ✓ Amount is positive (not negative)
  ✓ Amount is reasonable (not 999 trillion)
  ✓ Sender has enough balance
  
But WITHOUT revealing:
  ✗ The actual amount
  ✗ The sender's balance
  ✗ Any private information

The Solution: Bulletproofs

  • ✅ Prove combined 128-bit value is valid (transfer + remaining balance, each 64-bit)
  • ✅ Never reveal the amount value
  • ✅ Logarithmic-size proof (7 rounds for 128-bit range)
  • ✅ No trusted setup needed (the bulletproof generators G and H are derived deterministically from public protocol constants via hash-to-curve — cryptography/crypto/algebra_pedersen.go:36-37 — so there is no setup ceremony to trust)

How It Works (Simple Analogy)

The Bouncer Problem:

Show ID (Reveals Everything)

You: "I'm 25 years old"
Bouncer: "Show me your ID"

Bouncer learns:
  ✓ You're over 21
  ✓ Your exact age (25)
  ✓ Your address
  ✓ Your full name
  ✓ Your photo
  ✓ Everything else on the ID

Disclosure: everything on the ID is exposed

For DERO:

  • Bulletproof proves: "Combined 128-bit value is valid (transfer amount in lower 64 bits, remaining balance in upper 64 bits)"
  • Network learns: ✅ Both values are valid (in [0, 2^64))
  • Network learns: ❌ What either value actually is

The Proof Flow

What Network Sees:

  • ✅ Commitment (encrypted amount)
  • ✅ Bulletproof (logarithmic-size proof)
  • ✅ Proof is valid
  • ❌ Actual amount (hidden)

Protection Against Negative Transfers

The guarantee is cryptographic, not a string-parsing quirk: by the soundness of the Bulletproof range proof, no prover can construct a proof that verifies for a committed value outside the proven range. Combined with DERO's homomorphic value conservation, value cannot be created from nothing.

DERO packs two quantities into a single 128-bit value and range-proves them together — the transfer amount in the low 64 bits and the sender's remaining balance in the high 64 bits — so one Bulletproof binds both to non-negative 64-bit ranges (number = transfer + (balance << 64), cryptography/crypto/proof_generate.go:471).

A "negative" transfer is the uint64 wraparound of a value near 2^64. It fails the range proof from both directions:

Attack framingWhy the range proof rejects it
Treat the wraparound as the transfer amountA value near 2^64 lies outside [0, 2^64) — the low-64 range bound fails.
Treat it as receiving (so your own balance jumps)The conservation proof forces a matching decrease; the sender's remaining balance goes negative → wraps → the high-64 range bound fails.

The protection lives in verification (cryptography/crypto/proof_verify.go), not generation. The wallet builds the proof in proof_generate.go; an attacker controls their own wallet and could patch out any client-side check. The cryptographic guarantee comes from the verifier check that every node runs independently before accepting a block.

📐

Common misconception: A claim circulates that Go's BigInt.Text(2) emitting a '-' for negative values "breaks the bit loop" in proof generation, and that this is what stops negative transfers. It does not — the loop is if b == '1' { … } else { … }, which silently treats a stray '-' as a 0 bit. And for any real transaction the packed 128-bit number is positive, so no '-' appears at all. The actual safeguard is verifier-side Bulletproof soundness. See Negative Transfer Protection for the full derivation.


The Six Sigma Proofs

DERO uses six interconnected proofs that all must pass:

ProofWhat It ValidatesSecurity Level
A_ySender has private key🔒 Cryptographically secure
A_DEncrypted balance update correct🔒 Homomorphic validation
A_bBalance commitment valid🔒 Binding & hiding
A_XAdditional protocol constraints🔒 Protocol-specific
A_tRange-proof commitment for the packed 128-bit value (transfer + balance << 64) — closed by the inner product proof below🔒 Bulletproof — soundness under DL on bn256 (random oracle model)
A_uKey image (linking tag) is correctly derived from the sender's secret key — ties tx to the sender within the anonymity-set without revealing which slot is the sender🔒 Anti-replay, account-model linking (see Transaction Proofs § A_u)

All Bound Together:

Challenge hash (c) = hash(A_y || A_D || A_b || A_X || A_t || A_u || ...)

If ANY proof fails:
  → Challenge hash is different
  → Verification fails
  → Transaction rejected

Source: cryptography/crypto/proof_verify.go:98Verify() recomputes the challenge hash from all six recovered sigma components (lines 410-425), then closes A_t via the inner product proof at line 457.


Inner Product Proof — Closing A_t

The inner product proof is not a seventh independent check. It is the recursive closure of the A_t bulletproof above: A_t commits to polynomial coefficients of the range-proof relation; the inner product argument shows those coefficients fold consistently with the committed value, proving (with the rest of the bulletproof scaffolding) that the packed transfer + balance << 64 lies in [0, 2^128).

A failed inner product check is a failed A_t — and therefore a failed transaction. There is one bulletproof gate, with two named pieces.

Recursive Halving — How Logarithmic Scaling Works

The Algorithm:

Iterations:

  • Start: 128 elements
  • Iteration 1: 64 elements
  • Iteration 2: 32 elements
  • Iteration 3: 16 elements
  • Iteration 4: 8 elements
  • Iteration 5: 4 elements
  • Iteration 6: 2 elements
  • Iteration 7: 1 element

Total: log₂(128) = 7 iterations

Source: cryptography/crypto/proof_innerproduct.go:71 hardcodes length := 7 for the 128-bit range (note: this lives in Deserialize, so the 128-bit range size is fixed at the wire level — an attacker cannot submit a proof of a different range); the verifier closure call is proof.ip.Verify(...) at cryptography/crypto/proof_verify.go:457. The bulletproof input vector itself is packed at proof_innerproduct.go:41 (the "7 entries" structure).


Zero-Knowledge Property Explained

What "Zero-Knowledge" Means

After seeing a valid bulletproof, verifier learns:

InformationLearned?Reason
Combined 128-bit value is valid✅ YesThis is what's proven
Transfer and balance each in [0, 2^64)✅ YesImplicit from 128-bit structure
Exact transfer amount❌ NoZero-knowledge property
Exact remaining balance❌ NoZero-knowledge property
Any bits of either value❌ NoBits are hidden
Any private information❌ NoThe proof reveals nothing beyond the validity claim

Formal Properties:

  • Completeness: Valid proofs always verify
  • Soundness: Invalid proofs never verify
  • Zero-knowledge: No information leaked

Where Bulletproofs Are Used

Three Core Applications:

ApplicationWhat It ValidatesProtection
Transaction AmountsCombined 128-bit value (transfer + remaining balance)Prevents negative transfers
Balance SufficiencyBoth transfer and remaining balance in [0, 2^64)Prevents overdrafts
Asset (token) transfers via tx.Payloads[t]Range-proves the same packed value for each non-DERO asset moved in the transactionSame negative/overflow protection applied per asset payload (note: smart-contract STORE/LOAD state is stored plaintext in the graviton tree — it is not bulletproof-protected)

All three use the same bulletproof mechanism:

  • ✅ Prove value is in valid range
  • ✅ Never reveal the actual value
  • ✅ Cryptographic guarantee

Key Takeaways

What You Get

FeatureBenefitImpact
🔒 Zero-KnowledgeAmount hidden from networkTransactions don't leak amounts to observers
📦 Logarithmic Proofs7 rounds for 128-bit rangeEfficient transactions
🔐 No Trusted SetupPure cryptographyDecentralized security
🛡️ Soundness + ConservationNo verifying proof for out-of-range valuesNegative transfers cryptographically impossible
✅ Proven Securitybn256 elliptic curve discrete logStandard discrete log security assumption

What You're Protected From

The Bottom Line:

🔒

Verifier-side guarantee: Every node independently checks the Bulletproof. By soundness, no prover can construct a verifying proof for an out-of-range value. Combined with homomorphic value conservation, negative transfers are cryptographically impossible.

Performance + Privacy: DERO's bulletproof implementation keeps proofs logarithmic in size while preserving strong cryptographic guarantees.


Related Pages

Privacy Suite:

Technical Details:

Learn More: