mirror of https://github.com/nucypher/nucypher.git
Use a simple flag to denote optionality instead of VariableLengthBytestring
parent
944d3373e7
commit
c8a1d4095a
|
@ -987,11 +987,15 @@ class Ursula(Teacher, Character, Worker):
|
|||
# so we can cache the result of this method.
|
||||
# TODO: should this be a method of Teacher?
|
||||
timestamp = maya.now()
|
||||
if self.decentralized_identity_evidence is NOT_SIGNED:
|
||||
decentralized_identity_evidence = None
|
||||
else:
|
||||
decentralized_identity_evidence = self.decentralized_identity_evidence
|
||||
return NodeMetadata.author(signer=self.stamp.as_umbral_signer(),
|
||||
public_address=self.canonical_public_address,
|
||||
domain=self.domain,
|
||||
timestamp_epoch=timestamp.epoch,
|
||||
decentralized_identity_evidence=self.decentralized_identity_evidence,
|
||||
decentralized_identity_evidence=decentralized_identity_evidence,
|
||||
verifying_key=self.public_keys(SigningPower),
|
||||
encrypting_key=self.public_keys(DecryptingPower),
|
||||
certificate_bytes=self.certificate.public_bytes(Encoding.PEM),
|
||||
|
|
|
@ -15,7 +15,7 @@ You should have received a copy of the GNU Affero General Public License
|
|||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from typing import Optional, Sequence, Dict, Tuple, List, Iterable, Mapping, NamedTuple
|
||||
from typing import Optional, Sequence, Dict, Tuple, List, Iterable, Mapping, NamedTuple, Callable
|
||||
|
||||
from bytestring_splitter import (
|
||||
BytestringSplitter,
|
||||
|
@ -28,6 +28,7 @@ from eth_utils.address import to_checksum_address, to_canonical_address
|
|||
|
||||
from nucypher.utilities.versioning import Versioned
|
||||
|
||||
from nucypher.blockchain.eth.constants import LENGTH_ECDSA_SIGNATURE_WITH_RECOVERY
|
||||
from nucypher.crypto.utils import keccak_digest
|
||||
from nucypher.crypto.signing import InvalidSignature
|
||||
import nucypher.crypto.umbral_adapter as umbral # need it to mock `umbral.encrypt`
|
||||
|
@ -55,6 +56,38 @@ capsule_splitter = BytestringSplitter((Capsule, Capsule.serialized_size()))
|
|||
cfrag_splitter = BytestringSplitter((CapsuleFrag, CapsuleFrag.serialized_size()))
|
||||
kfrag_splitter = BytestringSplitter((KeyFrag, KeyFrag.serialized_size()))
|
||||
checksum_address_splitter = BytestringSplitter((to_checksum_address, ETH_ADDRESS_BYTE_LENGTH)) # TODO: is there a pre-defined constant?
|
||||
variable_length_splitter = BytestringSplitter(VariableLengthBytestring)
|
||||
|
||||
|
||||
_OPTIONAL_NONE = b'\x00'
|
||||
_OPTIONAL_SOME = b'\x01'
|
||||
|
||||
|
||||
def serialize_optional(value: Optional) -> bytes:
|
||||
if value is None:
|
||||
return _OPTIONAL_NONE
|
||||
else:
|
||||
return _OPTIONAL_SOME + bytes(value)
|
||||
|
||||
|
||||
def take_optional(take_obj: Callable[[bytes], Tuple[object, bytes]], data: bytes):
|
||||
optional_flag = data[0:1]
|
||||
remainder = data[1:]
|
||||
|
||||
if optional_flag == _OPTIONAL_NONE:
|
||||
return None, remainder
|
||||
elif optional_flag == _OPTIONAL_SOME:
|
||||
obj, remainder = take_obj(remainder)
|
||||
return obj, remainder
|
||||
else:
|
||||
raise ValueError(f"Incorrect optional flag: {optional_flag}")
|
||||
|
||||
|
||||
def take_decentralized_identity_evidence(data):
|
||||
expected_length = LENGTH_ECDSA_SIGNATURE_WITH_RECOVERY
|
||||
if len(data) < LENGTH_ECDSA_SIGNATURE_WITH_RECOVERY:
|
||||
raise ValueError(f"Not enough bytes to fit a decentralized_identity_evidence ({len(data)})")
|
||||
return data[:expected_length], data[expected_length:]
|
||||
|
||||
|
||||
class MessageKit(Versioned):
|
||||
|
@ -541,7 +574,7 @@ class ReencryptionRequest(Versioned):
|
|||
|
||||
hrac, publisher_vk, bob_vk, remainder = splitter(data, return_remainder=True)
|
||||
ekfrag, remainder = EncryptedKeyFrag.take(remainder)
|
||||
capsule_bytes, remainder = BytestringSplitter(VariableLengthBytestring)(remainder, return_remainder=True)
|
||||
capsule_bytes, remainder = variable_length_splitter(remainder, return_remainder=True)
|
||||
capsules = capsule_splitter.repeat(capsule_bytes)
|
||||
return cls(hrac, publisher_vk, bob_vk, ekfrag, capsules), remainder
|
||||
|
||||
|
@ -749,21 +782,17 @@ class NodeMetadataPayload(NamedTuple):
|
|||
public_address: bytes
|
||||
domain: str
|
||||
timestamp_epoch: int
|
||||
decentralized_identity_evidence: bytes # TODO: make its own type?
|
||||
verifying_key: PublicKey
|
||||
encrypting_key: PublicKey
|
||||
certificate_bytes: bytes # serialized `cryptography.x509.Certificate`
|
||||
host: str
|
||||
port: int
|
||||
decentralized_identity_evidence: Optional[bytes] # TODO: make its own type?
|
||||
|
||||
_splitter = BytestringSplitter(
|
||||
(bytes, ETH_ADDRESS_BYTE_LENGTH), # public_address
|
||||
VariableLengthBytestring, # domain_bytes
|
||||
(int, 4, {'byteorder': 'big'}), # timestamp_epoch
|
||||
|
||||
# FIXME: Fixed length doesn't work with federated. It was LENGTH_ECDSA_SIGNATURE_WITH_RECOVERY,
|
||||
VariableLengthBytestring, # decentralized_identity_evidence
|
||||
|
||||
key_splitter, # verifying_key
|
||||
key_splitter, # encrypting_key
|
||||
VariableLengthBytestring, # certificate_bytes
|
||||
|
@ -775,12 +804,12 @@ class NodeMetadataPayload(NamedTuple):
|
|||
as_bytes = bytes().join((self.public_address,
|
||||
bytes(VariableLengthBytestring(self.domain.encode('utf-8'))),
|
||||
self.timestamp_epoch.to_bytes(4, 'big'),
|
||||
bytes(VariableLengthBytestring(self.decentralized_identity_evidence)), # FIXME: Fixed length doesn't work with federated
|
||||
bytes(self.verifying_key),
|
||||
bytes(self.encrypting_key),
|
||||
bytes(VariableLengthBytestring(self.certificate_bytes)),
|
||||
bytes(VariableLengthBytestring(self.host.encode('utf-8'))),
|
||||
self.port.to_bytes(2, 'big'),
|
||||
serialize_optional(self.decentralized_identity_evidence),
|
||||
))
|
||||
return as_bytes
|
||||
|
||||
|
@ -791,7 +820,6 @@ class NodeMetadataPayload(NamedTuple):
|
|||
(public_address,
|
||||
domain,
|
||||
timestamp_epoch,
|
||||
decentralized_identity_evidence,
|
||||
verifying_key,
|
||||
encrypting_key,
|
||||
certificate_bytes,
|
||||
|
@ -799,15 +827,17 @@ class NodeMetadataPayload(NamedTuple):
|
|||
port,
|
||||
) = fields
|
||||
|
||||
decentralized_identity_evidence, remainder = take_optional(take_decentralized_identity_evidence, remainder)
|
||||
|
||||
obj = cls(public_address=public_address,
|
||||
domain=domain.decode('utf-8'),
|
||||
timestamp_epoch=timestamp_epoch,
|
||||
decentralized_identity_evidence=decentralized_identity_evidence,
|
||||
verifying_key=verifying_key,
|
||||
encrypting_key=encrypting_key,
|
||||
certificate_bytes=certificate_bytes,
|
||||
host=host.decode('utf-8'),
|
||||
port=port,
|
||||
decentralized_identity_evidence=decentralized_identity_evidence,
|
||||
)
|
||||
|
||||
return obj, remainder
|
||||
|
@ -920,13 +950,6 @@ class MetadataRequest(Versioned):
|
|||
|
||||
class MetadataResponse(Versioned):
|
||||
|
||||
_splitter = BytestringSplitter(
|
||||
signature_splitter,
|
||||
(int, 4, {'byteorder': 'big'}),
|
||||
VariableLengthBytestring,
|
||||
VariableLengthBytestring,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def author(cls,
|
||||
signer: Signer,
|
||||
|
@ -947,7 +970,7 @@ class MetadataResponse(Versioned):
|
|||
nodes_payload = b''.join(bytes(node) for node in other_nodes) if other_nodes else b''
|
||||
return (
|
||||
timestamp +
|
||||
bytes(VariableLengthBytestring(bytes(this_node) if this_node else b'')) +
|
||||
serialize_optional(this_node) +
|
||||
bytes(VariableLengthBytestring(nodes_payload))
|
||||
)
|
||||
|
||||
|
@ -985,8 +1008,15 @@ class MetadataResponse(Versioned):
|
|||
|
||||
@classmethod
|
||||
def _from_bytes_current(cls, data: bytes):
|
||||
signature, timestamp_epoch, maybe_this_node, maybe_other_nodes, remainder = cls._splitter(data, return_remainder=True)
|
||||
this_node = NodeMetadata.from_bytes(maybe_this_node) if maybe_this_node else None
|
||||
|
||||
splitter = BytestringSplitter(
|
||||
signature_splitter,
|
||||
(int, 4, {'byteorder': 'big'}),
|
||||
)
|
||||
|
||||
signature, timestamp_epoch, remainder = splitter(data, return_remainder=True)
|
||||
this_node, remainder = take_optional(NodeMetadata.take, remainder)
|
||||
maybe_other_nodes, remainder = variable_length_splitter(remainder, return_remainder=True)
|
||||
other_nodes = NodeMetadata._batch_from_bytes(maybe_other_nodes) if maybe_other_nodes else None
|
||||
obj = cls(signature=signature,
|
||||
timestamp_epoch=timestamp_epoch,
|
||||
|
|
|
@ -146,7 +146,7 @@ class NodeSprout:
|
|||
|
||||
@property
|
||||
def decentralized_identity_evidence(self):
|
||||
return self._metadata.decentralized_identity_evidence
|
||||
return self._metadata.decentralized_identity_evidence or NOT_SIGNED
|
||||
|
||||
@property
|
||||
def public_address(self):
|
||||
|
@ -178,7 +178,7 @@ class NodeSprout:
|
|||
checksum_address=self.checksum_address,
|
||||
domain=self._metadata.domain,
|
||||
timestamp=self.timestamp,
|
||||
decentralized_identity_evidence=self._metadata.decentralized_identity_evidence,
|
||||
decentralized_identity_evidence=self.decentralized_identity_evidence,
|
||||
certificate=load_pem_x509_certificate(self._metadata.certificate_bytes, backend=default_backend()),
|
||||
metadata=self._metadata
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue