pp2p-core 0.1.0__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.
- pp2p_core-0.1.0/PKG-INFO +66 -0
- pp2p_core-0.1.0/README.md +54 -0
- pp2p_core-0.1.0/pp2p_core.egg-info/PKG-INFO +66 -0
- pp2p_core-0.1.0/pp2p_core.egg-info/SOURCES.txt +7 -0
- pp2p_core-0.1.0/pp2p_core.egg-info/dependency_links.txt +1 -0
- pp2p_core-0.1.0/pp2p_core.egg-info/top_level.txt +1 -0
- pp2p_core-0.1.0/pp2p_core.py +131 -0
- pp2p_core-0.1.0/pyproject.toml +20 -0
- pp2p_core-0.1.0/setup.cfg +4 -0
pp2p_core-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pp2p_core
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python ctypes SDK for the PP2P Rust core
|
|
5
|
+
Author: PP2P
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# Python SDK
|
|
14
|
+
|
|
15
|
+
This package is a ctypes bridge over the PP2P Rust C ABI.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install pp2p_core
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Runtime requirements
|
|
24
|
+
|
|
25
|
+
- Python 3.9+
|
|
26
|
+
- Native PP2P core library (`pp2p_core.dll` / `libpp2p_core.so` / `libpp2p_core.dylib`)
|
|
27
|
+
|
|
28
|
+
Build native library first:
|
|
29
|
+
|
|
30
|
+
Windows:
|
|
31
|
+
```powershell
|
|
32
|
+
.\scripts\build_pp2p_core.ps1
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Linux/macOS:
|
|
36
|
+
```bash
|
|
37
|
+
./scripts/build_pp2p_core_unix.sh
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
If the library is not in `dist/pp2p_core/...`, set `PP2P_CORE_LIB` to its absolute path.
|
|
41
|
+
|
|
42
|
+
## Local dev install
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install -e ./bindings/python
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Example
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from pp2p_core import Pp2pCore
|
|
52
|
+
|
|
53
|
+
core = Pp2pCore()
|
|
54
|
+
alice = core.generate_identity()
|
|
55
|
+
bob = core.generate_identity()
|
|
56
|
+
|
|
57
|
+
env = core.sign_envelope(
|
|
58
|
+
private_key_b64=alice["private_key_b64"],
|
|
59
|
+
sender_peer_id=alice["peer_id"],
|
|
60
|
+
recipient_peer_id=bob["peer_id"],
|
|
61
|
+
payload={"type": "hello", "text": "hi"},
|
|
62
|
+
nonce="n1",
|
|
63
|
+
)
|
|
64
|
+
core.verify_envelope(env, signer_public_key_b64=alice["public_key_b64"])
|
|
65
|
+
print("ok")
|
|
66
|
+
```
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Python SDK
|
|
2
|
+
|
|
3
|
+
This package is a ctypes bridge over the PP2P Rust C ABI.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install pp2p_core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Runtime requirements
|
|
12
|
+
|
|
13
|
+
- Python 3.9+
|
|
14
|
+
- Native PP2P core library (`pp2p_core.dll` / `libpp2p_core.so` / `libpp2p_core.dylib`)
|
|
15
|
+
|
|
16
|
+
Build native library first:
|
|
17
|
+
|
|
18
|
+
Windows:
|
|
19
|
+
```powershell
|
|
20
|
+
.\scripts\build_pp2p_core.ps1
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Linux/macOS:
|
|
24
|
+
```bash
|
|
25
|
+
./scripts/build_pp2p_core_unix.sh
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
If the library is not in `dist/pp2p_core/...`, set `PP2P_CORE_LIB` to its absolute path.
|
|
29
|
+
|
|
30
|
+
## Local dev install
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install -e ./bindings/python
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Example
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from pp2p_core import Pp2pCore
|
|
40
|
+
|
|
41
|
+
core = Pp2pCore()
|
|
42
|
+
alice = core.generate_identity()
|
|
43
|
+
bob = core.generate_identity()
|
|
44
|
+
|
|
45
|
+
env = core.sign_envelope(
|
|
46
|
+
private_key_b64=alice["private_key_b64"],
|
|
47
|
+
sender_peer_id=alice["peer_id"],
|
|
48
|
+
recipient_peer_id=bob["peer_id"],
|
|
49
|
+
payload={"type": "hello", "text": "hi"},
|
|
50
|
+
nonce="n1",
|
|
51
|
+
)
|
|
52
|
+
core.verify_envelope(env, signer_public_key_b64=alice["public_key_b64"])
|
|
53
|
+
print("ok")
|
|
54
|
+
```
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pp2p_core
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python ctypes SDK for the PP2P Rust core
|
|
5
|
+
Author: PP2P
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# Python SDK
|
|
14
|
+
|
|
15
|
+
This package is a ctypes bridge over the PP2P Rust C ABI.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install pp2p_core
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Runtime requirements
|
|
24
|
+
|
|
25
|
+
- Python 3.9+
|
|
26
|
+
- Native PP2P core library (`pp2p_core.dll` / `libpp2p_core.so` / `libpp2p_core.dylib`)
|
|
27
|
+
|
|
28
|
+
Build native library first:
|
|
29
|
+
|
|
30
|
+
Windows:
|
|
31
|
+
```powershell
|
|
32
|
+
.\scripts\build_pp2p_core.ps1
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Linux/macOS:
|
|
36
|
+
```bash
|
|
37
|
+
./scripts/build_pp2p_core_unix.sh
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
If the library is not in `dist/pp2p_core/...`, set `PP2P_CORE_LIB` to its absolute path.
|
|
41
|
+
|
|
42
|
+
## Local dev install
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install -e ./bindings/python
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Example
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from pp2p_core import Pp2pCore
|
|
52
|
+
|
|
53
|
+
core = Pp2pCore()
|
|
54
|
+
alice = core.generate_identity()
|
|
55
|
+
bob = core.generate_identity()
|
|
56
|
+
|
|
57
|
+
env = core.sign_envelope(
|
|
58
|
+
private_key_b64=alice["private_key_b64"],
|
|
59
|
+
sender_peer_id=alice["peer_id"],
|
|
60
|
+
recipient_peer_id=bob["peer_id"],
|
|
61
|
+
payload={"type": "hello", "text": "hi"},
|
|
62
|
+
nonce="n1",
|
|
63
|
+
)
|
|
64
|
+
core.verify_envelope(env, signer_public_key_b64=alice["public_key_b64"])
|
|
65
|
+
print("ok")
|
|
66
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pp2p_core
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Python ctypes bridge for the Rust PP2P core C ABI.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import ctypes
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
import pathlib
|
|
11
|
+
import time
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _default_library_path() -> str:
|
|
16
|
+
env = os.environ.get("PP2P_CORE_LIB")
|
|
17
|
+
if env:
|
|
18
|
+
return env
|
|
19
|
+
|
|
20
|
+
if os.name == "nt":
|
|
21
|
+
rel = pathlib.Path("dist") / "pp2p_core" / "windows-x64" / "pp2p_core.dll"
|
|
22
|
+
elif os.uname().sysname == "Darwin":
|
|
23
|
+
rel = pathlib.Path("dist") / "pp2p_core" / "macos" / "libpp2p_core.dylib"
|
|
24
|
+
else:
|
|
25
|
+
rel = pathlib.Path("dist") / "pp2p_core" / "linux-x64" / "libpp2p_core.so"
|
|
26
|
+
|
|
27
|
+
candidates = [
|
|
28
|
+
pathlib.Path(__file__).resolve().parents[2] / rel,
|
|
29
|
+
pathlib.Path.cwd() / rel,
|
|
30
|
+
]
|
|
31
|
+
for candidate in candidates:
|
|
32
|
+
if candidate.exists():
|
|
33
|
+
return str(candidate)
|
|
34
|
+
|
|
35
|
+
# Return best-guess path so ctypes error mentions a useful location.
|
|
36
|
+
return str(candidates[0])
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class Pp2pCoreError(RuntimeError):
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class Pp2pCore:
|
|
44
|
+
def __init__(self, lib_path: str | None = None) -> None:
|
|
45
|
+
path = lib_path or _default_library_path()
|
|
46
|
+
self._lib = ctypes.CDLL(path)
|
|
47
|
+
|
|
48
|
+
self._lib.pp2p_generate_identity_json.restype = ctypes.c_void_p
|
|
49
|
+
self._lib.pp2p_peer_id_from_public_key_b64.argtypes = [ctypes.c_char_p]
|
|
50
|
+
self._lib.pp2p_peer_id_from_public_key_b64.restype = ctypes.c_void_p
|
|
51
|
+
self._lib.pp2p_sign_envelope_json.argtypes = [
|
|
52
|
+
ctypes.c_char_p,
|
|
53
|
+
ctypes.c_char_p,
|
|
54
|
+
ctypes.c_char_p,
|
|
55
|
+
ctypes.c_char_p,
|
|
56
|
+
ctypes.c_uint64,
|
|
57
|
+
ctypes.c_char_p,
|
|
58
|
+
]
|
|
59
|
+
self._lib.pp2p_sign_envelope_json.restype = ctypes.c_void_p
|
|
60
|
+
self._lib.pp2p_verify_envelope_json.argtypes = [
|
|
61
|
+
ctypes.c_char_p,
|
|
62
|
+
ctypes.c_char_p,
|
|
63
|
+
ctypes.c_uint64,
|
|
64
|
+
ctypes.c_uint64,
|
|
65
|
+
]
|
|
66
|
+
self._lib.pp2p_verify_envelope_json.restype = ctypes.c_ubyte
|
|
67
|
+
self._lib.pp2p_last_error_message.restype = ctypes.c_void_p
|
|
68
|
+
self._lib.pp2p_free_string.argtypes = [ctypes.c_void_p]
|
|
69
|
+
|
|
70
|
+
def _take_string(self, ptr: int | None) -> str:
|
|
71
|
+
if not ptr:
|
|
72
|
+
raise Pp2pCoreError(self.last_error())
|
|
73
|
+
try:
|
|
74
|
+
raw = ctypes.cast(ptr, ctypes.c_char_p).value or b""
|
|
75
|
+
return raw.decode("utf-8")
|
|
76
|
+
finally:
|
|
77
|
+
self._lib.pp2p_free_string(ptr)
|
|
78
|
+
|
|
79
|
+
def last_error(self) -> str:
|
|
80
|
+
ptr = self._lib.pp2p_last_error_message()
|
|
81
|
+
if not ptr:
|
|
82
|
+
return "unknown error"
|
|
83
|
+
return self._take_string(ptr)
|
|
84
|
+
|
|
85
|
+
def generate_identity(self) -> dict[str, Any]:
|
|
86
|
+
ptr = self._lib.pp2p_generate_identity_json()
|
|
87
|
+
return json.loads(self._take_string(ptr))
|
|
88
|
+
|
|
89
|
+
def peer_id_from_public_key_b64(self, public_key_b64: str) -> str:
|
|
90
|
+
ptr = self._lib.pp2p_peer_id_from_public_key_b64(public_key_b64.encode("utf-8"))
|
|
91
|
+
return self._take_string(ptr)
|
|
92
|
+
|
|
93
|
+
def sign_envelope(
|
|
94
|
+
self,
|
|
95
|
+
private_key_b64: str,
|
|
96
|
+
sender_peer_id: str,
|
|
97
|
+
recipient_peer_id: str,
|
|
98
|
+
payload: dict[str, Any],
|
|
99
|
+
nonce: str,
|
|
100
|
+
timestamp_ms: int | None = None,
|
|
101
|
+
) -> dict[str, Any]:
|
|
102
|
+
if timestamp_ms is None:
|
|
103
|
+
timestamp_ms = int(time.time() * 1000)
|
|
104
|
+
ptr = self._lib.pp2p_sign_envelope_json(
|
|
105
|
+
private_key_b64.encode("utf-8"),
|
|
106
|
+
sender_peer_id.encode("utf-8"),
|
|
107
|
+
recipient_peer_id.encode("utf-8"),
|
|
108
|
+
json.dumps(payload, separators=(",", ":")).encode("utf-8"),
|
|
109
|
+
ctypes.c_uint64(timestamp_ms),
|
|
110
|
+
nonce.encode("utf-8"),
|
|
111
|
+
)
|
|
112
|
+
return json.loads(self._take_string(ptr))
|
|
113
|
+
|
|
114
|
+
def verify_envelope(
|
|
115
|
+
self,
|
|
116
|
+
envelope: dict[str, Any],
|
|
117
|
+
signer_public_key_b64: str,
|
|
118
|
+
max_skew_ms: int = 60_000,
|
|
119
|
+
now_ms: int | None = None,
|
|
120
|
+
) -> bool:
|
|
121
|
+
if now_ms is None:
|
|
122
|
+
now_ms = int(time.time() * 1000)
|
|
123
|
+
ok = self._lib.pp2p_verify_envelope_json(
|
|
124
|
+
json.dumps(envelope, separators=(",", ":")).encode("utf-8"),
|
|
125
|
+
signer_public_key_b64.encode("utf-8"),
|
|
126
|
+
ctypes.c_uint64(now_ms),
|
|
127
|
+
ctypes.c_uint64(max_skew_ms),
|
|
128
|
+
)
|
|
129
|
+
if ok == 1:
|
|
130
|
+
return True
|
|
131
|
+
raise Pp2pCoreError(self.last_error())
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pp2p_core"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Python ctypes SDK for the PP2P Rust core"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
authors = [{ name = "PP2P" }]
|
|
12
|
+
license = "MIT"
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[tool.setuptools]
|
|
20
|
+
py-modules = ["pp2p_core"]
|