Beispiel #1
0
def _mock_ursula_reencrypts(ursula):
    delegating_privkey = SecretKey.random()
    capsule, _ciphertext = encrypt(delegating_privkey.public_key(), b'unused')
    signing_privkey = SecretKey.random()
    signing_pubkey = signing_privkey.public_key()
    signer = Signer(signing_privkey)
    priv_key_bob = SecretKey.random()
    pub_key_bob = priv_key_bob.public_key()
    kfrags = generate_kfrags(delegating_sk=delegating_privkey,
                             signer=signer,
                             receiving_pk=pub_key_bob,
                             threshold=2,
                             num_kfrags=4,
                             sign_delegating_key=False,
                             sign_receiving_key=False)

    ursula_pubkey = ursula.stamp.as_umbral_pubkey()

    alice_address = canonical_address_from_umbral_key(signing_pubkey)
    blockhash = bytes(32)

    specification = b''.join((bytes(capsule),
                              bytes(ursula_pubkey),
                              bytes(ursula.decentralized_identity_evidence),
                              alice_address,
                              blockhash))

    bobs_signer = Signer(priv_key_bob)
    task_signature = bytes(bobs_signer.sign(specification))

    cfrag = reencrypt(capsule, kfrags[0])
    cfrag_signature = ursula.stamp(bytes(cfrag))

    bob = Bob.from_public_keys(verifying_key=pub_key_bob)
    return WorkOrder.PRETask(capsule, task_signature, cfrag, cfrag_signature)
def test_pre_task(mock_ursula_reencrypts, ursula, get_random_checksum_address):
    identity_evidence = ursula.decentralized_identity_evidence
    task = mock_ursula_reencrypts(ursula)
    cfrag = task.cfrag
    capsule = task.capsule
    capsule_bytes = bytes(capsule)

    signature = ursula.stamp(capsule_bytes)

    task = WorkOrder.PRETask(capsule=capsule, signature=signature)
    assert capsule == task.capsule
    assert signature == task.signature

    task_bytes = bytes(task)
    assert bytes(capsule) + bytes(signature) == task_bytes

    deserialized_task = WorkOrder.PRETask.from_bytes(task_bytes)
    assert capsule == deserialized_task.capsule
    assert signature == deserialized_task.signature

    # Attaching cfrags to the task
    cfrag_bytes = bytes(cfrag)
    cfrag_signature = ursula.stamp(cfrag_bytes)

    task.attach_work_result(cfrag, cfrag_signature)
    assert capsule == task.capsule
    assert signature == task.signature
    assert cfrag == task.cfrag
    assert cfrag_signature == task.cfrag_signature

    task_bytes = bytes(task)
    assert bytes(capsule) + bytes(signature) + cfrag_bytes + bytes(
        cfrag_signature) == task_bytes

    deserialized_task = WorkOrder.PRETask.from_bytes(task_bytes)
    assert capsule == deserialized_task.capsule
    assert signature == deserialized_task.signature
    assert bytes(cfrag) == bytes(
        deserialized_task.cfrag
    )  # We compare bytes as there's no CapsuleFrag.__eq__
    assert cfrag_signature == deserialized_task.cfrag_signature

    # Task specification
    alice_address = to_canonical_address(get_random_checksum_address())
    blockhash = os.urandom(ETH_HASH_BYTE_LENGTH)

    specification = task.get_specification(bytes(ursula.stamp), alice_address,
                                           blockhash, identity_evidence)

    expected_specification = bytes(capsule) + bytes(
        ursula.stamp) + identity_evidence + alice_address + blockhash
    assert expected_specification == specification

    with pytest.raises(
            ValueError,
            match=f"blockhash must be of length {ETH_HASH_BYTE_LENGTH}"):
        task.get_specification(bytes(ursula.stamp), alice_address,
                               os.urandom(42), identity_evidence)
Beispiel #3
0
def _mock_ursula_reencrypts(ursula, corrupt_cfrag: bool = False):
    delegating_privkey = UmbralPrivateKey.gen_key()
    _symmetric_key, capsule = pre._encapsulate(delegating_privkey.get_pubkey())
    signing_privkey = UmbralPrivateKey.gen_key()
    signing_pubkey = signing_privkey.get_pubkey()
    signer = Signer(signing_privkey)
    priv_key_bob = UmbralPrivateKey.gen_key()
    pub_key_bob = priv_key_bob.get_pubkey()
    kfrags = pre.generate_kfrags(delegating_privkey=delegating_privkey,
                                 signer=signer,
                                 receiving_pubkey=pub_key_bob,
                                 threshold=2,
                                 N=4,
                                 sign_delegating_key=False,
                                 sign_receiving_key=False)
    capsule.set_correctness_keys(delegating_privkey.get_pubkey(), pub_key_bob,
                                 signing_pubkey)

    ursula_pubkey = ursula.stamp.as_umbral_pubkey()

    alice_address = canonical_address_from_umbral_key(signing_pubkey)
    blockhash = bytes(32)

    specification = b''.join((bytes(capsule), bytes(ursula_pubkey),
                              bytes(ursula.decentralized_identity_evidence),
                              alice_address, blockhash))

    bobs_signer = Signer(priv_key_bob)
    task_signature = bytes(bobs_signer(specification))

    metadata = bytes(ursula.stamp(task_signature))

    cfrag = pre.reencrypt(kfrags[0], capsule, metadata=metadata)

    if corrupt_cfrag:
        cfrag.proof.bn_sig = CurveBN.gen_rand(capsule.params.curve)

    cfrag_signature = bytes(ursula.stamp(bytes(cfrag)))

    bob = Bob.from_public_keys(verifying_key=pub_key_bob)
    task = WorkOrder.PRETask(capsule, task_signature, cfrag, cfrag_signature)
    work_order = WorkOrder(bob, None, alice_address, [task], None, ursula,
                           blockhash)

    evidence = IndisputableEvidence(task, work_order)
    return evidence
