Note
Go to the end to download the full example code or to run this example in your browser via JupyterLite.
Confidential transactions: amounts that add up unseen (2015)#
Gregory Maxwell replaced each amount with a Pedersen commitment \(C = g^v h^r\). Commitments multiply as amounts add, so anyone can check that nothing is created,
without seeing a single amount. Amounts live modulo the group order \(q\), though, so an output of \(q - 1\), which is \(-1\), balances an output one coin too large. Every output therefore carries a range proof: a commitment to each bit, with a ring signature over \(\{C_k, C_k / g^{2^k}\}\) showing that one of the two is a pure power of \(h\), so the bit is 0 or 1.
import matplotlib.pyplot as plt
import blockchainkit as bk
G = bk.crypto.TEACHING_GROUP
An honest payment#
50 coins in; 30 to the payee, 19 back as change, 1 as the fee.
valid; each output proves 16 bits
Inflation through a negative amount#
Outputs of 1,000 and -951 balance the 50 coins in, less the fee of 1.
big = bk.privacy.confidential_output(1_000, 700, seed=3)
minus = bk.crypto.pedersen_commit(G.q - 951, 1_111 - 700)
assert bk.privacy.commitments_balance(inputs, [big.commitment, minus], fee=1)
forged = bk.privacy.ConfidentialOutput(minus, change.range_proof)
assert not bk.privacy.verify_confidential(inputs, [big, forged], fee=1)
try:
bk.privacy.prove_range(G.q - 951, 411)
except ValueError as error:
print("no range proof for -951:", error)
no range proof for -951: value is not in [0, 2**16)
Proof size#
bits = [4, 8, 16, 24, 32]
sizes = [
len(bk.privacy.prove_range(5, 9, b).bit_commitments) * 4 for b in bits
] # Per bit: a commitment, a challenge and two responses.
fig, ax = plt.subplots(figsize=(6, 4))
ax.plot(bits, sizes, marker="o")
ax.set(xlabel="bits of range", ylabel="numbers in the proof")
ax.set_title("Bitwise range proofs grow linearly")
fig.tight_layout()
plt.show()

Exercise#
The sender knows every output’s blinding factor. Why must the payee learn its own output’s amount and blinding factor, and how does the payee check what it was paid? A worked solution is in Exercises: privacy.
Total running time of the script: (0 minutes 0.065 seconds)