Une transaction octet par octet
L’analyse complète du hex d’une transaction RingCT : chaque champ, chaque fonction — sur des données réelles et aléatoires
Une transaction Monero, ce sont trois blocs d’octets consécutifs : le préfixe (entrées, sorties, extra), la base RingCT (frais, montants chiffrés, engagements) et la partie élagable (Bulletproofs+, CLSAG, pseudo-sorties). Ci-dessous, un outil analyse n’importe quelle transaction v2 octet par octet, calcule le txid, vérifie l’équilibre et — avec une clé de visualisation — trouve « vos » sorties et déchiffre leurs montants. Pour une transaction aléatoire, il montre tous les secrets, pour que vous voyiez comment chaque fonction s’applique à des nombres concrets.
Comment lire les octets
La sérialisation de Monero est simple — pas d’en-têtes ni de noms de champs, juste des valeurs les unes après les autres. Deux types de briques :
- varint — un entier de longueur variable : 7 bits par octet, le bit de poids fort signifie « un autre octet suit ».
0x02= 2,0x80 0x01= 128,0x80 0xb5 0x18= 400000. - clé / point / scalaire — exactement 32 octets, sans longueur. Les tableaux de points dont la longueur est connue par le contexte (par exemple les
sde CLSAG, selon la taille de l’anneau) n’ont pas non plus de longueur.
Le parseur doit donc connaître le format à l’avance : le type RingCT, lu au milieu, décide de la façon de lire tout ce qui suit.
Quelles fonctions s’appliquent où
| Champ | Calculé par | Formule | En savoir plus |
|---|---|---|---|
| extra: R | l’expéditeur | R = r·G | stealth addresses |
| output: P | l’expéditeur | P = Hs(8·r·A ‖ i)·G + B | stealth addresses |
| view tag | l’expéditeur | Keccak("view_tag" ‖ 8rA ‖ i)[0] | view tags |
| ecdhInfo | l’expéditeur | v ⊕ Keccak("amount" ‖ Hs(8rA ‖ i))[0..8] | Pedersen |
| outPk | l’expéditeur | C = y·G + v·H, y = Hs("commitment_mask" ‖ Hs(8rA ‖ i)) | Pedersen |
| ring | le portefeuille de l’expéditeur | 16 indices globaux, loi gamma sur l’âge | leurres |
| key image | le propriétaire de l’entrée | I = x·Hp(P) | key image |
| pseudoOuts | l’expéditeur | C̃ = y'·G + v·H, masques choisis pour que Σ C̃ = Σ C + fee·H | RingCT |
| CLSAG | le propriétaire de l’entrée | un anneau de défis sur P_i et C_i − C̃ | signatures en anneau |
| Bulletproofs+ | l’expéditeur | preuve que 0 ≤ v < 2⁶⁴ pour toutes les sorties | preuves d’intervalle |
Ce qu’un nœud fait de ces octets
- Il les analyse ; tout octet en trop ou manquant entraîne un rejet.
- Il vérifie que les key images sont nouvelles et appartiennent au bon sous-groupe.
- Il reconstitue les 16 indices globaux à partir des décalages et charge depuis sa base les clés et engagements de ces sorties.
- Il vérifie l’équilibre
Σ C̃ = Σ outPk + fee·H— l’outil ci-dessous le fait aussi. - Il vérifie Bulletproofs+ et le CLSAG de chaque entrée.
Ce que fait le portefeuille du destinataire
- Il prend
Rdans extra et calcule le secret partagé8·a·R(une opération par transaction). - Pour chaque sortie : un hachage → comparaison du view tag ; pas de correspondance — on s’arrête.
- Correspondance — on compare
Hs(8aR ‖ i)·G + Bavec la clé de la sortie. - La sortie est à nous — on déchiffre le montant, on reconstitue le masque et on vérifie
y·G + v·Hpar rapport àoutPk.
L’outil montre toutes ces étapes avec des nombres concrets.
Le parseur a été vérifié par rapport au décodage JSON de monerod sur de vraies transactions de type 5 et de type 6 ainsi que sur une transaction coinbase : chaque champ et le txid correspondent. Le bouton « vraie tx du mainnet » en charge une — comparez le txid avec n’importe quel explorateur de blocs.
À quoi ressemblera une transaction FCMP++ ?
Le format des transactions FCMP++ peut encore changer avant le hard fork, il n’y a donc pas encore de parseur d’octets pour lui ici. Mais d’après l’implémentation actuelle, la structure générale est claire — et étonnamment proche de celle d’aujourd’hui :
| Dans RingCT | Dans FCMP++ | Fonctions |
|---|---|---|
| 16 décalages par entrée | une référence au bloc dont l’arbre sert de base à la preuve | racine du Curve Tree de toutes les sorties |
key image I = x·Hp(P) | la même L = x·Hp(O) | doubles dépenses détectées comme avant |
pseudo-sortie C̃ | C̃ = C + r_c·G — partie du tuple rerandomisé | rerandomisation |
| CLSAG par entrée | SA+L par entrée (quelques points et scalaires) | Schnorr généralisé |
| — | une seule preuve d’appartenance pour toute la transaction | Generalized Bulletproofs + diviseurs |
| view tag de 1 octet, ECDH sur Ed25519 | view tag de 3 octets, X25519, ancre Janus | Carrot |
Voyez la rerandomisation sur des nombres concrets dans l’outil. Une fois le format définitif, une analyse octet par octet des transactions FCMP++ sera aussi ajoutée ici.