**Motivations:** - Export Signet and mining wallet backups to git with only 2 versions kept - Document and add backup/restore scripts for signet and mining wallet **Correctifs:** - Backup-to-git uses SSH URL for passwordless cron; copy timestamped files only; prune to 2 versions; remove *-latest from backup repo **Evolutions:** - data/backup-to-git-cron.sh: daily export to git.4nkweb.com/4nk/backup - save-signet-datadir-backup.sh, restore-signet-from-backup.sh, export-mining-wallet.sh, import-mining-wallet.sh - features/backup-to-git-daily-cron.md, docs/MAINTENANCE.md backup section - .gitignore: data/backup-to-git.log **Pages affectées:** - .gitignore, data/backup-to-git-cron.sh, docs/MAINTENANCE.md, features/backup-to-git-daily-cron.md - save-signet-datadir-backup.sh, restore-signet-from-backup.sh, export-mining-wallet.sh, import-mining-wallet.sh - Plus autres fichiers modifiés ou non suivis déjà présents dans le working tree
61 lines
3.9 KiB
Markdown
61 lines
3.9 KiB
Markdown
# UserWallet — Dérivation de clés et clés multiples par pair
|
||
|
||
**Author:** Équipe 4NK
|
||
**Date:** 2026-02-02
|
||
**Version:** 1.0
|
||
|
||
## Objectif
|
||
|
||
Permettre à un pair (identité locale ou appareil distant) d’avoir **plusieurs clés publiques** et de **dériver** de nouvelles paires de clés de façon déterministe à partir d’une clé privée. Vérifier rapidement si une clé publique donnée « appartient » à une clé privée (clé principale ou l’une des clés dérivées).
|
||
|
||
## Modèle de données
|
||
|
||
### PairConfig
|
||
|
||
- **`publicKey?: string`** — Clé publique principale (hex 66 caractères). Utilisée pour ECDH, pairing, etc.
|
||
- **`publicKeys?: string[]`** — Liste optionnelle de clés publiques supplémentaires. Un pair « possède » toute clé dans `{ publicKey } ∪ publicKeys`.
|
||
|
||
Un pair peut donc avoir un nombre important de clés publiques différentes (principale + dérivées ou ajoutées).
|
||
|
||
## Dérivation déterministe (crypto)
|
||
|
||
Une seule clé privée permet d’obtenir plusieurs paires (clé privée enfant, clé publique enfant) sans stocker plusieurs secrets. La dérivation est **déterministe** : même index ⇒ même paire.
|
||
|
||
### Algorithme
|
||
|
||
- **Entrée** : clé privée parente (64 hex), index ≥ 0.
|
||
- **Procédé** : HMAC-SHA256(clé_privée_parente, `"userwallet-derive-v1-"` + index) → 32 octets ; réduction modulo (ordre de la courbe secp256k1 − 1) + 1 pour obtenir un scalaire valide ; clé publique = multiplication du point de base par ce scalaire (format compressé).
|
||
- **Sortie** : paire (clé privée enfant, clé publique enfant).
|
||
|
||
Courbe : secp256k1 (même que Bitcoin). La clé principale (index « aucun ») est la clé publique dérivée directement de la clé privée de l’identité.
|
||
|
||
### API (userwallet)
|
||
|
||
| Fonction | Rôle |
|
||
|----------|------|
|
||
| `deriveChildKeyPair(parentPrivateKeyHex, index)` | Retourne la paire (privée, publique) pour l’index donné. |
|
||
| `getDerivedPublicKeys(parentPrivateKeyHex, count)` | Retourne [clé principale, dérivée(0), …, dérivée(count−1)]. Longueur = 1 + count. |
|
||
| `publicKeyBelongsToIdentity(identityPrivateKeyHex, publicKeyHex, maxDerived?)` | Vrai si la clé publique est la clé principale ou l’une des dérivées d’indice 0..maxDerived−1. Par défaut maxDerived = 0 (seule la clé principale est testée). |
|
||
|
||
**Performance** : la vérification « cette clé appartient-elle à mon identité ? » est en O(1) pour la clé principale (une dérivation + comparaison). Pour les dérivées, au plus `maxDerived` dérivations + comparaisons ; en pratique on borne `maxDerived` pour rester rapide.
|
||
|
||
## Pairing (pairs et multi-clés)
|
||
|
||
| Fonction | Rôle |
|
||
|----------|------|
|
||
| `getPairPublicKeys(pair, identityPrivateKeyHex?, derivedCount?)` | Liste toutes les clés publiques du pair. Pour le pair local + clé privée fournie : clé principale + dérivées 0..derivedCount−1. Pour un pair distant : `publicKey` + `publicKeys`. |
|
||
| `pairContainsPublicKey(pair, publicKeyHex, identityPrivateKeyHex?, maxDerived?)` | Vrai si le pair possède cette clé (locale : dérivation bornée ; distant : test d’appartenance à `publicKey` / `publicKeys`). |
|
||
| `addPairPublicKey(pairUuid, publicKeyHex)` | Ajoute une clé à `publicKeys` du pair (sans doublon avec `publicKey`). |
|
||
|
||
## Fichiers concernés
|
||
|
||
- `userwallet/src/utils/crypto.ts` : `deriveChildKeyPair`, `getDerivedPublicKeys`, `publicKeyBelongsToIdentity`
|
||
- `userwallet/src/utils/pairing.ts` : `getPairPublicKeys`, `pairContainsPublicKey`, `addPairPublicKey`
|
||
- `userwallet/src/types/identity.ts` : `PairConfig.publicKeys`
|
||
|
||
## Usage typique
|
||
|
||
- **Obtenir N clés dérivées** : `getDerivedPublicKeys(identity.privateKey, N)`.
|
||
- **Vérifier qu’une clé appartient à l’identité** (avec au plus 100 dérivées) : `publicKeyBelongsToIdentity(identity.privateKey, somePubKey, 100)`.
|
||
- **Vérifier qu’un pair possède une clé** : `pairContainsPublicKey(pair, somePubKey, identity?.privateKey, 100)`.
|