Remove use of threshold decryption request when encrypting data - should not be returned when encrypting - it's use is for decrypting (variant and context)..

pull/3179/head
derekpierre 2023-07-09 10:41:02 -04:00
parent ee91cca87b
commit 6fb61bacec
4 changed files with 73 additions and 150 deletions

View File

@ -19,30 +19,18 @@ before_the_beginning_of_time = {
},
}
ciphertext, tdr = enrico.encrypt_for_dkg_and_produce_decryption_request(
ciphertext = enrico.encrypt_for_dkg(
plaintext=plaintext,
conditions=before_the_beginning_of_time,
ritual_id=ANYTHING_CAN_BE_PASSED_AS_RITUAL_ID,
)
cleartest_from_tdr = bob.threshold_decrypt(
cleartext_from_ciphertext = bob.threshold_decrypt(
ciphertext=ciphertext,
ritual_id=ANYTHING_CAN_BE_PASSED_AS_RITUAL_ID,
conditions=before_the_beginning_of_time,
)
cohort = bob._dkg_insight.fake_ritual.fake_nodes
cleartext_from_ciphertext = bob.decrypt_using_existing_decryption_request(
tdr,
participant_public_keys=bob._dkg_insight.fake_ritual.participant_public_keys,
cohort=cohort,
threshold=1,
)
decoded_cleartext_from_ciphertext = bytes(cleartext_from_ciphertext)
decoded_cleartext_from_tdr = bytes(cleartest_from_tdr)
assert decoded_cleartext_from_ciphertext == plaintext
assert plaintext == decoded_cleartext_from_tdr
print(f"Decrypted cleartext: {decoded_cleartext_from_ciphertext}")

View File

@ -12,10 +12,10 @@ from nucypher_core import (
from nucypher.characters.lawful import Bob, Enrico
from nucypher.cli.types import ChecksumAddress
from nucypher.crypto.ferveo import dkg
from nucypher.crypto.powers import ThresholdRequestDecryptingPower
from nucypher.network.decryption import ThresholdDecryptionClient
from nucypher.network.middleware import RestMiddleware
from nucypher.utilities.concurrency import Failure
class FakeNode:
@ -71,7 +71,7 @@ class DKGOmniscient:
class DKGInsight:
# TODO: Make these configurable:
tau = 1
tau = 1 # ritual id
security_threshold = 3
shares_num = 4
@ -102,36 +102,29 @@ class DKGOmniscient:
# Validators must be sorted by their public key
validators.sort(key=attrgetter("address"))
# Each validator holds their own DKG instance and generates a transcript every
# validator, including themselves
self.aggregation_messages = []
# Each validator generates a transcript which is publicly stored
self.transcripts = []
for sender in validators:
dkg = ferveo.Dkg(
tau=self.tau,
shares_num=self.shares_num,
security_threshold=self.security_threshold,
validators=validators,
transcript = dkg.generate_transcript(
ritual_id=self.tau,
me=sender,
shares=self.shares_num,
threshold=self.security_threshold,
nodes=validators,
)
self.aggregation_messages.append(
ferveo.ValidatorMessage(sender, dkg.generate_transcript())
)
self.transcripts.append((sender, transcript))
self.dkg = dkg
self.validators = validators
self.validator_keypairs = validator_keypairs
self.server_aggregate = dkg.aggregate_transcripts(self.aggregation_messages)
assert self.server_aggregate.verify(
self.shares_num, self.aggregation_messages
)
# And the client can also aggregate and verify the transcripts
self.client_aggregate = ferveo.AggregatedTranscript(
self.aggregation_messages
)
assert self.server_aggregate.verify(
self.shares_num, self.aggregation_messages
# any validator can generate the same aggregated transcript
self.server_aggregate, self.dkg_public_key = dkg.aggregate_transcripts(
ritual_id=self.tau,
me=validators[0],
shares=self.shares_num,
threshold=self.security_threshold,
transcripts=self.transcripts,
)
_dkg_insight = DKGInsight()
@ -148,7 +141,7 @@ class NiceGuyEddie(Enrico, DKGOmniscient):
del encrypting_key # We take this to match the Enrico public API, but we don't use it, because...
# ...we're going to use the DKG public key as the encrypting key, and ignore the key passed in.
encrypting_key_we_actually_want_to_use = self._dkg_insight.dkg.public_key
encrypting_key_we_actually_want_to_use = self._dkg_insight.dkg_public_key
super().__init__(
# https://imgflip.com/i/7o0po4
encrypting_key=encrypting_key_we_actually_want_to_use,
@ -174,54 +167,54 @@ class DKGOmniscientDecryptionClient(ThresholdDecryptionClient):
# We only really need one encrypted tdr.
etdr = list(encrypted_requests.values())[0]
# decrypt request
threshold_decryption_request = trdp.decrypt_encrypted_request(etdr)
ciphertext = threshold_decryption_request.ciphertext
conditions = str(threshold_decryption_request.conditions).encode()
ritual_id = threshold_decryption_request.ritual_id
variant = threshold_decryption_request.variant
# We can obtain the transcripts from the side-channel (deserialize) and aggregate them
validator_messages = [
ferveo.ValidatorMessage(validator, transcript)
for validator, transcript in self._learner._dkg_insight.transcripts
]
aggregate = ferveo.AggregatedTranscript(validator_messages)
assert aggregate.verify(
self._learner._dkg_insight.shares_num,
# TODO this list should have to be passed again (either make `verify` static or use list
# provided in constructor
validator_messages,
)
for validator, validator_keypair in zip(
self._learner._dkg_insight.validators,
self._learner._dkg_insight.validator_keypairs,
):
dkg = ferveo.Dkg(
tau=self._learner._dkg_insight.tau,
shares_num=self._learner._dkg_insight.shares_num,
security_threshold=self._learner._dkg_insight.security_threshold,
validators=self._learner._dkg_insight.validators,
# get decryption fragments/shares
decryption_share = dkg.derive_decryption_share(
ritual_id=ritual_id,
me=validator,
)
# We can also obtain the aggregated transcript from the side-channel (deserialize)
aggregate = ferveo.AggregatedTranscript(
self._learner._dkg_insight.aggregation_messages
)
assert aggregate.verify(
self._learner._dkg_insight.shares_num,
self._learner._dkg_insight.aggregation_messages,
)
decrypted_encryption_request = trdp.decrypt_encrypted_request(etdr)
ciphertext = decrypted_encryption_request.ciphertext
conditions_bytes = str(decrypted_encryption_request.conditions).encode()
decryption_share = aggregate.create_decryption_share_simple(
dkg=dkg,
shares=self._learner._dkg_insight.shares_num,
threshold=self._learner._dkg_insight.security_threshold,
nodes=self._learner._dkg_insight.validators,
aggregated_transcript=aggregate,
keypair=validator_keypair,
ciphertext=ciphertext,
aad=conditions_bytes,
validator_keypair=validator_keypair,
aad=conditions,
variant=dkg.FerveoVariant(variant),
)
decryption_share_bytes = bytes(decryption_share)
##### Uncomment for sanity check
# ferveo.DecryptionShareSimple.from_bytes(decryption_share_bytes) # No IOError! Let's go!
##################
decryption_response = ThresholdDecryptionResponse(
ritual_id=55, # TODO: Abstract this somewhere
decryption_share=bytes(decryption_share_bytes),
decryption_share=bytes(decryption_share),
)
encrypted_decryptiopn_response = trdp.encrypt_decryption_response(
encrypted_decryption_response = trdp.encrypt_decryption_response(
decryption_response=decryption_response,
requester_public_key=etdr.requester_public_key,
)
responses[validator.address] = encrypted_decryptiopn_response
responses[validator.address] = encrypted_decryption_response
NO_FAILURES = {}
return responses, NO_FAILURES

View File

@ -641,23 +641,15 @@ class Bob(Character):
)
return decryption_request
def get_decryption_shares_using_existing_decryption_request(
def _get_decryption_shares(
self,
decryption_request: ThresholdDecryptionRequest,
participant_public_keys: Dict[ChecksumAddress, SessionStaticKey],
cohort: List["Ursula"],
threshold: int,
variant: FerveoVariant = None,
) -> Dict[
ChecksumAddress, Union[DecryptionShareSimple, DecryptionSharePrecomputed]
]:
if variant is None:
variant = self.default_dkg_variant
if variant == FerveoVariant.PRECOMPUTED:
share_type = DecryptionSharePrecomputed
elif variant == FerveoVariant.SIMPLE:
share_type = DecryptionShareSimple
# use ephemeral key for request
requester_sk = SessionStaticSecret.random()
requester_public_key = requester_sk.public_key()
@ -666,9 +658,7 @@ class Bob(Character):
shared_secrets = {}
for ursula in cohort:
ursula_checksum_address = to_checksum_address(ursula.checksum_address)
participant_public_key = participant_public_keys[ursula_checksum_address]
shared_secret = requester_sk.derive_shared_secret(participant_public_key)
encrypted_decryption_request = decryption_request.encrypt(
shared_secret=shared_secret,
@ -688,6 +678,11 @@ class Bob(Character):
raise Ursula.NotEnoughUrsulas(f"Not enough Ursulas to decrypt: {failures}")
self.log.debug("Got enough shares to decrypt.")
if decryption_request.variant == FerveoVariant.PRECOMPUTED.value:
share_type = DecryptionSharePrecomputed
elif decryption_request.variant == FerveoVariant.SIMPLE.value:
share_type = DecryptionShareSimple
gathered_shares = {}
for provider_address, encrypted_decryption_response in successes.items():
shared_secret = shared_secrets[provider_address]
@ -700,34 +695,6 @@ class Bob(Character):
gathered_shares[provider_address] = decryption_share
return gathered_shares
def gather_decryption_shares(
self,
ritual_id: int,
cohort: List["Ursula"],
ciphertext: Ciphertext,
lingo: Lingo,
threshold: int,
variant: FerveoVariant,
participant_public_keys: Dict[ChecksumAddress, SessionStaticKey],
context: Optional[dict] = None,
) -> Dict[
ChecksumAddress, Union[DecryptionShareSimple, DecryptionSharePrecomputed]
]:
decryption_request = self.make_decryption_request(
ritual_id=ritual_id,
ciphertext=ciphertext,
lingo=lingo,
variant=variant,
context=context,
)
return self.get_decryption_shares_using_existing_decryption_request(
decryption_request,
participant_public_keys,
cohort,
threshold,
variant=variant,
)
def get_ritual_from_id(self, ritual_id):
# blockchain reads: get the DKG parameters and the cohort.
if not self.coordinator_agent:
@ -762,6 +729,7 @@ class Bob(Character):
f"{ursula} ({ursula.staking_provider_address}) is not part of the cohort"
)
self.remember_node(ursula)
try:
variant = FerveoVariant(getattr(FerveoVariant, variant.upper()).value)
except AttributeError:
@ -775,50 +743,25 @@ class Bob(Character):
else ritual.shares
) # TODO: #3095 get this from the ritual / put it on-chain?
participant_public_keys = ritual.participant_public_keys
decryption_shares = self.gather_decryption_shares(
decryption_request = self.make_decryption_request(
ritual_id=ritual_id,
cohort=ursulas,
ciphertext=ciphertext,
context=context,
lingo=conditions,
threshold=threshold,
variant=variant,
context=context,
)
participant_public_keys = ritual.participant_public_keys
decryption_shares = self._get_decryption_shares(
decryption_request=decryption_request,
participant_public_keys=participant_public_keys,
cohort=ursulas,
threshold=threshold,
)
return self._decrypt(
list(decryption_shares.values()), ciphertext, conditions, variant
)
def decrypt_using_existing_decryption_request(
self,
decryption_request,
participant_public_keys,
cohort,
threshold,
variant=None,
):
if variant is None:
variant = self.default_dkg_variant
addresses_and_dfrags = (
self.get_decryption_shares_using_existing_decryption_request(
decryption_request, participant_public_keys, cohort, threshold
)
)
# TODO: 3154
conditions_as_json_string = str(decryption_request.conditions)
conditions_as_list = json.loads(conditions_as_json_string)
return self._decrypt(
list(addresses_and_dfrags.values()),
decryption_request.ciphertext,
conditions_as_list,
variant,
)
@staticmethod
def _decrypt(
shares: List[Union[DecryptionShareSimple, DecryptionSharePrecomputed]],

View File

@ -35,19 +35,18 @@ def _attempt_decryption(BobClass, plaintext):
},
}
ciphertext, tdr = enrico.encrypt_for_dkg_and_produce_decryption_request(
ciphertext = enrico.encrypt_for_dkg(
plaintext=plaintext,
conditions=definitely_false_condition,
ritual_id=ANYTHING_CAN_BE_PASSED_AS_RITUAL_DATA,
)
decrypted_cleartext_from_ciphertext_list = bob.threshold_decrypt(
ciphertext=ciphertext,
decrypted_cleartext = bob.threshold_decrypt(
ritual_id=ANYTHING_CAN_BE_PASSED_AS_RITUAL_DATA,
ciphertext=ciphertext,
conditions=definitely_false_condition,
)
return decrypted_cleartext_from_ciphertext_list
return decrypted_cleartext
def test_user_controls_success():
@ -65,4 +64,4 @@ def test_user_controls_success():
def test_user_controls_failure():
plaintext = b"ever thus to deadbeats"
with pytest.raises(Ursula.NotEnoughUrsulas) as e:
result = _attempt_decryption(ThisBobAlwaysFails, plaintext)
_ = _attempt_decryption(ThisBobAlwaysFails, plaintext)