示例#1
0
def test_cannot_set_different_keys():
    """
    Once a key is set on a Capsule, it can't be changed to a different key.
    """
    params = default_params()

    capsule = Capsule(params,
                      point_e=Point.gen_rand(),
                      point_v=Point.gen_rand(),
                      bn_sig=CurveBN.gen_rand())

    capsule.set_correctness_keys(
        delegating=UmbralPrivateKey.gen_key().get_pubkey(),
        receiving=UmbralPrivateKey.gen_key().get_pubkey(),
        verifying=UmbralPrivateKey.gen_key().get_pubkey())

    with pytest.raises(ValueError):
        capsule.set_correctness_keys(
            delegating=UmbralPrivateKey.gen_key().get_pubkey())

    with pytest.raises(ValueError):
        capsule.set_correctness_keys(
            receiving=UmbralPrivateKey.gen_key().get_pubkey())

    with pytest.raises(ValueError):
        capsule.set_correctness_keys(
            verifying=UmbralPrivateKey.gen_key().get_pubkey())
示例#2
0
def test_cheating_ursula_sends_garbage(N, M):
    priv_key_alice = keys.UmbralPrivateKey.gen_key()
    pub_key_alice = priv_key_alice.get_pubkey()

    # Bob
    priv_key_bob = keys.UmbralPrivateKey.gen_key()
    pub_key_bob = priv_key_bob.get_pubkey()

    sym_key, capsule_alice = pre._encapsulate(pub_key_alice.point_key)
    kfrags = pre.split_rekey(priv_key_alice, pub_key_bob, M, N)

    cfrags, metadata = [], []
    for i, kfrag in enumerate(kfrags[:M]):

        # Example of potential metadata to describe the re-encryption request
        metadata_i = "This is an example of metadata for re-encryption request #{}"
        metadata_i = metadata_i.format(i).encode()

        cfrag = pre.reencrypt(kfrag, capsule_alice, metadata=metadata_i)

        capsule_alice.attach_cfrag(cfrag)
        cfrags.append(cfrag)

    # Let's put random garbage in one of the cfrags
    cfrags[0]._point_e1 = Point.gen_rand()
    cfrags[0]._point_v1 = Point.gen_rand()

    capsule_alice._reconstruct_shamirs_secret(pub_key_alice,
                                              priv_key_bob)  # activate capsule

    with pytest.raises(pre.GenericUmbralError):
        _unused_key = pre._decapsulate_reencrypted(pub_key_bob.point_key,
                                                   priv_key_bob.bn_key,
                                                   pub_key_alice.point_key,
                                                   capsule_alice)

    assert not pre._verify_correctness(
        capsule_alice,
        cfrags[0],
        pub_key_alice.point_key,
        pub_key_bob.point_key,
    )

    # The response of cheating Ursula is in cfrags[0],
    # so the rest of CFrags chould be correct:
    for cfrag_i, metadata_i in zip(cfrags[1:], metadata[1:]):
        assert pre._verify_correctness(
            capsule_alice,
            cfrag_i,
            pub_key_alice.point_key,
            pub_key_bob.point_key,
        )

    # Alternatively, we can try to open the capsule directly.
    # We should get an exception with an attached list of incorrect cfrags
    with pytest.raises(pre.UmbralCorrectnessError) as exception_info:
        _ = pre._open_capsule(capsule_alice, priv_key_bob, pub_key_alice)
    correctness_error = exception_info.value
    assert cfrags[0] in correctness_error.offending_cfrags
    assert len(correctness_error.offending_cfrags) == 1
def test_generate_random_points():
    for _ in range(10):
        point = Point.gen_rand()
        another_point = Point.gen_rand()
        assert isinstance(point, Point)
        assert isinstance(another_point, Point)
        assert point != another_point
示例#4
0
def test_cheating_ursula_sends_garbage(kfrags, prepared_capsule):
    capsule_alice = prepared_capsule

    cfrags = []
    for i, kfrag in enumerate(kfrags):
        # Example of potential metadata to describe the re-encryption request
        metadata_i = "This is an example of metadata for re-encryption request #{}"
        metadata_i = metadata_i.format(i).encode()

        cfrag = pre.reencrypt(kfrag, capsule_alice, metadata=metadata_i)
        cfrags.append(cfrag)

    # Let's put random garbage in one of the cfrags
    cfrags[0]._point_e1 = Point.gen_rand()
    cfrags[0]._point_v1 = Point.gen_rand()

    #  Of course, this CFrag is not valid ...
    assert not cfrags[0].verify_correctness(capsule_alice)

    # ... and trying to attach it raises an error.
    with pytest.raises(pre.UmbralCorrectnessError) as exception_info:
        capsule_alice.attach_cfrag(cfrags[0])

    correctness_error = exception_info.value
    assert cfrags[0] in correctness_error.offending_cfrags
    assert len(correctness_error.offending_cfrags) == 1

    # The response of cheating Ursula is in cfrags[0],
    # so the rest of CFrags should be correct:
    for cfrag_i in cfrags[1:]:
        assert cfrag_i.verify_correctness(capsule_alice)
        capsule_alice.attach_cfrag(cfrag_i)
示例#5
0
def test_cheating_ursula_sends_garbage(N, M):
    priv_key_alice = keys.UmbralPrivateKey.gen_key()
    pub_key_alice = priv_key_alice.get_pubkey()

    # Bob
    priv_key_bob = keys.UmbralPrivateKey.gen_key()
    pub_key_bob = priv_key_bob.get_pubkey()

    sym_key, capsule_alice = pre._encapsulate(pub_key_alice.point_key)
    kfrags = pre.split_rekey(priv_key_alice, pub_key_bob, M, N)

    cfrags, challenges, metadata = [], [], []
    for i, kfrag in enumerate(kfrags[:M]):
        cfrag = pre.reencrypt(kfrag, capsule_alice)

        # Example of potential metadata to describe the challenge request
        metadata_i = {
            'ursula_id': i,
            'timestamp': time.time(),
            'capsule': bytes(capsule_alice),
            'cfrag': bytes(cfrag)
        }

        metadata_i = str(metadata_i).encode()
        metadata.append(metadata_i)

        challenge = pre._challenge(kfrag, capsule_alice, cfrag, metadata_i)
        capsule_alice.attach_cfrag(cfrag)

        assert pre._check_challenge(capsule_alice, cfrag, challenge,
                                    pub_key_alice.point_key,
                                    pub_key_bob.point_key, metadata_i)

        cfrags.append(cfrag)
        challenges.append(challenge)

    # Let's put random garbage in one of the cfrags
    cfrags[0].point_eph_e1 = Point.gen_rand()
    cfrags[0].point_eph_v1 = Point.gen_rand()

    capsule_alice._reconstruct_shamirs_secret(pub_key_alice,
                                              priv_key_bob)  # activate capsule

    with pytest.raises(pre.GenericUmbralError):
        sym_key2 = pre._decapsulate_reencrypted(pub_key_bob.point_key,
                                                priv_key_bob.bn_key,
                                                pub_key_alice.point_key,
                                                capsule_alice)

    assert not pre._check_challenge(capsule_alice, cfrags[0], challenges[0],
                                    pub_key_alice.point_key,
                                    pub_key_bob.point_key, metadata[0])

    # The response of cheating Ursula is in capsules[0],
    # so the rest of challenges chould be correct:
    for i, challenge in enumerate(challenges[1:], 1):
        cfrag = cfrags[i]
        assert pre._check_challenge(capsule_alice, cfrag, challenge,
                                    pub_key_alice.point_key,
                                    pub_key_bob.point_key, metadata[i])
