Note
Go to the end to download the full example code or to run this example in your browser via JupyterLite.
Pedersen commitments: perfectly hiding and additive (1991)#
Pedersen committed to a value v as C = g**v * h**r, with a random blinding factor r and a second generator h whose logarithm nobody knows. For any other value there is a blinding factor giving the same C, so the commitment hides v perfectly; opening it to a different value would reveal log_g(h). And commitments multiply to a commitment of the sum.
Two commitments multiply into a commitment to the total, without anyone seeing the amounts. This homomorphism is how confidential transactions (Monero, Mimblewimble) let anyone check that inputs equal outputs.
from random import Random
import matplotlib.pyplot as plt
import blockchainkit as bk
Commit and add#
G = bk.crypto.TEACHING_GROUP
g, h = bk.crypto.pedersen_generators(G)
inputs = [(40, 1111), (2, 2222)] # (amount, blinding factor)
outputs = [(30, 1500), (12, 1833)]
c_in = [bk.crypto.pedersen_commit(v, r) for v, r in inputs]
c_out = [bk.crypto.pedersen_commit(v, r) for v, r in outputs]
balance_in = c_in[0] * c_in[1] % G.p
balance_out = c_out[0] * c_out[1] % G.p
assert balance_in == balance_out # 40 + 2 == 30 + 12, blindings also balance.
print("Inputs and outputs balance without revealing any amount")
Inputs and outputs balance without revealing any amount
Perfect hiding in a group small enough to search#
the same commitment opens as value 7 with blinding 100
the same commitment opens as value 8 with blinding 272
the same commitment opens as value 500 with blinding 402
Commitments look uniform whatever the value#
rng = Random(1991)
zeros = [bk.crypto.pedersen_commit(0, rng.randrange(small.q), small) for _ in range(2000)]
hundreds = [bk.crypto.pedersen_commit(100, rng.randrange(small.q), small) for _ in range(2000)]
fig, ax = plt.subplots(figsize=(7, 3.5))
ax.hist([zeros, hundreds], bins=20, label=["commit(0, r)", "commit(100, r)"])
ax.set(xlabel="commitment value", ylabel="count", title="Random blinding hides the amount")
ax.legend()
fig.tight_layout()
plt.show()

Exercise#
Suppose a dishonest committer knew x = log_g(h). Show how they could open C = g**v * h**r as any other value v’ by choosing r’. Why must h be derived by hashing rather than chosen by a participant?
Total running time of the script: (0 minutes 0.087 seconds)