pvfast 1.22.0__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.
- pvfast/__init__.py +26 -0
- pvfast/__main__.py +9 -0
- pvfast/ed25519.py +113 -0
- pvfast/internal-stwo-prover-provable-100-v1.json +4954 -0
- pvfast/internal_source_policy.py +885 -0
- pvfast/local_measure.py +222 -0
- pvfast/participant_cli.py +1849 -0
- pvfast/public_preflight.py +929 -0
- pvfast/remote_client.py +3612 -0
- pvfast-1.22.0.dist-info/METADATA +116 -0
- pvfast-1.22.0.dist-info/RECORD +14 -0
- pvfast-1.22.0.dist-info/WHEEL +4 -0
- pvfast-1.22.0.dist-info/entry_points.txt +3 -0
- pvfast-1.22.0.dist-info/licenses/LICENSE +202 -0
pvfast/__init__.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""The provably.fast participant client.
|
|
2
|
+
|
|
3
|
+
Stdlib only. This package is the command surface a participant uses against
|
|
4
|
+
https://provably.fast: device login, the research graph and map, lead proposals,
|
|
5
|
+
preflighted submissions and status. It never evaluates, scores or promotes, and
|
|
6
|
+
your credentials stay in PVFAST_REMOTE_CREDENTIALS on your own machine.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
__all__ = ["__version__", "main", "measure"]
|
|
11
|
+
|
|
12
|
+
__version__ = "1.22.0"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main(argv: list[str] | None = None) -> int:
|
|
16
|
+
"""Run the `pvfast` command."""
|
|
17
|
+
from .participant_cli import main as _main
|
|
18
|
+
|
|
19
|
+
return _main(argv)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def measure() -> None:
|
|
23
|
+
"""Run the `pvfast-measure` command: time your prover against the frontier's."""
|
|
24
|
+
from .local_measure import main as _measure
|
|
25
|
+
|
|
26
|
+
_measure()
|
pvfast/__main__.py
ADDED
pvfast/ed25519.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Ed25519 (RFC 8032), standard library only: signatures the checks Worker makes and an agent
|
|
2
|
+
verifies offline, and the agent's own key that signs its runs, posts and commitments.
|
|
3
|
+
|
|
4
|
+
Verification is cofactorless, as RFC 8032 and WebCrypto verify: [S]B = R + [h]A. Signing is the
|
|
5
|
+
RFC's deterministic algorithm. This arithmetic is not constant-time: it suits an agent's own
|
|
6
|
+
attribution key on its own machine, not a key guarding funds on a shared host.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import hashlib
|
|
11
|
+
|
|
12
|
+
_P = 2 ** 255 - 19
|
|
13
|
+
_L = 2 ** 252 + 27742317777372353535851937790883648493
|
|
14
|
+
_D = -121665 * pow(121666, _P - 2, _P) % _P
|
|
15
|
+
_SQRT_M1 = pow(2, (_P - 1) // 4, _P)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _recover_x(y: int, sign: int) -> int | None:
|
|
19
|
+
if y >= _P:
|
|
20
|
+
return None
|
|
21
|
+
x2 = (y * y - 1) * pow(_D * y * y + 1, _P - 2, _P) % _P
|
|
22
|
+
if x2 == 0:
|
|
23
|
+
return None if sign else 0
|
|
24
|
+
x = pow(x2, (_P + 3) // 8, _P)
|
|
25
|
+
if (x * x - x2) % _P:
|
|
26
|
+
x = x * _SQRT_M1 % _P
|
|
27
|
+
if (x * x - x2) % _P:
|
|
28
|
+
return None
|
|
29
|
+
return _P - x if (x & 1) != sign else x
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
_BY = 4 * pow(5, _P - 2, _P) % _P
|
|
33
|
+
_BX = _recover_x(_BY, 0)
|
|
34
|
+
_B = (_BX, _BY, 1, _BX * _BY % _P) # extended coordinates (X, Y, Z, T)
|
|
35
|
+
_NEUTRAL = (0, 1, 1, 0)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _add(p: tuple, q: tuple) -> tuple:
|
|
39
|
+
a = (p[1] - p[0]) * (q[1] - q[0]) % _P
|
|
40
|
+
b = (p[1] + p[0]) * (q[1] + q[0]) % _P
|
|
41
|
+
c = 2 * p[3] * q[3] * _D % _P
|
|
42
|
+
d = 2 * p[2] * q[2] % _P
|
|
43
|
+
e, f, g, h = b - a, d - c, d + c, b + a
|
|
44
|
+
return (e * f % _P, g * h % _P, f * g % _P, e * h % _P)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _multiply(scalar: int, point: tuple) -> tuple:
|
|
48
|
+
result = _NEUTRAL
|
|
49
|
+
while scalar:
|
|
50
|
+
if scalar & 1:
|
|
51
|
+
result = _add(result, point)
|
|
52
|
+
point = _add(point, point)
|
|
53
|
+
scalar >>= 1
|
|
54
|
+
return result
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _decompress(encoded: bytes) -> tuple | None:
|
|
58
|
+
if len(encoded) != 32:
|
|
59
|
+
return None
|
|
60
|
+
y = int.from_bytes(encoded, "little")
|
|
61
|
+
x = _recover_x(y & ((1 << 255) - 1), y >> 255)
|
|
62
|
+
if x is None:
|
|
63
|
+
return None
|
|
64
|
+
y &= (1 << 255) - 1
|
|
65
|
+
return (x, y, 1, x * y % _P)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _same(p: tuple, q: tuple) -> bool:
|
|
69
|
+
return (p[0] * q[2] - q[0] * p[2]) % _P == 0 and (p[1] * q[2] - q[1] * p[2]) % _P == 0
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def verify(public_key: bytes, message: bytes, signature: bytes) -> bool:
|
|
73
|
+
"""Whether `signature` is public_key's Ed25519 signature of `message`."""
|
|
74
|
+
if len(public_key) != 32 or len(signature) != 64:
|
|
75
|
+
return False
|
|
76
|
+
a = _decompress(public_key)
|
|
77
|
+
r = _decompress(signature[:32])
|
|
78
|
+
s = int.from_bytes(signature[32:], "little")
|
|
79
|
+
if a is None or r is None or s >= _L:
|
|
80
|
+
return False
|
|
81
|
+
h = int.from_bytes(hashlib.sha512(signature[:32] + public_key + message).digest(), "little") % _L
|
|
82
|
+
return _same(_multiply(s, _B), _add(r, _multiply(h, a)))
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _compress(point: tuple) -> bytes:
|
|
86
|
+
z_inverse = pow(point[2], _P - 2, _P)
|
|
87
|
+
x, y = point[0] * z_inverse % _P, point[1] * z_inverse % _P
|
|
88
|
+
return (y | ((x & 1) << 255)).to_bytes(32, "little")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _expand(seed: bytes) -> tuple[int, bytes]:
|
|
92
|
+
if len(seed) != 32:
|
|
93
|
+
raise ValueError("an Ed25519 seed is 32 bytes")
|
|
94
|
+
digest = hashlib.sha512(seed).digest()
|
|
95
|
+
scalar = int.from_bytes(digest[:32], "little")
|
|
96
|
+
scalar &= (1 << 254) - 8
|
|
97
|
+
scalar |= 1 << 254
|
|
98
|
+
return scalar, digest[32:]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def public_key(seed: bytes) -> bytes:
|
|
102
|
+
"""The public key of a 32-byte private seed."""
|
|
103
|
+
return _compress(_multiply(_expand(seed)[0], _B))
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def sign(seed: bytes, message: bytes) -> bytes:
|
|
107
|
+
"""The Ed25519 signature of `message` by the key with this 32-byte private seed."""
|
|
108
|
+
scalar, prefix = _expand(seed)
|
|
109
|
+
public = _compress(_multiply(scalar, _B))
|
|
110
|
+
r = int.from_bytes(hashlib.sha512(prefix + message).digest(), "little") % _L
|
|
111
|
+
encoded_r = _compress(_multiply(r, _B))
|
|
112
|
+
h = int.from_bytes(hashlib.sha512(encoded_r + public + message).digest(), "little") % _L
|
|
113
|
+
return encoded_r + ((r + h * scalar) % _L).to_bytes(32, "little")
|