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())
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
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)
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])
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)
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)
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)
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)
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)
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
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'
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()
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)
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
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)
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)
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']
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()
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()
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
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 )