nest-plugins-reference 0.1.0__tar.gz → 0.1.1__tar.gz
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.
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/PKG-INFO +1 -1
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/__init__.py +1 -1
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/auth/jwt_auth.py +3 -0
- nest_plugins_reference-0.1.1/nest_plugins_reference/identity/did_key.py +198 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/payments/prepaid_credits.py +26 -4
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/pyproject.toml +1 -1
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/tests/test_imports.py +1 -1
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/tests/test_plugins.py +41 -0
- nest_plugins_reference-0.1.0/nest_plugins_reference/identity/did_key.py +0 -101
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/.gitignore +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/README.md +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/auth/__init__.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/comms/__init__.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/comms/nest_native.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/coordination/__init__.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/coordination/contract_net.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/datafacts/__init__.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/datafacts/datafacts_v1.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/identity/__init__.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/memory/__init__.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/memory/blackboard.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/negotiation/__init__.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/negotiation/alternating_offers.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/payments/__init__.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/privacy/__init__.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/privacy/noop.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/py.typed +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/registry/__init__.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/registry/in_memory.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/transport/__init__.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/transport/in_memory.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/trust/__init__.py +0 -0
- {nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/trust/score_average.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nest-plugins-reference
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: NEST reference plugins: default implementations for all 12 layers
|
|
5
5
|
Project-URL: Homepage, https://github.com/mariagorskikh/nest
|
|
6
6
|
Project-URL: Repository, https://github.com/mariagorskikh/nest
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""DID:key identity plugin — deterministic public-key signatures for simulation.
|
|
3
|
+
|
|
4
|
+
This is intentionally dependency-free and deterministic so traces replay
|
|
5
|
+
byte-for-byte. It is not production cryptography; for real deployments, swap
|
|
6
|
+
to a proper Ed25519 implementation.
|
|
7
|
+
|
|
8
|
+
Example::
|
|
9
|
+
|
|
10
|
+
identity = DidKeyIdentity(AgentId("a1"), seed=b"secret")
|
|
11
|
+
sig = identity.sign(b"payload")
|
|
12
|
+
ok = identity.verify(b"payload", sig, AgentId("a1"))
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import hashlib
|
|
18
|
+
import json
|
|
19
|
+
import math
|
|
20
|
+
|
|
21
|
+
from nest_core.types import AgentId, AgentIdentity, Signature
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DidKeyIdentity:
|
|
25
|
+
"""Public-verifiable identity for simulation.
|
|
26
|
+
|
|
27
|
+
Example::
|
|
28
|
+
|
|
29
|
+
ident = DidKeyIdentity(AgentId("a1"), seed=b"seed")
|
|
30
|
+
sig = ident.sign(b"hello")
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, agent_id: AgentId, seed: bytes = b"") -> None:
|
|
34
|
+
self._agent_id = agent_id
|
|
35
|
+
self._seed = seed
|
|
36
|
+
self._public_numbers, self._private_exponent = _derive_keypair(seed, agent_id)
|
|
37
|
+
self._public_key = _encode_public_key(self._public_numbers)
|
|
38
|
+
self._known_keys: dict[AgentId, tuple[int, int]] = {agent_id: self._public_numbers}
|
|
39
|
+
|
|
40
|
+
def register_peer(
|
|
41
|
+
self,
|
|
42
|
+
agent_id: AgentId,
|
|
43
|
+
public_key: bytes,
|
|
44
|
+
private_key: bytes | None = None,
|
|
45
|
+
) -> None:
|
|
46
|
+
"""Register a peer's public key for verification.
|
|
47
|
+
|
|
48
|
+
Example::
|
|
49
|
+
|
|
50
|
+
ident.register_peer(AgentId("a2"), peer_pk)
|
|
51
|
+
"""
|
|
52
|
+
if private_key is not None:
|
|
53
|
+
msg = "register_peer accepts public keys only"
|
|
54
|
+
raise ValueError(msg)
|
|
55
|
+
self._known_keys[agent_id] = _decode_public_key(public_key)
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def public_key(self) -> bytes:
|
|
59
|
+
"""This agent's public key.
|
|
60
|
+
|
|
61
|
+
Example::
|
|
62
|
+
|
|
63
|
+
pk = ident.public_key
|
|
64
|
+
"""
|
|
65
|
+
return self._public_key
|
|
66
|
+
|
|
67
|
+
def sign(self, payload: bytes) -> Signature:
|
|
68
|
+
"""Sign a payload with this agent's private key.
|
|
69
|
+
|
|
70
|
+
Example::
|
|
71
|
+
|
|
72
|
+
sig = ident.sign(b"data")
|
|
73
|
+
"""
|
|
74
|
+
n, _e = self._public_numbers
|
|
75
|
+
digest = _digest_int(payload, n)
|
|
76
|
+
sig_int = pow(digest, self._private_exponent, n)
|
|
77
|
+
size = (n.bit_length() + 7) // 8
|
|
78
|
+
sig_bytes = sig_int.to_bytes(size, "big")
|
|
79
|
+
return Signature(signer=self._agent_id, value=sig_bytes, algorithm="sim-rsa-sha256")
|
|
80
|
+
|
|
81
|
+
def verify(self, payload: bytes, sig: Signature, agent: AgentId) -> bool:
|
|
82
|
+
"""Verify a signature from a given agent.
|
|
83
|
+
|
|
84
|
+
Example::
|
|
85
|
+
|
|
86
|
+
ok = ident.verify(b"data", sig, AgentId("a1"))
|
|
87
|
+
"""
|
|
88
|
+
if sig.signer != agent:
|
|
89
|
+
return False
|
|
90
|
+
public_numbers = self._known_keys.get(agent)
|
|
91
|
+
if public_numbers is None:
|
|
92
|
+
return False
|
|
93
|
+
n, e = public_numbers
|
|
94
|
+
sig_int = int.from_bytes(sig.value, "big")
|
|
95
|
+
if sig_int >= n:
|
|
96
|
+
return False
|
|
97
|
+
expected = _digest_int(payload, n)
|
|
98
|
+
actual = pow(sig_int, e, n)
|
|
99
|
+
return actual == expected
|
|
100
|
+
|
|
101
|
+
async def resolve(self, agent: AgentId) -> AgentIdentity:
|
|
102
|
+
"""Resolve an agent ID to its identity record.
|
|
103
|
+
|
|
104
|
+
Example::
|
|
105
|
+
|
|
106
|
+
info = await ident.resolve(AgentId("a1"))
|
|
107
|
+
"""
|
|
108
|
+
public_numbers = self._known_keys.get(agent)
|
|
109
|
+
pk = _encode_public_key(public_numbers) if public_numbers is not None else b""
|
|
110
|
+
return AgentIdentity(
|
|
111
|
+
agent_id=agent,
|
|
112
|
+
public_key=pk,
|
|
113
|
+
method="did:key",
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
_PUBLIC_EXPONENT = 65537
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _derive_keypair(seed: bytes, agent_id: AgentId) -> tuple[tuple[int, int], int]:
|
|
121
|
+
p = _derive_prime(seed, agent_id, b"p")
|
|
122
|
+
q = _derive_prime(seed, agent_id, b"q")
|
|
123
|
+
counter = 0
|
|
124
|
+
while p == q or math.gcd(_PUBLIC_EXPONENT, (p - 1) * (q - 1)) != 1:
|
|
125
|
+
counter += 1
|
|
126
|
+
q = _derive_prime(seed, agent_id, b"q" + counter.to_bytes(2, "big"))
|
|
127
|
+
n = p * q
|
|
128
|
+
phi = (p - 1) * (q - 1)
|
|
129
|
+
d = pow(_PUBLIC_EXPONENT, -1, phi)
|
|
130
|
+
return (n, _PUBLIC_EXPONENT), d
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _derive_prime(seed: bytes, agent_id: AgentId, label: bytes) -> int:
|
|
134
|
+
counter = 0
|
|
135
|
+
while True:
|
|
136
|
+
material = seed + b":" + str(agent_id).encode() + b":" + label + counter.to_bytes(4, "big")
|
|
137
|
+
digest = hashlib.sha512(material).digest()
|
|
138
|
+
candidate = int.from_bytes(digest[:32], "big")
|
|
139
|
+
candidate |= 1
|
|
140
|
+
candidate |= 1 << 255
|
|
141
|
+
if _is_probable_prime(candidate):
|
|
142
|
+
return candidate
|
|
143
|
+
counter += 1
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _is_probable_prime(n: int) -> bool:
|
|
147
|
+
if n < 2:
|
|
148
|
+
return False
|
|
149
|
+
small_primes = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37)
|
|
150
|
+
for prime in small_primes:
|
|
151
|
+
if n == prime:
|
|
152
|
+
return True
|
|
153
|
+
if n % prime == 0:
|
|
154
|
+
return False
|
|
155
|
+
|
|
156
|
+
d = n - 1
|
|
157
|
+
s = 0
|
|
158
|
+
while d % 2 == 0:
|
|
159
|
+
s += 1
|
|
160
|
+
d //= 2
|
|
161
|
+
|
|
162
|
+
for base in small_primes:
|
|
163
|
+
if base >= n:
|
|
164
|
+
continue
|
|
165
|
+
x = pow(base, d, n)
|
|
166
|
+
if x in (1, n - 1):
|
|
167
|
+
continue
|
|
168
|
+
for _ in range(s - 1):
|
|
169
|
+
x = pow(x, 2, n)
|
|
170
|
+
if x == n - 1:
|
|
171
|
+
break
|
|
172
|
+
else:
|
|
173
|
+
return False
|
|
174
|
+
return True
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _encode_public_key(public_numbers: tuple[int, int]) -> bytes:
|
|
178
|
+
n, e = public_numbers
|
|
179
|
+
return json.dumps(
|
|
180
|
+
{"alg": "sim-rsa-sha256", "e": e, "n": format(n, "x")},
|
|
181
|
+
sort_keys=True,
|
|
182
|
+
separators=(",", ":"),
|
|
183
|
+
).encode("ascii")
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _decode_public_key(public_key: bytes) -> tuple[int, int]:
|
|
187
|
+
try:
|
|
188
|
+
data = json.loads(public_key.decode("ascii"))
|
|
189
|
+
if data.get("alg") != "sim-rsa-sha256":
|
|
190
|
+
raise ValueError
|
|
191
|
+
return int(data["n"], 16), int(data["e"])
|
|
192
|
+
except (KeyError, TypeError, ValueError, json.JSONDecodeError) as exc:
|
|
193
|
+
msg = "Invalid public key"
|
|
194
|
+
raise ValueError(msg) from exc
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _digest_int(payload: bytes, modulus: int) -> int:
|
|
198
|
+
return int.from_bytes(hashlib.sha256(payload).digest(), "big") % modulus
|
|
@@ -29,10 +29,17 @@ class PrepaidCredits:
|
|
|
29
29
|
receipt = await pay.pay(AgentId("a2"), Money(amount=50), PaymentRef("p1"))
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
|
-
def __init__(
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
agent_id: AgentId,
|
|
35
|
+
initial_balance: int = 1000,
|
|
36
|
+
balances: dict[AgentId, int] | None = None,
|
|
37
|
+
payments: dict[PaymentRef, Receipt] | None = None,
|
|
38
|
+
) -> None:
|
|
33
39
|
self._agent_id = agent_id
|
|
34
|
-
self._balances
|
|
35
|
-
self.
|
|
40
|
+
self._balances = balances if balances is not None else {}
|
|
41
|
+
self._balances.setdefault(agent_id, initial_balance)
|
|
42
|
+
self._payments = payments if payments is not None else {}
|
|
36
43
|
|
|
37
44
|
def balance(self, agent: AgentId) -> int:
|
|
38
45
|
"""Check an agent's balance.
|
|
@@ -59,6 +66,13 @@ class PrepaidCredits:
|
|
|
59
66
|
|
|
60
67
|
receipt = await pay.pay(AgentId("a2"), Money(amount=50), PaymentRef("p1"))
|
|
61
68
|
"""
|
|
69
|
+
if amount.amount <= 0:
|
|
70
|
+
msg = f"Payment amount must be positive: {amount.amount}"
|
|
71
|
+
raise ValueError(msg)
|
|
72
|
+
if ref in self._payments:
|
|
73
|
+
msg = f"Duplicate payment reference: {ref}"
|
|
74
|
+
raise ValueError(msg)
|
|
75
|
+
|
|
62
76
|
payer_balance = self._balances.get(self._agent_id, 0)
|
|
63
77
|
if payer_balance < amount.amount:
|
|
64
78
|
msg = f"Insufficient balance: {payer_balance} < {amount.amount}"
|
|
@@ -94,6 +108,14 @@ class PrepaidCredits:
|
|
|
94
108
|
msg = f"Payment not found: {ref}"
|
|
95
109
|
raise ValueError(msg)
|
|
96
110
|
|
|
97
|
-
|
|
111
|
+
payee_balance = self._balances.get(receipt.payee, 0)
|
|
112
|
+
if payee_balance < receipt.amount.amount:
|
|
113
|
+
msg = (
|
|
114
|
+
f"Insufficient balance for refund: {receipt.payee} has "
|
|
115
|
+
f"{payee_balance}, needs {receipt.amount.amount}"
|
|
116
|
+
)
|
|
117
|
+
raise ValueError(msg)
|
|
118
|
+
|
|
119
|
+
self._balances[receipt.payee] = payee_balance - receipt.amount.amount
|
|
98
120
|
self._balances[receipt.payer] = self._balances.get(receipt.payer, 0) + receipt.amount.amount
|
|
99
121
|
del self._payments[ref]
|
|
@@ -6,4 +6,4 @@ def test_nest_plugins_reference_imports() -> None:
|
|
|
6
6
|
"""Importing nest_plugins_reference should succeed and expose a version string."""
|
|
7
7
|
import nest_plugins_reference
|
|
8
8
|
|
|
9
|
-
assert nest_plugins_reference.__version__ == "0.1.
|
|
9
|
+
assert nest_plugins_reference.__version__ == "0.1.1"
|
|
@@ -16,6 +16,7 @@ from nest_core.types import (
|
|
|
16
16
|
PaymentRef,
|
|
17
17
|
PaymentStatus,
|
|
18
18
|
Query,
|
|
19
|
+
Receipt,
|
|
19
20
|
ServiceRef,
|
|
20
21
|
Statement,
|
|
21
22
|
Task,
|
|
@@ -122,6 +123,23 @@ class TestDidKeyIdentity:
|
|
|
122
123
|
sig = ident.sign(b"payload")
|
|
123
124
|
assert not ident.verify(b"wrong", sig, AgentId("a1"))
|
|
124
125
|
|
|
126
|
+
def test_verify_peer_with_public_key_only(self) -> None:
|
|
127
|
+
from nest_plugins_reference.identity.did_key import DidKeyIdentity
|
|
128
|
+
|
|
129
|
+
sender = DidKeyIdentity(AgentId("a1"), seed=b"seed")
|
|
130
|
+
verifier = DidKeyIdentity(AgentId("a2"), seed=b"seed")
|
|
131
|
+
verifier.register_peer(AgentId("a1"), sender.public_key)
|
|
132
|
+
|
|
133
|
+
sig = sender.sign(b"payload")
|
|
134
|
+
assert verifier.verify(b"payload", sig, AgentId("a1"))
|
|
135
|
+
|
|
136
|
+
def test_register_peer_rejects_private_key(self) -> None:
|
|
137
|
+
from nest_plugins_reference.identity.did_key import DidKeyIdentity
|
|
138
|
+
|
|
139
|
+
ident = DidKeyIdentity(AgentId("a1"), seed=b"seed")
|
|
140
|
+
with pytest.raises(ValueError, match="public keys only"):
|
|
141
|
+
ident.register_peer(AgentId("a2"), ident.public_key, private_key=b"secret")
|
|
142
|
+
|
|
125
143
|
@pytest.mark.asyncio
|
|
126
144
|
async def test_resolve(self) -> None:
|
|
127
145
|
from nest_plugins_reference.identity.did_key import DidKeyIdentity
|
|
@@ -302,6 +320,29 @@ class TestPrepaidCredits:
|
|
|
302
320
|
q = await pay.quote(ServiceRef("svc"))
|
|
303
321
|
assert q.price.amount == 10
|
|
304
322
|
|
|
323
|
+
@pytest.mark.asyncio
|
|
324
|
+
async def test_shared_ledger_debits_calling_agent(self) -> None:
|
|
325
|
+
from nest_plugins_reference.payments.prepaid_credits import PrepaidCredits
|
|
326
|
+
|
|
327
|
+
balances = {AgentId("buyer"): 100, AgentId("seller"): 0}
|
|
328
|
+
payments: dict[PaymentRef, Receipt] = {}
|
|
329
|
+
buyer = PrepaidCredits(AgentId("buyer"), balances=balances, payments=payments)
|
|
330
|
+
seller = PrepaidCredits(AgentId("seller"), balances=balances, payments=payments)
|
|
331
|
+
|
|
332
|
+
await buyer.pay(AgentId("seller"), Money(amount=40), PaymentRef("p1"))
|
|
333
|
+
|
|
334
|
+
assert buyer.balance(AgentId("buyer")) == 60
|
|
335
|
+
assert seller.balance(AgentId("seller")) == 40
|
|
336
|
+
assert await seller.verify_payment(PaymentRef("p1")) == PaymentStatus.CONFIRMED
|
|
337
|
+
|
|
338
|
+
@pytest.mark.asyncio
|
|
339
|
+
async def test_rejects_non_positive_payment(self) -> None:
|
|
340
|
+
from nest_plugins_reference.payments.prepaid_credits import PrepaidCredits
|
|
341
|
+
|
|
342
|
+
pay = PrepaidCredits(AgentId("a1"), initial_balance=100)
|
|
343
|
+
with pytest.raises(ValueError, match="positive"):
|
|
344
|
+
await pay.pay(AgentId("a2"), Money(amount=0), PaymentRef("p1"))
|
|
345
|
+
|
|
305
346
|
|
|
306
347
|
# ---------------------------------------------------------------------------
|
|
307
348
|
# 8. Coordination: contract_net
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
"""DID:key identity plugin — Ed25519 key-based identity.
|
|
3
|
-
|
|
4
|
-
Uses hashlib for deterministic key derivation in simulation (no real crypto
|
|
5
|
-
needed for testing). For real deployments, swap to a proper Ed25519 library.
|
|
6
|
-
|
|
7
|
-
Example::
|
|
8
|
-
|
|
9
|
-
identity = DidKeyIdentity(AgentId("a1"), seed=b"secret")
|
|
10
|
-
sig = identity.sign(b"payload")
|
|
11
|
-
ok = identity.verify(b"payload", sig, AgentId("a1"))
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
from __future__ import annotations
|
|
15
|
-
|
|
16
|
-
import hashlib
|
|
17
|
-
import hmac
|
|
18
|
-
|
|
19
|
-
from nest_core.types import AgentId, AgentIdentity, Signature
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class DidKeyIdentity:
|
|
23
|
-
"""Ed25519-style identity using HMAC-SHA256 for simulation.
|
|
24
|
-
|
|
25
|
-
Example::
|
|
26
|
-
|
|
27
|
-
ident = DidKeyIdentity(AgentId("a1"), seed=b"seed")
|
|
28
|
-
sig = ident.sign(b"hello")
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
def __init__(self, agent_id: AgentId, seed: bytes = b"") -> None:
|
|
32
|
-
self._agent_id = agent_id
|
|
33
|
-
self._seed = seed
|
|
34
|
-
key_material = hashlib.sha256(seed + agent_id.encode()).digest()
|
|
35
|
-
self._private_key = key_material
|
|
36
|
-
self._public_key = hashlib.sha256(key_material).digest()
|
|
37
|
-
self._known_keys: dict[AgentId, bytes] = {agent_id: self._public_key}
|
|
38
|
-
self._private_keys: dict[AgentId, bytes] = {agent_id: self._private_key}
|
|
39
|
-
|
|
40
|
-
def register_peer(
|
|
41
|
-
self,
|
|
42
|
-
agent_id: AgentId,
|
|
43
|
-
public_key: bytes,
|
|
44
|
-
private_key: bytes | None = None,
|
|
45
|
-
) -> None:
|
|
46
|
-
"""Register a peer's public key (and optionally private key) for verification.
|
|
47
|
-
|
|
48
|
-
Example::
|
|
49
|
-
|
|
50
|
-
ident.register_peer(AgentId("a2"), peer_pk)
|
|
51
|
-
"""
|
|
52
|
-
self._known_keys[agent_id] = public_key
|
|
53
|
-
if private_key is not None:
|
|
54
|
-
self._private_keys[agent_id] = private_key
|
|
55
|
-
|
|
56
|
-
@property
|
|
57
|
-
def public_key(self) -> bytes:
|
|
58
|
-
"""This agent's public key.
|
|
59
|
-
|
|
60
|
-
Example::
|
|
61
|
-
|
|
62
|
-
pk = ident.public_key
|
|
63
|
-
"""
|
|
64
|
-
return self._public_key
|
|
65
|
-
|
|
66
|
-
def sign(self, payload: bytes) -> Signature:
|
|
67
|
-
"""Sign a payload with this agent's private key.
|
|
68
|
-
|
|
69
|
-
Example::
|
|
70
|
-
|
|
71
|
-
sig = ident.sign(b"data")
|
|
72
|
-
"""
|
|
73
|
-
sig_bytes = hmac.new(self._private_key, payload, hashlib.sha256).digest()
|
|
74
|
-
return Signature(signer=self._agent_id, value=sig_bytes, algorithm="hmac-sha256")
|
|
75
|
-
|
|
76
|
-
def verify(self, payload: bytes, sig: Signature, agent: AgentId) -> bool:
|
|
77
|
-
"""Verify a signature from a given agent.
|
|
78
|
-
|
|
79
|
-
Example::
|
|
80
|
-
|
|
81
|
-
ok = ident.verify(b"data", sig, AgentId("a1"))
|
|
82
|
-
"""
|
|
83
|
-
private_key = self._private_keys.get(agent)
|
|
84
|
-
if private_key is None:
|
|
85
|
-
return False
|
|
86
|
-
expected = hmac.new(private_key, payload, hashlib.sha256).digest()
|
|
87
|
-
return hmac.compare_digest(sig.value, expected)
|
|
88
|
-
|
|
89
|
-
async def resolve(self, agent: AgentId) -> AgentIdentity:
|
|
90
|
-
"""Resolve an agent ID to its identity record.
|
|
91
|
-
|
|
92
|
-
Example::
|
|
93
|
-
|
|
94
|
-
info = await ident.resolve(AgentId("a1"))
|
|
95
|
-
"""
|
|
96
|
-
pk = self._known_keys.get(agent, b"")
|
|
97
|
-
return AgentIdentity(
|
|
98
|
-
agent_id=agent,
|
|
99
|
-
public_key=pk,
|
|
100
|
-
method="did:key",
|
|
101
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/privacy/noop.py
RENAMED
|
File without changes
|
{nest_plugins_reference-0.1.0 → nest_plugins_reference-0.1.1}/nest_plugins_reference/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|