Today, I found a website for Pedersen commitment scheme; however, the generators g
and h
are not independent and therefore a prover can open a commitment c
into many ways. I computed the commitment c
for a message m
and a randomness r
(assuming that I know s
):
c = g^m * h^r
= g^m * (g^s)^r
= g^m * (g^(s * r))
= g^(m + s * r)
Say, I have committed to the message m
, randomness r
, and the commitment is c
(c = g ^ (m + s * r)
. Now I want to fake it, i.e., open it for some other message m'
, not equal to m
, and therefore I need to calculate a new randomness r'
: r' = (m - m' + s * r) * s^(-1)
. I took the original python code, posted on the website, and did a minor modification, returning s
. Moreover, I wrote another function fake_message to compute an arbitrary message for opening it to the same commitment c, but when I am running my modified code, the last line,
r2 = print(vv.open(param, c, m2, r2))
is returning false. My question is: what is wrong with my thinking, and the Python implementation? (I am using pycryptodome 3.10.1)
from Crypto import Random
from Crypto.Util import number
import sys
def generate(param):
p = param[0]
q = param[1]
g = param[2]
h = param[3]
s = param[4]
return p,q,g,h,s
class verifier:
def setup(self, security):
p = number.getPrime(2 * security, Random.new().read)
q = 2*p + 1 # hmm, no testing if q is prime or not.
g = number.getRandomRange(1, q-1)
s = number.getRandomRange(1, q-1)
print("Secret value:\t",s)
h = pow(g,s,q)
param = (p,q,g,h,s)
print("p=",p)
print("q=",q)
print("g=",g)
print("h=",h)
print("s=",s)
return param
def open(self, param, c, m, r):
p,q,g,h,s = generate(param)
res = (pow(g,m,q) * pow(h,r,q)) % q
return (c == res)
class prover:
def commit(self, param, m):
p,q,g,h,s= generate(param)
r = number.getRandomRange(1, q-1)
c = (pow(g,m,q) * pow(h,r,q)) % q
return c, r
# I am going to open it to a random arbitrary message m2
def fake_message(self, param, c, m1, r1):
p,q,g,h,s = generate(param)
#get a random message
m2 = number.getRandomRange(1, q-1)
r2 = ((m1 - m2 + s * r1) * number.inverse(s, q))%q
return (m2, r2)
security = 80
m = 2
vv = verifier()
pp = prover()
param = vv.setup(security)
c, r = pp.commit(param, m)
print(vv.open(param, c, m, r))
m2, r2 = pp.fake_message(param, c, m, r)
print(vv.open(param, c, m2, r2))