def _decapsulate_reencrypted(receiving_privkey: UmbralPrivateKey, capsule: Capsule, key_length: int = DEM_KEYSIZE) -> bytes: """Derive the same symmetric encapsulated_key""" params = capsule.params pub_key = receiving_privkey.get_pubkey().point_key priv_key = receiving_privkey.bn_key precursor = capsule._attached_cfrags[0].point_precursor dh_point = priv_key * precursor # Combination of CFrags via Shamir's Secret Sharing reconstruction xs = list() for cfrag in capsule._attached_cfrags: x = hash_to_curvebn(precursor, pub_key, dh_point, bytes(constants.X_COORDINATE), cfrag.kfrag_id, params=params) xs.append(x) e_summands, v_summands = list(), list() for cfrag, x in zip(capsule._attached_cfrags, xs): if precursor != cfrag.point_precursor: raise ValueError("Attached CFrags are not pairwise consistent") lambda_i = lambda_coeff(x, xs) e_summands.append(lambda_i * cfrag.point_e1) v_summands.append(lambda_i * cfrag.point_v1) e_prime = sum(e_summands[1:], e_summands[0]) v_prime = sum(v_summands[1:], v_summands[0]) # Secret value 'd' allows to make Umbral non-interactive d = hash_to_curvebn(precursor, pub_key, dh_point, bytes(constants.NON_INTERACTIVE), params=params) e, v, s = capsule.components() h = hash_to_curvebn(e, v, params=params) orig_pub_key = capsule.get_correctness_keys( )['delegating'].point_key # type: ignore if not (s / d) * orig_pub_key == (h * e_prime) + v_prime: raise GenericUmbralError() shared_key = d * (e_prime + v_prime) encapsulated_key = kdf(shared_key, key_length) return encapsulated_key
def test_extended_keccak_to_bn(testerchain, reencryption_validator): test_data = os.urandom(40) h = hash_to_curvebn(test_data, params=default_params(), hash_class=ExtendedKeccak) assert int(h) == reencryption_validator.functions.extendedKeccakToBN( test_data).call()
def verify_correctness(self, capsule) -> bool: if self.proof is None: raise CapsuleFrag.NoProofProvided correctness_keys = capsule.get_correctness_keys() delegating_pubkey = correctness_keys['delegating'] signing_pubkey = correctness_keys['verifying'] receiving_pubkey = correctness_keys['receiving'] params = capsule.params #### # Here are the formulaic constituents shared with `prove_correctness`. #### e = capsule.point_e v = capsule.point_v e1 = self.point_e1 v1 = self.point_v1 u = params.u u1 = self.proof.point_kfrag_commitment e2 = self.proof.point_e2 v2 = self.proof.point_v2 u2 = self.proof.point_kfrag_pok hash_input = [e, e1, e2, v, v1, v2, u, u1, u2] if self.proof.metadata is not None: hash_input.append(self.proof.metadata) h = hash_to_curvebn(*hash_input, params=params, hash_class=ExtendedKeccak) ######## precursor = self.point_precursor kfrag_id = self.kfrag_id validity_input = (kfrag_id, delegating_pubkey, receiving_pubkey, u1, precursor) kfrag_validity_message = bytes().join( bytes(item) for item in validity_input) # valid_kfrag_signature = self.proof.kfrag_signature.verify(kfrag_validity_message, signing_pubkey) valid_kfrag_signature = True z3 = self.proof.bn_sig correct_reencryption_of_e = z3 * e == e2 + (h * e1) correct_reencryption_of_v = z3 * v == v2 + (h * v1) correct_rk_commitment = z3 * u == u2 + (h * u1) return valid_kfrag_signature \ & correct_reencryption_of_e \ & correct_reencryption_of_v \ & correct_rk_commitment
def verify(self) -> bool: g = self.params.g e, v, s = self.components() h = hash_to_curvebn(e, v, params=self.params) result = s * g == v + (h * e) # type: bool return result
def test_curvebn_hash(): vector_file = os.path.join('vectors', 'vectors_curvebn_hash.json') try: with open(vector_file) as f: vector_suite = json.load(f) except OSError: raise params = default_params() for vector in vector_suite['vectors']: hash_input = [bytes.fromhex(item['bytes']) for item in vector['input']] expected = CurveBN.from_bytes(bytes.fromhex(vector['output'])) assert hash_to_curvebn(*hash_input, params=params) == expected
def prove_correctness(self, capsule, kfrag, metadata: Optional[bytes] = None): params = capsule.params # Check correctness of original ciphertext if not capsule.verify(): raise capsule.NotValid("Capsule verification failed.") rk = kfrag.bn_key t = CurveBN.gen_rand(params.curve) #### # Here are the formulaic constituents shared with `verify_correctness`. #### e = capsule.point_e v = capsule.point_v e1 = self.point_e1 v1 = self.point_v1 u = params.u u1 = kfrag.point_commitment e2 = t * e # type: Any v2 = t * v # type: Any u2 = t * u # type: Any hash_input = [e, e1, e2, v, v1, v2, u, u1, u2] if metadata is not None: hash_input.append(metadata) h = hash_to_curvebn(*hash_input, params=params, hash_class=ExtendedKeccak) ######## z3 = t + h * rk self.attach_proof(e2, v2, u1, u2, metadata=metadata, z3=z3, kfrag_signature=kfrag.signature_for_bob)
def derive_privkey_by_label( self, label: bytes, salt: Optional[bytes] = None, params: Optional[UmbralParameters] = None) -> UmbralPrivateKey: """ Derives an UmbralPrivateKey using a KDF from this instance of UmbralKeyingMaterial, a label, and an optional salt. """ params = params if params is not None else default_params() key_material = Hkdf( salt, self.__keying_material, hash=blake2b, ).expand(info=b"NuCypher/KeyDerivation/" + label, length=64) bn_key = hash_to_curvebn(key_material, params=params) return UmbralPrivateKey(bn_key, params)
def derive_privkey_by_label(self, label: bytes, salt: Optional[bytes] = None, params: Optional[UmbralParameters] = None) -> UmbralPrivateKey: """ Derives an UmbralPrivateKey using a KDF from this instance of UmbralKeyingMaterial, a label, and an optional salt. """ params = params if params is not None else default_params() key_material = HKDF( algorithm=hashes.BLAKE2b(64), length=64, salt=salt, info=b"NuCypher/KeyDerivation/"+label, backend=default_backend() ).derive(self.__keying_material) bn_key = hash_to_curvebn(key_material, params=params) return UmbralPrivateKey(bn_key, params)
def get_proof_challenge_scalar(self) -> CurveBN: umbral_params = default_params() e, v, _ = self.capsule.components() e1 = self.cfrag.point_e1 v1 = self.cfrag.point_v1 e2 = self.cfrag.proof.point_e2 v2 = self.cfrag.proof.point_v2 u = umbral_params.u u1 = self.cfrag.proof.point_kfrag_commitment u2 = self.cfrag.proof.point_kfrag_pok metadata = self.cfrag.proof.metadata from umbral.random_oracles import hash_to_curvebn, ExtendedKeccak hash_input = (e, e1, e2, v, v1, v2, u, u1, u2, metadata) h = hash_to_curvebn(*hash_input, params=umbral_params, hash_class=ExtendedKeccak) return h
def _encapsulate(alice_pubkey: UmbralPublicKey, key_length: int = DEM_KEYSIZE) -> Tuple[bytes, Capsule]: """Generates a symmetric key and its associated KEM ciphertext""" params = alice_pubkey.params g = params.g priv_r = CurveBN.gen_rand(params.curve) pub_r = priv_r * g # type: Any priv_u = CurveBN.gen_rand(params.curve) pub_u = priv_u * g # type: Any h = hash_to_curvebn(pub_r, pub_u, params=params) s = priv_u + (priv_r * h) shared_key = (priv_r + priv_u) * alice_pubkey.point_key # type: Any # Key to be used for symmetric encryption key = kdf(shared_key, key_length) return key, Capsule(point_e=pub_r, point_v=pub_u, bn_sig=s, params=params)
def test_cant_hash_arbitrary_object_into_bignum(): whatever = object() with pytest.raises(TypeError): hash_to_curvebn(whatever)
################### # hash_to_curvebn # ################### # Test vectors for different kinds of inputs (bytes, Points, CurveBNs, etc.) inputs = ([b''], [b'abc'], [capsule.point_e], [z], [capsule.point_e, z], points, ) vectors = list() for input_to_hash in inputs: bn_output = hash_to_curvebn(*input_to_hash, params=params) json_input = [{'class': data.__class__.__name__, 'bytes': hexlify(data), } for data in input_to_hash] json_input = {'input': json_input, 'output': hexlify(bn_output) } vectors.append(json_input) 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)
def generate_kfrags( delegating_privkey: UmbralPrivateKey, receiving_pubkey: UmbralPublicKey, threshold: int, N: int, signer: Signer, sign_delegating_key: Optional[bool] = True, sign_receiving_key: Optional[bool] = True, ) -> List[KFrag]: """ Creates a re-encryption key from Alice's delegating public key to Bob's receiving public key, and splits it in KFrags, using Shamir's Secret Sharing. Requires a threshold number of KFrags out of N. Returns a list of N KFrags """ if threshold <= 0 or threshold > N: raise ValueError( 'Arguments threshold and N must satisfy 0 < threshold <= N') if delegating_privkey.params != receiving_pubkey.params: raise ValueError("Keys must have the same parameter set.") params = delegating_privkey.params g = params.g delegating_pubkey = delegating_privkey.get_pubkey() bob_pubkey_point = receiving_pubkey.point_key # The precursor point is used as an ephemeral public key in a DH key exchange, # and the resulting shared secret 'dh_point' is used to derive other secret values private_precursor = CurveBN.gen_rand(params.curve) precursor = private_precursor * g # type: Any dh_point = private_precursor * bob_pubkey_point # Secret value 'd' allows to make Umbral non-interactive d = hash_to_curvebn(precursor, bob_pubkey_point, dh_point, bytes(constants.NON_INTERACTIVE), params=params) # Coefficients of the generating polynomial coefficients = [delegating_privkey.bn_key * (~d)] coefficients += [ CurveBN.gen_rand(params.curve) for _ in range(threshold - 1) ] bn_size = CurveBN.expected_bytes_length(params.curve) kfrags = list() for _ in range(N): kfrag_id = os.urandom(bn_size) # The index of the re-encryption key share (which in Shamir's Secret # Sharing corresponds to x in the tuple (x, f(x)), with f being the # generating polynomial), is used to prevent reconstruction of the # re-encryption key without Bob's intervention share_index = hash_to_curvebn(precursor, bob_pubkey_point, dh_point, bytes(constants.X_COORDINATE), kfrag_id, params=params) # The re-encryption key share is the result of evaluating the generating # polynomial for the index value rk = poly_eval(coefficients, share_index) commitment = rk * params.u # type: Any validity_message_for_bob = ( kfrag_id, delegating_pubkey, receiving_pubkey, commitment, precursor, ) # type: Any validity_message_for_bob = bytes().join( bytes(item) for item in validity_message_for_bob) signature_for_bob = signer(validity_message_for_bob) if sign_delegating_key and sign_receiving_key: mode = DELEGATING_AND_RECEIVING elif sign_delegating_key: mode = DELEGATING_ONLY elif sign_receiving_key: mode = RECEIVING_ONLY else: mode = NO_KEY validity_message_for_proxy = [kfrag_id, commitment, precursor, mode] # type: Any if sign_delegating_key: validity_message_for_proxy.append(delegating_pubkey) if sign_receiving_key: validity_message_for_proxy.append(receiving_pubkey) validity_message_for_proxy = bytes().join( bytes(item) for item in validity_message_for_proxy) signature_for_proxy = signer(validity_message_for_proxy) kfrag = KFrag( identifier=kfrag_id, bn_key=rk, point_commitment=commitment, point_precursor=precursor, signature_for_proxy=signature_for_proxy, signature_for_bob=signature_for_bob, keys_in_signature=mode, ) kfrags.append(kfrag) return kfrags
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') # TODO: Move this to an integration test? umbral_params = default_params() u_xcoord, u_ycoord = umbral_params.u.to_affine() u_sign = 2 + (u_ycoord % 2) assert u_sign == adjudicator_contract.functions.UMBRAL_PARAMETER_U_SIGN().call() assert u_xcoord == adjudicator_contract.functions.UMBRAL_PARAMETER_U_XCOORD().call() assert u_ycoord == adjudicator_contract.functions.UMBRAL_PARAMETER_U_YCOORD().call() # TODO: Move this to an integration test? test_data = os.urandom(40) h = hash_to_curvebn(test_data, params=umbral_params, hash_class=ExtendedKeccak) assert int(h) == adjudicator_contract.functions.extendedKeccakToBN(test_data).call() # Prepare one miner tx = escrow.functions.setMinerInfo(miner, 1000).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) value = escrow.functions.minerInfo(miner).call()[0] tx = adjudicator_contract.functions.evaluateCFrag(*args).transact({'from': investigator}) testerchain.wait_for_receipt(tx) # Hash of the data is saved and miner was not slashed assert adjudicator_contract.functions.evaluatedCFrags(data_hash).call() assert value == escrow.functions.minerInfo(miner).call()[0] assert 0 == escrow.functions.rewardInfo(investigator).call() events = evaluation_log.get_all_entries() assert 1 == len(events) event_args = events[0]['args'] assert data_hash == event_args['evaluationHash'] assert miner == event_args['miner'] assert investigator == event_args['investigator'] assert event_args['correctness'] # Can'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) # Challenge using bad 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() tx = adjudicator_contract.functions.evaluateCFrag(*args).transact({'from': investigator}) testerchain.wait_for_receipt(tx) # Hash of the data is saved and miner was slashed assert adjudicator_contract.functions.evaluatedCFrags(data_hash).call() assert value - BASE_PENALTY == escrow.functions.minerInfo(miner).call()[0] assert BASE_PENALTY / REWARD_COEFFICIENT == escrow.functions.rewardInfo(investigator).call() events = evaluation_log.get_all_entries() assert 2 == 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'] # 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() # 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) # Initial arguments were correct value = escrow.functions.minerInfo(miner).call()[0] reward = 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) assert adjudicator_contract.functions.evaluatedCFrags(data_hash).call() # Penalty was increased because it's the second violation assert value - (BASE_PENALTY + PENALTY_HISTORY_COEFFICIENT) == escrow.functions.minerInfo(miner).call()[0] assert reward + (BASE_PENALTY + PENALTY_HISTORY_COEFFICIENT) / REWARD_COEFFICIENT == \ escrow.functions.rewardInfo(investigator).call() events = evaluation_log.get_all_entries() assert 3 == len(events) event_args = events[2]['args'] assert data_hash == event_args['evaluationHash'] assert miner == event_args['miner'] assert investigator == event_args['investigator'] assert not event_args['correctness'] # 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) value = escrow.functions.minerInfo(miner).call()[0] reward = 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) assert adjudicator_contract.functions.evaluatedCFrags(data_hash).call() # Penalty was decreased because it's more than maximum available percentage of value assert value - value // PERCENTAGE_PENALTY_COEFFICIENT == escrow.functions.minerInfo(miner).call()[0] assert reward + value // PERCENTAGE_PENALTY_COEFFICIENT / REWARD_COEFFICIENT == \ escrow.functions.rewardInfo(investigator).call() events = evaluation_log.get_all_entries() assert 4 == len(events) event_args = events[3]['args'] assert data_hash == event_args['evaluationHash'] assert miner == event_args['miner'] assert investigator == event_args['investigator'] assert not event_args['correctness']