def verify(self): """ This implementation of verify has several steps. First, it reorganizes the pubkeys and messages into groups, where each group corresponds to a message. Then, it checks if the siganture has info on how it was aggregated. If so, we exponentiate each pk based on the exponent in the AggregationInfo. If not, we find public keys that share messages with others, and aggregate all of these securely (with exponents.). Finally, since each public key now corresponds to a unique message (since we grouped them), we can verify using the distinct verification procedure. """ message_hashes = self.aggregation_info.message_hashes public_keys = self.aggregation_info.public_keys assert (len(message_hashes) == len(public_keys)) hash_to_public_keys = {} for i in range(len(message_hashes)): if message_hashes[i] in hash_to_public_keys: hash_to_public_keys[message_hashes[i]].append(public_keys[i]) else: hash_to_public_keys[message_hashes[i]] = [public_keys[i]] final_message_hashes = [] final_public_keys = [] ec = public_keys[0].value.ec for message_hash, mapped_keys in hash_to_public_keys.items(): dedup = list(set(mapped_keys)) public_key_sum = JacobianPoint(Fq.one(ec.q), Fq.one(ec.q), Fq.zero(ec.q), True, ec) for public_key in dedup: try: exponent = self.aggregation_info.tree[(message_hash, public_key)] public_key_sum += (public_key.value * exponent) except KeyError: return False final_message_hashes.append(message_hash) final_public_keys.append(public_key_sum.to_affine()) mapped_hashes = [ hash_to_point_prehashed_Fq2(mh) for mh in final_message_hashes ] g1 = Fq(default_ec.n, -1) * generator_Fq() Ps = [g1] + final_public_keys Qs = [self.value.to_affine()] + mapped_hashes res = ate_pairing_multi(Ps, Qs, default_ec) return res == Fq12.one(default_ec.q)
def verify(self, message_hashes, public_keys): """ Verifies messages using the prepend method. It prepends public keys to message hashes before verifying. """ assert (len(message_hashes) == len(public_keys)) mapped_hashes = [ hash_to_point_prehashed_Fq2( hash256(public_keys[i].serialize() + message_hashes[i])) for i in range(len(message_hashes)) ] keys = [pk.value.to_affine() for pk in public_keys] g1 = Fq(default_ec.n, -1) * generator_Fq() Ps = [g1] + keys Qs = [self.value.to_affine()] + mapped_hashes res = ate_pairing_multi(Ps, Qs, default_ec) return res == Fq12.one(default_ec.q)
def sign_prehashed(self, h): r = hash_to_point_prehashed_Fq2(h).to_jacobian() aggregation_info = AggregationInfo.from_msg_hash( self.get_public_key(), h) return Signature.from_g2(self.value * r, aggregation_info)
def sign_prepend_prehashed(self, h): final_message = hash256(self.get_public_key().serialize() + h) r = hash_to_point_prehashed_Fq2(final_message).to_jacobian() return PrependSignature(self.value * r)