示例#6
0
def test_cannot_attach_cfrag_without_proof():
    """
    However, even when properly attaching keys, we can't attach the CFrag
    if it is unproven.
    """
    params = default_params()

    capsule = Capsule(params,
                      point_e=Point.gen_rand(),
                      point_v=Point.gen_rand(),
                      bn_sig=CurveBN.gen_rand())

    cfrag = CapsuleFrag(
        point_e1=Point.gen_rand(),
        point_v1=Point.gen_rand(),
        kfrag_id=os.urandom(10),
        point_precursor=Point.gen_rand(),
    )
    key_details = capsule.set_correctness_keys(
        UmbralPrivateKey.gen_key().get_pubkey(),
        UmbralPrivateKey.gen_key().get_pubkey(),
        UmbralPrivateKey.gen_key().get_pubkey())

    delegating_details, receiving_details, verifying_details = key_details

    assert all((delegating_details, receiving_details, verifying_details))

    with pytest.raises(cfrag.NoProofProvided):
        capsule.attach_cfrag(cfrag)
def test_bad_capsule_fails_reencryption(alices_keys):
    priv_key_alice, pub_key_alice = alices_keys

    kfrags = pre.split_rekey(priv_key_alice, pub_key_alice, 1, 2)

    bollocks_capsule = Capsule(point_e=Point.gen_rand(),
                               point_v=Point.gen_rand(),
                               bn_sig=CurveBN.gen_rand())

    with pytest.raises(Capsule.NotValid):
        pre.reencrypt(kfrags[0], bollocks_capsule)
示例#8
0
def test_bad_capsule_fails_reencryption(alices_keys):
    priv_key_alice, pub_key_alice = alices_keys

    k_frags, _unused_vkeys = umbral.split_rekey(priv_key_alice, pub_key_alice, 1, 2)

    bollocks_capsule = Capsule(point_eph_e=Point.gen_rand(),
                               point_eph_v=Point.gen_rand(),
                               bn_sig=BigNum.gen_rand())

    with pytest.raises(Capsule.NotValid):
        umbral.reencrypt(k_frags[0], bollocks_capsule)
示例#9
0
def test_bad_capsule_fails_reencryption(kfrags):
    params = default_params()

    bollocks_capsule = Capsule(params,
                               point_e=Point.gen_rand(),
                               point_v=Point.gen_rand(),
                               bn_sig=CurveBN.gen_rand())

    for kfrag in kfrags:
        with pytest.raises(Capsule.NotValid):
            pre.reencrypt(kfrag, bollocks_capsule)
示例#10
0
def test_cheating_ursula_sends_garbage(N, M):
    priv_key_alice = keys.UmbralPrivateKey.gen_key()
    pub_key_alice = priv_key_alice.get_pubkey()

    # Bob
    priv_key_bob = keys.UmbralPrivateKey.gen_key()
    pub_key_bob = priv_key_bob.get_pubkey()

    sym_key, capsule_alice = pre._encapsulate(pub_key_alice.point_key)
    k_frags = pre.split_rekey(priv_key_alice, pub_key_bob, M, N)

    c_frags, challenges = [], []
    for k_frag in k_frags[0:M]:
        c_frag = pre.reencrypt(k_frag, capsule_alice)
        challenge = pre.challenge(k_frag, capsule_alice, c_frag)
        capsule_alice.attach_cfrag(c_frag)

        assert pre.check_challenge(
            capsule_alice,
            c_frag,
            challenge,
            pub_key_alice.point_key,
            pub_key_bob.point_key,
        )

        c_frags.append(c_frag)
        challenges.append(challenge)

    # Let's put random garbage in one of the c_frags
    c_frags[0].point_eph_e1 = Point.gen_rand()
    c_frags[0].point_eph_v1 = Point.gen_rand()

    capsule_alice._reconstruct_shamirs_secret()  # activate capsule

    with pytest.raises(pre.GenericUmbralError):
        sym_key2 = pre.decapsulate_reencrypted(pub_key_bob.point_key,
                                               priv_key_bob.bn_key,
                                               pub_key_alice.point_key,
                                               capsule_alice)
        assert sym_key2 != sym_key
        assert not pre.check_challenge(capsule_alice, c_frags[0],
                                       challenges[0], pub_key_alice.point_key,
                                       pub_key_bob.point_key)

        # The response of cheating Ursula is in capsules[0],
        # so the rest of challenges chould be correct:
        for (c_frag, ch) in zip(c_frags[1:], challenges[1:]):
            assert pre.check_challenge(capsule_alice, c_frag, ch,
                                       pub_key_alice.point_key,
                                       pub_key_bob.point_key)
示例#11
0
def test_cannot_create_capsule_from_bogus_material(alices_keys):
    params = alices_keys[0].params

    with pytest.raises(TypeError):
        _capsule_of_questionable_parentage = Capsule(params,
                                                     point_e=Point.gen_rand(),
                                                     point_v=42,
                                                     bn_sig=CurveBN.gen_rand())

    with pytest.raises(TypeError):
        _capsule_of_questionable_parentage = Capsule(params,
                                                     point_e=Point.gen_rand(),
                                                     point_v=Point.gen_rand(),
                                                     bn_sig=42)
示例#12
0
def test_capsule_equality():
    params = default_params()

    one_capsule = Capsule(params,
                          point_e=Point.gen_rand(),
                          point_v=Point.gen_rand(),
                          bn_sig=CurveBN.gen_rand())

    another_capsule = Capsule(params,
                              point_e=Point.gen_rand(),
                              point_v=Point.gen_rand(),
                              bn_sig=CurveBN.gen_rand())

    assert one_capsule != another_capsule
示例#13
0
def test_bad_capsule_fails_reencryption(alices_keys, bobs_keys):
    delegating_privkey, _signing_privkey = alices_keys
    signer_alice = Signer(_signing_privkey)

    _receiving_privkey, receiving_pubkey = bobs_keys

    kfrags = pre.split_rekey(delegating_privkey, signer_alice,
                             receiving_pubkey, 1, 2)

    bollocks_capsule = Capsule(point_e=Point.gen_rand(),
                               point_v=Point.gen_rand(),
                               bn_sig=CurveBN.gen_rand())

    with pytest.raises(Capsule.NotValid):
        pre.reencrypt(kfrags[0], bollocks_capsule)
def test_serialize_point_at_infinity():

    p = Point.gen_rand()
    point_at_infinity = p - p

    bytes_point_at_infinity = point_at_infinity.to_bytes()
    assert bytes_point_at_infinity == b'\x00'
示例#15
0
def test_ec_point_operations(testerchain, reencryption_validator):
    valid_point = Point.gen_rand()
    x, y = valid_point.to_affine()

    assert reencryption_validator.functions.is_on_curve(x, y).call()

    bad_y = y - 1
    assert not reencryption_validator.functions.is_on_curve(x, bad_y).call()

    sign = 2 + (y % 2)
    assert reencryption_validator.functions.check_compressed_point(sign, x,
                                                                   y).call()

    bad_sign = 3 - (y % 2)
    assert not reencryption_validator.functions.check_compressed_point(
        bad_sign, x, y).call()

    P = valid_point
    scalar = CurveBN.gen_rand()
    Q = scalar * P
    qx, qy = Q.to_affine()

    assert reencryption_validator.functions.ecmulVerify(
        x, y, int(scalar), qx, qy).call()
    assert not reencryption_validator.functions.ecmulVerify(
        x, y, int(scalar), x, y).call()
