Adresses à usage unique
Les stealth addresses : envoyer de l’argent à une adresse sans l’inscrire sur la blockchain
L’expéditeur choisit un r aléatoire, publie R = r·G et envoie l’argent à la clé à usage unique P = Hs(8·r·A ‖ i)·G + B. Le destinataire la retrouve en calculant la même chose via a : Hs(8·a·R ‖ i)·G + B. Il la dépense avec la clé privée x = Hs(8·a·R ‖ i) + b.
L’objectif
Nous voulons :
- que ni l’adresse du destinataire, ni rien qui se répète d’un paiement à l’autre vers une même personne n’apparaisse sur la blockchain ;
- que le destinataire retrouve lui-même ses sorties, sans communiquer avec l’expéditeur ;
- que seul le destinataire puisse dépenser la sortie.
La solution est un échange de clés Diffie–Hellman intégré à chaque transaction.
Pas à pas
1. L’expéditeur choisit un r aléatoire
Un nouveau r aléatoire (clé privée de transaction) pour chaque transaction. Sa version publique R = r·G (clé publique de transaction) est inscrite dans le champ tx_extra de la transaction.
2. Le secret partagé
L’expéditeur calcule 8·r·A (A est la clé publique de visualisation tirée de l’adresse). Plus tard, le destinataire calcule 8·a·R. C’est le même point, car a·R = a·r·G = r·a·G = r·A. Dans le code de Monero, on l’appelle la key derivation (dérivation de clé).
Le facteur 8 (le cofacteur) « nettoie » le point de toute composante d’ordre faible : même si quelqu’un fournit un R malveillant, le résultat tombe dans le bon sous-groupe.
3. La clé à usage unique
C’est l’adresse à usage unique (clé publique de sortie). Elle ressemble à un point aléatoire : sans a ni r, il n’y a rien à quoi la comparer.
4. Le destinataire balaie
Pour chaque nouvelle transaction et chaque sortie i, le portefeuille calcule Hs(8·a·R ‖ i)·G + B et le compare à P. Correspondance — la sortie est à nous. Cela ne demande que la clé de visualisation a et la clé publique B — un portefeuille en lecture seule peut donc trouver les paiements entrants.
5. Le destinataire dépense
La clé privée de la sortie à usage unique :
Il faut pour cela la clé de dépense b. La clé x signe la dépense, et la key image est calculée à partir d’elle.
Le montant est lui aussi chiffré avec le secret partagé
Un masque pour le montant est dérivé du même secret partagé. Le montant de la sortie (8 octets) est stocké sous la forme amount ⊕ Keccak("amount" ‖ Hs(8rA ‖ i))[0..8], et le facteur d’aveuglement de l’engagement sous la forme Hs("commitment_mask" ‖ Hs(8rA ‖ i)). Le destinataire calcule la même chose et déchiffre le montant. Plus de détails dans engagements de Pedersen.
Points faibles
- Le balayage coûte cher : une multiplication de point pour chaque sortie de chaque transaction. Partiellement résolu par les view tags.
- L’attaque Janus : un expéditeur qui soupçonne que deux sous-adresses appartiennent à la même personne peut construire une sortie à partir de morceaux des deux et voir si le destinataire « remarque » le paiement. Les portefeuilles ont une protection partielle ; Carrot la ferme complètement.
- L’expéditeur connaît r et peut prouver à un tiers qu’il a payé une adresse donnée (parfois utile — une « preuve de paiement »).