From 05e3708a745d66f7b512ddb7d7df63121e2a361c Mon Sep 17 00:00:00 2001 From: Piotr Roslaniec Date: Mon, 10 Jul 2023 13:39:37 +0200 Subject: [PATCH] fix: python typings don't match runtime --- .github/workflows/nucypher-core.yml | 32 +++ .../nucypher_core/__init__.pyi | 195 ++++++++++-------- nucypher-core-python/nucypher_core/ferveo.py | 2 +- nucypher-core-python/nucypher_core/ferveo.pyi | 72 ++++--- nucypher-core-python/nucypher_core/umbral.pyi | 40 ++-- nucypher-core-python/src/lib.rs | 7 - 6 files changed, 211 insertions(+), 137 deletions(-) diff --git a/.github/workflows/nucypher-core.yml b/.github/workflows/nucypher-core.yml index 33fb1abe..d27b2931 100644 --- a/.github/workflows/nucypher-core.yml +++ b/.github/workflows/nucypher-core.yml @@ -96,6 +96,38 @@ jobs: with: cmd: --cwd nucypher-core-wasm/examples/node test + python-test: + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - stable + python: + - "3.10" + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python }} + + - name: Install Rust toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + + - name: Install nucypher-core Python package + run: pip install -e . + working-directory: nucypher-core-python + + - name: Install pip dependencies + run: pip install mypy + + - name: Run mypy.stubtest + run: python -m mypy.stubtest nucypher_core + working-directory: nucypher-core-python + trigger-wheels: runs-on: ubuntu-latest needs: test diff --git a/nucypher-core-python/nucypher_core/__init__.pyi b/nucypher-core-python/nucypher_core/__init__.pyi index fce1d08b..677d609f 100644 --- a/nucypher-core-python/nucypher_core/__init__.pyi +++ b/nucypher-core-python/nucypher_core/__init__.pyi @@ -1,4 +1,4 @@ -from typing import List, Dict, Sequence, Optional, Mapping, Tuple, Set +from typing import List, Dict, Sequence, Optional, Mapping, Tuple, Set, final from .umbral import ( SecretKey, @@ -10,12 +10,13 @@ from .umbral import ( RecoverableSignature ) -from .ferveo import ( +from .ferveo import ( FerveoPublicKey, Ciphertext ) +@final class Address: def __init__(self, address_bytes: bytes): @@ -31,32 +32,31 @@ class Address: ... +@final class Conditions: def __init__(self, conditions: str): ... - @classmethod - def from_string(cls, conditions: str) -> Conditions: + @staticmethod + def from_string(conditions: str) -> Conditions: ... def __str__(self) -> str: ... +@final class Context: def __init__(self, context: str): ... - @classmethod - def from_string(cls, context: str) -> Context: - ... - def __str__(self) -> str: ... +@final class MessageKit: @staticmethod @@ -64,10 +64,10 @@ class MessageKit: ... def __init__( - self, - policy_encrypting_key: PublicKey, - plaintext: bytes, - conditions: Optional[Conditions] + self, + policy_encrypting_key: PublicKey, + plaintext: bytes, + conditions: Optional[Conditions] ): ... @@ -75,25 +75,29 @@ class MessageKit: ... def decrypt_reencrypted( - self, - sk: SecretKey, - policy_encrypting_key: PublicKey, - vcfrags: Sequence[VerifiedCapsuleFrag] + self, + sk: SecretKey, + policy_encrypting_key: PublicKey, + vcfrags: Sequence[VerifiedCapsuleFrag] ) -> bytes: ... + def __bytes__(self) -> bytes: + ... + capsule: Capsule conditions: Optional[Conditions] +@final class HRAC: def __init__( - self, - publisher_verifying_key: PublicKey, - bob_verifying_key: PublicKey, - label: bytes, + self, + publisher_verifying_key: PublicKey, + bob_verifying_key: PublicKey, + label: bytes, ): ... @@ -105,22 +109,23 @@ class HRAC: ... +@final class EncryptedKeyFrag: def __init__( - self, - signer: Signer, - recipient_key: PublicKey, - hrac: HRAC, - verified_kfrag: VerifiedKeyFrag, + self, + signer: Signer, + recipient_key: PublicKey, + hrac: HRAC, + verified_kfrag: VerifiedKeyFrag, ): ... def decrypt( - self, - sk: SecretKey, - hrac: HRAC, - publisher_verifying_key: PublicKey, + self, + sk: SecretKey, + hrac: HRAC, + publisher_verifying_key: PublicKey, ) -> VerifiedKeyFrag: ... @@ -132,15 +137,16 @@ class EncryptedKeyFrag: ... +@final class TreasureMap: def __init__( - self, - signer: Signer, - hrac: HRAC, - policy_encrypting_key: PublicKey, - assigned_kfrags: Mapping[Address, Tuple[PublicKey, VerifiedKeyFrag]], - threshold: int, + self, + signer: Signer, + hrac: HRAC, + policy_encrypting_key: PublicKey, + assigned_kfrags: Mapping[Address, Tuple[PublicKey, VerifiedKeyFrag]], + threshold: int, ): ... @@ -168,12 +174,13 @@ class TreasureMap: ... +@final class EncryptedTreasureMap: def decrypt( - self, - sk: SecretKey, - publisher_verifying_key: PublicKey, + self, + sk: SecretKey, + publisher_verifying_key: PublicKey, ) -> TreasureMap: ... @@ -185,17 +192,18 @@ class EncryptedTreasureMap: ... +@final class ReencryptionRequest: def __init__( - self, - capsules: Sequence[Capsule], - hrac: HRAC, - encrypted_kfrag: EncryptedKeyFrag, - publisher_verifying_key: PublicKey, - bob_verifying_key: PublicKey, - conditions: Optional[Conditions], - context: Optional[Context], + self, + capsules: Sequence[Capsule], + hrac: HRAC, + encrypted_kfrag: EncryptedKeyFrag, + publisher_verifying_key: PublicKey, + bob_verifying_key: PublicKey, + conditions: Optional[Conditions], + context: Optional[Context], ): ... @@ -221,18 +229,19 @@ class ReencryptionRequest: ... +@final class ReencryptionResponse: def __init__(self, signer: Signer, capsules_and_vcfrags: Sequence[Tuple[Capsule, VerifiedCapsuleFrag]]): ... def verify( - self, - capsules: Sequence[Capsule], - alice_verifying_key: PublicKey, - ursula_verifying_key: PublicKey, - policy_encrypting_key: PublicKey, - bob_encrypting_key: PublicKey, + self, + capsules: Sequence[Capsule], + alice_verifying_key: PublicKey, + ursula_verifying_key: PublicKey, + policy_encrypting_key: PublicKey, + bob_encrypting_key: PublicKey, ) -> List[VerifiedCapsuleFrag]: ... @@ -244,6 +253,7 @@ class ReencryptionResponse: ... +@final class RetrievalKit: @staticmethod @@ -251,10 +261,10 @@ class RetrievalKit: ... def __init__( - self, - capsule: Capsule, - queried_addresses: Set[Address], - conditions: Optional[Conditions], + self, + capsule: Capsule, + queried_addresses: Set[Address], + conditions: Optional[Conditions], ): ... @@ -272,19 +282,20 @@ class RetrievalKit: ... +@final class RevocationOrder: def __init__( - self, - signer: Signer, - staking_provider_address: Address, - encrypted_kfrag: EncryptedKeyFrag, + self, + signer: Signer, + staking_provider_address: Address, + encrypted_kfrag: EncryptedKeyFrag, ): ... def verify( - self, - alice_verifying_key: PublicKey, + self, + alice_verifying_key: PublicKey, ) -> Tuple[Address, EncryptedKeyFrag]: ... @@ -296,20 +307,21 @@ class RevocationOrder: ... +@final class NodeMetadataPayload: def __init__( - self, - staking_provider_address: Address, - domain: str, - timestamp_epoch: int, - verifying_key: PublicKey, - encrypting_key: PublicKey, - ferveo_public_key: FerveoPublicKey, - certificate_der: bytes, - host: str, - port: int, - operator_signature: RecoverableSignature, + self, + staking_provider_address: Address, + domain: str, + timestamp_epoch: int, + verifying_key: PublicKey, + encrypting_key: PublicKey, + ferveo_public_key: FerveoPublicKey, + certificate_der: bytes, + host: str, + port: int, + operator_signature: RecoverableSignature, ): ... @@ -337,6 +349,7 @@ class NodeMetadataPayload: ... +@final class NodeMetadata: def __init__(self, signer: Signer, payload: NodeMetadataPayload): @@ -355,18 +368,23 @@ class NodeMetadata: ... +@final class FleetStateChecksum: def __init__(self, other_nodes: Sequence[NodeMetadata], this_node: Optional[NodeMetadata]): ... + def __bytes__(self) -> bytes: + ... + +@final class MetadataRequest: def __init__( - self, - fleet_state_checksum: FleetStateChecksum, - announce_nodes: Sequence[NodeMetadata], + self, + fleet_state_checksum: FleetStateChecksum, + announce_nodes: Sequence[NodeMetadata], ): ... @@ -382,6 +400,7 @@ class MetadataRequest: ... +@final class MetadataResponsePayload: def __init__(self, timestamp_epoch: int, announce_nodes: Sequence[NodeMetadata]): @@ -392,6 +411,7 @@ class MetadataResponsePayload: announce_nodes: List[NodeMetadata] +@final class MetadataResponse: def __init__(self, signer: Signer, payload: MetadataResponsePayload): @@ -408,9 +428,11 @@ class MetadataResponse: ... +@final class ThresholdDecryptionRequest: - def __init__(self, ritual_id: int, variant: int, ciphertext: Ciphertext, conditions: Optional[Conditions], context: Optional[Context]): + def __init__(self, ritual_id: int, variant: int, ciphertext: Ciphertext, conditions: Optional[Conditions], + context: Optional[Context]): ... ritual_id: int @@ -423,7 +445,8 @@ class ThresholdDecryptionRequest: ciphertext: Ciphertext - def encrypt(self, shared_secret: SessionSharedSecret, requester_public_key: SessionStaticKey) -> EncryptedThresholdDecryptionRequest: + def encrypt(self, shared_secret: SessionSharedSecret, + requester_public_key: SessionStaticKey) -> EncryptedThresholdDecryptionRequest: ... @staticmethod @@ -434,14 +457,15 @@ class ThresholdDecryptionRequest: ... +@final class EncryptedThresholdDecryptionRequest: ritual_id: int requester_public_key: SessionStaticKey def decrypt( - self, - shared_secret: SessionSharedSecret + self, + shared_secret: SessionSharedSecret ) -> ThresholdDecryptionRequest: ... @@ -453,6 +477,7 @@ class EncryptedThresholdDecryptionRequest: ... +@final class ThresholdDecryptionResponse: def __init__(self, ritual_id: int, decryption_share: bytes): @@ -473,13 +498,13 @@ class ThresholdDecryptionResponse: ... +@final class EncryptedThresholdDecryptionResponse: - ritual_id: int def decrypt( - self, - shared_secret: SessionSharedSecret + self, + shared_secret: SessionSharedSecret ) -> ThresholdDecryptionResponse: ... @@ -491,10 +516,12 @@ class EncryptedThresholdDecryptionResponse: ... +@final class SessionSharedSecret: ... +@final class SessionStaticKey: @staticmethod @@ -505,6 +532,7 @@ class SessionStaticKey: ... +@final class SessionStaticSecret: @staticmethod @@ -518,6 +546,7 @@ class SessionStaticSecret: ... +@final class SessionSecretFactory: @staticmethod diff --git a/nucypher-core-python/nucypher_core/ferveo.py b/nucypher-core-python/nucypher_core/ferveo.py index ac550a22..3593b4b2 100644 --- a/nucypher-core-python/nucypher_core/ferveo.py +++ b/nucypher-core-python/nucypher_core/ferveo.py @@ -18,8 +18,8 @@ AggregatedTranscript = _ferveo.AggregatedTranscript DkgPublicKey = _ferveo.DkgPublicKey SharedSecret = _ferveo.SharedSecret +FerveoVariant = _ferveo.FerveoVariant ThresholdEncryptionError = _ferveo.ThresholdEncryptionError -InvalidShareNumberParameter = _ferveo.InvalidShareNumberParameter InvalidDkgStateToDeal = _ferveo.InvalidDkgStateToDeal InvalidDkgStateToAggregate = _ferveo.InvalidDkgStateToAggregate InvalidDkgStateToVerify = _ferveo.InvalidDkgStateToVerify diff --git a/nucypher-core-python/nucypher_core/ferveo.pyi b/nucypher-core-python/nucypher_core/ferveo.pyi index b708fa56..4d540655 100644 --- a/nucypher-core-python/nucypher_core/ferveo.pyi +++ b/nucypher-core-python/nucypher_core/ferveo.pyi @@ -1,13 +1,13 @@ -from typing import Sequence - +from typing import Sequence, final +@final class Keypair: @staticmethod def random() -> Keypair: ... @staticmethod - def from_secure_randomness(data: bytes) -> Keypair: + def from_secure_randomness(bytes: bytes) -> Keypair: ... @staticmethod @@ -15,7 +15,7 @@ class Keypair: ... @staticmethod - def from_bytes(data: bytes) -> Keypair: + def from_bytes(bytes: bytes) -> Keypair: ... def __bytes__(self) -> bytes: @@ -24,10 +24,10 @@ class Keypair: def public_key(self) -> FerveoPublicKey: ... - +@final class FerveoPublicKey: @staticmethod - def from_bytes(data: bytes) -> FerveoPublicKey: + def from_bytes(bytes: bytes) -> FerveoPublicKey: ... def __bytes__(self) -> bytes: @@ -36,7 +36,11 @@ class FerveoPublicKey: def __hash__(self) -> int: ... + @staticmethod + def serialized_size() -> int: + ... +@final class Validator: def __init__(self, address: str, public_key: FerveoPublicKey): @@ -46,25 +50,29 @@ class Validator: public_key: FerveoPublicKey - +@final class Transcript: @staticmethod - def from_bytes(data: bytes) -> Transcript: + def from_bytes(bytes: bytes) -> Transcript: ... def __bytes__(self) -> bytes: ... - +@final class DkgPublicKey: @staticmethod - def from_bytes(data: bytes) -> DkgPublicKey: + def from_bytes(bytes: bytes) -> DkgPublicKey: ... def __bytes__(self) -> bytes: ... + @staticmethod + def serialized_size() -> int: + ... +@final class ValidatorMessage: def __init__( @@ -77,7 +85,7 @@ class ValidatorMessage: validator: Validator transcript: Transcript - +@final class Dkg: def __init__( @@ -98,34 +106,33 @@ class Dkg: def aggregate_transcripts(self, messages: Sequence[ValidatorMessage]) -> AggregatedTranscript: ... - +@final class Ciphertext: @staticmethod - def from_bytes(data: bytes) -> Ciphertext: + def from_bytes(bytes: bytes) -> Ciphertext: ... def __bytes__(self) -> bytes: ... - +@final class DecryptionShareSimple: @staticmethod - def from_bytes(data: bytes) -> DecryptionShareSimple: + def from_bytes(bytes: bytes) -> DecryptionShareSimple: ... def __bytes__(self) -> bytes: ... - - +@final class DecryptionSharePrecomputed: @staticmethod - def from_bytes(data: bytes) -> DecryptionSharePrecomputed: + def from_bytes(bytes: bytes) -> DecryptionSharePrecomputed: ... def __bytes__(self) -> bytes: ... - +@final class AggregatedTranscript: def __init__(self, messages: Sequence[ValidatorMessage]): @@ -153,35 +160,44 @@ class AggregatedTranscript: ... @staticmethod - def from_bytes(data: bytes) -> AggregatedTranscript: + def from_bytes(bytes: bytes) -> AggregatedTranscript: ... def __bytes__(self) -> bytes: ... - +@final class SharedSecret: @staticmethod - def from_bytes(data: bytes) -> SharedSecret: + def from_bytes(bytes: bytes) -> SharedSecret: ... def __bytes__(self) -> bytes: ... -def encrypt(message: bytes, add: bytes, dkg_public_key: DkgPublicKey) -> Ciphertext: +@final +class FerveoVariant: + @staticmethod + def simple() -> str: ... + + @staticmethod + def precomputed() -> str: ... + + +def encrypt(message: bytes, aad: bytes, dkg_public_key: DkgPublicKey) -> Ciphertext: ... def combine_decryption_shares_simple( - decryption_shares: Sequence[DecryptionShareSimple], + shares: Sequence[DecryptionShareSimple], ) -> bytes: ... def combine_decryption_shares_precomputed( - decryption_shares: Sequence[DecryptionSharePrecomputed], + shares: Sequence[DecryptionSharePrecomputed], ) -> SharedSecret: ... @@ -198,10 +214,6 @@ class ThresholdEncryptionError(Exception): pass -class InvalidShareNumberParameter(Exception): - pass - - class InvalidDkgStateToDeal(Exception): pass @@ -259,4 +271,4 @@ class ValidatorPublicKeyMismatch(Exception): class SerializationError(Exception): - pass \ No newline at end of file + pass diff --git a/nucypher-core-python/nucypher_core/umbral.pyi b/nucypher-core-python/nucypher_core/umbral.pyi index 0937d27d..0733cb74 100644 --- a/nucypher-core-python/nucypher_core/umbral.pyi +++ b/nucypher-core-python/nucypher_core/umbral.pyi @@ -1,6 +1,7 @@ -from typing import Optional, Tuple, List, Sequence +from typing import Optional, Tuple, List, final +@final class SecretKey: @staticmethod @@ -18,6 +19,7 @@ class SecretKey: ... +@final class SecretKeyFactory: @staticmethod @@ -28,10 +30,6 @@ class SecretKeyFactory: def seed_size() -> int: ... - @staticmethod - def from_secure_randomness(seed: bytes) -> SecretKeyFactory: - ... - def make_secret(self, label: bytes) -> bytes: ... @@ -42,10 +40,11 @@ class SecretKeyFactory: ... @staticmethod - def from_secure_randomness(data: bytes) -> SecretKeyFactory: + def from_secure_randomness(seed: bytes) -> SecretKeyFactory: ... +@final class PublicKey: @staticmethod @@ -60,6 +59,7 @@ class PublicKey: ... +@final class Signer: def __init__(self, secret_key: SecretKey): @@ -72,6 +72,7 @@ class Signer: ... +@final class Signature: def verify(self, verifying_pk: PublicKey, message: bytes) -> bool: @@ -92,6 +93,7 @@ class Signature: ... +@final class RecoverableSignature: @staticmethod @@ -102,6 +104,7 @@ class RecoverableSignature: ... +@final class Capsule: @staticmethod @@ -115,14 +118,15 @@ class Capsule: ... +@final class KeyFrag: def verify( self, verifying_pk: PublicKey, - delegating_pk: Optional[PublicKey], - receiving_pk: Optional[PublicKey], - ) -> VerifiedKeyFrag: + delegating_pk: Optional[PublicKey] = ..., + receiving_pk: Optional[PublicKey] = ..., + ) -> VerifiedKeyFrag: ... def skip_verification(self) -> VerifiedKeyFrag: @@ -136,6 +140,7 @@ class KeyFrag: ... +@final class VerifiedKeyFrag: def __bytes__(self) -> bytes: @@ -153,10 +158,11 @@ def generate_kfrags( shares: int, sign_delegating_key: bool, sign_receiving_key: bool, - ) -> List[VerifiedKeyFrag]: +) -> List[VerifiedKeyFrag]: ... +@final class CapsuleFrag: def verify( @@ -165,7 +171,7 @@ class CapsuleFrag: verifying_pk: PublicKey, delegating_pk: PublicKey, receiving_pk: PublicKey, - ) -> VerifiedCapsuleFrag: + ) -> VerifiedCapsuleFrag: ... def skip_verification(self) -> VerifiedCapsuleFrag: @@ -182,6 +188,7 @@ class CapsuleFrag: ... +@final class VerifiedCapsuleFrag: def __bytes__(self) -> bytes: @@ -198,20 +205,21 @@ def reencrypt(capsule: Capsule, kfrag: VerifiedKeyFrag) -> VerifiedCapsuleFrag: ... +@final class CurvePoint: - - def coordinates(self) -> Tuple[bytes, bytes]: - ... + coordinates: Tuple[bytes, bytes] +@final class Parameters: - def __init__(self) -> None: + def __init__(self, *args) -> None: ... u: CurvePoint +@final class ReencryptionEvidence: def __init__( @@ -221,7 +229,7 @@ class ReencryptionEvidence: verifying_pk: PublicKey, delegating_pk: PublicKey, receiving_pk: PublicKey, - ): + ): ... def __bytes__(self) -> bytes: diff --git a/nucypher-core-python/src/lib.rs b/nucypher-core-python/src/lib.rs index f6c34fce..723cf05b 100644 --- a/nucypher-core-python/src/lib.rs +++ b/nucypher-core-python/src/lib.rs @@ -141,13 +141,6 @@ impl Context { } } - #[staticmethod] - pub fn from_bytes(context: String) -> Self { - Self { - backend: context.into(), - } - } - fn __str__(&self) -> &str { self.backend.as_ref() }