示例#16
0
def generate_test_points_bytes(quantity=2):
    points_bytes = [
        (SECP256K1, 714, b'\x02x{DR\x94\x8f\x17\xb8\xa2\x14t\x11\xdb\xb1VK\xdb\xc2\xa0T\x97iCK\x8cz~\xea\xa3\xb7AJ'),
    ]
    for _ in range(quantity):
        args = (SECP256K1, 714, Point.gen_rand(curve=SECP256K1).to_bytes())
        points_bytes.append(args)
    return points_bytes
def test_capsule_creation(alices_keys):
    with pytest.raises(TypeError):
        rare_capsule = Capsule()  # Alice cannot make a capsule this way.

    # Some users may create capsules their own way.
    custom_capsule = Capsule(point_e=Point.gen_rand(),
                             point_v=Point.gen_rand(),
                             bn_sig=CurveBN.gen_rand())

    assert isinstance(custom_capsule, Capsule)

    # Typical Alice, constructing a typical capsule
    _, alices_public_key = alices_keys
    plaintext = b'peace at dawn'
    ciphertext, typical_capsule = pre.encrypt(alices_public_key, plaintext)

    assert isinstance(typical_capsule, Capsule)
示例#18
0
def generate_test_points_affine(quantity=2):
    points_affine = [
        (SECP256K1, 714, (54495335564072000415434275044935054036617226655045445809732056033758606213450,
                            26274482902044210718566767736429706729731617411738990314884135712590488065008)),
    ]
    for _ in range(quantity):
        args = (SECP256K1, 714, Point.gen_rand(curve=SECP256K1).to_affine())
        points_affine.append(args)
    return points_affine
示例#19
0
def test_cannot_attach_cfrag_without_keys():
    """
    We need the proper keys to verify the correctness of CFrags
    in order to attach them to a Capsule.
    """
    params = default_params()

    capsule = Capsule(params,
                      point_e=Point.gen_rand(),
                      point_v=Point.gen_rand(),
                      bn_sig=CurveBN.gen_rand())

    cfrag = CapsuleFrag(
        point_e1=Point.gen_rand(),
        point_v1=Point.gen_rand(),
        kfrag_id=os.urandom(10),
        point_precursor=Point.gen_rand(),
    )

    with pytest.raises(TypeError):
        capsule.attach_cfrag(cfrag)
def test_capsule_equality():
    one_capsule = Capsule(point_eph_e=Point.gen_rand(),
                          point_eph_v=Point.gen_rand(),
                          bn_sig=BigNum.gen_rand())

    another_capsule = Capsule(point_eph_e=Point.gen_rand(),
                              point_eph_v=Point.gen_rand(),
                              bn_sig=BigNum.gen_rand())

    assert one_capsule != another_capsule

    activated_capsule = Capsule(e_prime=Point.gen_rand(),
                                v_prime=Point.gen_rand(),
                                noninteractive_point=Point.gen_rand())

    assert activated_capsule != one_capsule
def test_capsule_equality():
    one_capsule = Capsule(point_e=Point.gen_rand(),
                          point_v=Point.gen_rand(),
                          bn_sig=CurveBN.gen_rand())

    another_capsule = Capsule(point_e=Point.gen_rand(),
                              point_v=Point.gen_rand(),
                              bn_sig=CurveBN.gen_rand())

    assert one_capsule != another_capsule

    activated_capsule = Capsule(point_e_prime=Point.gen_rand(),
                                point_v_prime=Point.gen_rand(),
                                point_noninteractive=Point.gen_rand())

    assert activated_capsule != one_capsule
def test_cannot_create_capsule_from_bogus_material(alices_keys):
    with pytest.raises(TypeError):
        capsule_of_questionable_parentage = pre.Capsule(point_e=Point.gen_rand(),
                                                        point_v=42,
                                                        bn_sig=CurveBN.gen_rand())

    with pytest.raises(TypeError):
        capsule_of_questionable_parentage = pre.Capsule(point_e=Point.gen_rand(),
                                                        point_v=Point.gen_rand(),
                                                        bn_sig=42)

    with pytest.raises(TypeError):
        capsule_of_questionable_parentage = pre.Capsule(point_e_prime=Point.gen_rand(),
                                                        point_v_prime=42,
                                                        point_noninteractive=Point.gen_rand())

    with pytest.raises(TypeError):
        capsule_of_questionable_parentage = pre.Capsule(point_e_prime=Point.gen_rand(),
                                                        point_v_prime=Point.gen_rand(),
                                                        point_noninteractive=42)
示例#23
0
def random_ec_point2():
    yield Point.gen_rand()
def test_evaluate_cfrag(testerchain, escrow, adjudicator_contract):
    creator, miner, wrong_miner, investigator, *everyone_else = testerchain.interface.w3.eth.accounts
    evaluation_log = adjudicator_contract.events.CFragEvaluated.createFilter(
        fromBlock='latest')

    worker_stake = 1000
    worker_penalty_history = 0
    investigator_balance = 0
    number_of_evaluations = 0

    # Prepare one miner
    tx = escrow.functions.setMinerInfo(miner, worker_stake).transact()
    testerchain.wait_for_receipt(tx)

    # Generate miner's Umbral key
    miner_umbral_private_key = UmbralPrivateKey.gen_key()
    miner_umbral_public_key_bytes = miner_umbral_private_key.get_pubkey(
    ).to_bytes(is_compressed=False)

    # Sign Umbral public key using eth-key
    hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
    hash_ctx.update(miner_umbral_public_key_bytes)
    miner_umbral_public_key_hash = hash_ctx.finalize()
    provider = testerchain.interface.provider
    address = to_canonical_address(miner)
    sig_key = provider.ethereum_tester.backend._key_lookup[address]
    signed_miner_umbral_public_key = bytes(
        sig_key.sign_msg_hash(miner_umbral_public_key_hash))

    # Prepare hash of the data
    metadata = os.urandom(33)
    capsule, cfrag = fragments(metadata)

    assert cfrag.verify_correctness(capsule)

    capsule_bytes = capsule.to_bytes()
    cfrag_bytes = cfrag.to_bytes()

    # Bob prepares supporting Evidence
    evidence = IndisputableEvidence(capsule, cfrag, ursula=None)

    evidence_data = evidence.precompute_values()
    assert len(evidence_data) == 20 * 32 + 32 + 20 + 1

    # This check is a workaround in order to test the signature validation is correct.
    # In reality, this check should be part of the isCapsuleFragCorrect logic,
    # but we're facing with "Stack too deep" errors at the moment.
    # address = adjudicator_contract.functions.aliceAddress(cfrag_bytes, evidence_data).call()
    # assert address == to_checksum_address(evidence_data[-21:-1].hex())

    proof_challenge_scalar = int(evidence.get_proof_challenge_scalar())
    # computeProofChallengeScalar = adjudicator_contract.functions.computeProofChallengeScalar
    # assert proof_challenge_scalar == computeProofChallengeScalar(capsule_bytes, cfrag_bytes).call()

    hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
    hash_ctx.update(capsule_bytes + cfrag_bytes)
    data_hash = hash_ctx.finalize()
    # This capsule and cFrag are not yet evaluated
    assert not adjudicator_contract.functions.evaluatedCFrags(data_hash).call()

    # Generate requester's Umbral key
    requester_umbral_private_key = UmbralPrivateKey.gen_key()
    requester_umbral_public_key_bytes = requester_umbral_private_key.get_pubkey(
    ).to_bytes(is_compressed=False)

    # Sign capsule and cFrag
    capsule_signature_by_requester = sign_data(capsule_bytes,
                                               requester_umbral_private_key)
    capsule_signature_by_requester_and_miner = sign_data(
        capsule_signature_by_requester, miner_umbral_private_key)
    cfrag_signature_by_miner = sign_data(cfrag_bytes, miner_umbral_private_key)

    # Challenge using good data
    args = (capsule_bytes, capsule_signature_by_requester,
            capsule_signature_by_requester_and_miner, cfrag_bytes,
            cfrag_signature_by_miner, requester_umbral_public_key_bytes,
            miner_umbral_public_key_bytes, signed_miner_umbral_public_key,
            evidence_data)

    assert worker_stake == escrow.functions.minerInfo(miner).call()[0]

    tx = adjudicator_contract.functions.evaluateCFrag(*args).transact(
        {'from': investigator})
    testerchain.wait_for_receipt(tx)
    number_of_evaluations += 1
    # Hash of the data is saved and miner was not slashed
    assert adjudicator_contract.functions.evaluatedCFrags(data_hash).call()
    assert worker_stake == escrow.functions.minerInfo(miner).call()[0]
    assert investigator_balance == escrow.functions.rewardInfo(
        investigator).call()

    events = evaluation_log.get_all_entries()
    assert number_of_evaluations == len(events)
    event_args = events[-1]['args']
    assert data_hash == event_args['evaluationHash']
    assert miner == event_args['miner']
    assert investigator == event_args['investigator']
    assert event_args['correctness']

    # Test: Don't evaluate miner with data that already was checked
    with pytest.raises((TransactionFailed, ValueError)):
        tx = adjudicator_contract.functions.evaluateCFrag(*args).transact()
        testerchain.wait_for_receipt(tx)

    # Test: Ursula produces incorrect proof:
    metadata = os.urandom(34)
    capsule, cfrag = fragments(metadata)
    capsule_bytes = capsule.to_bytes()
    # Corrupt proof
    cfrag.proof.bn_sig = CurveBN.gen_rand(capsule.params.curve)
    cfrag_bytes = cfrag.to_bytes()
    assert not cfrag.verify_correctness(capsule)

    hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
    hash_ctx.update(capsule_bytes + cfrag_bytes)
    data_hash = hash_ctx.finalize()
    capsule_signature_by_requester = sign_data(capsule_bytes,
                                               requester_umbral_private_key)
    capsule_signature_by_requester_and_miner = sign_data(
        capsule_signature_by_requester, miner_umbral_private_key)
    cfrag_signature_by_miner = sign_data(cfrag_bytes, miner_umbral_private_key)
    evidence = IndisputableEvidence(capsule, cfrag, ursula=None)
    evidence_data = evidence.precompute_values()
    args = (capsule_bytes, capsule_signature_by_requester,
            capsule_signature_by_requester_and_miner, cfrag_bytes,
            cfrag_signature_by_miner, requester_umbral_public_key_bytes,
            miner_umbral_public_key_bytes, signed_miner_umbral_public_key,
            evidence_data)

    assert not adjudicator_contract.functions.evaluatedCFrags(data_hash).call()
    tx = adjudicator_contract.functions.evaluateCFrag(*args).transact(
        {'from': investigator})
    testerchain.wait_for_receipt(tx)
    number_of_evaluations += 1

    # Hash of the data is saved and miner was slashed
    assert adjudicator_contract.functions.evaluatedCFrags(data_hash).call()

    penalty, reward = compute_penalty_and_reward(worker_stake,
                                                 worker_penalty_history)
    worker_stake -= penalty
    investigator_balance += reward
    worker_penalty_history += 1

    assert worker_stake == escrow.functions.minerInfo(miner).call()[0]
    assert investigator_balance == escrow.functions.rewardInfo(
        investigator).call()

    events = evaluation_log.get_all_entries()
    assert number_of_evaluations == len(events)
    event_args = events[-1]['args']
    assert data_hash == event_args['evaluationHash']
    assert miner == event_args['miner']
    assert investigator == event_args['investigator']
    assert not event_args['correctness']

    ###############################
    # Test: Bob produces wrong precomputed data
    ###############################

    metadata = os.urandom(34)
    capsule, cfrag = fragments(metadata)
    capsule_bytes = capsule.to_bytes()
    cfrag_bytes = cfrag.to_bytes()
    assert cfrag.verify_correctness(capsule)

    hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
    hash_ctx.update(capsule_bytes + cfrag_bytes)
    data_hash = hash_ctx.finalize()
    capsule_signature_by_requester = sign_data(capsule_bytes,
                                               requester_umbral_private_key)
    capsule_signature_by_requester_and_miner = sign_data(
        capsule_signature_by_requester, miner_umbral_private_key)
    cfrag_signature_by_miner = sign_data(cfrag_bytes, miner_umbral_private_key)
    evidence = IndisputableEvidence(capsule, cfrag, ursula=None)
    evidence_data = evidence.precompute_values()

    # Bob produces a random point and gets the bytes of coords x and y
    random_point_bytes = Point.gen_rand().to_bytes(is_compressed=False)[1:]
    # He uses this garbage instead of correct precomputation of z*E
    evidence_data = bytearray(evidence_data)
    evidence_data[32:32 + 64] = random_point_bytes
    evidence_data = bytes(evidence_data)

    args = (capsule_bytes, capsule_signature_by_requester,
            capsule_signature_by_requester_and_miner, cfrag_bytes,
            cfrag_signature_by_miner, requester_umbral_public_key_bytes,
            miner_umbral_public_key_bytes, signed_miner_umbral_public_key,
            evidence_data)

    assert not adjudicator_contract.functions.evaluatedCFrags(data_hash).call()

    # Evaluation must fail since Bob precomputed wrong values
    with pytest.raises((TransactionFailed, ValueError)):
        tx = adjudicator_contract.functions.evaluateCFrag(*args).transact(
            {'from': investigator})
        testerchain.wait_for_receipt(tx)

    ###############################
    # Test: Signatures and Metadata mismatch
    ###############################

    # TODO

    ###############################
    # Test: Second violation. Penalty is increased
    ###############################

    # Prepare hash of the data
    metadata = os.urandom(34)
    capsule, cfrag = fragments(metadata)
    capsule_bytes = capsule.to_bytes()
    # Corrupt proof
    cfrag.proof.bn_sig = CurveBN.gen_rand(capsule.params.curve)
    cfrag_bytes = cfrag.to_bytes()
    hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
    hash_ctx.update(capsule_bytes + cfrag_bytes)
    data_hash = hash_ctx.finalize()
    capsule_signature_by_requester = sign_data(capsule_bytes,
                                               requester_umbral_private_key)
    capsule_signature_by_requester_and_miner = sign_data(
        capsule_signature_by_requester, miner_umbral_private_key)
    cfrag_signature_by_miner = sign_data(cfrag_bytes, miner_umbral_private_key)
    evidence = IndisputableEvidence(capsule, cfrag, ursula=None)
    evidence_data = evidence.precompute_values()
    args = [
        capsule_bytes, capsule_signature_by_requester,
        capsule_signature_by_requester_and_miner, cfrag_bytes,
        cfrag_signature_by_miner, requester_umbral_public_key_bytes,
        miner_umbral_public_key_bytes, signed_miner_umbral_public_key,
        evidence_data
    ]
    assert not adjudicator_contract.functions.evaluatedCFrags(data_hash).call()

    worker_stake = escrow.functions.minerInfo(miner).call()[0]
    investigator_balance = escrow.functions.rewardInfo(investigator).call()
    assert not adjudicator_contract.functions.evaluatedCFrags(data_hash).call()
    tx = adjudicator_contract.functions.evaluateCFrag(*args).transact(
        {'from': investigator})
    testerchain.wait_for_receipt(tx)
    number_of_evaluations += 1

    assert adjudicator_contract.functions.evaluatedCFrags(data_hash).call()

    previous_penalty = penalty
    penalty, reward = compute_penalty_and_reward(worker_stake,
                                                 worker_penalty_history)
    # Penalty was increased because it's the second violation
    assert penalty == previous_penalty + PENALTY_HISTORY_COEFFICIENT
    worker_stake -= penalty
    investigator_balance += reward
    worker_penalty_history += 1

    assert worker_stake == escrow.functions.minerInfo(miner).call()[0]
    assert investigator_balance == escrow.functions.rewardInfo(
        investigator).call()

    events = evaluation_log.get_all_entries()
    assert number_of_evaluations == len(events)
    event_args = events[-1]['args']
    assert data_hash == event_args['evaluationHash']
    assert miner == event_args['miner']
    assert investigator == event_args['investigator']
    assert not event_args['correctness']

    ###############################
    # Test: Third violation. Penalty reaches the maximum allowed
    ###############################

    # Prepare corrupted data again
    capsule, cfrag = fragments(metadata)
    capsule_bytes = capsule.to_bytes()
    # Corrupt proof
    cfrag.proof.bn_sig = CurveBN.gen_rand(capsule.params.curve)
    cfrag_bytes = cfrag.to_bytes()
    hash_ctx = hashes.Hash(hashes.SHA256(), backend=backend)
    hash_ctx.update(capsule_bytes + cfrag_bytes)
    data_hash = hash_ctx.finalize()
    capsule_signature_by_requester = sign_data(capsule_bytes,
                                               requester_umbral_private_key)
    capsule_signature_by_requester_and_miner = sign_data(
        capsule_signature_by_requester, miner_umbral_private_key)
    cfrag_signature_by_miner = sign_data(cfrag_bytes, miner_umbral_private_key)
    evidence = IndisputableEvidence(capsule, cfrag, ursula=None)
    evidence_data = evidence.precompute_values()
    args = [
        capsule_bytes, capsule_signature_by_requester,
        capsule_signature_by_requester_and_miner, cfrag_bytes,
        cfrag_signature_by_miner, requester_umbral_public_key_bytes,
        miner_umbral_public_key_bytes, signed_miner_umbral_public_key,
        evidence_data
    ]

    worker_stake = escrow.functions.minerInfo(miner).call()[0]
    investigator_balance = escrow.functions.rewardInfo(investigator).call()
    assert not adjudicator_contract.functions.evaluatedCFrags(data_hash).call()
    tx = adjudicator_contract.functions.evaluateCFrag(*args).transact(
        {'from': investigator})
    testerchain.wait_for_receipt(tx)
    number_of_evaluations += 1

    assert adjudicator_contract.functions.evaluatedCFrags(data_hash).call()

    penalty, reward = compute_penalty_and_reward(worker_stake,
                                                 worker_penalty_history)
    # Penalty has reached maximum available percentage of value
    assert penalty == worker_stake // PERCENTAGE_PENALTY_COEFFICIENT
    worker_stake -= penalty
    investigator_balance += reward
    worker_penalty_history += 1

    assert worker_stake == escrow.functions.minerInfo(miner).call()[0]
    assert investigator_balance == escrow.functions.rewardInfo(
        investigator).call()

    events = evaluation_log.get_all_entries()
    assert number_of_evaluations == len(events)
    event_args = events[-1]['args']
    assert data_hash == event_args['evaluationHash']
    assert miner == event_args['miner']
    assert investigator == event_args['investigator']
    assert not event_args['correctness']

    #################
    # Test: Invalid evaluations
    ##############

    # Can't evaluate miner using broken signatures
    wrong_args = args[:]
    wrong_args[1] = capsule_signature_by_requester[1:]
    with pytest.raises((TransactionFailed, ValueError)):
        tx = adjudicator_contract.functions.evaluateCFrag(
            *wrong_args).transact()
        testerchain.wait_for_receipt(tx)
    wrong_args = args[:]
    wrong_args[2] = capsule_signature_by_requester_and_miner[1:]
    with pytest.raises((TransactionFailed, ValueError)):
        tx = adjudicator_contract.functions.evaluateCFrag(
            *wrong_args).transact()
        testerchain.wait_for_receipt(tx)
    wrong_args = args[:]
    wrong_args[4] = cfrag_signature_by_miner[1:]
    with pytest.raises((TransactionFailed, ValueError)):
        tx = adjudicator_contract.functions.evaluateCFrag(
            *wrong_args).transact()
        testerchain.wait_for_receipt(tx)
    wrong_args = args[:]
    wrong_args[7] = signed_miner_umbral_public_key[1:]
    with pytest.raises((TransactionFailed, ValueError)):
        tx = adjudicator_contract.functions.evaluateCFrag(
            *wrong_args).transact()
        testerchain.wait_for_receipt(tx)

    # Can't evaluate miner using wrong keys
    wrong_args = args[:]
    wrong_args[5] = UmbralPrivateKey.gen_key().get_pubkey().to_bytes(
        is_compressed=False)
    with pytest.raises((TransactionFailed, ValueError)):
        tx = adjudicator_contract.functions.evaluateCFrag(
            *wrong_args).transact()
        testerchain.wait_for_receipt(tx)
    wrong_args = args[:]
    wrong_args[6] = UmbralPrivateKey.gen_key().get_pubkey().to_bytes(
        is_compressed=False)
    with pytest.raises((TransactionFailed, ValueError)):
        tx = adjudicator_contract.functions.evaluateCFrag(
            *wrong_args).transact()
        testerchain.wait_for_receipt(tx)

    # Can't use signature for another data
    wrong_args = args[:]
    wrong_args[0] = bytes(args[0][0] + 1) + args[0][1:]
    with pytest.raises((TransactionFailed, ValueError)):
        tx = adjudicator_contract.functions.evaluateCFrag(
            *wrong_args).transact()
        testerchain.wait_for_receipt(tx)
    wrong_args = args[:]
    wrong_args[3] = bytes(args[3][0] + 1) + args[3][1:]
    with pytest.raises((TransactionFailed, ValueError)):
        tx = adjudicator_contract.functions.evaluateCFrag(
            *wrong_args).transact()
        testerchain.wait_for_receipt(tx)

    # Can't evaluate nonexistent miner
    address = to_canonical_address(wrong_miner)
    sig_key = provider.ethereum_tester.backend._key_lookup[address]
    signed_wrong_miner_umbral_public_key = bytes(
        sig_key.sign_msg_hash(miner_umbral_public_key_hash))
    wrong_args = args[:]
    wrong_args[7] = signed_wrong_miner_umbral_public_key
    with pytest.raises((TransactionFailed, ValueError)):
        tx = adjudicator_contract.functions.evaluateCFrag(
            *wrong_args).transact()
        testerchain.wait_for_receipt(tx)
