| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- ProofWitness = namedtuple("ProofWitness", [
- "v1", "v2", "v3", "v4", "r", "b", "σ"
- ])
- class ProofPublic:
- def __init__(self):
- self.C = None
- self.D = None
- self.X = None
- self.Y = None
- self.Z = None
- class ProofCommits:
- def __init__(self):
- self.v1 = None
- self.v2 = None
- self.v3 = None
- self.v4 = None
- self.r = None
- self.b = None
- self.σ = None
- self.σ_G1 = None
- self.σ_G2 = None
- self.v3_G1 = None
- self.v4_G2 = None
- self.blind_x = None
- self.blind_y = None
- self.blind_z = None
- # Used by inner product
- self.C0 = None
- self.C1 = None
- def transcript(self):
- points = [
- self.v1, self.v2, self.v3, self.v4, self.r, self.b, #self.σ,
- self.σ_G1, self.σ_G2, self.v3_G1, self.v4_G2,
- self.blind_x, self.blind_y, self.blind_z, self.C0, self.C1
- ]
- assert all(P is not None for P in points)
- points = [P.xy() for P in points]
- return list(zip(*points))
- class ProofResponses:
- def __init__(self):
- self.v1 = None
- self.v2 = None
- self.v3 = None
- self.v4 = None
- self.r = None
- self.b = None
- self.σ = None
- self.blind_x = None
- self.blind_y = None
- self.blind_z = None
- self.txy = None
- Proof = namedtuple("Proof", [
- "R", "s", "boolean_check"
- ])
- RingProof = namedtuple("RingProof", [
- "c0", "s0", "s1"
- ])
- def make_proof(Ei, witness):
- G1, G2, G3, G4, H = gens[Ei]
- S = Scalar[Ei]
- blind_x = int(S.random_element())
- blind_y = int(S.random_element())
- blind_xy = int(S.random_element())
- # We want that blind_xy + blind_z == witness.b
- blind_z = int(S(witness.b - blind_xy))
- k_v1 = int(S.random_element())
- k_v2 = int(S.random_element())
- k_v3 = int(S.random_element())
- k_v4 = int(S.random_element())
- k_r = int(S.random_element())
- k_b = int(S.random_element())
- k_σ = int(S.random_element())
- k_blind_x = int(S.random_element())
- k_blind_y = int(S.random_element())
- k_blind_xy = int(S.random_element())
- k_blind_z = int(S.random_element())
- # Used for inner product
- k_t0 = int(S.random_element())
- k_t1 = int(S.random_element())
- R = ProofCommits()
- R.v1 = k_v1 * G1
- R.v2 = k_v2 * G2
- R.v3 = k_v3 * G3
- R.v4 = k_v4 * G4
- R.r = k_r * H
- R.b = k_b * H
- # Used for 2nd proof
- R.σ_G1 = k_σ * G1
- R.σ_G2 = k_σ * G2
- R.v3_G1 = k_v3 * G1
- R.v4_G2 = k_v4 * G2
- R.blind_x = k_blind_x * H
- R.blind_y = k_blind_y * H
- R.blind_xy = k_blind_xy * H
- R.blind_z = k_blind_z * H
- # σ (v1 - v3)
- # σ (v2 - v4)
- # (k_σ + c σ)(k_v1 - k_v3 + c*(v1 - v3))
- #
- # sage: var("k_σ c σ k_v1 k_v3 v1 v3")
- # sage: ((k_σ + c*σ)*(k_v1 - k_v3 + c*(v1 - v3))).expand().collect(c)
- # (v1*σ - v3*σ)*c^2 + (k_σ*v1 - k_σ*v3 + k_v1*σ - k_v3*σ)*c + k_v1*k_σ - k_v3*k_σ
- R.C0 = (
- (k_v3*k_σ - k_v1*k_σ) * G1 +
- (k_v4*k_σ - k_v2*k_σ) * G2 +
- k_t0 * H
- )
- R.C1 = (
- (k_σ*witness.v3 - k_σ*witness.v1 + k_v3*witness.σ - k_v1*witness.σ) * G1 +
- (k_σ*witness.v4 - k_σ*witness.v2 + k_v4*witness.σ - k_v2*witness.σ) * G2 +
- k_t1 * H
- )
- c = hash_scalar(Ei, R.transcript())
- s = ProofResponses()
- s.v1 = int( k_v1 + c*witness.v1 )
- s.v2 = int( k_v2 + c*witness.v2 )
- s.v3 = int( k_v3 + c*witness.v3 )
- s.v4 = int( k_v4 + c*witness.v4 )
- s.r = int( k_r + c*witness.r )
- s.b = int( k_b + c*witness.b )
- s.σ = int( k_σ + c*witness.σ )
- s.blind_x = int(k_blind_x + c*blind_x)
- s.blind_y = int(k_blind_y + c*blind_y)
- s.blind_xy = int(k_blind_xy + c*blind_xy)
- s.blind_z = int(k_blind_z + c*blind_z)
- s.txy = c**2 * blind_xy + c * k_t1 + k_t0
- public = ProofPublic()
- public.X = ((witness.v3 - witness.v1) * G1 +
- (witness.v4 - witness.v2) * G2 +
- blind_x * H)
- public.Y = witness.σ * G1 + witness.σ * G2 + blind_y * H
- public.XY = (
- witness.σ * (witness.v3 - witness.v1) * G1 +
- witness.σ * (witness.v4 - witness.v2) * G2 +
- blind_xy * H
- )
- public.Z = witness.v1 * G1 + witness.v2 * G2 + blind_z * H
- assert witness.σ in (0, 1)
- if witness.σ == 0:
- assert public.XY == blind_xy * H
- assert (
- public.XY + public.Z
- ==
- witness.v1*G1 + witness.v2*G2 + (blind_xy + blind_z)*H
- )
- else:
- assert witness.σ == 1
- assert (
- public.XY
- ==
- (witness.v3 - witness.v1) * G1 +
- (witness.v4 - witness.v2) * G2 +
- blind_xy * H
- )
- assert (
- public.XY + public.Z
- ==
- witness.v3*G1 + witness.v4*G2 + (blind_xy + blind_z)*H
- )
- assert blind_xy + blind_z == witness.b
- P1 = public.Y
- P2 = public.Y - G1 - G2
- assert blind_y*H == [P1, P2][witness.σ]
- if witness.σ == 0:
- assert blind_y*H == P1
- assert blind_y*H - G1 - G2 == P2
- else:
- assert witness.σ == 1
- assert blind_y*H + G1 + G2 == P1
- assert blind_y*H == P2
- boolean_check = make_ring_sig(Ei, [P1, P2], blind_y, int(witness.σ))
- assert verify_ring_sig(Ei, boolean_check, [P1, P2])
- return Proof(R, s, boolean_check), public
- def make_ring_sig(Ei, public_keys, secret, j):
- H, S = gens[Ei][-1], Scalar[Ei]
- assert len(public_keys) == 2
- assert secret*H == public_keys[j]
- assert j in (0, 1)
- k0 = int(S.random_element())
- R0 = k0*H
- c1 = hash_scalar(Ei, R0.xy())
- s1 = int(S.random_element())
- R1 = s1*H - c1*public_keys[(j + 1) % 2]
- c0 = hash_scalar(Ei, R1.xy())
- s0 = k0 + c0*secret
- if j == 1:
- c0 = c1
- s0, s1 = s1, s0
- proof = RingProof(c0, s0, s1)
- return proof
- def verify_ring_sig(Ei, proof, public_keys):
- H = gens[Ei][-1]
- S = Scalar[Ei]
- assert len(public_keys) == 2
- R1 = proof.s0*H - proof.c0*public_keys[0]
- c1 = hash_scalar(Ei, R1.xy())
- R2 = proof.s1*H - c1*public_keys[1]
- c2 = hash_scalar(Ei, R2.xy())
- return c2 == proof.c0
- def verify_proof(Ei, proof, public):
- G1, G2, G3, G4, H = gens[Ei]
- S = Scalar[Ei]
- R, s = proof.R, proof.s
- c = hash_scalar(Ei, R.transcript())
- if (s.v1 * G1 +
- s.v2 * G2 +
- s.v3 * G3 +
- s.v4 * G4 +
- s.r * H
- !=
- R.v1 + R.v2 + R.v3 + R.v4 + R.r + c*public.C
- ):
- return False
- # Now we want to prove that
- # D = v1 G1 + v2 G2 + b H
- # or
- # D = v3 G1 + v4 G2 + b H
- # We do this by checking:
- # X = (v1 - v2)G + b_X H
- # Y = σ G + b_Y H
- # D = xy G + v2 G + b_D H
- # σ ∈ {0, 1}
- # X = (v1 - v2)G + b_X H
- if (s.v3 * G1 - s.v1 * G1 +
- s.v4 * G2 - s.v2 * G2 +
- s.blind_x * H
- !=
- R.v3_G1 - R.v1 + R.v4_G2 - R.v2 + R.blind_x + c*public.X
- ):
- return False
- # Y = σ G + b_Y H
- if (s.σ * G1 + s.σ * G2 + s.blind_y * H
- !=
- R.σ_G1 + R.σ_G2 + R.blind_y + c*public.Y
- ):
- return False
- # Z = v1 G1 + v2 G2
- if (s.v1 * G1 + s.v2 * G2 + s.blind_z * H
- !=
- R.v1 + R.v2 + R.blind_z + c*public.Z
- ):
- return False
- # Inner product verification. We select either P1 or P2
- # prove D1 = x1 y1 G1 + b1 H
- if (s.σ*(s.v3 - s.v1)*G1 + s.σ*(s.v4 - s.v2)*G2 + s.txy*H
- !=
- c**2*public.XY + c*R.C1 + R.C0
- ):
- return False
- # check D is correct
- if public.D != public.XY + public.Z:
- return False
- # boolean check proof for s
- P1 = public.Y
- P2 = public.Y - G1 - G2
- if not verify_ring_sig(Ei, proof.boolean_check, [P1, P2]):
- return False
- return True
- def hash_scalar(Ei, values):
- S = Scalar[Ei]
- hasher = hashlib.sha256()
- for value in values:
- hasher.update(str(value).encode())
- return S(int(hasher.hexdigest(), 16))
- # Test proving system
- def test_proof():
- G1, G2, G3, G4, H = gens[E1]
- S = Scalar[E1]
- P1, P2 = [E[E2].random_point() for _ in range(2)]
- (P1_x, P1_y), (P2_x, P2_y) = P1.xy(), P2.xy()
- r, b = [S.random_element() for _ in range(2)]
- C = hash_nodes(E1, P1, P2, r)
- # σ = 0 for P1, or σ = 1 for P2
- σ = S(1)
- D = hash_point(E1, P2, b)
- proof, public = make_proof(
- E1,
- ProofWitness(
- P1_x,
- P1_y,
- P2_x,
- P2_y,
- r,
- b,
- σ
- )
- )
- public.C = C
- public.D = D
- assert verify_proof(E1, proof, public)
- # Now try the other side too
- σ = S(0)
- D = hash_point(E1, P1, b)
- proof, public = make_proof(
- E1,
- ProofWitness(
- P1_x,
- P1_y,
- P2_x,
- P2_y,
- r,
- b,
- σ
- )
- )
- public.C = C
- public.D = D
- assert verify_proof(E1, proof, public)
- # Test the ring sigs too
- secret = int(S.random_element())
- P1 = secret*H
- P2 = E[E1].random_point()
- proof = make_ring_sig(E1, [P1, P2], secret, 0)
- assert verify_ring_sig(E1, proof, [P1, P2])
- # Also try in reverse
- P1, P2 = P2, P1
- proof = make_ring_sig(E1, [P1, P2], secret, 1)
- assert verify_ring_sig(E1, proof, [P1, P2])
- # Ring sigs is our boolean proof for σ
- σ = S(0)
- b = S.random_element()
- # Verifier only has P
- # We prove that σ ∈ {0, 1}
- P = σ*G1 + b*H
- # They can only make a ring signature on H
- # if σ is 0 or 1
- # P1 = P represents σ = 0
- P1 = P
- # P2 = P - G1 represents σ = 1
- P2 = P - G1
- proof = make_ring_sig(E1, [P1, P2], b, 0)
- assert verify_ring_sig(E1, proof, [P1, P2])
- # Also try σ = 1
- σ = S(1)
- P = σ*G1 + b*H
- P1 = P
- P2 = P - G1
- proof = make_ring_sig(E1, [P1, P2], b, 1)
- assert verify_ring_sig(E1, proof, [P1, P2])
|