From 036418b4fa4f41a77446a3b647b962efdf3c4789 Mon Sep 17 00:00:00 2001 From: TheRON Date: Mon, 8 Jun 2026 09:24:48 -0400 Subject: [PATCH] Updated --- G1WALLET-SPEC.md | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/G1WALLET-SPEC.md b/G1WALLET-SPEC.md index 70cd6ca..4b5d933 100644 --- a/G1WALLET-SPEC.md +++ b/G1WALLET-SPEC.md @@ -1,7 +1,7 @@ # G1WALLET — Self-Sovereign Ğ1 Wallet Specification **Project:** kane-diagnostics -**Version:** 1.0 +**Version:** 2.0 **Prerequisite reading:** README.md, ADDON-SKELETON-SPEC.md, ASSOCIATION-CHANNEL-MODEL.md, CRY01-SPEC.md, FOR-PARTICIPANTS-AND-PROFESSIONALS.md --- @@ -27,15 +27,15 @@ This principle is non-negotiable. Any architecture that requires the platform to ## Self-Custody Model -The keypair derivation algorithm is scrypt + Ed25519 — the same algorithm used by Cesium and Ğecko. It is a documented open standard. The same credentials always produce the same keypair, on any device, in any browser. +The keypair derivation algorithm is BIP39 mnemonic + Ed25519 — the standard used by Duniter v2 and Ğecko. The same mnemonic always produces the same keypair, on any device, in any browser. **What this means:** -- The private key is derived in the browser from the participant's pseudo and password +- The private key is derived in the browser from the participant's 12-word BIP39 mnemonic phrase - The private key exists only in browser memory for the duration of the wallet session - On page close, the private key is gone - The server never sees the private key — not in a POST, not in a cookie, not in a log - The public key is the only thing the server ever knows about -- If the participant loses their credentials, the key is unrecoverable — no reset, no recovery +- If the participant loses their mnemonic phrase, the key is unrecoverable — no reset, no recovery **What the Civic Infrastructure stores:** - The participant's Ğ1 public key — stored in their Hubzilla channel settings after first wallet unlock @@ -55,16 +55,18 @@ The only operator-specific wallet function is Ğ1 certification signing — the ### Client-Side (JavaScript) -All key operations happen in the browser using the WebCrypto API and a vendored scrypt implementation. +All key operations happen in the browser using the WebCrypto API and a vendored BIP39 implementation. **Key derivation:** ``` -pseudo + password → scrypt(N=4096, r=16, p=1) → 32-byte seed → Ed25519 keypair +12-word BIP39 mnemonic → PBKDF2(SHA-512, salt="mnemonic", iter=2048) → 64-byte seed → Ed25519 keypair ``` -The scrypt parameters match the Duniter/Cesium standard exactly. A keypair derived in `g1wallet` is identical to the same keypair derived in Cesium or Ğecko from the same credentials. +This is the Duniter v2 / Ğecko standard. A keypair derived in `g1wallet` from a given mnemonic is identical to the keypair derived in Ğecko from the same mnemonic. -**Vendored library:** `vendor/scrypt-js-3.0.1.min.js` — pinned version, included in the repo, no CDN dependency. +**Note on Duniter v1 / Cesium1 compatibility:** Cesium1 used `scrypt(pseudo, password)` — that derivation is obsolete. Duniter v1 is shut down. `g1wallet` targets Duniter v2 exclusively. + +**Vendored library:** `vendor/bip39-3.1.0.min.js` — pinned version, included in the repo, no CDN dependency. **Signing:** The browser's native `SubtleCrypto.sign()` with the Ed25519 algorithm signs Duniter transaction documents. The signed bytes are base64-encoded and sent to the orchestrator for broadcast. The private key object is marked non-extractable in the WebCrypto API — it cannot be read back out of memory by JavaScript. @@ -87,7 +89,7 @@ The orchestrator: ## Wallet Session -A wallet session begins when the participant successfully derives their keypair in the browser. The session is held in browser memory only — not in a PHP session variable, not in localStorage, not in a cookie. +A wallet session begins when the participant successfully derives their keypair in the browser. The session is held in browser memory only — cot in a PHP session variable, not in localStorage, not in a cookie. The wallet session provides: - The participant's Ğ1 public key (safe to expose — it is public) @@ -105,7 +107,7 @@ When a participant navigates away from the Hubzilla page, the session ends and t LOCKED → UNLOCKED → SIGNING ``` -**LOCKED** — no active session. The wallet unlock form is displayed. The participant enters their pseudo and password. +**LOCKED** — no active session. The wallet unlock form is displayed. The participant enters their 12-word BIP39 mnemonic phrase. **UNLOCKED** — keypair is in browser memory. Public key is displayed. Balance is shown. Signing operations are available. @@ -202,7 +204,7 @@ hubzilla/addon/g1wallet/ js/ g1wallet.js — key derivation, signing, session management, event API vendor/ - scrypt-js-3.0.1.min.js — vendored scrypt implementation, pinned version + bip39-3.1.0.min.js — vendored BIP39 implementation, pinned version README.md ``` @@ -263,22 +265,22 @@ Two new endpoints added to `main.py` on the orchestrator: `g1wallet` must be built before `cry01` signal submission and `poll01` ballot submission are functional. It is a dependency of both. 1. `g1wallet.js` — key derivation, signing, session management, event API. This is the most critical file. It must be tested against the Duniter standard key derivation before any PHP is written. -2. `vendor/scrypt-js-3.0.1.min.js` — download and pin before writing `g1wallet.js` +2. `vendor/bip39-3.1.0.min.js` — download and pin before writing `g1wallet.js` 3. `g1wallet.php` — entry point, routing, access state 4. `g1wallet_renderer.php` — unlock form, unlocked interface 5. `g1wallet_spool.php` — pubkey store, broadcast relay 6. Orchestrator additions — broadcast and balance endpoints in `main.py` 7. Widget, PDL, CSS -8. Integration test: derive keypair, verify public key matches Cesium for same credentials, sign a test document, broadcast to Duniter testnet +8. Integration test: derive keypair from test mnemonic, verify public key matches Ğecko output for same mnemonic, sign a test document, broadcast to Duniter testnet --- ## What Not To Do - Do not send the private key to the server. Ever. Under any circumstance. -- Do not send the password or pseudo to the server. Ever. +- Do not send the mnemonic phrase to the server. Ever. - Do not store the private key in localStorage, sessionStorage, or any browser persistent storage. -- Do not use a CDN for the scrypt library — vendor it with a pinned version. +- Do not use a CDN for the BIP39 library — vendor it with a pinned version. - Do not implement batch signing — one document, one confirmation, one click. - Do not allow the wallet to auto-sign without explicit participant confirmation of the document being signed. - Do not exceed 500 lines in any PHP file.