mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2026-11-05 12:22:06 +00:00
TS port slice 6: Nostr event protocol layer with rust-nostr cross-fixtures
- NIP-01 event serialization/id computation, BIP-340 signing and verification via @noble/curves, SeedPass event builders (manifest 30070, chunk 30071, delta 30072 with d/e tags), and REQ/EVENT/EOSE/OK/NOTICE/ CLOSED client-relay framing. Transport-agnostic; the WebSocket adapter lands with the interface milestones. - Cross-implementation fixtures generated through the Python side's nostr_sdk (rust-nostr) with pinned created_at: TS ids match theirs byte-for-byte, their signatures verify in TS, and TS-signed events reproduce identical ids. The generator caches signatures across runs (BIP-340 aux randomness) so fixture output stays byte-deterministic and the CI drift job holds. - 143 core parity tests (Node + jsdom) + 16 CLI tests green. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
1 parent
e91d5d0be2
commit
774c992153
8 files changed
+518
-3
No files matched your search
@@ -906,6 +906,78 @@ def gen_entry_secrets() -> dict:
|
||||
}
|
||||
|
||||
|
||||
def gen_nostr_events(snapshot: dict, delta_replay: dict) -> dict:
|
||||
"""Signed Nostr events for the snapshot/chunk/delta model.
|
||||
|
||||
Event ids are deterministic (NIP-01 serialization); BIP-340 signatures
|
||||
use random aux data and are NOT. To keep the generator byte-deterministic
|
||||
we reuse the previously committed signature whenever the event id is
|
||||
unchanged — a fresh signature is only produced for new/changed events.
|
||||
"""
|
||||
import json as json_mod
|
||||
|
||||
from nostr_sdk import EventBuilder, EventId, Keys, Kind, Tag, Timestamp
|
||||
|
||||
# Sync client identity: BIP-85 app 1237, account index 0 (nostr_keys.json)
|
||||
bip85 = _bip85(MNEMONICS[PRIMARY])
|
||||
entropy = bip85.derive_entropy(index=0, entropy_bytes=32, app_no=NOSTR_KEY_APP_ID)
|
||||
keys = Keys.parse(entropy.hex())
|
||||
|
||||
existing_sigs: dict[str, str] = {}
|
||||
existing_path = FIXTURES_DIR / "nostr_events.json"
|
||||
if existing_path.exists():
|
||||
try:
|
||||
for ev in json_mod.loads(existing_path.read_text())["events"]:
|
||||
existing_sigs[ev["event"]["id"]] = ev["event"]["sig"]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def build(name: str, kind: int, content: str, tags: list) -> dict:
|
||||
builder = (
|
||||
EventBuilder(Kind(kind), content)
|
||||
.tags(tags)
|
||||
.custom_created_at(Timestamp.from_secs(FIXED_UNIX))
|
||||
)
|
||||
event = json_mod.loads(builder.sign_with_keys(keys).as_json())
|
||||
cached_sig = existing_sigs.get(event["id"])
|
||||
if cached_sig:
|
||||
event["sig"] = cached_sig
|
||||
return {"name": name, "event": event}
|
||||
|
||||
events = [
|
||||
build(
|
||||
"chunk-0",
|
||||
30071,
|
||||
snapshot["chunks_b64"][0],
|
||||
[Tag.identifier(snapshot["chunk_metas"][0]["id"])],
|
||||
),
|
||||
build(
|
||||
"manifest",
|
||||
30070,
|
||||
snapshot["manifest_json"],
|
||||
[Tag.identifier(snapshot["manifest_id"])],
|
||||
),
|
||||
build(
|
||||
"delta-1",
|
||||
30072,
|
||||
delta_replay["delta_payloads_b64"][0],
|
||||
[Tag.event(EventId.parse(snapshot["manifest_id"]))],
|
||||
),
|
||||
]
|
||||
|
||||
return {
|
||||
"description": (
|
||||
"Signed Nostr events from the Python-side nostr_sdk (rust-nostr) "
|
||||
"with pinned created_at. Ids are NIP-01-deterministic; signatures "
|
||||
"are cached across generator runs (BIP-340 aux randomness)."
|
||||
),
|
||||
"mnemonic_id": PRIMARY,
|
||||
"signer_private_key_hex": entropy.hex(),
|
||||
"signer_public_key_hex": keys.public_key().to_hex(),
|
||||
"events": events,
|
||||
}
|
||||
|
||||
|
||||
def gen_kdf_metadata() -> dict:
|
||||
return {
|
||||
"description": (
|
||||
@@ -959,6 +1031,9 @@ def main() -> None:
|
||||
files["entry_secrets.json"] = gen_entry_secrets()
|
||||
files["sync_merge.json"] = gen_sync_merge()
|
||||
files["delta_replay.json"] = gen_delta_replay()
|
||||
files["nostr_events.json"] = gen_nostr_events(
|
||||
files["nostr_snapshot.json"], files["delta_replay.json"]
|
||||
)
|
||||
|
||||
for name, data in files.items():
|
||||
data["fixture_version"] = FIXTURE_VERSION
|
||||
|
||||
Reference in new issue
Block a user