koi-net 1.1.0b5__py3-none-any.whl → 1.1.0b6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of koi-net might be problematic. Click here for more details.

@@ -1,5 +1,5 @@
1
1
  from logging import getLogger
2
- from koi_net.protocol.errors import ErrorTypes
2
+ from koi_net.protocol.errors import ErrorType
3
3
  from koi_net.protocol.event import EventType
4
4
  from rid_lib.types import KoiNetNode
5
5
  from ..processor.interface import ProcessorInterface
@@ -36,15 +36,15 @@ class ErrorHandler:
36
36
 
37
37
  def handle_protocol_error(
38
38
  self,
39
- error_type: ErrorTypes,
39
+ error_type: ErrorType,
40
40
  node: KoiNetNode
41
41
  ):
42
42
  logger.info(f"Handling protocol error {error_type} for node {node!r}")
43
43
  match error_type:
44
- case ErrorTypes.UnknownNode:
44
+ case ErrorType.UnknownNode:
45
45
  logger.info("Peer doesn't know me, attempting handshake...")
46
46
  self.actor.handshake_with(node)
47
47
 
48
- case ErrorTypes.InvalidKey: ...
49
- case ErrorTypes.InvalidSignature: ...
50
- case ErrorTypes.InvalidTarget: ...
48
+ case ErrorType.InvalidKey: ...
49
+ case ErrorType.InvalidSignature: ...
50
+ case ErrorType.InvalidTarget: ...
koi_net/network/graph.py CHANGED
@@ -41,7 +41,7 @@ class NetworkGraph:
41
41
  logger.debug(f"Added edge {rid!r} ({edge_profile.source} -> {edge_profile.target})")
42
42
  logger.debug("Done")
43
43
 
44
- def get_edge(self, source: KoiNetNode, target: KoiNetNode,) -> EdgeProfile | None:
44
+ def get_edge(self, source: KoiNetNode, target: KoiNetNode,) -> KoiNetEdge | None:
45
45
  """Returns edge RID given the RIDs of a source and target node."""
46
46
  if (source, target) in self.dg.edges:
47
47
  edge_data = self.dg.get_edge_data(source, target)
@@ -1,51 +1,60 @@
1
1
  """Pydantic models for request and response/payload objects in the KOI-net API."""
2
2
 
3
- from pydantic import BaseModel
3
+ from typing import Literal
4
+ from pydantic import BaseModel, Field
4
5
  from rid_lib import RID, RIDType
5
6
  from rid_lib.ext import Bundle, Manifest
6
7
  from .event import Event
7
- from .errors import ErrorTypes
8
+ from .errors import ErrorType
8
9
 
9
10
 
10
11
  # REQUEST MODELS
11
12
 
12
13
  class PollEvents(BaseModel):
13
- rid: RID
14
+ type: Literal["poll_events"] = Field("poll_events")
14
15
  limit: int = 0
15
16
 
16
17
  class FetchRids(BaseModel):
18
+ type: Literal["fetch_rids"] = Field("fetch_rids")
17
19
  rid_types: list[RIDType] = []
18
20
 
19
21
  class FetchManifests(BaseModel):
22
+ type: Literal["fetch_manifests"] = Field("fetch_manifests")
20
23
  rid_types: list[RIDType] = []
21
24
  rids: list[RID] = []
22
25
 
23
26
  class FetchBundles(BaseModel):
27
+ type: Literal["fetch_bundles"] = Field("fetch_bundles")
24
28
  rids: list[RID]
25
29
 
26
30
 
27
31
  # RESPONSE/PAYLOAD MODELS
28
32
 
29
33
  class RidsPayload(BaseModel):
34
+ type: Literal["rids_payload"] = Field("rids_payload")
30
35
  rids: list[RID]
31
36
 
32
37
  class ManifestsPayload(BaseModel):
38
+ type: Literal["manifests_payload"] = Field("manifests_payload")
33
39
  manifests: list[Manifest]
34
40
  not_found: list[RID] = []
35
41
 
36
42
  class BundlesPayload(BaseModel):
43
+ type: Literal["bundles_payload"] = Field("bundles_payload")
37
44
  bundles: list[Bundle]
38
45
  not_found: list[RID] = []
39
46
  deferred: list[RID] = []
40
47
 
41
48
  class EventsPayload(BaseModel):
49
+ type: Literal["events_payload"] = Field("events_payload")
42
50
  events: list[Event]
43
51
 
44
52
 
45
53
  # ERROR MODELS
46
54
 
