def commit(self, messages, zkp=True): """ Construct the product of messages and optionaly a Pedersen commitment and its proof. Args: messages: Messages (attributes) to commit to zkp (bool): Whether to construct a Pedersen commitment and proof the knowledge of the messages for this commitment. Returns: :py:class:`UserCommitmentMessage`: user's packed commitment. """ lhs = self.pk.generators[0].group.wsum( messages, self.pk.generators[2 : len(messages) + 2] ) com_nizk_proof = None if zkp: self.s1 = self.pk.generators[0].group.order().random() lhs = self.s1 * self.pk.generators[1] + lhs # TODO: Extract into a separate ExtendedProofStmt. secret_vars = [Secret() for _ in range(len(messages) + 1)] secrets = [self.s1] + messages rhs = wsum_secrets(secret_vars, self.pk.generators[1 : len(messages) + 2]) com_stmt = DLRep(lhs, rhs) com_nizk_proof = com_stmt.prove( {s: v for s, v in zip(secret_vars, secrets)} ) return UserCommitmentMessage(com_message=lhs, com_nizk_proof=com_nizk_proof)
def construct_stmt(self, precommitment): infty = self.generators[0].group.infinite() p1 = DLRep(infty, self.alpha * self.generators[0] + self.beta * self.lhs[0]) p2 = DLRep(precommitment, self.alpha * self.generators[1] + self.beta * self.lhs[1]) return p1 & p2
def construct_stmt(self, precommitment): r""" Proof of knowledge of a signature. This is an implementation of a proof :math:`\Pi_5` detailed on page 7 of the `Constant-Size Dynamick-TAA` paper. """ self.A1, self.A2 = precommitment["A1"], precommitment["A2"] g0, g1, g2 = self.bases[0], self.bases[1], self.bases[2] dl1 = DLRep(self.A1, self.r1 * g1 + self.r2 * g2) dl2 = DLRep( g0.group.infinite(), self.delta1 * g1 + self.delta2 * g2 + self.secret_vars[0] * (-1 * self.A1), ) self.pair_lhs = self.A2.pair(self.pk.w) + (-1 * self.pk.gen_pairs[0]) bases = [ -1 * (self.A2.pair(self.pk.h0)), self.bases[2].pair(self.pk.w), self.pk.gen_pairs[2], ] bases.extend(self.pk.gen_pairs[1 : len(self.bases)]) # Build secret names [e, r1, delta1, s, m_i] new_secret_vars = ( self.secret_vars[:1] + [self.r1, self.delta1] + self.secret_vars[1:] ) pairings_stmt = DLRep(self.pair_lhs, wsum_secrets(new_secret_vars, bases)) constructed_stmt = AndProofStmt(dl1, dl2, pairings_stmt) constructed_stmt.lhs = [p.lhs for p in constructed_stmt.subproofs] return constructed_stmt
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_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_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_same_random_values_in_commitments(group): (g, ) = make_generators(1, group) generators = [g, g, g] pub = group.wsum([Bn(100), Bn(100), Bn(100)], generators) x = Secret() p = DLRep(pub, wsum_secrets([x, x, x], generators)) prover = p.get_prover({x: 100}) commitments = prover.commit()
def test_dlrep_interactive_1(group): sk, g = group.order().random(), group.generator() pk = sk * g x = Secret() p = DLRep(pk, x * g) prover = p.get_prover({x: sk}) verifier = p.get_verifier() protocol = SigmaProtocol(verifier, prover) assert 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_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_get_many_different_provers(group, num): generators = make_generators(num, group) secrets = [Secret(name="secret_%i" % i) for i in range(num)] secrets_vals = [Bn(i) for i in range(num)] secret_dict = {secret: val for secret, val in zip(secrets, secrets_vals)} p = DLRep(group.wsum(secrets_vals, generators), wsum_secrets(secrets, generators)) prover = p.get_prover(secret_dict) _, commitment = prover.commit() assert isinstance(commitment, EcPt)
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 verify_blinding(self, pk): """ Verify the NIZK proof for Pedersen commitment. """ if self.com_nizk_proof is None: raise ValueError("No proof to verify") # TODO: Extract into a separate ExtendedProofStmt. lhs = self.com_message generators = pk.generators[1 : len(self.com_nizk_proof.responses) + 1] secret_vars = [Secret() for _ in self.com_nizk_proof.responses] proof = DLRep(lhs, wsum_secrets(secret_vars, generators)) return proof.verify(self.com_nizk_proof)
def construct_stmt(self, precommitment): """ Construct the internal proof statement. """ if self.is_prover: # Indicators that tell us which or-clause is true actual_value = ensure_bn(self.x.value) value_as_bits = decompose_into_n_bits(actual_value, self.num_bits) zero_simulated = [b == 1 for b in value_as_bits] one_simulated = [b == 0 for b in value_as_bits] bit_proofs = [] for i in range(self.num_bits): p0 = DLRep(precommitment["Cs"][i], self.randomizers[i] * self.h) p1 = DLRep(precommitment["Cs"][i] - self.g, self.randomizers[i] * self.h) # When we are a prover, mark which disjunct is true if self.is_prover: p0.set_simulated(zero_simulated[i]) p1.set_simulated(one_simulated[i]) bit_proofs.append(p0 | p1) return AndProofStmt(*bit_proofs)
def test_generators_sharing_a_secret(group, num): generators = make_generators(num, group) unique_secret = 4 x = Secret() secret_vals = [Bn(unique_secret) for _ in range(num)] lhs = group.wsum(secret_vals, generators) rhs = wsum_secrets([x] * num, generators) p = DLRep(lhs, rhs) prover = p.get_prover({x: unique_secret}) assert isinstance(prover, DLRepProver) _, commitment = prover.commit() assert isinstance(commitment, EcPt)
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 construct_stmt(self, precommitment): """ Build the internal proof statement. See the formula in Protocol 1 of the `Thinking Inside the BLAC Box: Smarter Protocols for Faster Anonymous Blacklisting` paper. """ infty = self.g.group.infinite() p1 = DLRep(infty, self.alpha * self.g + self.beta * self.lhs[0]) p2 = DLRep(precommitment, self.alpha * self.h + self.beta * self.lhs[1]) statements = [p1, p2] if self.bind: # If the binding parameter is set, we add a DLRep member repeating # the first member without randomizing the secret. statements.append(DLRep(self.lhs[0], self.x * self.g)) return AndProofStmt(*statements)
def __call__(self, com, g, h, a, b, x, r): """ Get a conjunction of two range-power-of-two proofs. Args: com: Value of the Pedersen commitment, :math:`C = x G + r H` g: First commitment base point :math:`G` h: Second commitment base point :math:`H` a: Lower limit :math:`a` b: Upper limit :math:`b` x: Value for which we construct a range proof r: Randomizer of the commitment :math:`r` """ a = ensure_bn(a) b = ensure_bn(b) num_bits = (b - a - 1).num_bits() offset = Bn(2)**num_bits - (b - a) com_shifted1 = com - a * g com_shifted2 = com_shifted1 + offset * g x1 = Secret() x2 = Secret() if x.value is not None: x1.value = x.value - a x2.value = x.value - a + offset # Ensure secret is in range if x.value < a or x.value >= b: warnings.warn("Secret outside of given range [{}, {})".format( a, b)) com_stmt = DLRep(com, x * g + r * h) p1 = PowerTwoRangeStmt( com=com_shifted1, g=g, h=h, num_bits=num_bits, x=x1, randomizer=r, ) p2 = PowerTwoRangeStmt( com=com_shifted2, g=g, h=h, num_bits=num_bits, x=x2, randomizer=r, ) return com_stmt & p1 & p2
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 __call__(self, a, b, x=None): """ Get a conjunction of two range-power-of-two proofs. Args: a: Lower limit :math:`a` b: Upper limit :math:`b` x: Value for which we construct a range proof """ group = EcGroup() g = group.hash_to_point(b"g") h = group.hash_to_point(b"h") r = Secret(value=group.order().random()) com = (x * g + r * h).eval() a = ensure_bn(a) b = ensure_bn(b) num_bits = (b - a - 1).num_bits() offset = Bn(2)**num_bits - (b - a) com_shifted1 = com - a * g com_shifted2 = com_shifted1 + offset * g x1 = Secret() x2 = Secret() if x is not None: x1.value = x.value - a x2.value = x.value - a + offset com_stmt = DLRep(com, x * g + r * h) p1 = PowerTwoRangeStmt( com=com_shifted1, g=g, h=h, num_bits=num_bits, x=x1, randomizer=r, ) p2 = PowerTwoRangeStmt( com=com_shifted2, g=g, h=h, num_bits=num_bits, x=x2, randomizer=r, ) return com_stmt & p1 & p2
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_dlrep_non_interactive_2(group): (g, ) = make_generators(1, group) x = Secret() p = DLRep(4 * g, x * g) tr = p.prove({x: 4}) assert p.verify(tr)