def test_dlrep_non_interactive_1(group): g, h = make_generators(2, group) expr = Secret(value=3) * g + Secret(value=4) * h p = DLRep(expr.eval(), expr) tr = p.prove() prover = p.get_prover() assert p.verify(tr)
def test_bbsplus_and_range(): from zksk.primitives.rangeproof import RangeStmt from zksk.utils import make_generators mG = BilinearGroupPair() keypair = BBSPlusKeypair.generate(mG, 9) pk, sk = keypair.pk, keypair.sk generators, h0 = keypair.generators, keypair.h0 creator = BBSPlusSignatureCreator(pk) msg_val = Bn(30) lhs = creator.commit([msg_val]) presignature = sk.sign(lhs.com_message) signature = creator.obtain_signature(presignature) e, s, m = Secret(signature.e), Secret(signature.s), Secret(msg_val) p1 = BBSPlusSignatureStmt([e, s, m], pk, signature) g, h = make_generators(2, mG.G1) randomizer = Secret(value=mG.G1.order().random()) com = m * g + randomizer * h p2 = RangeStmt(com.eval(), g, h, 18, 9999, m, randomizer) stmt = p1 & p2 proof = stmt.prove() assert stmt.verify(proof)
def test_signature_non_interactive_proof(): mG = BilinearGroupPair() keypair = BBSPlusKeypair.generate(mG, 9) messages = [Bn(30), Bn(31), Bn(32)] pk, sk = keypair.pk, keypair.sk generators, h0 = keypair.generators, keypair.h0 creator = BBSPlusSignatureCreator(pk) lhs = creator.commit(messages) presignature = sk.sign(lhs.com_message) signature = creator.obtain_signature(presignature) e, s, m1, m2, m3 = (Secret() for _ in range(5)) secret_dict = { e: signature.e, s: signature.s, m1: messages[0], m2: messages[1], m3: messages[2], } p1 = BBSPlusSignatureStmt([e, s, m1, m2, m3], pk, signature) tr = p1.prove(secret_dict) p1 = BBSPlusSignatureStmt([Secret() for _ in range(5)], pk) assert p1.verify(tr)
def test_signature_proof(): mG = BilinearGroupPair() keypair = BBSPlusKeypair.generate(mG, 9) messages = [Bn(30), Bn(31), Bn(32)] pk, sk = keypair.pk, keypair.sk generators, h0 = keypair.generators, keypair.h0 creator = BBSPlusSignatureCreator(pk) lhs = creator.commit(messages) presignature = sk.sign(lhs.com_message) signature = creator.obtain_signature(presignature) e, s, m1, m2, m3 = (Secret() for _ in range(5)) secret_dict = { e: signature.e, s: signature.s, m1: messages[0], m2: messages[1], m3: messages[2], } p1 = BBSPlusSignatureStmt([e, s, m1, m2, m3], pk, signature) prover = p1.get_prover(secret_dict) p2 = BBSPlusSignatureStmt([Secret() for _ in range(5)], pk) verifier = p2.get_verifier() pc = prover.precommit() verifier.process_precommitment(pc) com = prover.commit() chal = verifier.send_challenge(com) resp = prover.compute_response(chal) assert verifier.verify(resp)
def test_and_proof_different_environments(params): x, y = Secret(), Secret() p1, p2, secrets_dict = params and_proof = AndProofStmt(p1, p2) prover = and_proof.get_prover(secrets_dict) verifier = and_proof.get_verifier() assert verify(verifier, prover)
def test_dlrep_simulation(group): g, h = make_generators(2, group=group) x, y = Secret(value=3), Secret(value=4) expr = x * g + y * h p = DLRep(expr.eval(), expr) tr = p.simulate() assert (not p.verify(tr)) and p.verify_simulation_consistency(tr)
def test_dlrep_non_interactive_with_message(group): g, h = make_generators(2, group) expr = Secret(value=3) * g + Secret(value=4) * h p = DLRep(expr.eval(), expr) tr = p.prove(message="mymessage") assert DLRep(expr.eval(), expr).verify(tr, message="mymessage")
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_dlrep_interactive_2(group): g, h = make_generators(2, group) x, y = Secret(), Secret() p = DLRep(10 * g + 15 * h, x * g + y * h) prover = p.get_prover({x: 10, y: 15}) verifier = p.get_verifier() protocol = SigmaProtocol(verifier, prover) assert protocol.verify()
def test_dlrep_bad_hash(group): g, h = make_generators(2, group=group) x, y = Secret(), Secret() secret_dict = {x: 2, y: 3} p1 = DLRep(2 * g + 3 * h, x * g + y * h) p2 = DLRep(2 * g + 3 * h, y * h + x * g) tr = p1.prove(secret_dict) assert p1.verify(tr) with pytest.raises(StatementMismatch): p2.verify(tr)
def test_dlne_non_interactive_2(group): g = group.generator() x = Secret(value=3) y = 3 * g y2 = 397474 * g g2 = 1397 * g p1 = DLNotEqual([y, g], [y2, g2], x, bind=True) tr = p1.prove() p2 = DLNotEqual([y, g], [y2, g2], Secret(), bind=True) assert p2.verify(tr)
def test_range_stmt_non_interactive_outside_range(group): x = Secret(value=15) randomizer = Secret(value=group.order().random()) g, h = make_generators(2, group) lo = 7 hi = 15 com = x * g + randomizer * h with pytest.warns(UserWarning): stmt = RangeStmt(com.eval(), g, h, lo, hi, x, randomizer)
def test_dlrep_wrong_secrets(group): g = group.generator() g1 = 2 * g g2 = 5 * g x1 = Secret() x2 = Secret() p = DLRep(g, x1 * g1 + x2 * g2) prover = p.get_prover({x1: 10, x2: 15}) verifier = p.get_verifier() protocol = SigmaProtocol(verifier, prover) assert not protocol.verify()
def test_dlrep_wrong_public_elements(group): g, h = make_generators(2, group=group) x, y = Secret(value=3), Secret(value=4) expr = x * g + y * h public_wrong = get_random_point() p = DLRep(public_wrong, expr) prover = p.get_prover() verifier = p.get_verifier() protocol = SigmaProtocol(verifier, prover) assert not protocol.verify()
def test_dlrep_wrong_response_non_interactive(group): g, h = make_generators(2, group=group) x, y = Secret(value=3), Secret(value=4) expr = x * g + y * h p = DLRep(expr.eval(), expr) tr = p.prove(message="mymessage") # Turn one of the responses random tr.responses[1] = group.order().random() assert not p.verify(tr, message="mymessage")
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_diff_groups_dlrep(group): g, h = make_generators(2, group) x, y = Secret(), Secret() # Precondition for the test. other_group = EcGroup(706) assert other_group != group, "Test assumption is broken." h = other_group.generator() expr = x * g + y * h z = get_random_point(group) with pytest.raises(InvalidExpression): p = DLRep(z, expr)
def test_range_stmt_non_interactive_start_at_zero(group): x = Secret(value=3) randomizer = Secret(value=group.order().random()) g, h = make_generators(2, group) lo = 0 hi = 5 com = x * g + randomizer * h stmt = RangeStmt(com.eval(), g, h, lo, hi, x, randomizer) tr = stmt.prove() assert stmt.verify(tr)
def test_signature_and_dlrne_fails_on_wrong_secret(): """ We manually modify a secret in the DLNE member, i.e we wrongfully claim to use the same "s" i the signature and in the DLNE. Should be detected and raise an Exception. """ mG = BilinearGroupPair() keypair = BBSPlusKeypair.generate(mG, 9) messages = [Bn(30), Bn(31), Bn(32)] pk, sk = keypair.pk, keypair.sk generators, h0 = keypair.generators, keypair.h0 creator = BBSPlusSignatureCreator(pk) lhs = creator.commit(messages) presignature = sk.sign(lhs.com_message) signature = creator.obtain_signature(presignature) e, s, m1, m2, m3 = (Secret() for _ in range(5)) secret_dict = { e: signature.e, s: signature.s, m1: messages[0], m2: messages[1], m3: messages[2], } sigproof = BBSPlusSignatureStmt([e, s, m1, m2, m3], pk, signature) g1 = mG.G1.generator() pg1 = signature.s * g1 pg2, g2 = mG.G1.order().random() * g1, mG.G1.order().random() * g1 dneq = DLNotEqual((pg1, g1), (pg2, g2), s, bind=True) secrets = [Secret() for _ in range(5)] sigproof1 = BBSPlusSignatureStmt(secrets, pk, signature) dneq1 = DLNotEqual((pg1, g1), (pg2, g2), secrets[1], bind=True) andp = sigproof & dneq andp1 = sigproof1 & dneq1 prov = andp.get_prover(secret_dict) prov.subs[1].secret_values[s] = signature.s + 1 ver = andp1.get_verifier() ver.process_precommitment(prov.precommit()) commitment = prov.commit() challenge = ver.send_challenge(commitment) responses = prov.compute_response(challenge) with pytest.raises(ValidationError): ver.verify(responses)
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_range_proof_outside(): group = EcGroup() x = Secret(value=15) randomizer = Secret(value=group.order().random()) g, h = make_generators(2, group) lo = 0 hi = 14 com = x * g + randomizer * h with pytest.raises(Exception): stmt = RangeStmt(com.eval(), g, h, lo, hi, x, randomizer) nizk = stmt.prove() stmt.verify(nizk)
def test_signature_and_dlrne_does_not_fail_on_wrong_secret_when_non_binding(): """ Manually modify a secret in the DLNE member, i.e we wrongfully claim to use the same "s" i the signature and in the DLNE. Should not be detected since bindings in the DLNE are False. """ mG = BilinearGroupPair() keypair = BBSPlusKeypair.generate(mG, 9) messages = [Bn(30), Bn(31), Bn(32)] pk, sk = keypair.pk, keypair.sk generators, h0 = keypair.generators, keypair.h0 creator = BBSPlusSignatureCreator(pk) lhs = creator.commit(messages) presignature = sk.sign(lhs.com_message) signature = creator.obtain_signature(presignature) e, s, m1, m2, m3 = (Secret() for _ in range(5)) secret_dict = { e: signature.e, s: signature.s, m1: messages[0], m2: messages[1], m3: messages[2], } sigproof = BBSPlusSignatureStmt([e, s, m1, m2, m3], pk, signature) g1 = mG.G1.generator() pg1 = signature.s * g1 + g1 pg2, g2 = mG.G1.order().random() * g1, mG.G1.order().random() * g1 splus = Secret(signature.s + 1) dneq = DLNotEqual((pg1, g1), (pg2, g2), splus, bind=False) secrets = [Secret() for _ in range(5)] sigproof1 = BBSPlusSignatureStmt(secrets, pk, signature) # Note difference: dneq above uses an independent secret for dneq, # here it is bound to the secret s (secrets[1]) from the signature proof dneq1 = DLNotEqual((pg1, g1), (pg2, g2), secrets[1]) andp = sigproof & dneq andp1 = sigproof1 & dneq1 prov = andp.get_prover(secret_dict) ver = andp1.get_verifier() ver.process_precommitment(prov.precommit()) commitment = prov.commit() challenge = ver.send_challenge(commitment) responses = prov.compute_response(challenge) assert ver.verify(responses)
def blind_commit(self, raw_values, blindness_rand=None, h_rand=None): """"a blind commitment to values. Arguments blindness_rand and h_rand enable ACL compatability. Args: raw_values (Bn mod q/string/bytes []): committed values. blindness_rand (Bn mod q): forces the blinding's randomness. (optional) h_rand (Bn): fix the randomness for H. (optional) Raises: Error: bad value encoding. values can only be Bn, bytes, or string. Error: blindness generator is unknown Returns: BlPedersenCommitment: commitment BlPedersenPrivate: commitment's values and randomness """ values = [self.process_raw_value(raw) for raw in raw_values] if len(values) > len(self.HS): self.expand_params_len(len(values)) rand = self.q.random() rand_2 = self.q.random() if h_rand is not None: rand = h_rand if blindness_rand is None: blindness_rand = self.q.random() C = rand * self.H + rand_2 * self.H_2 C += self.group.wsum(values, self.HS[:len(values)]) bl_commit = blindness_rand * C bl_z = blindness_rand * self.Z bcommit = BlPedersenCommitment(bl_z=bl_z, bl_commit=bl_commit) bpriv = BlPedersenPrivate( param=self, raw_values=raw_values, values=[ Secret(val, name=f"val_{i}") for (i, val) in enumerate(values) ], rand=Secret(rand, name="rand"), rand_2=Secret(rand_2, name="rand_2"), blindness_rand=Secret(blindness_rand, name="blindness_rand"), ) return (bcommit, bpriv)
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_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 test_range_stmt_non_interactive_start_at_nonzero(group): x = Secret(value=14) randomizer = Secret(value=group.order().random()) g, h = make_generators(2, group) lo = 6 hi = 16 com = x * g + randomizer * h stmt1 = RangeStmt(com.eval(), g, h, lo, hi, x, randomizer) tr = stmt1.prove() stmt2 = RangeStmt(com.eval(), g, h, lo, hi, Secret(), Secret()) assert stmt2.verify(tr)
def test_dlrep_interactive_3(group): """Emulate actual workflow with independent provers and verifiers.""" sk, g = group.order().random(), group.generator() pk = sk * g x = Secret() p1 = DLRep(pk, x * g) prover = p1.get_prover({x: sk}) x = Secret() p2 = DLRep(pk, x * g) verifier = p2.get_verifier() protocol = SigmaProtocol(verifier, prover) assert protocol.verify()
def test_and_dlrep_partial_binding(): """ Claim to use (H0 = h0*x, H1 != h1*x) , (H1 = h1*x, H3 != h3*x) with the same x (not only cheating, a contradiction). Should be undetected as binding is off in at least one proof """ secrets = get_secrets_new(4) generators = make_generators(4) lhs_values = [x.value * g for x, g in zip(secrets, generators)] y3 = secrets[2].value * generators[3] p1 = DLNotEqual( [lhs_values[0], generators[0]], [lhs_values[1], generators[1]], secrets[0], bind=False, ) p2 = DLNotEqual([lhs_values[1], generators[1]], [y3, generators[3]], secrets[1], bind=True) andp = p1 & p2 sprime = Secret() p1_prime = DLNotEqual( [lhs_values[0], generators[0]], [lhs_values[1], generators[1]], sprime, bind=False, ) p2_prime = DLNotEqual([lhs_values[1], generators[1]], [y3, generators[3]], sprime, bind=True) andp_prime = p1_prime & p2_prime protocol = SigmaProtocol(andp_prime.get_verifier(), andp.get_prover()) assert protocol.verify()
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_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()