47
55
  class ErrorResponse(BaseModel):
48
- error: ErrorTypes
56
+ type: Literal["error_response"] = Field("error_response")
57
+ error: ErrorType
49
58
 
50
59
  # TYPES
51
60
 
@@ -27,7 +27,7 @@ class SignedEnvelope(BaseModel, Generic[T]):
27
27
  )
28
28
 
29
29
  logger.debug(f"Verifying envelope: {unsigned_envelope.model_dump_json()}")
30
-
30
+
31
31
  pub_key.verify(
32
32
  self.signature,
33
33
  unsigned_envelope.model_dump_json().encode()
@@ -1,23 +1,23 @@
1
1
  from enum import StrEnum
2
2
 
3
3
 
4
- class ErrorTypes(StrEnum):
4
+ class ErrorType(StrEnum):
5
5
  UnknownNode = "unknown_node"
6
6
  InvalidKey = "invalid_key"
7
7
  InvalidSignature = "invalid_signature"
8
8
  InvalidTarget = "invalid_target"
9
9
 
10
10
  class ProtocolError(Exception):
11
- error_type: ErrorTypes
11
+ error_type: ErrorType
12
12
 
13
13
  class UnknownNodeError(ProtocolError):
14
- error_type = ErrorTypes.UnknownNode
14
+ error_type = ErrorType.UnknownNode
15
15
 
16
16
  class InvalidKeyError(ProtocolError):
17
- error_type = ErrorTypes.InvalidKey
17
+ error_type = ErrorType.InvalidKey
18
18
 
19
19
  class InvalidSignatureError(ProtocolError):
20
- error_type = ErrorTypes.InvalidSignature
20
+ error_type = ErrorType.InvalidSignature
21
21
 
22
22
  class InvalidTargetError(ProtocolError):
23
- error_type = ErrorTypes.InvalidTarget
23
+ error_type = ErrorType.InvalidTarget
@@ -1,22 +1,64 @@
1
1
  import logging
2
- from base64 import urlsafe_b64decode, urlsafe_b64encode
2
+ from base64 import b64decode, b64encode
3
3
  from cryptography.hazmat.primitives import hashes
4
4
  from cryptography.hazmat.primitives.asymmetric import ec
5
5
  from cryptography.hazmat.primitives import serialization
6
6
  from rid_lib.ext.utils import sha256_hash
7
+ from cryptography.hazmat.primitives.asymmetric.utils import (
8
+ decode_dss_signature,
9
+ encode_dss_signature
10
+ )
7
11
 
8
12
  logger = logging.getLogger(__name__)
9
13
 
10
14
 
15
+ def der_to_raw_signature(der_signature: bytes, curve=ec.SECP256R1()) -> bytes:
16
+ """Convert a DER-encoded signature to raw r||s format."""
17
+
18
+ # Decode the DER signature to get r and s
19
+ r, s = decode_dss_signature(der_signature)
20
+
21
+ # Determine byte length based on curve bit size
22
+ byte_length = (curve.key_size + 7) // 8
23
+
24
+ # Convert r and s to big-endian byte arrays of fixed length
25
+ r_bytes = r.to_bytes(byte_length, byteorder='big')
26
+ s_bytes = s.to_bytes(byte_length, byteorder='big')
27
+
28
+ # Concatenate r and s
29
+ return r_bytes + s_bytes
30
+
31
+
32
+ def raw_to_der_signature(raw_signature: bytes, curve=ec.SECP256R1()) -> bytes:
33
+ """Convert a raw r||s signature to DER format."""
34
+
35
+ # Determine byte length based on curve bit size
36
+ byte_length = (curve.key_size + 7) // 8
37
+
38
+ # Split the raw signature into r and s components
39
+ if len(raw_signature) != 2 * byte_length:
40
+ raise ValueError(f"Raw signature must be {2 * byte_length} bytes for {curve.name}")
41
+
42
+ r_bytes = raw_signature[:byte_length]
43
+ s_bytes = raw_signature[byte_length:]
44
+
45
+ # Convert bytes to integers
46
+ r = int.from_bytes(r_bytes, byteorder='big')
47
+ s = int.from_bytes(s_bytes, byteorder='big')
48
+
49
+ # Encode as DER
50
+ return encode_dss_signature(r, s)
51
+
52
+
11
53
  class PrivateKey:
12
54
  priv_key: ec.EllipticCurvePrivateKey
13
55
 
14
56
  def __init__(self, priv_key):
15
57
  self.priv_key = priv_key
16
-
58
+
17
59
  @classmethod
18
60
  def generate(cls):
19
- return cls(priv_key=ec.generate_private_key(ec.SECP192R1()))
61
+ return cls(priv_key=ec.generate_private_key(ec.SECP256R1()))
20
62
 
21
63
  def public_key(self) -> "PublicKey":
22
64
  return PublicKey(self.priv_key.public_key())
@@ -40,12 +82,14 @@ class PrivateKey:
40
82
  def sign(self, message: bytes) -> str:
41
83
  hashed_message = sha256_hash(message.decode())
42
84
 
43
- signature = urlsafe_b64encode(
44
- self.priv_key.sign(
45
- data=message,
46
- signature_algorithm=ec.ECDSA(hashes.SHA256())
47
- )
48
- ).decode()
85
+ der_signature_bytes = self.priv_key.sign(
86
+ data=message,
87
+ signature_algorithm=ec.ECDSA(hashes.SHA256())
88
+ )
89
+
90
+ raw_signature_bytes = der_to_raw_signature(der_signature_bytes)
91
+
92
+ signature = b64encode(raw_signature_bytes).decode()
49
93
 
50
94
  logger.debug(f"Signing message with [{self.public_key().to_der()}]")
51
95
  logger.debug(f"hash: {hashed_message}")
@@ -78,29 +122,39 @@ class PublicKey:
78
122
  def from_der(cls, pub_key_der: str):
79
123
  return cls(
80
124
  pub_key=serialization.load_der_public_key(
81
- data=urlsafe_b64decode(pub_key_der)
125
+ data=b64decode(pub_key_der)
82
126
  )
83
127
  )
84
128
 
85
129
  def to_der(self) -> str:
86
- return urlsafe_b64encode(
130
+ return b64encode(
87
131
  self.pub_key.public_bytes(
88
132
  encoding=serialization.Encoding.DER,
89
133
  format=serialization.PublicFormat.SubjectPublicKeyInfo
90
134
  )
91
135
  ).decode()
92
136
 
137
+
93
138
  def verify(self, signature: str, message: bytes) -> bool:
94
- hashed_message = sha256_hash(message.decode())
139
+ # hashed_message = sha256_hash(message.decode())
140
+
141
+ # print(message.hex())
142
+ # print()
143
+ # print(hashed_message)
144
+ # print()
145
+ # print(message.decode())
95
146
 
96
- logger.debug(f"Verifying message with [{self.to_der()}]")
97
- logger.debug(f"hash: {hashed_message}")
98
- logger.debug(f"signature: {signature}")
147
+ # logger.debug(f"Verifying message with [{self.to_der()}]")
148
+ # logger.debug(f"hash: {hashed_message}")
149
+ # logger.debug(f"signature: {signature}")
150
+
151
+ raw_signature_bytes = b64decode(signature)
152
+ der_signature_bytes = raw_to_der_signature(raw_signature_bytes)
99
153
 
100
154
  # NOTE: throws cryptography.exceptions.InvalidSignature on failure
101
155
 
102
156
  self.pub_key.verify(
103
- signature=urlsafe_b64decode(signature),
157
+ signature=der_signature_bytes,
104
158
  data=message,
105
159
  signature_algorithm=ec.ECDSA(hashes.SHA256())
106
160
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: koi-net
3
- Version: 1.1.0b5
3
+ Version: 1.1.0b6
4
4
  Summary: Implementation of KOI-net protocol in Python
5
5
  Project-URL: Homepage, https://github.com/BlockScience/koi-net/
6
6
  Author-email: Luke Miller <luke@block.science>
@@ -11,9 +11,9 @@ koi_net/secure.py,sha256=cGNF2assqCaYq0i0fhQBm7aREoAdpY-XVypDsE1ALaU,3970
11
11
  koi_net/server.py,sha256=dZfSKrNHqIVD1qc9WkYRO30L4so-A7iW4IsX63oSmlE,4265
12
12
  koi_net/network/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  koi_net/network/behavior.py,sha256=NZLvWlrxR0uWriE3ZzCXmocUVccQthy7Xx8E_8KBwsg,1208
14
- koi_net/network/error_handler.py,sha256=CrmCpBY2oj4nl7uXrIYusUHDKxPZ1HDuQAtiBSZarRI,1623
14
+ koi_net/network/error_handler.py,sha256=_dAl2ovpUZEVhPc8_dcLA7I-FoMNqQNwFy0QLa4uTSY,1617
15
15
  koi_net/network/event_queue.py,sha256=DWs26C235iYkP4koKcdbhmIOHGZRJ48d072BoNWyiHo,7325
16
- koi_net/network/graph.py,sha256=NLstBsPa9By0luxcTjThnqVd3hxfQdFwn8tWgJ6u4l4,4144
16
+ koi_net/network/graph.py,sha256=60SLiR3aNXIOGe-URzMGgx8abmMEJtz37EJs6jeImEM,4143
17
17
  koi_net/network/request_handler.py,sha256=vBXw2GO5vGAYCs18flWbln4kO_HmY1G9uuFu9MYqedY,6852
18
18
  koi_net/network/resolver.py,sha256=coIp4M6k0-8sUfAy4h2NMx_7zCNroWlCHKOj3AXZVhc,5412
19
19
  koi_net/network/response_handler.py,sha256=__R_EvEpjaMz3PCDvkNgWF_EAHe2nePGk-zK_cT4C4g,2077
@@ -24,15 +24,15 @@ koi_net/processor/interface.py,sha256=ebDwqggznFRfp2PT8-UJPUAvCwX8nZaaQ68FUeWQvm
24
24
  koi_net/processor/knowledge_object.py,sha256=avQnsaeqqiJxy40P1VGljuQMtAGmJB-TBa4pmBXTaIs,3863
25
25
  koi_net/processor/knowledge_pipeline.py,sha256=i7FpCFl0UIOwCI5zhP1i8M4PX4A48VN28iV9jruvN5k,9486
26
26
  koi_net/protocol/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
- koi_net/protocol/api_models.py,sha256=bHhbLeq8I7nVBuW-AXgKfb1O58_mLogHRG8A_LZt2IE,1188
27
+ koi_net/protocol/api_models.py,sha256=jzRZWW_ZB5YsBAiwCom882-WIbr0rPyelJxExRgHZGc,1755
28
28
  koi_net/protocol/consts.py,sha256=bisbVEojPIHlLhkLafBzfIhH25TjNfvTORF1g6YXzIM,243
29
29
  koi_net/protocol/edge.py,sha256=dQKtI0_eX2E6tD7kMExv6DeJMkqNo2cY-LxJMJbiK0E,963
30
- koi_net/protocol/envelope.py,sha256=W-K3rjwqwAL9wCXb2_gpAUwnc2xOVdZ1UWMoDlLrqJY,1690
31
- koi_net/protocol/errors.py,sha256=A83QiYe_fJdxW2lsNsLCujWxDr5sk1UmYYd3TGbSNJA,601
30
+ koi_net/protocol/envelope.py,sha256=BkBabUZXDOiGJnfBJm5BHTQZflsiQ3jBmG1gNOtmeO4,1698
31
+ koi_net/protocol/errors.py,sha256=uKPQ-TGLouZuK0xd2pXuCQoRTyu_JFsydSCLml13Cz8,595
32
32
  koi_net/protocol/event.py,sha256=eGgihEj1gliLoQRk8pVB2q_was0AGo-PbT3Hqnpn3oU,1379
33
33
  koi_net/protocol/node.py,sha256=7GQzHORFr9cP4BqJgir6EGSWCskL-yqmvJksIiLfcWU,409
34
- koi_net/protocol/secure.py,sha256=Reem9Z4le4uWXM9uczNOdmgVBg8p4YQav-7_c3pZ1CQ,3366
35
- koi_net-1.1.0b5.dist-info/METADATA,sha256=mEMpi26qrfQMeiULMmoDf3iBUVGb8bvgXhTVa9BqhvU,37118
36
- koi_net-1.1.0b5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
37
- koi_net-1.1.0b5.dist-info/licenses/LICENSE,sha256=03mgCL5qth2aD9C3F3qNVs4sFJSpK9kjtYCyOwdSp7s,1069
38
- koi_net-1.1.0b5.dist-info/RECORD,,
34
+ koi_net/protocol/secure.py,sha256=6sRLWxG5EDF0QLBj29gk3hPmZnPXATrTTFdwx39wQfY,5127
35
+ koi_net-1.1.0b6.dist-info/METADATA,sha256=G2VwaYEW0oLstoINlbOJlT-f2yAhSXEOZP3shspdgqo,37118
36
+ koi_net-1.1.0b6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
37
+ koi_net-1.1.0b6.dist-info/licenses/LICENSE,sha256=03mgCL5qth2aD9C3F3qNVs4sFJSpK9kjtYCyOwdSp7s,1069
38
+ koi_net-1.1.0b6.dist-info/RECORD,,