Technique › RingCT

RingCT : vue d’ensemble

Comment adresses à usage unique, CLSAG, engagements et Bulletproofs+ s’assemblent dans une même transaction

En bref

RingCT (Ring Confidential Transactions) est le format de transaction de Monero depuis 2017. Chaque entrée = un anneau de 16 sorties + un engagement de pseudo-sortie + une signature CLSAG + une key image. Chaque sortie = une clé à usage unique + un engagement + un montant chiffré + un view tag. Par transaction : une preuve Bulletproofs+ et une vérification de l’équilibre.

Anatomie d’une transaction

Transaction (type RCTTypeBulletproofPlus) Entrées anneau : 16 références à des sorties (décalages des indices globaux) key image I pseudo-sortie C̃ CLSAG : c₀, s₀…s₁₅, D × nombre d’entrées ~ 0,7 Ko par entrée Sorties clé à usage unique P engagement C montant chiffré (8 octets) view tag (1 octet) × nombre de sorties (2…16) Pour toute la transaction tx_extra : R (clé publique de transaction) [+ clés supplémentaires] frais (en clair) Bulletproofs+ : une preuve agrégée pour toutes les sorties
Une transaction typique à 1 entrée/2 sorties pèse environ 1,5 Ko, à 2 entrées/2 sorties environ 2,2 Ko.

Ce que vérifie un nœud, et comment

  1. La key image est nouvelle et appartient au bon sous-groupe (l·I = 0) — pas de double dépense.
  2. Tous les membres de l’anneau existent, ont plus de 10 blocs, et la taille de l’anneau est exactement 16.
  3. Équilibre : Σ C̃ = Σ C_out + fee·H — égalité exacte de points.
  4. Bulletproofs+ est valide — tous les montants des sorties sont dans [0, 2⁶⁴).
  5. CLSAG est valide pour chaque entrée — le signataire connaît la clé de l’une des 16 sorties, et cette même sortie a le même montant que la pseudo-sortie, et la key image lui appartient.

La vérification 5 est la plus astucieuse. CLSAG prouve la connaissance de deux secrets pour une même position de l’anneau :

P_π = x·G     and     C_π − C̃ = z·G

Le premier dit « je possède la sortie », le second « la pseudo-sortie contient le même montant que l’entrée réelle ». Comme la position π est la même pour les deux (et cachée par l’anneau), on ne peut pas combiner le montant d’une sortie avec la clé d’une autre.

Qui voit quoi

ObservateurExpéditeurDestinataire
Quelle entrée est la vraie1 sur 16le sait1 sur 16
Adresse du destinatairenonla connaîtla connaît (la sienne)
Montant de la sortienonle connaîtseulement ses propres sorties
Fraisouiouioui
Nombre d’entrées et de sortiesouiouioui
Moment (bloc)ouiouioui

Les trois dernières lignes sont des métadonnées que RingCT ne cache pas. Elles sous-tendent la plupart des heuristiques d’analyse.

Historique des versions de RingCT

TypeDepuisCe qui a changé
RCTTypeFull / Simple2017MLSAG + preuves d’intervalle Borromean
RCTTypeBulletproof2018Bulletproofs au lieu de Borromean (transactions ~10× plus petites)
RCTTypeBulletproof22019Montant chiffré sur 8 octets au lieu de 32, masque dérivé de façon déterministe
RCTTypeCLSAG2020CLSAG au lieu de MLSAG
RCTTypeBulletproofPlus2022Bulletproofs+, anneau de 16, view tags
FCMP++prochain hard forkanneaux remplacés par une preuve d’appartenance sur toute la chaîne

Code : vérifier l’équilibre

Vous pouvez reproduire la vérification de l’équilibre sur une vraie transaction. Les pseudo-sorties se trouvent dans rctsig_prunable.pseudoOuts, les engagements des sorties dans rct_signatures.outPk :

// tx = transaction JSON from monerod (get_transactions, decode_as_json)
const sum = (pts) => pts.reduce((acc, p) => XMR.add(acc, XMR.decodePoint(p)), XMR.ZERO);
const lhs = sum(tx.rctsig_prunable.pseudoOuts);
const rhs = XMR.add(sum(tx.rct_signatures.outPk), XMR.mul(BigInt(tx.rct_signatures.txnFee), XMR.H));
console.log(XMR.eq(lhs, rhs)); // true — the balance holds, yet no amount is known

Faites la même expérience avec des montants inventés dans le calculateur d’engagements.