def verify_signature(self, alice_pubkey: 'UmbralPublicKey'): """ Verifies the revocation was from the provided pubkey. """ if not self.signature.verify(self.prefix + self.arrangement_id, alice_pubkey): raise InvalidSignature( "Revocation has an invalid signature: {}".format(self.signature)) return True
def set_policy(id_as_hex): """ REST endpoint for setting a kFrag. """ policy_message_kit = UmbralMessageKit.from_bytes(request.data) alices_verifying_key = policy_message_kit.sender_verifying_key alice = _alice_class.from_public_keys( verifying_key=alices_verifying_key) try: cleartext = this_node.verify_from(alice, policy_message_kit, decrypt=True) except InvalidSignature: # TODO: Perhaps we log this? Essentially 355. return Response(status_code=400) if not this_node.federated_only: # This splitter probably belongs somewhere canonical. transaction_splitter = BytestringSplitter(32) tx, kfrag_bytes = transaction_splitter(cleartext, return_remainder=True) try: # Get all of the arrangements and verify that we'll be paid. # TODO: We'd love for this part to be impossible to reduce the risk of collusion. #1274 arranged_addresses = this_node.policy_agent.fetch_arrangement_addresses_from_policy_txid( tx, timeout=this_node.synchronous_query_timeout) except TimeExhausted: # Alice didn't pay. Return response with that weird status code. this_node.suspicious_activities_witnessed['freeriders'].append( (alice, f"No transaction matching {tx}.")) return Response(status=402) this_node_has_been_arranged = this_node.checksum_address in arranged_addresses if not this_node_has_been_arranged: this_node.suspicious_activities_witnessed['freeriders'].append( (alice, f"The transaction {tx} does not list me as a Worker - it lists {arranged_addresses}." )) return Response(status=402) else: _tx = NO_BLOCKCHAIN_CONNECTION kfrag_bytes = cleartext kfrag = KFrag.from_bytes(kfrag_bytes) if not kfrag.verify(signing_pubkey=alices_verifying_key): raise InvalidSignature("{} is invalid".format(kfrag)) with ThreadedSession(db_engine) as session: datastore.attach_kfrag_to_saved_arrangement(alice, id_as_hex, kfrag, session=session) # TODO: Sign the arrangement here. #495 return "" # TODO: Return A 200, with whatever policy metadata.
def reencrypt_via_rest(id_as_hex): from nucypher.policy.models import WorkOrder # Avoid circular import arrangement_id = binascii.unhexlify(id_as_hex) work_order = WorkOrder.from_rest_payload(arrangement_id, request.data) log.info("Work Order from {}, signed {}".format( work_order.bob, work_order.receipt_signature)) with ThreadedSession(db_engine) as session: policy_arrangement = datastore.get_policy_arrangement( arrangement_id=id_as_hex.encode(), session=session) kfrag_bytes = policy_arrangement.kfrag # Careful! :-) verifying_key_bytes = policy_arrangement.alice_pubkey_sig.key_data # TODO: Push this to a lower level. Perhaps to Ursula character? #619 kfrag = KFrag.from_bytes(kfrag_bytes) alices_verifying_key = UmbralPublicKey.from_bytes(verifying_key_bytes) cfrag_byte_stream = b"" alices_address = canonical_address_from_umbral_key( alices_verifying_key) if not alices_address == work_order.alice_address: message = f"This Bob ({work_order.bob}) sent an Alice's ETH address " \ f"({work_order.alice_address}) that doesn't match " \ f"the one I have ({alices_address})." raise SuspiciousActivity(message) bob_pubkey = work_order.bob.stamp.as_umbral_pubkey() if not work_order.alice_address_signature.verify( message=alices_address, verifying_key=bob_pubkey): message = f"This Bob ({work_order.bob}) sent an invalid signature of Alice's ETH address" raise InvalidSignature(message) # This is Bob's signature of Alice's verifying key as ETH address. alice_address_signature = bytes(work_order.alice_address_signature) for capsule, capsule_signature in zip(work_order.capsules, work_order.capsule_signatures): # This is the capsule signed by Bob capsule_signature = bytes(capsule_signature) # Ursula signs on top of it. Now both are committed to the same capsule. # She signs Alice's address too. ursula_signature = stamp(capsule_signature + alice_address_signature) capsule.set_correctness_keys(verifying=alices_verifying_key) cfrag = pre.reencrypt(kfrag, capsule, metadata=bytes(ursula_signature)) log.info(f"Re-encrypting for {capsule}, made {cfrag}.") signature = stamp(bytes(cfrag) + bytes(capsule)) cfrag_byte_stream += VariableLengthBytestring(cfrag) + signature # TODO: Put this in Ursula's datastore work_order_tracker.append(work_order) headers = {'Content-Type': 'application/octet-stream'} return Response(response=cfrag_byte_stream, headers=headers)
def from_rest_payload(cls, arrangement_id, rest_payload, ursula, alice_address): payload_splitter = BytestringSplitter(Signature) + key_splitter payload_elements = payload_splitter(rest_payload, msgpack_remainder=True) signature, bob_verifying_key, (tasks_bytes, blockhash) = payload_elements # TODO: check freshness of blockhash? ursula_identity_evidence = b'' if ursula._stamp_has_valid_signature_by_worker(): ursula_identity_evidence = ursula.decentralized_identity_evidence tasks = [] for task_bytes in tasks_bytes: task = cls.PRETask.from_bytes(task_bytes) tasks.append(task) # Each task signature has to match the original specification specification = task.get_specification(ursula.stamp, alice_address, blockhash, ursula_identity_evidence) if not task.signature.verify(specification, bob_verifying_key): raise InvalidSignature() # Check receipt receipt_bytes = b"wo:" + bytes(ursula.stamp) + keccak_digest( *[bytes(task.capsule) for task in tasks]) if not signature.verify(receipt_bytes, bob_verifying_key): raise InvalidSignature() bob = Bob.from_public_keys(verifying_key=bob_verifying_key) return cls(bob=bob, ursula=ursula, arrangement_id=arrangement_id, tasks=tasks, alice_address=alice_address, blockhash=blockhash, receipt_signature=signature)
def from_rest_payload(cls, arrangement_id, rest_payload, ursula, alice_address): payload_splitter = BytestringSplitter( Signature) + key_splitter + BytestringSplitter( ETH_HASH_BYTE_LENGTH) signature, bob_verifying_key, blockhash, remainder = payload_splitter( rest_payload, return_remainder=True) tasks = { capsule: cls.PRETask(capsule, sig) for capsule, sig in cls.PRETask.input_splitter.repeat(remainder) } # TODO: check freshness of blockhash? #259 ursula_identity_evidence = b'' if ursula._stamp_has_valid_signature_by_worker(): ursula_identity_evidence = ursula.decentralized_identity_evidence for task in tasks.values(): # Each task signature has to match the original specification specification = task.get_specification(ursula.stamp, alice_address, blockhash, ursula_identity_evidence) if not task.signature.verify(specification, bob_verifying_key): raise InvalidSignature() # Check receipt capsules = b''.join(map(bytes, tasks.keys())) receipt_bytes = cls.HEADER + bytes(ursula.stamp) + capsules if not signature.verify(receipt_bytes, bob_verifying_key): raise InvalidSignature() bob = Bob.from_public_keys(verifying_key=bob_verifying_key) return cls(bob=bob, ursula=ursula, arrangement_id=arrangement_id, tasks=tasks, alice_address=alice_address, blockhash=blockhash, receipt_signature=signature)
def from_rest_payload(cls, arrangement_id, rest_payload, ursula_pubkey_bytes, alice_address): payload_splitter = BytestringSplitter(Signature) + key_splitter payload_elements = payload_splitter(rest_payload, msgpack_remainder=True) signature, bob_verifying_key, (tasks_bytes, blockhash) = payload_elements # TODO: check freshness of blockhash? # Check receipt receipt_bytes = b"wo:" + ursula_pubkey_bytes + msgpack.dumps( tasks_bytes) if not signature.verify(receipt_bytes, bob_verifying_key): raise InvalidSignature() tasks = [] for task_bytes in tasks_bytes: task = cls.Task.from_bytes(task_bytes) tasks.append(task) # Each task signature has to match the original specification specification = task.get_specification(ursula_pubkey_bytes, alice_address, blockhash) if not task.signature.verify(specification, bob_verifying_key): raise InvalidSignature() bob = Bob.from_public_keys(verifying_key=bob_verifying_key) return cls(bob=bob, arrangement_id=arrangement_id, tasks=tasks, alice_address=alice_address, blockhash=blockhash, receipt_signature=signature)
def complete(self, cfrags_and_signatures): good_cfrags = [] if not len(self) == len(cfrags_and_signatures): raise ValueError("Ursula gave back the wrong number of cfrags. She's up to something.") ursula_verifying_key = self.ursula.stamp.as_umbral_pubkey() for task, (cfrag, cfrag_signature) in zip(self.tasks.values(), cfrags_and_signatures): # Validate re-encryption signatures if cfrag_signature.verify(ursula_verifying_key, bytes(cfrag)): good_cfrags.append(cfrag) else: raise InvalidSignature(f"{cfrag} is not properly signed by Ursula.") # TODO: Instead of raising, we should do something (#957) for task, (cfrag, cfrag_signature) in zip(self.tasks.values(), cfrags_and_signatures): task.attach_work_result(cfrag, cfrag_signature) self.completed = maya.now() return good_cfrags
def precompute_values(self) -> bytes: umbral_params = default_params() e, v, _ = self.capsule.components() e1 = self.cfrag.point_e1 v1 = self.cfrag.point_v1 e2 = self.cfrag.proof.point_e2 v2 = self.cfrag.proof.point_v2 u = umbral_params.u u1 = self.cfrag.proof.point_kfrag_commitment u2 = self.cfrag.proof.point_kfrag_pok h = self.get_proof_challenge_scalar() e1h = h * e1 v1h = h * v1 u1h = h * u1 z = self.cfrag.proof.bn_sig ez = z * e vz = z * v uz = z * u def raw_bytes_from_point(point: Point, only_y_coord=False) -> bytes: uncompressed_point_bytes = point.to_bytes(is_compressed=False) if only_y_coord: y_coord_start = (1 + Point.expected_bytes_length(is_compressed=False)) // 2 return uncompressed_point_bytes[y_coord_start:] else: return uncompressed_point_bytes[1:] # E points e_y = raw_bytes_from_point(e, only_y_coord=True) ez_xy = raw_bytes_from_point(ez) e1_y = raw_bytes_from_point(e1, only_y_coord=True) e1h_xy = raw_bytes_from_point(e1h) e2_y = raw_bytes_from_point(e2, only_y_coord=True) # V points v_y = raw_bytes_from_point(v, only_y_coord=True) vz_xy = raw_bytes_from_point(vz) v1_y = raw_bytes_from_point(v1, only_y_coord=True) v1h_xy = raw_bytes_from_point(v1h) v2_y = raw_bytes_from_point(v2, only_y_coord=True) # U points uz_xy = raw_bytes_from_point(uz) u1_y = raw_bytes_from_point(u1, only_y_coord=True) u1h_xy = raw_bytes_from_point(u1h) u2_y = raw_bytes_from_point(u2, only_y_coord=True) # Get hashed KFrag validity message hash_function = hashes.Hash(hashes.SHA256(), backend=backend) kfrag_id = self.cfrag.kfrag_id precursor = self.cfrag.point_precursor delegating_pubkey = self.delegating_pubkey receiving_pubkey = self.receiving_pubkey validity_input = (kfrag_id, delegating_pubkey, receiving_pubkey, u1, precursor) kfrag_validity_message = bytes().join(bytes(item) for item in validity_input) hash_function.update(kfrag_validity_message) hashed_kfrag_validity_message = hash_function.finalize() # Get Alice's verifying pubkey as ETH address alice_address = canonical_address_from_umbral_key(self.verifying_pubkey) # Get KFrag signature's v value v_value = 27 pubkey_bytes = recover_pubkey_from_signature(prehashed_message=hashed_kfrag_validity_message, signature=self.cfrag.proof.kfrag_signature, v_value_to_try=v_value) if not pubkey_bytes == self.verifying_pubkey.to_bytes(): v_value = 28 pubkey_bytes = recover_pubkey_from_signature(prehashed_message=hashed_kfrag_validity_message, signature=self.cfrag.proof.kfrag_signature, v_value_to_try=v_value) if not pubkey_bytes == self.verifying_pubkey.to_bytes(): raise InvalidSignature("Bad signature: Not possible to recover public key from it.") # Bundle everything together pieces = ( e_y, ez_xy, e1_y, e1h_xy, e2_y, v_y, vz_xy, v1_y, v1h_xy, v2_y, uz_xy, u1_y, u1h_xy, u2_y, hashed_kfrag_validity_message, alice_address, v_value.to_bytes(1, 'big'), ) return b''.join(pieces)