def test_and_dlrne_binding_1(): secrets, secret_values, secret_dict = get_secrets(4) generators = make_generators(4) lhs_values = [x * g for x, g in zip(secret_values, generators)] p1 = DLNotEqual( [lhs_values[0], generators[0]], [lhs_values[1], generators[1]], secrets[0], bind=True, ) p2 = DLRep(lhs_values[0], secrets[0] * generators[0]) andp = p1 & p2 p1_prime = DLNotEqual( [lhs_values[0], generators[0]], [lhs_values[1], generators[1]], secrets[0], bind=True, ) p2_prime = DLRep(lhs_values[0], Secret(name=secrets[0].name) * generators[0]) andp_prime = p1_prime & p2_prime protocol = SigmaProtocol(andp_prime.get_verifier(), andp.get_prover(secret_dict)) assert protocol.verify()
def params(group): n1 = 3 n2 = 4 generators1 = make_generators(n1) generators2 = make_generators(n2) x0 = Secret() x1 = Secret() x2 = Secret() x3 = Secret() x4 = Secret() x5 = Secret() secrets = [x0, x1, x2, x3, x4, x5] secrets_dict = dict([ (x0, Bn(1)), (x1, Bn(2)), (x2, Bn(5)), (x3, Bn(100)), (x4, Bn(43)), (x5, Bn(10)), ]) sum_1 = group.wsum([secrets_dict[x0], secrets_dict[x1], secrets_dict[x2]], generators1) secrets_2 = [secrets_dict[x0]] for i in range(3, 6): secrets_2.append(secrets_dict[secrets[i]]) sum_2 = group.wsum(secrets_2, generators2) p1 = DLRep(sum_1, wsum_secrets([x0, x1, x2], generators1)) p2 = DLRep(sum_2, wsum_secrets([x0, x3, x4, x5], generators2)) return p1, p2, secrets_dict
def test_and_dlrne_does_not_fail_on_same_dl_when_not_binding(): """ Prove (H0 = h0*x, H1 != h1*x), H2 = h2*x with same secret name x. Should not be detected as binding is off by default. """ secrets, secret_values, secret_dict = get_secrets(4) generators = make_generators(4) lhs_values = [x * g for x, g in zip(secret_values, generators)] y3 = secret_values[2] * generators[3] s0 = secrets[0] p1 = DLNotEqual([lhs_values[0], generators[0]], [lhs_values[1], generators[1]], s0) p2 = DLRep(lhs_values[2], s0 * generators[2]) andp = p1 & p2 s0_prime = Secret(name=secrets[0].name) p1_prime = DLNotEqual([lhs_values[0], generators[0]], [lhs_values[1], generators[1]], s0_prime) p2_prime = DLRep(lhs_values[2], s0_prime * generators[2]) andp_prime = p1_prime & p2_prime prov = andp.get_prover(secret_dict) prov.subs[1].secret_values[s0] = secret_values[2] protocol = SigmaProtocol(andp_prime.get_verifier(), prov) assert protocol.verify()
def test_and_proof_partially_defined_secrets(): generators = make_generators(2) x = Secret(value=4) x2 = Secret() p1 = DLRep(4 * generators[0], x * generators[0]) p2 = DLRep(3 * generators[1], x2 * generators[1]) andp = p1 & p2 tr = andp.prove({x2: 3}) assert andp.verify(tr)
def test_multiple_and_dlrep_fails_on_bad_secret_when_binding(): secrets, secret_values, secret_dict = get_secrets(4) generators = make_generators(4) lhs_values = [x * g for x, g in zip(secret_values, generators)] p1 = DLNotEqual( [lhs_values[0], generators[0]], [lhs_values[1], generators[1]], secrets[0], bind=True, ) p2 = DLRep(lhs_values[0], secrets[0] * generators[0]) p3 = DLNotEqual( [lhs_values[2], generators[2]], [lhs_values[1], generators[1]], secrets[2], bind=True, ) p4 = DLNotEqual( [lhs_values[1], generators[1]], [lhs_values[3], generators[3]], secrets[0], bind=True, ) andp = p1 & p2 & p3 & p4 p11 = DLNotEqual( [lhs_values[0], generators[0]], [lhs_values[1], generators[1]], secrets[0], bind=True, ) p21 = DLRep(lhs_values[0], secrets[0] * generators[0]) p31 = DLNotEqual( [lhs_values[2], generators[2]], [lhs_values[1], generators[1]], secrets[2], bind=True, ) p41 = DLNotEqual( [lhs_values[1], generators[1]], [lhs_values[3], generators[3]], secrets[0], bind=True, ) andp1 = p11 & p21 & p31 & p41 prov = andp.get_prover(secret_dict) prov.subs[1].secret_values[secrets[0]] = secret_values[1] protocol = SigmaProtocol(andp1.get_verifier(), prov) with pytest.raises(ValidationError): protocol.verify()
def prove_values(self, bpriv, reveal_mask=None): """A nizk proof of opening with the revealed values. The proof contains the raw value of all revealed values. This protocol does not reveal any information about non-revealed values. Error: Either reveal_mask should be None or have the same size of private values. Args: bpriv (BlPedersenPrivate): values and randomness. reveal_mask (boolean []): reveals value[i] iff reveal_mask[i] Optional: mask=None -> reveal nothing Returns: (BlPedersenProof): a nizk proof for commitment (self) """ param = bpriv.param if reveal_mask is None: reveal_mask = len(bpriv.values) * [False] if len(reveal_mask) != len(bpriv.values): raise Exception( 'The size of reveal mask does not match the number of attributes' ) # randomness expr_bl_z = bpriv.blindness_rand * param.Z expr_bl_h = bpriv.blindness_rand * param.H expr_bl_h2 = bpriv.blindness_rand * param.H_2 bl_h, bl_h2 = expr_bl_h.eval(), expr_bl_h2.eval() stmt = (DLRep(self.bl_z, expr_bl_z) & DLRep(bl_h, expr_bl_h) & DLRep(bl_h2, expr_bl_h2)) # attributes bl_hi = list() for i in range(len(bpriv.values)): expr = bpriv.blindness_rand * param.HS[i] bl_hi.append(expr.eval()) stmt = stmt & DLRep(bl_hi[i], expr) # proof revealed_values = list() revealed_acc = param.group.infinite() expr_bl_commit = bpriv.rand * bl_h + bpriv.rand_2 * bl_h2 for i in range(len(bpriv.values)): if reveal_mask[i]: revealed_values.append(bpriv.raw_values[i]) revealed_acc += bpriv.values[i].value * bl_hi[i] else: revealed_values.append(None) expr_bl_commit += bpriv.values[i] * bl_hi[i] stmt = stmt & DLRep(self.bl_commit - revealed_acc, expr_bl_commit) bproof = BlPedersenProof(bl_h=bl_h, bl_h2=bl_h2, bl_hi=bl_hi, revealed_values=revealed_values, nizk_proof=stmt.prove()) return bproof
def test_and_proof_with_complex_expression(group): g = group.generator() g1 = 2 * g g2 = 5 * g g3 = 10 * g x1 = Secret() x2 = Secret() x3 = Secret() proof = DLRep(10 * g1 + 15 * g2, x1 * g1 + x2 * g2) & DLRep( 15 * g1 + 35 * g3, x2 * g1 + x3 * g3) prover = proof.get_prover({x1: 10, x2: 15, x3: 35}) verifier = proof.get_verifier() assert verify(verifier, prover)
def test_and_proof_simulation_2(group): n = 3 secret_values = [Bn(i) for i in range(n)] secrets = [Secret() for _ in range(n)] generators = make_generators(n, group) lhs = group.wsum(secret_values, generators) subproof1 = DLRep(lhs, wsum_secrets(secrets, generators)) subproof2 = DLRep(lhs, wsum_secrets(secrets, generators)) andp = AndProofStmt(subproof1, subproof2) tr = andp.simulate() assert andp.verify_simulation_consistency(tr) assert not andp.verify(tr)
def test_and_proof_simulation_1(group): n = 3 secret_values = [Bn(i) for i in range(n)] secrets = [Secret() for _ in range(n)] generators = make_generators(n, group) lhs = group.wsum(secret_values, generators) subproof1 = DLRep(lhs, wsum_secrets(secrets, generators)) subproof2 = DLRep(lhs, wsum_secrets(secrets, generators)) andp = AndProofStmt(subproof1, subproof2) andv = andp.get_verifier() tr = andp.simulate_proof() tr.stmt_hash = andp.prehash_statement().digest() assert not andv.verify_nizk(tr)
def test_multiple_and_dlrep_binding(): secrets = get_secrets_new(4) generators = make_generators(4) lhs_values = [x.value * g for x, g in zip(secrets, generators)] p1 = DLNotEqual( [lhs_values[0], generators[0]], [lhs_values[1], generators[1]], secrets[0], bind=False, ) p2 = DLRep(lhs_values[2], secrets[2] * generators[2]) p3 = DLNotEqual( [lhs_values[2], generators[2]], [lhs_values[1], generators[1]], secrets[2], bind=True, ) p4 = DLNotEqual( [lhs_values[1], generators[1]], [lhs_values[3], generators[3]], secrets[1], bind=True, ) andp = p1 & p2 & p3 & p4 s0 = Secret() s2 = Secret() p1prime = DLNotEqual([lhs_values[0], generators[0]], [lhs_values[1], generators[1]], s0, bind=False) p2prime = DLRep(lhs_values[2], s2 * generators[2]) p3prime = DLNotEqual([lhs_values[2], generators[2]], [lhs_values[1], generators[1]], s2, bind=True) # Note difference: p4prime binds s0 instead of secrets[1] in the original proof p4prime = DLNotEqual([lhs_values[1], generators[1]], [lhs_values[3], generators[3]], s0, bind=True) andp1 = p1prime & p2prime & p3prime & p4prime protocol = SigmaProtocol(andp1.get_verifier(), andp.get_prover()) assert protocol.verify()
def verify_proof(self, bc_param, bproof): """Verify a PedersenProof for this commitment. Important: besides verifying the proof, you should verify the parameters. Args: bc_param (BlPedersenParam): commitment parameters bproof (BlPedersenProof): a nizk proof for self Returns: boolean: pass/fail """ if bc_param.get_param_num() < len(bproof.bl_hi): bc_param.expand_params_len(len(bproof.bl_hi)) bl_rand_sec = Secret(name="blindness_rand") # randomness expr_bl_z = bl_rand_sec * bc_param.Z expr_bl_h = bl_rand_sec * bc_param.H expr_bl_h2 = bl_rand_sec * bc_param.H_2 stmt = (DLRep(self.bl_z, expr_bl_z) & DLRep(bproof.bl_h, expr_bl_h) & DLRep(bproof.bl_h2, expr_bl_h2)) # attributes for i in range(len(bproof.bl_hi)): expr = bl_rand_sec * bc_param.HS[i] stmt = stmt & DLRep(bproof.bl_hi[i], expr) # proof revealed_acc = bc_param.group.infinite() expr_bl_commit = Secret(name="rand") * bproof.bl_h + Secret( name="rand_2") * bproof.bl_h2 for i in range(len(bproof.bl_hi)): if bproof.revealed_values[i] is None: expr_bl_commit += Secret(name=f"val_{i}") * bproof.bl_hi[i] else: val = bc_param.process_raw_value(bproof.revealed_values[i]) revealed_acc += val * bproof.bl_hi[i] stmt = stmt & DLRep(self.bl_commit - revealed_acc, expr_bl_commit) # Having an invalid revealed secret leads to different # {commit-revealed_acc} value between prover and verifier. Since this # value is a zksk.statement constant, the mismatch results in a # StatementMismatch exception. verify_proof checks for this exception # and convert it to False try: is_valid = stmt.verify(bproof.nizk_proof) except StatementMismatch: return False return is_valid
def test_multiple_or_proof_infix_operator(group, params): p1, p2, secrets = params g = group.generator() x10 = Secret() secrets.update({x10: 13}) orproof = p1 | p2 | DLRep(13 * g, x10 * g) assert verify_proof(orproof, secrets)
def test_multiple_or_proofs(group, params): p1, p2, secrets = params g = group.generator() x10 = Secret() secrets.update({x10: 13}) orproof = OrProofStmt(p1, OrProofStmt(p2, DLRep(13 * g, x10 * g))) assert verify_proof(orproof, secrets)
def test_multiple_dlrne_simulation(): secrets, secret_values, secret_dict = get_secrets(4) generators = make_generators(4) lhs_values = [x * g for x, g in zip(secret_values, generators)] p1 = DLNotEqual( [lhs_values[0], generators[0]], [lhs_values[1], generators[1]], secrets[0], bind=False, ) p2 = DLRep(lhs_values[2], secrets[2] * generators[2]) p3 = DLNotEqual( [lhs_values[2], generators[2]], [lhs_values[1], generators[1]], secrets[2], bind=True, ) p4 = DLNotEqual( [lhs_values[1], generators[1]], [lhs_values[3], generators[3]], secrets[0], bind=True, ) andp = p1 & p2 & p3 & p4 tr = andp.simulate() assert andp.verify_simulation_consistency(tr) assert not andp.verify(tr)
def test_dlrep_or_rangeproof(group): g, h = make_generators(2) x = Secret(9) y = Secret(42) z = Secret(40) c = x.value * g + y.value * h c2 = z.value * g + y.value * h stmt1 = DLRep(c, x * g + y * h) & RangeStmt(c, g, h, 0, 50, x, y) stmt2 = DLRep(c2, z * g + y * h) & RangeStmt(c2, g, h, 0, 50, z, y) stmt1.set_simulated() or_stmt = OrProofStmt(stmt1, stmt2) nizk = or_stmt.prove() assert or_stmt.verify(nizk)
def test_and_or_proof_composition(params): p1, p2, secrets = params g1 = 7 * p1.bases[0] g2 = 8 * p1.bases[0] xb = Secret(name="xb") xa = Secret(name="xa") p0 = DLRep(7 * g1 + 18 * g2, xb * g1 + xa * g2) secrets[xb] = 7 secrets[xa] = 18 orproof = OrProofStmt(p1, p2) andp = AndProofStmt(orproof, p0) andp = AndProofStmt(andp, DLRep(15 * p1.bases[0], Secret(value=15) * p1.bases[0])) prover = andp.get_prover(secrets) verifier = andp.get_verifier() assert verify(verifier, prover)
def test_multiple_or_proofs_composition(group, params): p1, p2, secrets = params g = group.generator() x10 = Secret() secrets.update({x10: 13}) orp1 = OrProofStmt(p2, p1) orp2 = OrProofStmt(p1, DLRep(13 * g, x10 * g)) orproof = OrProofStmt(orp1, p2, orp2) assert verify_proof(orproof, secrets)
def test_invalid_or_composition_inside_two_or(): r = Secret(10) g1, g2, g3, g4 = make_generators(4) st11 = DLRep(r.value * g1, r * g1) st12 = DLRep(2 * g2, r * g2) st12.set_simulated() st1 = st11 | st12 st21 = DLRep(7 * g3, r * g3) st21.simluation = True st22 = DLRep(r.value * g4, r * g4) st2 = st21 | st22 st = st1 & st2 with pytest.raises(InvalidSecretsError): st.prove()
def test_statement_zk_proof() -> None: vm = sy.VirtualMachine() client = vm.get_root_client() sy.load("zksk") # third party from zksk import DLRep from zksk import Secret from zksk import utils num = 2 seed = 42 num_sy = sy.lib.python.Int(num) seed_sy = sy.lib.python.Int(seed) # Setup: Peggy and Victor agree on two group generators. G, H = utils.make_generators(num=num, seed=seed) # Setup: generate a secret randomizer. r = Secret(utils.get_random_num(bits=128)) # This is Peggy's secret bit. top_secret_bit = 1 # A Pedersen commitment to the secret bit. C = top_secret_bit * G + r.value * H # Peggy's definition of the proof statement, and proof generation. # (The first or-clause corresponds to the secret value 0, and the second to the value 1. Because # the real value of the bit is 1, the clause that corresponds to zero is marked as simulated.) stmt = DLRep(C, r * H, simulated=True) | DLRep(C - G, r * H) zk_proof = stmt.prove() # send over the network and get back num_ptr = num_sy.send(client) seed_prt = seed_sy.send(client) c_ptr = C.send(client) zk_proof_ptr = zk_proof.send(client) num2 = num_ptr.get().upcast() seed2 = seed_prt.get().upcast() C2 = c_ptr.get() zk_proof2 = zk_proof_ptr.get() # Setup: get the agreed group generators. G, H = utils.make_generators(num=num2, seed=seed2) # Setup: define a randomizer with an unknown value. r = Secret() stmt = DLRep(C2, r * H) | DLRep(C2 - G, r * H) assert stmt.verify(zk_proof2)
def test_dlrep_and_dlrne_fails_on_same_dl_when_binding(): """ Prove (H0 = h0*x, H1 != h1*x), H2 = h2*x with same secret name x. Should be detected as binding is on. """ secrets, secret_values, secret_dict = get_secrets(4) generators = make_generators(4) lhs_values = [x * g for x, g in zip(secret_values, generators)] y3 = secret_values[2] * generators[3] p1 = DLNotEqual( [lhs_values[0], generators[0]], [lhs_values[1], generators[1]], secrets[0], bind=True, ) p2 = DLRep(lhs_values[2], secrets[0] * generators[2]) andp = p1 & p2 # Twin proof s0_prime = Secret(name=secrets[0].name) p1_prime = DLNotEqual( [lhs_values[0], generators[0]], [lhs_values[1], generators[1]], s0_prime, bind=True, ) p2_prime = DLRep(lhs_values[2], s0_prime * generators[2]) andp_prime = p1_prime & p2_prime prov = andp.get_prover(secret_dict) prov.subs[1].secret_values[secrets[0]] = secret_values[2] ver = andp_prime.get_verifier() ver.process_precommitment(prov.precommit()) com = prov.commit() chal = ver.send_challenge(com) resp = prov.compute_response(chal) with pytest.raises(ValidationError): ver.verify(resp)
def test_and_dlrne_non_interactive_1(group): g = group.generator() x = Secret(value=3) y = 3 * g y2 = 397474 * g g2 = 1397 * g pr = DLNotEqual([y, g], [y2, g2], x, bind=True) p2 = DLNotEqual([2 * y, 2 * g], [y2, g2], x, bind=True) andp = pr & p2 & DLRep(y, x * g) tr = andp.prove() assert andp.verify(tr)
def test_and_dlrne_non_interactive_2(): secrets, secret_values, secret_dict = get_secrets(4) generators = make_generators(4) lhs_values = [x * g for x, g in zip(secret_values, generators)] p1 = DLNotEqual( [lhs_values[0], generators[0]], [lhs_values[1], generators[1]], secrets[0], bind=True, ) p2 = DLRep(lhs_values[0], secrets[0] * generators[0]) p3 = DLNotEqual( [lhs_values[2], generators[2]], [lhs_values[1], generators[1]], secrets[2], bind=True, ) andp = p1 & p2 & p3 s0 = Secret() s2 = Secret() p11 = DLNotEqual([lhs_values[0], generators[0]], [lhs_values[1], generators[1]], s0, bind=True) p21 = DLRep(lhs_values[0], s0 * generators[0]) p31 = DLNotEqual([lhs_values[2], generators[2]], [lhs_values[1], generators[1]], s2, bind=True) andp1 = p11 & p21 & p31 tr = andp.prove(secret_dict) assert andp1.verify(tr)
def test_and_proof_fails_when_bases_belong_to_different_groups(group): """ An alien EcPt is inserted in the generators """ g1 = group.generator() other_group = EcGroup(706) assert group != other_group g2 = other_group.generator() x = Secret(value=Bn(42)) y1 = group.wsum([x.value], [g1]) y2 = other_group.wsum([x.value], [g2]) p1 = DLRep(y1, wsum_secrets([x], [g1])) p2 = DLRep(y2, wsum_secrets([x], [g2])) and_proof = AndProofStmt(p1, p2) prover = and_proof.get_prover() verifier = and_proof.get_verifier() # An exception should be raised because of a shared secrets linked to two different groups with pytest.raises(GroupMismatchError): verify(verifier, prover)
def test_nizk_serde() -> None: vm = sy.VirtualMachine() client = vm.get_root_client() # third party from zksk import DLRep from zksk import Secret from zksk import utils sy.load("zksk") num = 2 seed = 42 G, H = utils.make_generators(num=num, seed=seed) # Setup: generate a secret randomizer. r = Secret(utils.get_random_num(bits=128)) # This is Peggy's secret bit. top_secret_bit = 1 # A Pedersen commitment to the secret bit. C = top_secret_bit * G + r.value * H # Peggy's definition of the proof statement, and proof generation. # (The first or-clause corresponds to the secret value 0, and the second to the value 1. Because # the real value of the bit is 1, the clause that corresponds to zero is marked as simulated.) stmt = DLRep(C, r * H, simulated=True) | DLRep(C - G, r * H) # zksk.base.NIZK zk_proof = stmt.prove() # test serde zk_proof_ptr = zk_proof.send(client) zk_proof2 = zk_proof_ptr.get() assert zk_proof == zk_proof2
def test_malicious_and_proofs(): x0 = Secret() x2 = Secret() x1 = Secret() generators = make_generators(3) g1 = generators[0] g2 = generators[1] g3 = generators[2] secret_dict = {x0: 3, x2: 50, x1: 12} mal_secret_dict = {x0: 3, x2: 51} andp = AndProofStmt( DLRep(12 * g1 + 50 * g2, x1 * g1 + x2 * g2), DLRep(3 * g3 + 51 * g2, x0 * g1 + x2 * g2), ) prov = andp.get_prover(secret_dict) prov.subs[1].secret_values = mal_secret_dict verif = andp.get_verifier() com = prov.commit() chal = verif.send_challenge(com) resp = prov.compute_response(chal) with pytest.raises(ValidationError): verif.verify(resp)
def test_or_and_proof_composition(params): p1, p2, secrets = params andp = AndProofStmt(p1, p2) g1 = 7 * p1.bases[0] g2 = 8 * p1.bases[0] xb = Secret(name="xb") xa = Secret(name="xa") p0 = DLRep(7 * g1 + 18 * g2, xb * g1 + xa * g2) secrets[xa] = 7 secrets[Secret(name="xc")] = 18 orproof = OrProofStmt(p0, andp) prover = orproof.get_prover(secrets) verifier = orproof.get_verifier() assert verify(verifier, prover)
def test_invalid_or_composition(): r = Secret(10) g1, g2, g3 = make_generators(3) st1 = DLRep(10 * g1, r * g1) st21 = DLRep(10 * g2, r * g2) st22 = DLRep(12 * g3, r * g3) st22.set_simulated() st2 = st21 | st22 st = st1 & st2 with pytest.raises(InvalidSecretsError): st.prove()
def ZK_equality(G,H): ##Generate two El-Gamal ciphertexts (C1,C2) and (D1,D2) # Setup: generate secret randomizers. # m is the secret bit. m = Secret(utils.get_random_num(bits=2)) r1 = Secret(utils.get_random_num(bits=128)) r2 = Secret(utils.get_random_num(bits=128)) C1 = r1.value*G #print("this is C1:", C1) C2 = r1.value * H + m.value * G D1 = r2.value * G D2 = r2.value * H + m.value * G ##Generate a NIZK proving equality of the plaintexts stmt = DLRep(C1,r1*G) & DLRep(C2,r1*H+m*G) & DLRep(D1,r2*G) & DLRep(D2,r2*H+m*G) zk_proof = stmt.prove() #Return two ciphertexts and the proof return (C1,C2), (D1,D2), zk_proof
g3 = group.hash_to_point(b"three") # Preparing the secrets. # In practice, they probably should be big integers (petlib.bn.Bn) x0 = Secret() x1 = Secret() x2 = Secret() # Set up the proof statement. # First, compute the values, "left-hand side". y1 = 4 * g0 + 5 * g1 y2 = 4 * g2 + 7 * g3 # Next, create the proof statement. stmt = DLRep(y1, x0 * g0 + x1 * g1) \ & DLRep(y2, x0 * g2 + x2 * g3) # This is an equivalent way to create the proof statement above. stmt_1 = DLRep(y1, x0 * g0 + x1 * g1) stmt_2 = DLRep(y2, x0 * g2 + x2 * g3) equivalent_stmt = AndProofStmt(stmt_1, stmt_2) assert stmt.get_proof_id() == equivalent_stmt.get_proof_id() # Simulate the prover and verifier interacting. prover = stmt.get_prover({x0: 4, x1: 5, x2: 7}) verifier = stmt.get_verifier() commitment = prover.commit()
from zksk import Secret, DLRep group = EcGroup() # Create the base points on the curve. g0 = group.hash_to_point(b"one") g1 = group.hash_to_point(b"two") g2 = group.hash_to_point(b"three") # Preparing the secrets. # In practice, they probably should be big integers (petlib.bn.Bn) x0 = Secret(value=3) x1 = Secret(value=40) x2 = Secret(value=50) # Set up the proof statement. y0 = x0.value * g0 y1 = x1.value * g1 y2 = x2.value * g2 stmt = (DLRep(y0, x0 * g0) | DLRep(y1, x1 * g1)) & DLRep(y2, x2 * g2) # Execute the protocol. prover = stmt.get_prover() verifier = stmt.get_verifier() commitment = prover.commit() challenge = verifier.send_challenge(commitment) response = prover.compute_response(challenge) assert verifier.verify(response)