agmem 0.1.3__py3-none-any.whl → 0.1.5__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.
- {agmem-0.1.3.dist-info → agmem-0.1.5.dist-info}/METADATA +24 -18
- {agmem-0.1.3.dist-info → agmem-0.1.5.dist-info}/RECORD +25 -24
- memvcs/commands/daemon.py +21 -3
- memvcs/commands/distill.py +10 -2
- memvcs/commands/federated.py +7 -1
- memvcs/commands/garden.py +10 -2
- memvcs/commands/gc.py +18 -1
- memvcs/commands/prove.py +4 -2
- memvcs/commands/timeline.py +28 -0
- memvcs/commands/when.py +28 -0
- memvcs/core/compression_pipeline.py +165 -0
- memvcs/core/crypto_verify.py +12 -1
- memvcs/core/distiller.py +70 -4
- memvcs/core/federated.py +80 -9
- memvcs/core/gardener.py +80 -5
- memvcs/core/ipfs_remote.py +168 -8
- memvcs/core/knowledge_graph.py +79 -6
- memvcs/core/objects.py +33 -21
- memvcs/core/pack.py +201 -1
- memvcs/core/remote.py +200 -3
- memvcs/core/zk_proofs.py +145 -11
- {agmem-0.1.3.dist-info → agmem-0.1.5.dist-info}/WHEEL +0 -0
- {agmem-0.1.3.dist-info → agmem-0.1.5.dist-info}/entry_points.txt +0 -0
- {agmem-0.1.3.dist-info → agmem-0.1.5.dist-info}/licenses/LICENSE +0 -0
- {agmem-0.1.3.dist-info → agmem-0.1.5.dist-info}/top_level.txt +0 -0
memvcs/core/zk_proofs.py
CHANGED
|
@@ -1,26 +1,160 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Zero-knowledge proof system for agmem
|
|
2
|
+
Zero-knowledge proof system for agmem.
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
Hash/signature-based proofs: keyword containment (Merkle set membership),
|
|
5
|
+
memory freshness (signed timestamp). Full zk-SNARK backend can be added later.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
import base64
|
|
9
|
+
import hashlib
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
8
12
|
from pathlib import Path
|
|
9
|
-
from typing import Optional, Tuple
|
|
13
|
+
from typing import Optional, List, Tuple, Any, Dict
|
|
14
|
+
|
|
15
|
+
from .crypto_verify import (
|
|
16
|
+
build_merkle_tree,
|
|
17
|
+
merkle_proof,
|
|
18
|
+
verify_merkle_proof,
|
|
19
|
+
load_public_key,
|
|
20
|
+
load_private_key_from_env,
|
|
21
|
+
sign_merkle_root,
|
|
22
|
+
verify_signature,
|
|
23
|
+
ED25519_AVAILABLE,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _word_hashes(content: str) -> List[str]:
|
|
28
|
+
"""Extract words and return sorted list of SHA-256 hashes (hex)."""
|
|
29
|
+
words = set()
|
|
30
|
+
for word in content.split():
|
|
31
|
+
w = word.strip().lower()
|
|
32
|
+
if len(w) >= 1:
|
|
33
|
+
words.add(w)
|
|
34
|
+
return sorted(hashlib.sha256(w.encode()).hexdigest() for w in words)
|
|
10
35
|
|
|
11
36
|
|
|
12
37
|
def prove_keyword_containment(memory_path: Path, keyword: str, output_proof_path: Path) -> bool:
|
|
13
|
-
"""
|
|
14
|
-
|
|
38
|
+
"""
|
|
39
|
+
Prove memory file contains keyword without revealing content.
|
|
40
|
+
Proof: Merkle set membership of H(keyword) over word hashes in file.
|
|
41
|
+
"""
|
|
42
|
+
if not memory_path.exists() or not memory_path.is_file():
|
|
43
|
+
return False
|
|
44
|
+
try:
|
|
45
|
+
content = memory_path.read_text(encoding="utf-8", errors="replace")
|
|
46
|
+
except Exception:
|
|
47
|
+
return False
|
|
48
|
+
word_hashes_list = _word_hashes(content)
|
|
49
|
+
keyword_hash = hashlib.sha256(keyword.strip().lower().encode()).hexdigest()
|
|
50
|
+
if keyword_hash not in word_hashes_list:
|
|
51
|
+
return False
|
|
52
|
+
root = build_merkle_tree(word_hashes_list)
|
|
53
|
+
proof_path_list = merkle_proof(word_hashes_list, keyword_hash)
|
|
54
|
+
if proof_path_list is None:
|
|
55
|
+
return False
|
|
56
|
+
proof_data = {
|
|
57
|
+
"statement_type": "keyword",
|
|
58
|
+
"keyword_hash": keyword_hash,
|
|
59
|
+
"root": root,
|
|
60
|
+
"path": proof_path_list,
|
|
61
|
+
}
|
|
62
|
+
output_proof_path.parent.mkdir(parents=True, exist_ok=True)
|
|
63
|
+
output_proof_path.write_text(json.dumps(proof_data, indent=2))
|
|
64
|
+
return True
|
|
15
65
|
|
|
16
66
|
|
|
17
67
|
def prove_memory_freshness(
|
|
18
|
-
memory_path: Path, after_timestamp: str, output_proof_path: Path
|
|
68
|
+
memory_path: Path, after_timestamp: str, output_proof_path: Path, mem_dir: Optional[Path] = None
|
|
19
69
|
) -> bool:
|
|
20
|
-
"""
|
|
21
|
-
|
|
70
|
+
"""
|
|
71
|
+
Prove memory was updated after date without revealing content.
|
|
72
|
+
Proof: signed file mtime (or current time) and optional public key.
|
|
73
|
+
"""
|
|
74
|
+
if not memory_path.exists() or not memory_path.is_file():
|
|
75
|
+
return False
|
|
76
|
+
if not ED25519_AVAILABLE:
|
|
77
|
+
return False
|
|
78
|
+
try:
|
|
79
|
+
stat = memory_path.stat()
|
|
80
|
+
ts = stat.st_mtime
|
|
81
|
+
from datetime import datetime, timezone
|
|
82
|
+
|
|
83
|
+
iso_ts = datetime.fromtimestamp(ts, tz=timezone.utc).isoformat()
|
|
84
|
+
except Exception:
|
|
85
|
+
return False
|
|
86
|
+
private_pem = load_private_key_from_env() if mem_dir is not None else None
|
|
87
|
+
if private_pem is None:
|
|
88
|
+
return False
|
|
89
|
+
try:
|
|
90
|
+
sig_hex = sign_merkle_root(iso_ts, private_pem)
|
|
91
|
+
except Exception:
|
|
92
|
+
return False
|
|
93
|
+
proof_data = {"statement_type": "freshness", "timestamp": iso_ts, "signature": sig_hex}
|
|
94
|
+
if mem_dir is not None:
|
|
95
|
+
pub_pem = load_public_key(mem_dir)
|
|
96
|
+
if pub_pem is not None:
|
|
97
|
+
proof_data["public_key_pem_b64"] = base64.b64encode(pub_pem).decode()
|
|
98
|
+
output_proof_path.parent.mkdir(parents=True, exist_ok=True)
|
|
99
|
+
output_proof_path.write_text(json.dumps(proof_data, indent=2))
|
|
100
|
+
return True
|
|
101
|
+
|
|
22
102
|
|
|
103
|
+
def verify_proof(proof_path: Path, statement_type: str, **kwargs: Any) -> bool:
|
|
104
|
+
"""
|
|
105
|
+
Verify a proof. statement_type in ("keyword", "freshness").
|
|
106
|
+
For keyword: pass keyword=... (the keyword string).
|
|
107
|
+
For freshness: pass after_timestamp=... (ISO date string). Optional mem_dir=... for public key.
|
|
108
|
+
"""
|
|
109
|
+
if not proof_path.exists() or not proof_path.is_file():
|
|
110
|
+
return False
|
|
111
|
+
try:
|
|
112
|
+
data = json.loads(proof_path.read_text())
|
|
113
|
+
except Exception:
|
|
114
|
+
return False
|
|
115
|
+
if data.get("statement_type") != statement_type:
|
|
116
|
+
return False
|
|
117
|
+
if statement_type == "keyword":
|
|
118
|
+
keyword = kwargs.get("keyword")
|
|
119
|
+
if keyword is None:
|
|
120
|
+
return False
|
|
121
|
+
keyword_hash = hashlib.sha256(keyword.strip().lower().encode()).hexdigest()
|
|
122
|
+
if data.get("keyword_hash") != keyword_hash:
|
|
123
|
+
return False
|
|
124
|
+
root = data.get("root")
|
|
125
|
+
path_list = data.get("path")
|
|
126
|
+
if not root or path_list is None:
|
|
127
|
+
return False
|
|
128
|
+
return verify_merkle_proof(keyword_hash, path_list, root)
|
|
129
|
+
if statement_type == "freshness":
|
|
130
|
+
after_ts = kwargs.get("after_timestamp")
|
|
131
|
+
if after_ts is None:
|
|
132
|
+
return False
|
|
133
|
+
ts_str = data.get("timestamp")
|
|
134
|
+
sig_hex = data.get("signature")
|
|
135
|
+
if not ts_str or not sig_hex:
|
|
136
|
+
return False
|
|
137
|
+
pub_pem_b64 = data.get("public_key_pem_b64")
|
|
138
|
+
if pub_pem_b64:
|
|
139
|
+
try:
|
|
140
|
+
pub_pem = base64.b64decode(pub_pem_b64)
|
|
141
|
+
except Exception:
|
|
142
|
+
return False
|
|
143
|
+
else:
|
|
144
|
+
mem_dir = kwargs.get("mem_dir")
|
|
145
|
+
if mem_dir is None:
|
|
146
|
+
return False
|
|
147
|
+
pub_pem = load_public_key(Path(mem_dir))
|
|
148
|
+
if pub_pem is None:
|
|
149
|
+
return False
|
|
150
|
+
if not verify_signature(ts_str, sig_hex, pub_pem):
|
|
151
|
+
return False
|
|
152
|
+
try:
|
|
153
|
+
from datetime import datetime
|
|
23
154
|
|
|
24
|
-
|
|
25
|
-
|
|
155
|
+
after_dt = datetime.fromisoformat(after_ts.replace("Z", "+00:00"))
|
|
156
|
+
ts_dt = datetime.fromisoformat(ts_str.replace("Z", "+00:00"))
|
|
157
|
+
return ts_dt >= after_dt
|
|
158
|
+
except Exception:
|
|
159
|
+
return False
|
|
26
160
|
return False
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|