示例#25
0
def test_evaluate_cfrag(testerchain, escrow, adjudicator, token_economics,
                        blockchain_ursulas, mock_ursula_reencrypts):
    ursula = list(blockchain_ursulas)[0]

    creator, non_staker, investigator, *everyone_else = testerchain.client.accounts
    evaluation_log = adjudicator.events.CFragEvaluated.createFilter(
        fromBlock='latest')
    verdict_log = adjudicator.events.IncorrectCFragVerdict.createFilter(
        fromBlock='latest')

    worker_stake = 1000
    worker_penalty_history = 0
    investigator_balance = 0
    number_of_evaluations = 0

    def compute_penalty_and_reward(stake: int,
                                   penalty_history: int) -> Tuple[int, int]:
        penalty_ = token_economics.base_penalty
        penalty_ += token_economics.penalty_history_coefficient * penalty_history
        penalty_ = min(penalty_,
                       stake // token_economics.percentage_penalty_coefficient)
        reward_ = penalty_ // token_economics.reward_coefficient
        return penalty_, reward_

    # Prepare one staker
    staker = ursula.checksum_address
    tx = escrow.functions.setStakerInfo(staker, worker_stake,
                                        ursula.worker_address).transact()
    testerchain.wait_for_receipt(tx)

    assert ursula._stamp_has_valid_signature_by_worker()

    # Prepare evaluation data
    evidence = mock_ursula_reencrypts(ursula)
    capsule = evidence.task.capsule
    cfrag = evidence.task.cfrag
    assert cfrag.verify_correctness(capsule)

    evidence_data = evidence.precompute_values()
    assert len(evidence_data) == 20 * 32 + 32 + 20 + 5

    data_hash = sha256_digest(capsule, cfrag)
    # This capsule and cFrag are not yet evaluated
    assert not adjudicator.functions.evaluatedCFrags(data_hash).call()

    args = list(evidence.evaluation_arguments())

    # Challenge using good data
    assert worker_stake == escrow.functions.getAllTokens(staker).call()

    tx = adjudicator.functions.evaluateCFrag(*args).transact(
        {'from': investigator})
    testerchain.wait_for_receipt(tx)
    number_of_evaluations += 1
    # Hash of the data is saved and staker was not slashed
    assert adjudicator.functions.evaluatedCFrags(data_hash).call()
    assert worker_stake == escrow.functions.getAllTokens(staker).call()
    assert investigator_balance == escrow.functions.rewardInfo(
        investigator).call()

    events = evaluation_log.get_all_entries()
    assert number_of_evaluations == len(events)
    event_args = events[-1]['args']
    assert data_hash == event_args['evaluationHash']
    assert investigator == event_args['investigator']
    assert event_args['correctness']
    assert 0 == len(verdict_log.get_all_entries())

    ###############################
    # Test: Don't evaluate staker with data that already was checked
    ###############################
    with pytest.raises(TransactionFailed):
        tx = adjudicator.functions.evaluateCFrag(*args).transact()
        testerchain.wait_for_receipt(tx)

    ###############################
    # Test: Ursula produces incorrect proof:
    ###############################
    evidence = mock_ursula_reencrypts(ursula, corrupt_cfrag=True)
    capsule = evidence.task.capsule
    cfrag = evidence.task.cfrag
    assert not cfrag.verify_correctness(capsule)

    args = list(evidence.evaluation_arguments())

    data_hash = sha256_digest(capsule, cfrag)
    assert not adjudicator.functions.evaluatedCFrags(data_hash).call()

    tx = adjudicator.functions.evaluateCFrag(*args).transact(
        {'from': investigator})
    testerchain.wait_for_receipt(tx)
    number_of_evaluations += 1

    # Hash of the data is saved and staker was slashed
    assert adjudicator.functions.evaluatedCFrags(data_hash).call()

    penalty, reward = compute_penalty_and_reward(worker_stake,
                                                 worker_penalty_history)
    worker_stake -= penalty
    investigator_balance += reward
    worker_penalty_history += 1

    assert worker_stake == escrow.functions.getAllTokens(staker).call()
    assert investigator_balance == escrow.functions.rewardInfo(
        investigator).call()

    events = evaluation_log.get_all_entries()
    assert number_of_evaluations == len(events)
    event_args = events[-1]['args']
    assert data_hash == event_args['evaluationHash']
    assert investigator == event_args['investigator']
    assert not event_args['correctness']
    events = verdict_log.get_all_entries()
    assert number_of_evaluations - 1 == len(events)
    event_args = events[-1]['args']
    assert data_hash == event_args['evaluationHash']
    assert ursula.worker_address == event_args['worker']
    assert staker == event_args['staker']

    ###############################
    # Test: Bob produces wrong precomputed data
    ###############################

    evidence = mock_ursula_reencrypts(ursula)
    capsule = evidence.task.capsule
    cfrag = evidence.task.cfrag
    assert cfrag.verify_correctness(capsule)

    # Bob produces a random point and gets the bytes of coords x and y
    random_point_bytes = Point.gen_rand().to_bytes(is_compressed=False)[1:]
    # He uses this garbage instead of correct precomputation of z*E
    evidence_data = bytearray(evidence_data)
    evidence_data[32:32 + 64] = random_point_bytes
    evidence_data = bytes(evidence_data)

    args = list(evidence.evaluation_arguments())
    args[-1] = evidence_data

    data_hash = sha256_digest(capsule, cfrag)
    assert not adjudicator.functions.evaluatedCFrags(data_hash).call()

    # Evaluation must fail since Bob precomputed wrong values
    with pytest.raises(TransactionFailed):
        tx = adjudicator.functions.evaluateCFrag(*args).transact(
            {'from': investigator})
        testerchain.wait_for_receipt(tx)

    ###############################
    # Test: Second violation. Penalty is increased
    ###############################

    evidence = mock_ursula_reencrypts(ursula, corrupt_cfrag=True)
    capsule = evidence.task.capsule
    cfrag = evidence.task.cfrag
    assert not cfrag.verify_correctness(capsule)

    args = list(evidence.evaluation_arguments())

    data_hash = sha256_digest(capsule, cfrag)
    assert not adjudicator.functions.evaluatedCFrags(data_hash).call()

    worker_stake = escrow.functions.getAllTokens(staker).call()
    investigator_balance = escrow.functions.rewardInfo(investigator).call()

    assert not adjudicator.functions.evaluatedCFrags(data_hash).call()
    tx = adjudicator.functions.evaluateCFrag(*args).transact(
        {'from': investigator})
    testerchain.wait_for_receipt(tx)
    number_of_evaluations += 1

    assert adjudicator.functions.evaluatedCFrags(data_hash).call()

    previous_penalty = penalty
    penalty, reward = compute_penalty_and_reward(worker_stake,
                                                 worker_penalty_history)
    # Penalty was increased because it's the second violation
    assert penalty == previous_penalty + token_economics.penalty_history_coefficient
    worker_stake -= penalty
    investigator_balance += reward
    worker_penalty_history += 1

    assert worker_stake == escrow.functions.getAllTokens(staker).call()
    assert investigator_balance == escrow.functions.rewardInfo(
        investigator).call()

    events = evaluation_log.get_all_entries()
    assert number_of_evaluations == len(events)
    event_args = events[-1]['args']
    assert data_hash == event_args['evaluationHash']
    assert investigator == event_args['investigator']
    assert not event_args['correctness']
    events = verdict_log.get_all_entries()
    assert number_of_evaluations - 1 == len(events)
    event_args = events[-1]['args']
    assert data_hash == event_args['evaluationHash']
    assert ursula.worker_address == event_args['worker']
    assert staker == event_args['staker']

    ###############################
    # Test: Third violation. Penalty reaches the maximum allowed
    ###############################

    evidence = mock_ursula_reencrypts(ursula, corrupt_cfrag=True)
    capsule = evidence.task.capsule
    cfrag = evidence.task.cfrag
    assert not cfrag.verify_correctness(capsule)

    args = list(evidence.evaluation_arguments())

    data_hash = sha256_digest(capsule, cfrag)
    assert not adjudicator.functions.evaluatedCFrags(data_hash).call()

    worker_stake = escrow.functions.getAllTokens(staker).call()
    investigator_balance = escrow.functions.rewardInfo(investigator).call()

    tx = adjudicator.functions.evaluateCFrag(*args).transact(
        {'from': investigator})
    testerchain.wait_for_receipt(tx)
    number_of_evaluations += 1

    assert adjudicator.functions.evaluatedCFrags(data_hash).call()

    penalty, reward = compute_penalty_and_reward(worker_stake,
                                                 worker_penalty_history)
    # Penalty has reached maximum available percentage of value
    assert penalty == worker_stake // token_economics.percentage_penalty_coefficient
    worker_stake -= penalty
    investigator_balance += reward
    worker_penalty_history += 1

    assert worker_stake == escrow.functions.getAllTokens(staker).call()
    assert investigator_balance == escrow.functions.rewardInfo(
        investigator).call()

    events = evaluation_log.get_all_entries()
    assert number_of_evaluations == len(events)
    event_args = events[-1]['args']
    assert data_hash == event_args['evaluationHash']
    assert investigator == event_args['investigator']
    assert not event_args['correctness']
    events = verdict_log.get_all_entries()
    assert number_of_evaluations - 1 == len(events)
    event_args = events[-1]['args']
    assert data_hash == event_args['evaluationHash']
    assert ursula.worker_address == event_args['worker']
    assert staker == event_args['staker']

    #################
    # Test: Invalid evaluations
    ##############

    evidence = mock_ursula_reencrypts(ursula, corrupt_cfrag=True)
    capsule = evidence.task.capsule
    cfrag = evidence.task.cfrag
    assert not cfrag.verify_correctness(capsule)

    args = list(evidence.evaluation_arguments())

    data_hash = sha256_digest(capsule, cfrag)
    assert not adjudicator.functions.evaluatedCFrags(data_hash).call()

    # Can't evaluate staker using broken signatures
    wrong_args = list(args)
    wrong_args[2] = evidence.task.cfrag_signature[1:]
    with pytest.raises(TransactionFailed):
        tx = adjudicator.functions.evaluateCFrag(*wrong_args).transact()
        testerchain.wait_for_receipt(tx)

    wrong_args = list(args)
    wrong_args[3] = evidence.task.signature[1:]
    with pytest.raises(TransactionFailed):
        tx = adjudicator.functions.evaluateCFrag(*wrong_args).transact()
        testerchain.wait_for_receipt(tx)

    wrong_args = list(args)
    wrong_args[7] = wrong_args[7][1:]
    with pytest.raises(TransactionFailed):
        tx = adjudicator.functions.evaluateCFrag(*wrong_args).transact()
        testerchain.wait_for_receipt(tx)

    # Can't evaluate staker using wrong keys
    wrong_args = list(args)
    wrong_args[5] = UmbralPrivateKey.gen_key().get_pubkey().to_bytes(
        is_compressed=False)[1:]
    with pytest.raises(TransactionFailed):
        tx = adjudicator.functions.evaluateCFrag(*wrong_args).transact()
        testerchain.wait_for_receipt(tx)

    wrong_args = list(args)
    wrong_args[6] = UmbralPrivateKey.gen_key().get_pubkey().to_bytes(
        is_compressed=False)[1:]
    with pytest.raises(TransactionFailed):
        tx = adjudicator.functions.evaluateCFrag(*wrong_args).transact()
        testerchain.wait_for_receipt(tx)

    # Can't use signature for another data
    wrong_args = list(args)
    wrong_args[1] = os.urandom(len(bytes(cfrag)))
    with pytest.raises(TransactionFailed):
        tx = adjudicator.functions.evaluateCFrag(*wrong_args).transact()
        testerchain.wait_for_receipt(tx)

    # Can't evaluate nonexistent staker
    signed_stamp = testerchain.client.sign_message(account=non_staker,
                                                   message=bytes(ursula.stamp))

    wrong_args = list(args)
    wrong_args[7] = signed_stamp
    with pytest.raises(TransactionFailed):
        tx = adjudicator.functions.evaluateCFrag(*wrong_args).transact()
        testerchain.wait_for_receipt(tx)

    # Can't evaluate staker without tokens
    tx = escrow.functions.setStakerInfo(non_staker, 0,
                                        ursula.worker_address).transact()
    testerchain.wait_for_receipt(tx)
    with pytest.raises((TransactionFailed, ValueError)):
        tx = adjudicator.functions.evaluateCFrag(*wrong_args).transact()
        testerchain.wait_for_receipt(tx)

    # If the non-staker starts to stake, then she can be slashed
    new_staker = non_staker
    tx = escrow.functions.setStakerInfo(new_staker, worker_stake,
                                        ursula.worker_address).transact()
    testerchain.wait_for_receipt(tx)

    evidence = mock_ursula_reencrypts(ursula, corrupt_cfrag=True)
    capsule = evidence.task.capsule
    cfrag = evidence.task.cfrag
    assert not cfrag.verify_correctness(capsule)

    args = list(evidence.evaluation_arguments())
    data_hash = sha256_digest(capsule, cfrag)
    assert not adjudicator.functions.evaluatedCFrags(data_hash).call()

    tx = adjudicator.functions.evaluateCFrag(*args).transact(
        {'from': investigator})
    testerchain.wait_for_receipt(tx)
    number_of_evaluations += 1

    assert adjudicator.functions.evaluatedCFrags(data_hash).call()

    penalty, reward = compute_penalty_and_reward(worker_stake,
                                                 worker_penalty_history)
    worker_stake -= penalty
    investigator_balance += reward
    worker_penalty_history += 1

    assert worker_stake == escrow.functions.getAllTokens(new_staker).call()
    assert investigator_balance == escrow.functions.rewardInfo(
        investigator).call()

    events = evaluation_log.get_all_entries()
    assert number_of_evaluations == len(events)
    event_args = events[-1]['args']
    assert data_hash == event_args['evaluationHash']
    assert investigator == event_args['investigator']
    assert not event_args['correctness']
    events = verdict_log.get_all_entries()
    assert number_of_evaluations - 1 == len(events)
    event_args = events[-1]['args']
    assert data_hash == event_args['evaluationHash']
    assert ursula.worker_address == event_args['worker']
    assert new_staker == event_args['staker']
示例#26
0
def test_ec_point_operations(testerchain, reencryption_validator):
    valid_point = Point.gen_rand()
    x, y = valid_point.to_affine()

    # Test isOnCurve
    assert reencryption_validator.functions.isOnCurve(x, y).call()

    bad_y = y - 1
    assert not reencryption_validator.functions.isOnCurve(x, bad_y).call()

    # Test checkCompressedPoint
    sign = 2 + (y % 2)
    assert reencryption_validator.functions.checkCompressedPoint(sign, x,
                                                                 y).call()

    bad_sign = 3 - (y % 2)
    assert not reencryption_validator.functions.checkCompressedPoint(
        bad_sign, x, y).call()

    # Test checkSerializedCoordinates
    coords = valid_point.to_bytes(is_compressed=False)[1:]
    assert reencryption_validator.functions.checkSerializedCoordinates(
        coords).call()

    coords = coords[:-1] + ((coords[-1] + 42) % 256).to_bytes(1, 'big')
    assert not reencryption_validator.functions.checkSerializedCoordinates(
        coords).call()

    # Test ecmulVerify
    P = valid_point
    scalar = CurveBN.gen_rand()
    Q = scalar * P
    qx, qy = Q.to_affine()

    assert reencryption_validator.functions.ecmulVerify(
        x, y, int(scalar), qx, qy).call()
    assert not reencryption_validator.functions.ecmulVerify(
        x, y, int(scalar), x, y).call()

    # Test eqAffineJacobian
    Q_affine = [qx, qy]
    Q_jacobian = [qx, qy, 1]
    assert reencryption_validator.functions.eqAffineJacobian(
        Q_affine, Q_jacobian).call()

    P_jacobian = [x, y, 1]
    assert not reencryption_validator.functions.eqAffineJacobian(
        Q_affine, P_jacobian).call()

    point_at_infinity = [x, y, 0]
    random_point = Point.gen_rand()
    assert not reencryption_validator.functions.eqAffineJacobian(
        random_point.to_affine(), point_at_infinity).call()

    # Test doubleJacobian
    doubleP = reencryption_validator.functions.doubleJacobian(
        P_jacobian).call()
    assert reencryption_validator.functions.eqAffineJacobian(
        (P + P).to_affine(), doubleP).call()

    # Test addAffineJacobian
    scalar1 = CurveBN.gen_rand()
    scalar2 = CurveBN.gen_rand()
    R1 = scalar1 * P
    R2 = scalar2 * P

    assert R1 + R2 == (scalar1 + scalar2) * P
    R = reencryption_validator.functions.addAffineJacobian(
        R1.to_affine(), R2.to_affine()).call()
    assert reencryption_validator.functions.eqAffineJacobian(
        (R1 + R2).to_affine(), R).call()

    P_plus_P = reencryption_validator.functions.addAffineJacobian(
        P.to_affine(), P.to_affine()).call()
    assert reencryption_validator.functions.eqAffineJacobian(
        (P + P).to_affine(), P_plus_P).call()
示例#27
0
def test_validate_cfrag(testerchain, reencryption_validator,
                        mock_ursula_reencrypts):
    ursula_privkey = UmbralPrivateKey.gen_key()
    ursula_stamp = SignatureStamp(verifying_key=ursula_privkey.pubkey,
                                  signer=Signer(ursula_privkey))
    ursula = Mock(stamp=ursula_stamp)

    ###############################
    # Test: Ursula produces correct proof:
    ###############################

    # Bob prepares supporting Evidence
    evidence = mock_ursula_reencrypts(ursula)
    evidence_data = evidence.precompute_values()
    assert len(evidence_data) == 20 * 32 + 32 + 20 + 5

    # Challenge using good data
    capsule = evidence.task.capsule
    cfrag = evidence.task.cfrag
    capsule_bytes = capsule.to_bytes()
    cfrag_bytes = cfrag.to_bytes()
    args = (capsule_bytes, cfrag_bytes, evidence_data)
    assert reencryption_validator.functions.validateCFrag(*args).call()

    ###############################
    # Test: Ursula produces incorrect proof:
    ###############################
    evidence = mock_ursula_reencrypts(ursula, corrupt_cfrag=True)
    capsule = evidence.task.capsule
    cfrag = evidence.task.cfrag
    capsule_bytes = capsule.to_bytes()
    cfrag_bytes = cfrag.to_bytes()
    assert not cfrag.verify_correctness(capsule)

    evidence_data = evidence.precompute_values()
    args = (capsule_bytes, cfrag_bytes, evidence_data)
    assert not reencryption_validator.functions.validateCFrag(*args).call()

    ###############################
    # Test: Bob produces wrong precomputed data
    ###############################
    evidence = mock_ursula_reencrypts(ursula)
    capsule = evidence.task.capsule
    cfrag = evidence.task.cfrag
    capsule_bytes = capsule.to_bytes()
    cfrag_bytes = cfrag.to_bytes()
    assert cfrag.verify_correctness(capsule)

    evidence_data = evidence.precompute_values()

    # Bob produces a random point and gets the bytes of coords x and y
    random_point_bytes = Point.gen_rand().to_bytes(is_compressed=False)[1:]
    # He uses this garbage instead of correct precomputation of z*E
    evidence_data = bytearray(evidence_data)
    evidence_data[32:32 + 64] = random_point_bytes
    evidence_data = bytes(evidence_data)

    args = (capsule_bytes, cfrag_bytes, evidence_data)

    # Evaluation must fail since Bob precomputed wrong values
    with pytest.raises(TransactionFailed):
        _ = reencryption_validator.functions.validateCFrag(*args).call()
示例#28
0
vector_suite = {
    'name' : 'Test vectors for umbral.curvebn.CurveBN.hash()',
    'params' : 'default',
    'vectors' : vectors
}

create_test_vector_file(vector_suite, 'vectors_curvebn_hash.json', generate_again=generate_again)
#print(json.dumps(vector_suite, indent=2))


##########
# Points #
##########

point1 = Point.gen_rand(curve)
point2 = Point.gen_rand(curve)

# Expected results for some Point operations
expected = [('Addition', point1 + point2),
            ('Subtraction', point1 - point2),
            ('Multiplication', bn1 * point1),
            ('Inversion', -point1),
            ('To_affine.X', point1.to_affine()[0]),
            ('To_affine.Y', point1.to_affine()[1]),
            ('kdf', kdf(point1, pre.DEM_KEYSIZE)),
            ]

expected = [{'operation': op, 'result': hexlify(result)} for (op, result) in expected]

# Definition of test vector
示例#29
0
def test_cheating_ursula_sends_garbage(N, M):
    priv_key_alice = keys.UmbralPrivateKey.gen_key()
    pub_key_alice = priv_key_alice.get_pubkey()

    # Bob
    priv_key_bob = keys.UmbralPrivateKey.gen_key()
    pub_key_bob = priv_key_bob.get_pubkey()

    sym_key, capsule_alice = pre._encapsulate(pub_key_alice.point_key)
    kfrags = pre.split_rekey(priv_key_alice, pub_key_bob, M, N)

    cfrags, challenges = [], []
    for i, kfrag in enumerate(kfrags[:M]):
        cfrag = pre.reencrypt(kfrag, capsule_alice)
        metadata = ("Challenge metadata: index {}".format(i)).encode()
        challenge = pre._challenge(kfrag, capsule_alice, cfrag, metadata)
        capsule_alice.attach_cfrag(cfrag)

        assert pre._check_challenge(capsule_alice,
                                   cfrag,
                                   challenge,
                                   pub_key_alice.point_key,
                                   pub_key_bob.point_key,
                                   metadata
                                   )

        cfrags.append(cfrag)
        challenges.append(challenge)

    # Let's put random garbage in one of the cfrags
    cfrags[0].point_eph_e1 = Point.gen_rand()
    cfrags[0].point_eph_v1 = Point.gen_rand()

    capsule_alice._reconstruct_shamirs_secret(pub_key_alice, priv_key_bob)    # activate capsule

    with pytest.raises(pre.GenericUmbralError):
        sym_key2 = pre._decapsulate_reencrypted(pub_key_bob.point_key,
                                               priv_key_bob.bn_key,
                                               pub_key_alice.point_key,
                                               capsule_alice)

    metadata = b"Challenge metadata: index 0"
    assert not pre._check_challenge(capsule_alice, 
                                   cfrags[0], 
                                   challenges[0], 
                                   pub_key_alice.point_key, 
                                   pub_key_bob.point_key,
                                   metadata
                                   )

    # The response of cheating Ursula is in capsules[0],
    # so the rest of challenges chould be correct:
    for i, challenge in enumerate(challenges[1:], 1):
        cfrag = cfrags[i]
        metadata = ("Challenge metadata: index {}".format(i)).encode()
        assert pre._check_challenge(capsule_alice, 
                                   cfrag, 
                                   challenge, 
                                   pub_key_alice.point_key, 
                                   pub_key_bob.point_key,
                                   metadata
                                   )