mirror of https://github.com/nucypher/nucypher.git
Merge pull request #278 from jMyles/umbral-compat
Uses Alice's Stamp as a signer for KFrags; Bob and Ursula validate them as such.pull/276/head^2
commit
19b0f71555
2
Pipfile
2
Pipfile
|
@ -21,7 +21,7 @@ apistar = "*"
|
|||
mypy = "*"
|
||||
pytest-mypy = "*"
|
||||
maya = "*"
|
||||
pyumbral = {git = "https://github.com/nucypher/pyumbral.git"}
|
||||
pyumbral = {git = "https://github.com/nucypher/pyumbral.git", ref = "kfrag-signing"}
|
||||
requests = "*"
|
||||
hendrix = {git = "https://github.com/hendrix/hendrix", ref = "tags/3.0.0rc1"}
|
||||
constantSorrow = {git = "https://github.com/nucypher/constantSorrow.git", ref = "nucypher-depend"}
|
||||
|
|
|
@ -19,7 +19,7 @@ from nucypher.crypto.api import secure_random, keccak_digest, encrypt_and_sign
|
|||
from nucypher.crypto.constants import PUBLIC_KEY_LENGTH
|
||||
from nucypher.crypto.kits import UmbralMessageKit
|
||||
from nucypher.crypto.powers import CryptoPower, SigningPower, EncryptingPower, DelegatingPower, NoSigningPower
|
||||
from nucypher.crypto.signature import Signature, signature_splitter, SignatureStamp, StrangerStamp
|
||||
from nucypher.crypto.signing import Signature, signature_splitter, SignatureStamp, StrangerStamp
|
||||
from nucypher.network import blockchain_client
|
||||
from nucypher.network.protocols import dht_value_splitter, dht_with_hrac_splitter
|
||||
from nucypher.network.server import NucypherDHTServer, NucypherSeedOnlyDHTServer, ProxyRESTServer
|
||||
|
@ -79,7 +79,8 @@ class Character(object):
|
|||
if is_me:
|
||||
self.network_middleware = network_middleware or NetworkyStuff()
|
||||
try:
|
||||
self._stamp = SignatureStamp(self._crypto_power.power_ups(SigningPower).keypair)
|
||||
signing_power = self._crypto_power.power_ups(SigningPower)
|
||||
self._stamp = signing_power.get_signature_stamp()
|
||||
except NoSigningPower:
|
||||
self._stamp = constants.NO_SIGNING_POWER
|
||||
|
||||
|
@ -87,8 +88,9 @@ class Character(object):
|
|||
self.attach_server()
|
||||
else:
|
||||
if network_middleware is not None:
|
||||
raise TypeError("Can't attach network middleware to a Character who isn't me. What are you even trying to do?")
|
||||
self._stamp = StrangerStamp(self._crypto_power.power_ups(SigningPower).keypair)
|
||||
raise TypeError(
|
||||
"Can't attach network middleware to a Character who isn't me. What are you even trying to do?")
|
||||
self._stamp = StrangerStamp(self.public_key(SigningPower))
|
||||
|
||||
def __eq__(self, other):
|
||||
return bytes(self.stamp) == bytes(other.stamp)
|
||||
|
@ -189,6 +191,7 @@ class Character(object):
|
|||
message_kit: Union[UmbralMessageKit, bytes],
|
||||
signature: Signature = None,
|
||||
decrypt=False,
|
||||
delegator_signing_key: UmbralPublicKey = None,
|
||||
) -> tuple:
|
||||
"""
|
||||
Inverse of encrypt_for.
|
||||
|
@ -196,11 +199,14 @@ class Character(object):
|
|||
:param actor_that_sender_claims_to_be: A Character instance representing
|
||||
the actor whom the sender claims to be. We check the public key
|
||||
owned by this Character instance to verify.
|
||||
:param messages: The messages to be verified.
|
||||
:param message_kit: the message to be (perhaps decrypted and) verified.
|
||||
:param signature: The signature to check.
|
||||
:param decrypt: Whether or not to decrypt the messages.
|
||||
:param signature_is_on_cleartext: True if we expect the signature to be
|
||||
on the cleartext. Otherwise, we presume that the ciphertext is what
|
||||
is signed.
|
||||
:param delegator_signing_key: A signing key from the original delegator.
|
||||
This is used only when decrypting a MessageKit with an activated Capsule
|
||||
to check that the KFrag used to create each attached CFrag is the
|
||||
authentic KFrag initially created by the delegator.
|
||||
|
||||
:return: Whether or not the signature is valid, the decrypted plaintext
|
||||
or NO_DECRYPTION_PERFORMED
|
||||
"""
|
||||
|
@ -215,7 +221,7 @@ class Character(object):
|
|||
|
||||
if decrypt:
|
||||
# We are decrypting the message; let's do that first and see what the sig header says.
|
||||
cleartext_with_sig_header = self.decrypt(message_kit)
|
||||
cleartext_with_sig_header = self.decrypt(message_kit, verifying_key=delegator_signing_key)
|
||||
sig_header, cleartext = default_constant_splitter(cleartext_with_sig_header, return_remainder=True)
|
||||
if sig_header == constants.SIGNATURE_IS_ON_CIPHERTEXT:
|
||||
# THe ciphertext is what is signed - note that for later.
|
||||
|
@ -254,8 +260,8 @@ class Character(object):
|
|||
If they don't have the correct Power, the appropriate PowerUpError is raised.
|
||||
"""
|
||||
|
||||
def decrypt(self, message_kit):
|
||||
return self._crypto_power.power_ups(EncryptingPower).decrypt(message_kit)
|
||||
def decrypt(self, message_kit, verifying_key: UmbralPublicKey = None):
|
||||
return self._crypto_power.power_ups(EncryptingPower).decrypt(message_kit, verifying_key)
|
||||
|
||||
def sign(self, message):
|
||||
return self._crypto_power.power_ups(SigningPower).sign(message)
|
||||
|
@ -302,7 +308,8 @@ class Character(object):
|
|||
powers_and_keys=({SigningPower: pubkey})
|
||||
)
|
||||
else:
|
||||
message = "Suspicious Activity: Discovered node with bad signature: {}. Propagated by: {}:{}".format(node_meta, address, port)
|
||||
message = "Suspicious Activity: Discovered node with bad signature: {}. Propagated by: {}:{}".format(
|
||||
node_meta, address, port)
|
||||
self.log.warn(message)
|
||||
return new_nodes
|
||||
|
||||
|
@ -335,7 +342,8 @@ class Alice(Character, PolicyAuthor):
|
|||
:param n: Total number of kfrags to generate
|
||||
"""
|
||||
bob_pubkey_enc = bob.public_key(EncryptingPower)
|
||||
return self._crypto_power.power_ups(DelegatingPower).generate_kfrags(bob_pubkey_enc, label, m, n)
|
||||
delegating_power = self._crypto_power.power_ups(DelegatingPower)
|
||||
return delegating_power.generate_kfrags(bob_pubkey_enc, self.stamp, label, m, n)
|
||||
|
||||
def create_policy(self, bob: "Bob", label: bytes, m: int, n: int):
|
||||
"""
|
||||
|
|
|
@ -117,7 +117,7 @@ class DerivedKeyBasedPower(CryptoPowerUp):
|
|||
class SigningPower(KeyPairBasedPower):
|
||||
_keypair_class = SigningKeypair
|
||||
not_found_error = NoSigningPower
|
||||
provides = ("sign", "generate_self_signed_cert")
|
||||
provides = ("sign", "generate_self_signed_cert", "get_signature_stamp")
|
||||
|
||||
|
||||
class EncryptingPower(KeyPairBasedPower):
|
||||
|
@ -131,7 +131,7 @@ class DelegatingPower(DerivedKeyBasedPower):
|
|||
def __init__(self):
|
||||
self.umbral_keying_material = UmbralKeyingMaterial()
|
||||
|
||||
def generate_kfrags(self, bob_pubkey_enc, label, m, n) -> Union[UmbralPublicKey, List]:
|
||||
def generate_kfrags(self, bob_pubkey_enc, signer, label, m, n) -> Union[UmbralPublicKey, List]:
|
||||
"""
|
||||
Generates re-encryption key frags ("KFrags") and returns them.
|
||||
|
||||
|
@ -144,5 +144,5 @@ class DelegatingPower(DerivedKeyBasedPower):
|
|||
# TODO: salt? #265
|
||||
|
||||
__private_key = self.umbral_keying_material.derive_privkey_by_label(label)
|
||||
kfrags = pre.split_rekey(__private_key, bob_pubkey_enc, m, n)
|
||||
kfrags = pre.split_rekey(__private_key, signer, bob_pubkey_enc, m, n)
|
||||
return __private_key.get_pubkey(), kfrags
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
from nucypher.crypto import api as API
|
||||
from umbral.keys import UmbralPublicKey
|
||||
from cryptography.hazmat.primitives.asymmetric.utils import decode_dss_signature, encode_dss_signature
|
||||
from nucypher.crypto.api import keccak_digest
|
||||
from bytestring_splitter import BytestringSplitter
|
||||
|
||||
|
||||
class Signature(object):
|
||||
"""
|
||||
The Signature object allows signatures to be made and verified.
|
||||
"""
|
||||
_EXPECTED_LENGTH = 64 # With secp256k1
|
||||
|
||||
def __init__(self, r: int, s: int):
|
||||
# TODO: Sanity check for proper r and s.
|
||||
self.r = r
|
||||
self.s = s
|
||||
|
||||
def __repr__(self):
|
||||
return "ECDSA Signature: {}".format(bytes(self).hex()[:15])
|
||||
|
||||
def verify(self, message: bytes, pubkey: UmbralPublicKey) -> bool:
|
||||
"""
|
||||
Verifies that a message's signature was valid.
|
||||
|
||||
:param message: The message to verify
|
||||
:param pubkey: UmbralPublicKey of the signer
|
||||
|
||||
:return: True if valid, False if invalid
|
||||
"""
|
||||
return API.ecdsa_verify(message, self._der_encoded_bytes(), pubkey)
|
||||
|
||||
@classmethod
|
||||
def from_bytes(cls, signature_as_bytes, der_encoded=False):
|
||||
# TODO: Change the int literals to variables which account for the order of the curve.
|
||||
if der_encoded:
|
||||
r, s = decode_dss_signature(signature_as_bytes)
|
||||
else:
|
||||
if not len(signature_as_bytes) == 64:
|
||||
raise ValueError("Looking for exactly 64 bytes if you call from_bytes with der_encoded=False.")
|
||||
else:
|
||||
r = int.from_bytes(signature_as_bytes[:32], "big")
|
||||
s = int.from_bytes(signature_as_bytes[32:], "big")
|
||||
return cls(r, s)
|
||||
|
||||
def _der_encoded_bytes(self):
|
||||
return encode_dss_signature(self.r, self.s)
|
||||
|
||||
def __bytes__(self):
|
||||
return self.r.to_bytes(32, "big") + self.s.to_bytes(32, "big")
|
||||
|
||||
def __len__(self):
|
||||
return len(bytes(self))
|
||||
|
||||
def __add__(self, other):
|
||||
return bytes(self) + other
|
||||
|
||||
def __radd__(self, other):
|
||||
return other + bytes(self)
|
||||
|
||||
def __eq__(self, other):
|
||||
# TODO: Consider constant time
|
||||
return bytes(self) == bytes(other) or self._der_encoded_bytes() == other
|
||||
|
||||
|
||||
signature_splitter = BytestringSplitter(Signature)
|
||||
|
||||
|
||||
class SignatureStamp(object):
|
||||
"""
|
||||
Can be called to sign something or used to express the signing public
|
||||
key as bytes.
|
||||
"""
|
||||
|
||||
def __init__(self, signing_keypair):
|
||||
self._sign = signing_keypair.sign
|
||||
self._as_bytes = bytes(signing_keypair.pubkey)
|
||||
self._as_umbral_pubkey = signing_keypair.pubkey
|
||||
|
||||
def __bytes__(self):
|
||||
return self._as_bytes
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self._sign(*args, **kwargs)
|
||||
|
||||
def __hash__(self):
|
||||
return int.from_bytes(self, byteorder="big")
|
||||
|
||||
def __eq__(self, other):
|
||||
return other == bytes(self)
|
||||
|
||||
def __add__(self, other):
|
||||
return bytes(self) + other
|
||||
|
||||
def __radd__(self, other):
|
||||
return other + bytes(self)
|
||||
|
||||
def __len__(self):
|
||||
return len(bytes(self))
|
||||
|
||||
def __bool__(self):
|
||||
return True
|
||||
|
||||
def as_umbral_pubkey(self):
|
||||
return self._as_umbral_pubkey
|
||||
|
||||
def fingerprint(self):
|
||||
"""
|
||||
Hashes the key using keccak-256 and returns the hexdigest in bytes.
|
||||
|
||||
:return: Hexdigest fingerprint of key (keccak-256) in bytes
|
||||
"""
|
||||
return keccak_digest(bytes(self)).hex().encode()
|
||||
|
||||
|
||||
class StrangerStamp(SignatureStamp):
|
||||
"""
|
||||
SignatureStamp of a stranger (ie, can only be used to glean public key, not to sign)
|
||||
"""
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
message = "This isn't your SignatureStamp; it belongs to (a Stranger). You can't sign with it."
|
||||
raise TypeError(message)
|
|
@ -0,0 +1,61 @@
|
|||
from nucypher.crypto.api import keccak_digest
|
||||
from bytestring_splitter import BytestringSplitter
|
||||
from umbral.signing import Signature, Signer
|
||||
|
||||
signature_splitter = BytestringSplitter(Signature)
|
||||
|
||||
|
||||
class SignatureStamp(object):
|
||||
"""
|
||||
Can be called to sign something or used to express the signing public
|
||||
key as bytes.
|
||||
"""
|
||||
|
||||
def __init__(self, signing_key, signer: Signer=None):
|
||||
self.__signer = signer
|
||||
self._as_bytes = bytes(signing_key)
|
||||
self._as_umbral_pubkey = signing_key
|
||||
|
||||
def __bytes__(self):
|
||||
return self._as_bytes
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self.__signer(*args, **kwargs)
|
||||
|
||||
def __hash__(self):
|
||||
return int.from_bytes(self, byteorder="big")
|
||||
|
||||
def __eq__(self, other):
|
||||
return other == bytes(self)
|
||||
|
||||
def __add__(self, other):
|
||||
return bytes(self) + other
|
||||
|
||||
def __radd__(self, other):
|
||||
return other + bytes(self)
|
||||
|
||||
def __len__(self):
|
||||
return len(bytes(self))
|
||||
|
||||
def __bool__(self):
|
||||
return True
|
||||
|
||||
def as_umbral_pubkey(self):
|
||||
return self._as_umbral_pubkey
|
||||
|
||||
def fingerprint(self):
|
||||
"""
|
||||
Hashes the key using keccak-256 and returns the hexdigest in bytes.
|
||||
|
||||
:return: Hexdigest fingerprint of key (keccak-256) in bytes
|
||||
"""
|
||||
return keccak_digest(bytes(self)).hex().encode()
|
||||
|
||||
|
||||
class StrangerStamp(SignatureStamp):
|
||||
"""
|
||||
SignatureStamp of a stranger (ie, can only be used to glean public key, not to sign)
|
||||
"""
|
||||
def __call__(self, *args, **kwargs):
|
||||
message = "This isn't your SignatureStamp; it belongs to (a Stranger). You can't sign with it."
|
||||
raise TypeError(message)
|
|
@ -1,17 +1,20 @@
|
|||
from nucypher.crypto.api import encrypt_and_sign
|
||||
from nucypher.crypto.signature import SignatureStamp
|
||||
from nucypher.crypto.powers import SigningPower
|
||||
from nucypher.crypto.signing import SignatureStamp
|
||||
from nucypher.keystore.keypairs import SigningKeypair
|
||||
from constant_sorrow.constants import NO_SIGNING_POWER
|
||||
from umbral.keys import UmbralPublicKey
|
||||
from umbral.signing import Signer
|
||||
|
||||
|
||||
class DataSource:
|
||||
|
||||
def __init__(self, policy_pubkey_enc, signer=NO_SIGNING_POWER, label=None):
|
||||
def __init__(self, policy_pubkey_enc, signing_keypair=NO_SIGNING_POWER, label=None):
|
||||
self.policy_pubkey = policy_pubkey_enc
|
||||
if signer is NO_SIGNING_POWER:
|
||||
signer = SignatureStamp(SigningKeypair()) # TODO: Generate signing key properly. #241
|
||||
self.stamp = signer
|
||||
if signing_keypair is NO_SIGNING_POWER:
|
||||
signing_keypair = SigningKeypair() # TODO: Generate signing key properly. #241
|
||||
signing_power = SigningPower(keypair=signing_keypair)
|
||||
self.stamp = signing_power.get_signature_stamp()
|
||||
self.label = label
|
||||
|
||||
def encapsulate_single_message(self, message):
|
||||
|
|
|
@ -7,13 +7,15 @@ from umbral.keys import UmbralPrivateKey, UmbralPublicKey
|
|||
from umbral import pre
|
||||
from umbral.config import default_curve
|
||||
from nucypher.crypto.kits import MessageKit
|
||||
from nucypher.crypto.signature import Signature
|
||||
from nucypher.crypto.signing import SignatureStamp
|
||||
from umbral.signing import Signature, Signer
|
||||
|
||||
|
||||
class Keypair(object):
|
||||
"""
|
||||
A parent Keypair class for all types of Keypairs.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
umbral_key: Union[UmbralPrivateKey, UmbralPublicKey] = None,
|
||||
generate_keys_if_needed=True):
|
||||
|
@ -34,7 +36,8 @@ class Keypair(object):
|
|||
self._privkey = UmbralPrivateKey.gen_key()
|
||||
self.pubkey = self._privkey.get_pubkey()
|
||||
else:
|
||||
raise ValueError("Either pass a valid key as umbral_key or, if you want to generate keys, set generate_keys_if_needed to True.")
|
||||
raise ValueError(
|
||||
"Either pass a valid key as umbral_key or, if you want to generate keys, set generate_keys_if_needed to True.")
|
||||
|
||||
def serialize_pubkey(self, as_b64=False) -> bytes:
|
||||
"""
|
||||
|
@ -61,10 +64,11 @@ class EncryptingKeypair(Keypair):
|
|||
"""
|
||||
A keypair for Umbral
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def decrypt(self, message_kit: MessageKit) -> bytes:
|
||||
def decrypt(self, message_kit: MessageKit, verifying_key: UmbralPublicKey = None) -> bytes:
|
||||
"""
|
||||
Decrypt data encrypted with Umbral.
|
||||
|
||||
|
@ -72,8 +76,10 @@ class EncryptingKeypair(Keypair):
|
|||
"""
|
||||
cleartext = pre.decrypt(ciphertext=message_kit.ciphertext,
|
||||
capsule=message_kit.capsule,
|
||||
priv_key=self._privkey,
|
||||
alice_pub_key=message_kit.policy_pubkey)
|
||||
decrypting_key=self._privkey,
|
||||
delegating_pubkey=message_kit.policy_pubkey,
|
||||
verifying_key=verifying_key,
|
||||
)
|
||||
|
||||
return cleartext
|
||||
|
||||
|
@ -82,6 +88,7 @@ class SigningKeypair(Keypair):
|
|||
"""
|
||||
A SigningKeypair that uses ECDSA.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
@ -99,3 +106,7 @@ class SigningKeypair(Keypair):
|
|||
def generate_self_signed_cert(self, common_name):
|
||||
cryptography_key = self._privkey.to_cryptography_privkey()
|
||||
return generate_self_signed_certificate(common_name, default_curve(), cryptography_key)
|
||||
|
||||
def get_signature_stamp(self):
|
||||
signer = Signer(self._privkey)
|
||||
return SignatureStamp(signing_key=self.pubkey, signer=signer)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from typing import Union
|
||||
|
||||
from nucypher.crypto.signature import Signature
|
||||
from nucypher.crypto.signing import Signature
|
||||
from bytestring_splitter import BytestringSplitter
|
||||
from nucypher.keystore.db.models import Key, PolicyArrangement, Workorder
|
||||
from umbral.fragments import KFrag
|
||||
|
@ -21,7 +21,7 @@ class KeyStore(object):
|
|||
"""
|
||||
A storage class of cryptographic keys.
|
||||
"""
|
||||
kfrag_splitter = BytestringSplitter(Signature, (KFrag, KFrag.get_size()))
|
||||
kfrag_splitter = BytestringSplitter(Signature, (KFrag, KFrag.expected_bytes_length()))
|
||||
|
||||
def __init__(self, sqlalchemy_engine=None):
|
||||
"""
|
||||
|
|
|
@ -5,7 +5,7 @@ from kademlia.utils import digest
|
|||
from constant_sorrow import default_constant_splitter, constants
|
||||
from nucypher.crypto.api import keccak_digest
|
||||
from nucypher.crypto.constants import PUBLIC_KEY_LENGTH, KECCAK_DIGEST_LENGTH
|
||||
from nucypher.crypto.signature import Signature
|
||||
from nucypher.crypto.signing import Signature
|
||||
from bytestring_splitter import BytestringSplitter
|
||||
from nucypher.network.node import NucypherNode
|
||||
from nucypher.network.routing import NucypherRoutingTable
|
||||
|
|
|
@ -12,7 +12,7 @@ from nucypher.characters import Bob, Ursula
|
|||
from nucypher.crypto.api import keccak_digest
|
||||
from nucypher.crypto.constants import KECCAK_DIGEST_LENGTH
|
||||
from nucypher.crypto.powers import SigningPower, DelegatingPower
|
||||
from nucypher.crypto.signature import Signature
|
||||
from nucypher.crypto.signing import Signature
|
||||
from nucypher.crypto.splitters import key_splitter
|
||||
from bytestring_splitter import BytestringSplitter
|
||||
from nucypher.blockchain.eth.policies import BlockchainArrangement
|
||||
|
|
|
@ -7,7 +7,6 @@ from nucypher.crypto.constants import CFRAG_LENGTH_WITHOUT_PROOF
|
|||
|
||||
|
||||
def test_bob_cannot_follow_the_treasure_map_in_isolation(enacted_policy, bob):
|
||||
|
||||
# Assume for the moment that Bob has already received a TreasureMap, perhaps via a side channel.
|
||||
hrac, treasure_map = enacted_policy.hrac(), enacted_policy.treasure_map
|
||||
bob.treasure_maps[hrac] = treasure_map
|
||||
|
@ -134,11 +133,13 @@ def test_bob_can_issue_a_work_order_to_a_specific_ursula(enacted_policy, bob,
|
|||
the_correct_cfrag = pre.reencrypt(the_kfrag, capsule)
|
||||
|
||||
# The first CFRAG_LENGTH_WITHOUT_PROOF bytes (ie, the cfrag proper, not the proof material), are the same:
|
||||
assert bytes(the_cfrag)[:CapsuleFrag.get_size()] == bytes(the_correct_cfrag)[:CapsuleFrag.get_size()] # It's the correct cfrag!
|
||||
assert bytes(the_cfrag)[:CapsuleFrag.expected_bytes_length()] == bytes(the_correct_cfrag)[
|
||||
:CapsuleFrag.expected_bytes_length()] # It's the correct cfrag!
|
||||
|
||||
assert the_correct_cfrag.verify_correctness(capsule,
|
||||
pubkey_a=enacted_policy.public_key,
|
||||
pubkey_b=bob.public_key(EncryptingPower))
|
||||
delegating_pubkey=enacted_policy.public_key,
|
||||
signing_pubkey=alice.stamp.as_umbral_pubkey(),
|
||||
encrypting_pubkey=bob.public_key(EncryptingPower))
|
||||
|
||||
# Now we'll show that Ursula saved the correct WorkOrder.
|
||||
work_orders_from_bob = ursula.work_orders(bob=bob)
|
||||
|
@ -187,7 +188,7 @@ def test_bob_remembers_that_he_has_cfrags_for_a_particular_capsule(enacted_polic
|
|||
capsule_side_channel[0].capsule.attach_cfrag(new_cfrag)
|
||||
|
||||
|
||||
def test_bob_gathers_and_combines(enacted_policy, bob, ursulas, capsule_side_channel):
|
||||
def test_bob_gathers_and_combines(enacted_policy, bob, alice, capsule_side_channel):
|
||||
# The side channel is represented as a single MessageKit, which is all that Bob really needs.
|
||||
the_message_kit, the_data_source = capsule_side_channel
|
||||
|
||||
|
@ -199,7 +200,7 @@ def test_bob_gathers_and_combines(enacted_policy, bob, ursulas, capsule_side_cha
|
|||
|
||||
# Bob can't decrypt yet with just two CFrags. He needs to gather at least m.
|
||||
with pytest.raises(pre.GenericUmbralError):
|
||||
bob.decrypt(the_message_kit)
|
||||
bob.decrypt(the_message_kit, verifying_key=alice.stamp.as_umbral_pubkey())
|
||||
|
||||
number_left_to_collect = enacted_policy.treasure_map.m - len(bob._saved_work_orders)
|
||||
|
||||
|
@ -213,6 +214,8 @@ def test_bob_gathers_and_combines(enacted_policy, bob, ursulas, capsule_side_cha
|
|||
|
||||
# Now.
|
||||
# At long last.
|
||||
is_valid, cleartext = bob.verify_from(the_data_source, the_message_kit, decrypt=True)
|
||||
is_valid, cleartext = bob.verify_from(the_data_source, the_message_kit,
|
||||
decrypt=True,
|
||||
delegator_signing_key=alice.stamp.as_umbral_pubkey())
|
||||
assert cleartext == b'Welcome to the flippering.'
|
||||
assert is_valid
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import pytest
|
||||
from nucypher.crypto.api import secure_random
|
||||
from nucypher.crypto.signature import Signature
|
||||
from nucypher.crypto.signing import Signature
|
||||
from bytestring_splitter import BytestringSplitter
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from nucypher.crypto.api import ecdsa_sign
|
||||
from umbral.keys import UmbralPrivateKey
|
||||
from nucypher.crypto.signature import Signature
|
||||
from nucypher.crypto.signing import Signature
|
||||
|
||||
|
||||
def test_signature_can_verify():
|
||||
|
|
|
@ -11,7 +11,7 @@ from nucypher.characters import Alice, Bob
|
|||
from nucypher.keystore import keystore
|
||||
from nucypher.keystore.db import Base
|
||||
|
||||
from nucypher.crypto.signature import SignatureStamp
|
||||
from nucypher.crypto.signing import SignatureStamp
|
||||
from nucypher.data_sources import DataSource
|
||||
from nucypher.keystore import keystore
|
||||
from nucypher.keystore.db import Base
|
||||
|
@ -97,7 +97,7 @@ def test_keystore():
|
|||
def capsule_side_channel(enacted_policy):
|
||||
signing_keypair = SigningKeypair()
|
||||
data_source = DataSource(policy_pubkey_enc=enacted_policy.public_key,
|
||||
signer=SignatureStamp(signing_keypair))
|
||||
signing_keypair=signing_keypair)
|
||||
message_kit, _signature = data_source.encapsulate_single_message(b"Welcome to the flippering.")
|
||||
return message_kit, data_source
|
||||
|
||||
|
|
Loading…
Reference in New Issue