def test_work_order_with_multiple_capsules(mock_ursula_reencrypts, ursula,
                                           get_random_checksum_address,
                                           federated_bob, federated_alice,
                                           number):

    tasks = [mock_ursula_reencrypts(ursula) for _ in range(number)]
    material = [(task.capsule, task.signature, task.cfrag,
                 task.cfrag_signature) for task in tasks]
    capsules, signatures, cfrags, cfrag_signatures = zip(*material)

    arrangement_id = os.urandom(Arrangement.ID_LENGTH)
    alice_address = canonical_address_from_umbral_key(federated_alice.stamp)
    blockhash = b'\0' * ETH_HASH_BYTE_LENGTH  # TODO: Prove freshness of work order - #259
    identity_evidence = ursula.decentralized_identity_evidence

    # Test construction of WorkOrders by Bob
    work_order = WorkOrder.construct_by_bob(
        arrangement_id=arrangement_id,
        bob=federated_bob,
        alice_verifying=federated_alice.stamp.as_umbral_pubkey(),
        ursula=ursula,
        capsules=capsules)

    receipt_input = WorkOrder.HEADER + bytes(ursula.stamp) + b''.join(
        map(bytes, capsules))
    bob_verifying_pubkey = federated_bob.stamp.as_umbral_pubkey()

    assert work_order.bob == federated_bob
    assert work_order.arrangement_id == arrangement_id
    assert work_order.alice_address == alice_address
    assert len(work_order.tasks) == len(work_order) == number
    for capsule in capsules:
        assert work_order.tasks[capsule].capsule == capsule
        task = WorkOrder.PRETask(capsule, signature=None)
        specification = task.get_specification(ursula.stamp, alice_address,
                                               blockhash, identity_evidence)
        assert work_order.tasks[capsule].signature.verify(
            bob_verifying_pubkey, specification)
    assert work_order.receipt_signature.verify(bob_verifying_pubkey,
                                               receipt_input)
    assert work_order.ursula == ursula
    assert work_order.blockhash == blockhash
    assert not work_order.completed

    # Test WorkOrders' payload serialization and deserialization
    tasks_bytes = b''.join(map(bytes, work_order.tasks.values()))
    expected_payload = bytes(work_order.receipt_signature) + bytes(
        federated_bob.stamp) + blockhash + tasks_bytes

    payload = work_order.payload()
    assert expected_payload == payload

    same_work_order = WorkOrder.from_rest_payload(
        arrangement_id=arrangement_id,
        rest_payload=payload,
        ursula=ursula,
        alice_address=alice_address)

    assert same_work_order.bob == federated_bob
    assert same_work_order.arrangement_id == arrangement_id
    assert same_work_order.alice_address == alice_address
    assert len(same_work_order.tasks) == len(same_work_order) == number
    for capsule in capsules:
        assert same_work_order.tasks[capsule].capsule == capsule
        assert same_work_order.tasks[capsule].signature == work_order.tasks[
            capsule].signature
    assert same_work_order.receipt_signature == work_order.receipt_signature
    assert same_work_order.ursula == ursula
    assert same_work_order.blockhash == blockhash
    assert not same_work_order.completed

    tampered_payload = bytearray(payload)
    somewhere_over_the_blockhash = 64 + 33 + 5
    tampered_payload[somewhere_over_the_blockhash] = 255 - payload[
        somewhere_over_the_blockhash]
    with pytest.raises(InvalidSignature):
        _ = WorkOrder.from_rest_payload(arrangement_id=arrangement_id,
                                        rest_payload=bytes(tampered_payload),
                                        ursula=ursula,
                                        alice_address=alice_address)

    # Testing WorkOrder.complete()

    # Let's use the original task signatures in our WorkOrder, instead
    for capsule, task_signature in zip(capsules, signatures):
        work_order.tasks[capsule].signature = task_signature

    # Now, complete() works as intended
    good_cfrags = work_order.complete(list(zip(cfrags, cfrag_signatures)))
    assert work_order.completed
    assert len(good_cfrags) == number

    # Testing some additional expected exceptions
    with pytest.raises(ValueError,
                       match="Ursula gave back the wrong number of cfrags"):
        work_order.complete(list(zip(cfrags, cfrag_signatures))[1:])

    bad_cfrag_signature = ursula.stamp(os.urandom(10))
    with pytest.raises(InvalidSignature,
                       match=f"{cfrags[0]} is not properly signed by Ursula."):
        work_order.complete(
            list(
                zip(cfrags,
                    [bad_cfrag_signature] + list(cfrag_signatures[1:]))))