Merge pull request #3193 from derekpierre/no-exposed-variant

Don't expose Ferveo variant in python Bob public API
pull/3195/head
David Núñez 2023-07-25 17:02:23 +02:00 committed by GitHub
commit 57267c7019
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 34 additions and 68 deletions

View File

@ -0,0 +1 @@
Don't allow users to specify the FerveoVariant to use for threshold decryption. The default, simple variant, will be used.

View File

@ -438,7 +438,7 @@ class Alice(Character, actors.PolicyAuthor):
class Bob(Character):
banner = BOB_BANNER
default_dkg_variant = FerveoVariant.SIMPLE
_default_dkg_variant = FerveoVariant.SIMPLE
_default_crypto_powerups = [SigningPower, DecryptingPower]
_threshold_decryption_client_class = ThresholdDecryptionClient
@ -622,7 +622,7 @@ class Bob(Character):
return cohort
@staticmethod
def make_decryption_request(
def __make_decryption_request(
ritual_id: int,
ciphertext: Ciphertext,
lingo: Lingo,
@ -712,7 +712,6 @@ class Bob(Character):
conditions: Lingo,
context: Optional[dict] = None,
ursulas: Optional[List["Ursula"]] = None,
variant: str = "simple",
peering_timeout: int = 60,
) -> bytes:
ritual = self.get_ritual_from_id(ritual_id)
@ -730,20 +729,14 @@ class Bob(Character):
)
self.remember_node(ursula)
try:
variant = FerveoVariant(getattr(FerveoVariant, variant.upper()).value)
except AttributeError:
raise ValueError(
f"Invalid variant: {variant}; Options are: {list(v.name.lower() for v in list(FerveoVariant))}"
)
variant = self._default_dkg_variant
threshold = (
(ritual.shares // 2) + 1
if variant == FerveoVariant.SIMPLE
else ritual.shares
) # TODO: #3095 get this from the ritual / put it on-chain?
decryption_request = self.make_decryption_request(
decryption_request = self.__make_decryption_request(
ritual_id=ritual_id,
ciphertext=ciphertext,
lingo=conditions,
@ -758,12 +751,12 @@ class Bob(Character):
threshold=threshold,
)
return self._decrypt(
return self.__decrypt(
list(decryption_shares.values()), ciphertext, conditions, variant
)
@staticmethod
def _decrypt(
def __decrypt(
shares: List[Union[DecryptionShareSimple, DecryptionSharePrecomputed]],
ciphertext: Ciphertext,
conditions: Lingo,
@ -1453,7 +1446,6 @@ class Enrico:
"""A data source that encrypts data for some policy's public key"""
banner = ENRICO_BANNER
default_dkg_variant = FerveoVariant.SIMPLE
def __init__(self, encrypting_key: Union[PublicKey, DkgPublicKey]):
self.signing_power = SigningPower()
@ -1480,29 +1472,6 @@ class Enrico:
ciphertext = encrypt(plaintext, conditions_bytes, self.policy_pubkey)
return ciphertext
def encrypt_for_dkg_and_produce_decryption_request(
self,
plaintext: bytes,
conditions: Lingo,
ritual_id: int,
variant: int = None,
context: Optional[bytes] = None,
) -> Tuple[Ciphertext, ThresholdDecryptionRequest]:
ciphertext = self.encrypt_for_dkg(plaintext=plaintext, conditions=conditions)
if variant is None:
variant = self.default_dkg_variant.value
tdr = ThresholdDecryptionRequest(
ritual_id=ritual_id,
ciphertext=ciphertext,
conditions=Conditions(json.dumps(conditions)),
context=context,
variant=variant,
)
return ciphertext, tdr
@classmethod
def from_alice(cls, alice: Alice, label: bytes):
"""

View File

@ -78,6 +78,7 @@ def verify_aggregate(
):
pvss_aggregated.verify(shares, transcripts)
def derive_decryption_share(
nodes: List[Validator],
aggregated_transcript: AggregatedTranscript,
@ -93,7 +94,7 @@ def derive_decryption_share(
try:
derive_share = _VARIANTS[variant]
except KeyError:
raise Exception(f"invalid variant {variant}")
raise ValueError(f"Invalid variant {variant}")
share = derive_share(
# first arg here is intended to be "self" since the method is unbound
aggregated_transcript,

View File

@ -134,7 +134,6 @@ def test_ursula_ritualist(testerchain, coordinator_agent, cohort, alice, bob):
ritual_id=RITUAL_ID,
ciphertext=ciphertext,
conditions=CONDITIONS,
# params=cohort[0].dkg_storage.get_dkg_params(RITUAL_ID),
peering_timeout=0
)
assert bytes(cleartext) == PLAINTEXT.encode()

View File

@ -1,5 +1,6 @@
from time import time
from typing import List
from unittest.mock import PropertyMock, patch
import pytest
import pytest_twisted
@ -9,6 +10,7 @@ from web3.datastructures import AttributeDict
from nucypher.blockchain.eth.agents import CoordinatorAgent
from nucypher.characters.lawful import Enrico, Ursula
from nucypher.crypto.ferveo.dkg import FerveoVariant
from nucypher.policy.conditions.lingo import ConditionLingo
from tests.constants import TESTERCHAIN_CHAIN_ID
from tests.mock.coordinator import MockCoordinatorAgent
@ -31,17 +33,17 @@ ROUND_1_EVENT_NAME = "StartRitual"
ROUND_2_EVENT_NAME = "StartAggregationRound"
PARAMS = [ # dkg_size, ritual_id, variant
(2, 0, "precomputed"),
(4, 1, "precomputed"),
(8, 2, "precomputed"),
(2, 3, "simple"),
(4, 4, "simple"),
(8, 5, "simple"),
(2, 0, FerveoVariant.PRECOMPUTED),
(4, 1, FerveoVariant.PRECOMPUTED),
(8, 2, FerveoVariant.PRECOMPUTED),
(2, 3, FerveoVariant.SIMPLE),
(4, 4, FerveoVariant.SIMPLE),
(8, 5, FerveoVariant.SIMPLE),
# TODO: slow and need additional accounts for testing
# (16, 6, "precomputed"),
# (16, 7, "simple"),
# (32, 8, "precomputed"),
# (32, 9, "simple"),
# (16, 6, FerveoVariant.PRECOMPUTED),
# (16, 7, FerveoVariant.SIMPLE),
# (32, 8, FerveoVariant.PRECOMPUTED),
# (32, 9, FerveoVariant.SIMPLE),
]
BLOCKS = list(reversed(range(1, 1000)))
@ -127,7 +129,6 @@ def test_ursula_ritualist(
test_registry_source_manager,
):
"""Tests the DKG and the encryption/decryption of a message"""
cohort = cohort[:dkg_size]
def initialize():
@ -185,24 +186,18 @@ def test_ursula_ritualist(
print("==================== DKG DECRYPTION ====================")
bob.start_learning_loop(now=True)
cleartext = bob.threshold_decrypt(
ritual_id=ritual_id,
ciphertext=ciphertext,
conditions=CONDITIONS,
peering_timeout=0,
variant=variant
)
assert bytes(cleartext) == PLAINTEXT.encode()
# mock the use of non-default variants since it can no longer be specified
with patch.object(
bob, "_default_dkg_variant", new_callable=PropertyMock(return_value=variant)
):
cleartext = bob.threshold_decrypt(
ritual_id=ritual_id,
ciphertext=ciphertext,
conditions=CONDITIONS,
peering_timeout=0,
)
assert bytes(cleartext) == PLAINTEXT.encode()
# again, but without `params`
cleartext = bob.threshold_decrypt(
ritual_id=ritual_id,
ciphertext=ciphertext,
conditions=CONDITIONS,
peering_timeout=0,
variant=variant
)
assert bytes(cleartext) == PLAINTEXT.encode()
print("==================== DECRYPTION SUCCESSFUL ====================")
def error_handler(e):

View File

@ -15,6 +15,7 @@ from nucypher_core.umbral import SecretKey, Signer
from nucypher.blockchain.eth.signers.software import Web3Signer
from nucypher.characters.lawful import Alice, Bob, Enrico, Ursula
from nucypher.config.constants import TEMPORARY_DOMAIN
from nucypher.crypto.ferveo.dkg import FerveoVariant
from nucypher.crypto.keystore import Keystore
from nucypher.crypto.powers import (
DecryptingPower,
@ -191,7 +192,7 @@ def test_ritualist(temp_dir_path, testerchain, dkg_public_key):
ciphertext = enrico.encrypt_for_dkg(plaintext=plaintext, conditions=CONDITIONS)
decryption_request = ThresholdDecryptionRequest(
ritual_id=ritual_id,
variant=0,
variant=FerveoVariant.SIMPLE.value,
ciphertext=ciphertext,
conditions=Conditions(json.dumps(CONDITIONS)),
)