alethech 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.
- alethech-0.1.0/LICENSE +21 -0
- alethech-0.1.0/PKG-INFO +14 -0
- alethech-0.1.0/README.md +98 -0
- alethech-0.1.0/alethech/__init__.py +6 -0
- alethech-0.1.0/alethech/canonical.py +106 -0
- alethech-0.1.0/alethech/cli.py +605 -0
- alethech-0.1.0/alethech/crypto.py +132 -0
- alethech-0.1.0/alethech/objects.py +343 -0
- alethech-0.1.0/alethech/store.py +183 -0
- alethech-0.1.0/alethech/verify.py +244 -0
- alethech-0.1.0/alethech.egg-info/PKG-INFO +14 -0
- alethech-0.1.0/alethech.egg-info/SOURCES.txt +17 -0
- alethech-0.1.0/alethech.egg-info/dependency_links.txt +1 -0
- alethech-0.1.0/alethech.egg-info/entry_points.txt +2 -0
- alethech-0.1.0/alethech.egg-info/requires.txt +6 -0
- alethech-0.1.0/alethech.egg-info/top_level.txt +1 -0
- alethech-0.1.0/pyproject.toml +30 -0
- alethech-0.1.0/setup.cfg +4 -0
- alethech-0.1.0/tests/test_protocol.py +448 -0
alethech-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AliceLabs LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
alethech-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: alethech
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Verifiable agent continuity protocol — local-first, zero-LLM, zero-blockchain
|
|
5
|
+
Author: AliceLabs
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: cryptography>=42.0
|
|
10
|
+
Requires-Dist: click>=8.0
|
|
11
|
+
Provides-Extra: dev
|
|
12
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
13
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
14
|
+
Dynamic: license-file
|
alethech-0.1.0/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# alethech
|
|
2
|
+
|
|
3
|
+
> Verifiable agent continuity protocol — local-first, zero-LLM, zero-blockchain.
|
|
4
|
+
> The art of un-concealing transmission integrity.
|
|
5
|
+
|
|
6
|
+
From Greek **ἀλήθεια** (aletheia, "truth as un-concealment") + **τέχνη** (techne, "art, craft").
|
|
7
|
+
The art of revealing that a memory was not modified after being signed.
|
|
8
|
+
|
|
9
|
+
This is the reference implementation of the protocol specified in `docs/implementacion-nucleo-minimo.md` (rev 2).
|
|
10
|
+
|
|
11
|
+
## the property
|
|
12
|
+
|
|
13
|
+
> **This memory set forms part of a cryptographically verifiable history associated with a determined identity, whose commits can be independently verified with respect to their integrity, cryptographic authorship, and provenance relations.**
|
|
14
|
+
>
|
|
15
|
+
> **When a reference checkpoint exists, it can additionally be verified that the presented history continues from that checkpoint.**
|
|
16
|
+
|
|
17
|
+
The protocol does NOT prove that the agent's claims are true — only that they were signed by the identity that claims them. The truth being un-concealed is the truth about transmission integrity, not about content.
|
|
18
|
+
|
|
19
|
+
## status
|
|
20
|
+
|
|
21
|
+
Implementation of rev 2 spec. Six commands. No LLM, no MCP, no MarketNow, no UTA, no network, no P2P, no cloud, no consensus, no trust providers, no marketplace, no skill verification, no multi-agent consensus.
|
|
22
|
+
|
|
23
|
+
## install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install alethech
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
For development:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
git clone https://github.com/eddyflores100-lang/alethech.git
|
|
33
|
+
cd alethech
|
|
34
|
+
git checkout protocol-rev2
|
|
35
|
+
pip install -e .
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## usage
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
alethech init # generate identity + genesis commit
|
|
42
|
+
alethech commit --content <json-file> # create signed MemoryCommit
|
|
43
|
+
alethech evidence --tool <name> # create signed EvidenceCommit
|
|
44
|
+
--input <file> --output <file>
|
|
45
|
+
alethech verify # verify the whole store, offline
|
|
46
|
+
alethech export --output <dir> # portable package
|
|
47
|
+
alethech import --input <dir> # import external memory
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## what it does NOT do
|
|
51
|
+
|
|
52
|
+
- It does NOT prove that the agent's claims are true. Only that they were signed by the identity that claims them.
|
|
53
|
+
- It does NOT detect rollback without an external checkpoint.
|
|
54
|
+
- It does NOT encrypt content at rest.
|
|
55
|
+
- It does NOT delegate permissions between agents.
|
|
56
|
+
- It does NOT call any LLM.
|
|
57
|
+
|
|
58
|
+
## what the name means
|
|
59
|
+
|
|
60
|
+
**alethech** comes from:
|
|
61
|
+
|
|
62
|
+
- **aletheia (ἀλήθεια)** — Greek for "truth", more precisely "un-concealment" (Heidegger's reading: truth as the act of revealing what was hidden)
|
|
63
|
+
- **techne (τέχνη)** — Greek for "art, craft, technique"
|
|
64
|
+
|
|
65
|
+
So alethech = "the art of un-concealing". The protocol un-conceals:
|
|
66
|
+
- whether a memory was modified after being signed
|
|
67
|
+
- who signed it
|
|
68
|
+
- when it was signed
|
|
69
|
+
- what its provenance is
|
|
70
|
+
- whether the chain of custody is intact
|
|
71
|
+
|
|
72
|
+
It does NOT un-conceal whether the content is true — that's the agent's responsibility, not the protocol's.
|
|
73
|
+
|
|
74
|
+
## tests
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
python -m pytest tests/
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
34 tests covering:
|
|
81
|
+
- crypto primitives (Ed25519, SHA-256, base64url, base32)
|
|
82
|
+
- JCS canonicalization (RFC 8785)
|
|
83
|
+
- agent_id derivation (cryptographic binding to public_key)
|
|
84
|
+
- MemoryCommit signing, tamper detection, wrong-key rejection
|
|
85
|
+
- EvidenceCommit signing
|
|
86
|
+
- all 6 CLI commands
|
|
87
|
+
- checkpoint emission + rollback detection
|
|
88
|
+
- identity_mismatch detection
|
|
89
|
+
- export/import roundtrip preservation
|
|
90
|
+
- tampered manifest rejection
|
|
91
|
+
|
|
92
|
+
## license
|
|
93
|
+
|
|
94
|
+
MIT.
|
|
95
|
+
|
|
96
|
+
## related repositories
|
|
97
|
+
|
|
98
|
+
- The companion project `memex` (Python/ChromaDB memory system) is a separate layer that handles retrieval, MCP, and graph memory. `alethech` is the cryptographic protocol layer that lives on top of `memex` to make its memory verifiable. The two will eventually converge via a write-hook integration.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""JCS (JSON Canonicalization Scheme) — RFC 8785.
|
|
2
|
+
|
|
3
|
+
Serializes JSON to a canonical byte string suitable for hashing and signing.
|
|
4
|
+
|
|
5
|
+
Implementation notes:
|
|
6
|
+
- Object keys sorted by UTF-16 code unit (RFC 8785 §3.2.3).
|
|
7
|
+
- Strings escaped per RFC 8259 (no escaped non-ASCII — UTF-8 direct).
|
|
8
|
+
- Numbers: integer if no fractional/exponent, else minimal float repr.
|
|
9
|
+
- No whitespace, no trailing newline.
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import math
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
# Characters that MUST be escaped in JCS (RFC 8259 §7)
|
|
17
|
+
_ESCAPE_MAP = {
|
|
18
|
+
'"': '\\"',
|
|
19
|
+
"\\": "\\\\",
|
|
20
|
+
"\b": "\\b",
|
|
21
|
+
"\f": "\\f",
|
|
22
|
+
"\n": "\\n",
|
|
23
|
+
"\r": "\\r",
|
|
24
|
+
"\t": "\\t",
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _escape_string(s: str) -> str:
|
|
29
|
+
"""Escape a string per RFC 8259. Non-ASCII chars are emitted as UTF-8."""
|
|
30
|
+
out = ['"']
|
|
31
|
+
for ch in s:
|
|
32
|
+
if ch in _ESCAPE_MAP:
|
|
33
|
+
out.append(_ESCAPE_MAP[ch])
|
|
34
|
+
elif ord(ch) < 0x20:
|
|
35
|
+
out.append("\\u%04x" % ord(ch))
|
|
36
|
+
else:
|
|
37
|
+
out.append(ch)
|
|
38
|
+
out.append('"')
|
|
39
|
+
return "".join(out)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _serialize_number(n: float | int) -> str:
|
|
43
|
+
"""Serialize a number per RFC 8785 §3.2.2.3."""
|
|
44
|
+
if isinstance(n, bool):
|
|
45
|
+
# bool is a subclass of int — handle before number conversion
|
|
46
|
+
raise TypeError("booleans are not valid JCS values at top level")
|
|
47
|
+
|
|
48
|
+
if isinstance(n, int):
|
|
49
|
+
return str(n)
|
|
50
|
+
|
|
51
|
+
# float
|
|
52
|
+
if n != n: # NaN
|
|
53
|
+
raise ValueError("NaN not representable in JCS")
|
|
54
|
+
if n == math.inf:
|
|
55
|
+
raise ValueError("Infinity not representable in JCS")
|
|
56
|
+
if n == -math.inf:
|
|
57
|
+
raise ValueError("-Infinity not representable in JCS")
|
|
58
|
+
|
|
59
|
+
if n == 0.0:
|
|
60
|
+
# Preserve sign of zero per RFC 8785
|
|
61
|
+
return "-0" if math.copysign(1.0, n) < 0 else "0"
|
|
62
|
+
|
|
63
|
+
# Integer-valued float (e.g. 3.0)
|
|
64
|
+
if n == int(n) and abs(n) < 1e21:
|
|
65
|
+
return str(int(n))
|
|
66
|
+
|
|
67
|
+
# Use repr for shortest round-trippable representation, then strip
|
|
68
|
+
# any trailing exponent that Python adds unnecessarily.
|
|
69
|
+
s = repr(n)
|
|
70
|
+
# Python repr is fine for our purposes — it produces minimal round-trip
|
|
71
|
+
return s
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _serialize_value(v: Any) -> str:
|
|
75
|
+
if v is None:
|
|
76
|
+
return "null"
|
|
77
|
+
if v is True:
|
|
78
|
+
return "true"
|
|
79
|
+
if v is False:
|
|
80
|
+
return "false"
|
|
81
|
+
if isinstance(v, (int, float)):
|
|
82
|
+
return _serialize_number(v)
|
|
83
|
+
if isinstance(v, str):
|
|
84
|
+
return _escape_string(v)
|
|
85
|
+
if isinstance(v, list):
|
|
86
|
+
return "[" + ",".join(_serialize_value(x) for x in v) + "]"
|
|
87
|
+
if isinstance(v, dict):
|
|
88
|
+
# Sort keys by UTF-16 code unit (RFC 8785 §3.2.3)
|
|
89
|
+
items = sorted(v.items(), key=lambda kv: kv[0].encode("utf-16-be"))
|
|
90
|
+
parts = []
|
|
91
|
+
for k, val in items:
|
|
92
|
+
if not isinstance(k, str):
|
|
93
|
+
raise TypeError(f"non-string object key: {k!r}")
|
|
94
|
+
parts.append(_escape_string(k) + ":" + _serialize_value(val))
|
|
95
|
+
return "{" + ",".join(parts) + "}"
|
|
96
|
+
raise TypeError(f"unserializable type: {type(v).__name__}")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def canonical_json(value: Any) -> str:
|
|
100
|
+
"""Return the JCS canonical string for the value."""
|
|
101
|
+
return _serialize_value(value)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def canonical_json_bytes(value: Any) -> bytes:
|
|
105
|
+
"""Return the JCS canonical bytes for the value (UTF-8 encoded)."""
|
|
106
|
+
return canonical_json(value).encode("utf-8")
|