diff options
Diffstat (limited to 'CHECKLIST.md')
| -rw-r--r-- | CHECKLIST.md | 98 |
1 files changed, 64 insertions, 34 deletions
diff --git a/CHECKLIST.md b/CHECKLIST.md index 3b50c2a..02c8a4c 100644 --- a/CHECKLIST.md +++ b/CHECKLIST.md | |||
| @@ -70,40 +70,69 @@ | |||
| 70 | - [x] DNS query logging for unauthenticated clients | 70 | - [x] DNS query logging for unauthenticated clients |
| 71 | - [x] Verified working with GrapheneOS phone (commit `236b61d`) | 71 | - [x] Verified working with GrapheneOS phone (commit `236b61d`) |
| 72 | 72 | ||
| 73 | ## Phase 3: On-Device Wallet + ESP32-to-ESP32 Payments — IN PROGRESS | 73 | ## Phase 3: On-Device Wallet + Nostr Identity + Wifistr — IN PROGRESS |
| 74 | ### Wallet Module (wallet.c/h) | 74 | ### nucula Wallet Integration |
| 75 | - [x] `hash_to_curve()` — SHA256 try-and-increment with Cashu domain separator | 75 | - [x] Add nucula as git submodule (`nucula_src/`) |
| 76 | - [x] `point_add()`, `scalar_mul()` — mbedTLS secp256k1 primitives | 76 | - [x] Create `components/secp256k1/` (symlink to nucula's libsecp256k1) |
| 77 | - [x] `random_scalar()` — ESP32 hardware RNG mod curve order | 77 | - [x] Create `components/nucula_lib/` (C++ bridge + C API) |
| 78 | - [x] Proof storage: `wallet_add_proofs()`, `wallet_remove_proof()`, `wallet_clear()` | 78 | - [x] C bridge: `nucula_wallet.h` (init, receive, send, swap_all, balance, proofs_json) |
| 79 | - [x] Keyset fetching: `wallet_fetch_keysets()` — GET /v1/keys from mint | 79 | - [x] All wallet operations tested on Board A: pay, swap, send, persistence |
| 80 | - [x] Full swap: `wallet_swap_proofs()` — generates blinded messages, POST /v1/swap, unblinds signatures | 80 | |
| 81 | - [x] Token creation: `wallet_create_token()` — encode proofs as `cashuA` token | 81 | ### Nostr Identity Derivation (identity.c/h) |
| 82 | - [x] Wallet API endpoints: `GET /wallet`, `POST /wallet/swap`, `POST /wallet/send` | 82 | - [x] Create `identity.h` — API: `identity_init(nsec_hex)`, derived value accessors |
| 83 | - [x] Payment flow integration: received proofs added to wallet after session creation | 83 | - [x] Create `identity.c` — HMAC-SHA512 derivation via mbedtls, npub via secp256k1 |
| 84 | - [x] mbedTLS 3.x compatibility (no direct point field access, no point_negate) | 84 | - [x] Derive STA MAC: `tollgate_derive(nsec, "sta-mac", 0)` → 6 bytes, locally administered |
| 85 | - [x] Unblinding: `C = C_ + (order - r) * G` approach | 85 | - [x] Derive AP MAC: `tollgate_derive(nsec, "ap-mac", 0)` → 6 bytes, locally administered |
| 86 | - [x] Clean build (0 warnings, 0 errors) | 86 | - [x] Derive SSID: `"TollGate-" + hex(AP_MAC[3:6])` |
| 87 | 87 | - [x] Derive AP IP: hash-based from AP MAC bytes | |
| 88 | ### Wallet Persistence (wallet_persist.c/h) | 88 | - [x] Compute npub: secp256k1 x-only pubkey from nsec |
| 89 | - [ ] Implement `wallet_persist_save()` — serialize wallet to `/spiffs/wallet.json` | 89 | - [x] Set MACs via `esp_wifi_set_mac()` in boot sequence |
| 90 | - [ ] Implement `wallet_persist_load()` — deserialize wallet from `/spiffs/wallet.json` on boot | 90 | |
| 91 | - [ ] Add `persist_threshold_sats` to config.json and config struct | 91 | ### Nostr Event Signing (nostr_event.c/h) |
| 92 | - [ ] Threshold logic: only persist when `balance >= persist_threshold_sats` | 92 | - [x] Create `nostr_event.h` — NIP-01 event struct + sign/serialize API |
| 93 | - [ ] Wire `wallet_persist_save()` into wallet mutations (add_proofs, swap, create_token) | 93 | - [x] Create `nostr_event.c` — canonical JSON, SHA-256 ID, Schnorr signature |
| 94 | - [ ] Wire `wallet_persist_load()` into `wallet_init()` | 94 | - [x] Uses `secp256k1_schnorrsig_sign32()` for BIP-340 signatures |
| 95 | - [ ] Build and verify clean compile | 95 | |
| 96 | ### Geohash Encoding (geohash.c/h) | ||
| 97 | - [x] Create `geohash.h` — `geohash_encode(lat, lon, precision, out)` | ||
| 98 | - [x] Create `geohash.c` — standard base-32 geohash encoding | ||
| 99 | |||
| 100 | ### Wifistr Service Discovery (wifistr.c/h) | ||
| 101 | - [x] Create `wifistr.h` — `wifistr_publish()` API | ||
| 102 | - [x] Create `wifistr.c` — kind 38787 event builder + WebSocket relay publish | ||
| 103 | - [x] Build event with tags: d, ssid, h, security, g, c | ||
| 104 | - [x] WebSocket client: raw TCP + TLS (esp_tls.h) + HTTP Upgrade | ||
| 105 | - [x] Publish on boot + periodic timer (6h default) | ||
| 106 | |||
| 107 | ### Config Changes (config.c/h) | ||
| 108 | - [x] Add to struct: nsec, npub, nostr_geohash, nostr_relays, nostr_publish_interval_s, sta_mac, ap_mac | ||
| 109 | - [x] Remove from JSON parsing: ap_ssid, ap_ip (now derived from nsec) | ||
| 110 | - [x] Keep: ap_password, ap_channel, ap_max_conn (hardcoded defaults) | ||
| 111 | - [x] Update default config.json template with nsec and Nostr fields | ||
| 112 | |||
| 113 | ### Boot Sequence Changes (tollgate_main.c) | ||
| 114 | - [x] Call `identity_init(nsec)` after config load, before WiFi init | ||
| 115 | - [x] Set STA/AP MAC via `esp_wifi_set_mac()` after `esp_wifi_init()`, before `esp_wifi_start()` | ||
| 116 | - [x] Remove old `tollgate_config_derive_unique()` call | ||
| 117 | - [x] Use derived SSID/IP in AP configuration | ||
| 118 | - [x] Start wifistr publish task after services start | ||
| 119 | |||
| 120 | ### Build System | ||
| 121 | - [x] Add identity.c, nostr_event.c, geohash.c, wifistr.c to CMakeLists.txt SRCS | ||
| 122 | - [x] Add `secp256k1` to REQUIRES (for identity.c and nostr_event.c) | ||
| 123 | - [x] Clean build (0 errors, 0 warnings) | ||
| 96 | 124 | ||
| 97 | ### Hardware Testing | 125 | ### Hardware Testing |
| 98 | - [ ] Flash Board A, verify wallet boot (keyset fetch succeeds) | 126 | - [x] Flash Board A, verify wallet boot (keyset fetch succeeds) |
| 99 | - [ ] Pay Board A with Cashu token, verify proofs stored (GET /wallet) | 127 | - [x] Pay Board A with Cashu token, verify proofs stored (GET /wallet) |
| 100 | - [ ] Test POST /wallet/swap on Board A | 128 | - [x] Test POST /wallet/swap on Board A |
| 101 | - [ ] Test POST /wallet/send on Board A, verify token is valid | 129 | - [x] Test POST /wallet/send on Board A, verify token is valid |
| 102 | - [ ] Verify persistence survives reboot on Board A | 130 | - [x] Flash Board A with new identity derivation, verify derived SSID/MAC/IP |
| 103 | - [ ] Flash Board B with TollGate firmware | 131 | - [x] Verify captive portal works with new SSID/IP |
| 104 | - [ ] Load Board B with balance (pay it a token) | 132 | - [x] Verify payment flow still works with identity-derived config |
| 105 | - [ ] Board B creates send token via POST /wallet/send | 133 | - [x] Verify wifistr event published to relay (damus + nos.lol) |
| 106 | - [ ] Cross-board payment: Board B token → Board A (laptop relay) | 134 | - [ ] Flash Board B with new firmware (different nsec) |
| 135 | - [ ] Cross-board payment: Board B token → Board A | ||
| 107 | - [ ] Verify both boards show correct balances after cross-board payment | 136 | - [ ] Verify both boards show correct balances after cross-board payment |
| 108 | 137 | ||
| 109 | ### Tests 25-27 (deferred from Phase 2, need Board B) | 138 | ### Tests 25-27 (deferred from Phase 2, need Board B) |
| @@ -131,8 +160,9 @@ | |||
| 131 | 160 | ||
| 132 | ## Reminders | 161 | ## Reminders |
| 133 | - Do NOT ask for instructions — proceed independently, skip blocked items, work on unblocked ones | 162 | - Do NOT ask for instructions — proceed independently, skip blocked items, work on unblocked ones |
| 134 | - Board A: `/dev/ttyACM0`, MAC `94:a9:90:2e:37:7c`, SSID `TollGate-377C`, AP IP `10.55.85.1` | 163 | - Board A: `/dev/ttyACM0`, factory MAC `94:a9:90:2e:37:7c` |
| 135 | - Board B: `/dev/ttyACM1`, MAC `fc:01:2c:c5:50:50` | 164 | - Board B: `/dev/ttyACM1`, factory MAC `fc:01:2c:c5:50:50` |
| 165 | - Identity is now derived from nsec in config.json (SSID, IP, MAC all deterministic) | ||
| 136 | - testnut.cashu.space auto-pays invoices: `cashu -h https://testnut.cashu.space invoice <amount>` | 166 | - testnut.cashu.space auto-pays invoices: `cashu -h https://testnut.cashu.space invoice <amount>` |
| 137 | - Token generation: `cashu -h https://testnut.cashu.space send --legacy <amount> 2>&1 | grep '^cashuA' | head -1` | 167 | - Token generation: `cashu -h https://testnut.cashu.space send --legacy <amount> 2>&1 | grep '^cashuA' | head -1` |
| 138 | - sudo password: `c03rad0r123` | 168 | - sudo password: `c03rad0r123` |