This commit is contained in:
2026-06-08 09:24:48 -04:00
parent 2a5d6788c1
commit 036418b4fa

View File

@@ -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.