Passer de Blake2_128 à Blake2_128Concat pour les Maps

Je travaille actuellement à dumper le Storage, à la fois pour mes besoins de montée en compétence sur Rust et Substrate mais aussi pour prévenir des situations délicates sur l’état des données grâce à quelques tests (Golden Testing en l’occurrence).

Mais je suis tombé sur un os (deux en réalité) : pour les Map suivantes, nous encodons la clé avec Blake2_128 :

IdentitiesNames

pub type IdentitiesNames<T: Config> = StorageMap<_, Blake2_128, IdtyName, (), OptionQuery>;

IdentityIndexOf

pub type IdentityIndexOf<T: Config> =
        StorageMap<_, Blake2_128, T::AccountId, T::IdtyIndex, OptionQuery>;

Blake2_128 n’est pas énumérable

Parmi les algorithmes de hachage proposés par Substrate, existe Blake2_128. Celui-ci est catégorisé “Cryptographique” au sens où il empêche sa sortie d’être influencée par la donnée en entrée, ce qui est important pour les données stockées pouvant être manipulées par l’utilisateur (typiquement un pseudonyme), car cela pourrait créer une mauvaise répartition des valeurs dans le Storage et dégrader les performances de la blockchain.

Le gros inconvénient de cette version : il n’est pas possible de connaître la pré-image utilisée.

Par exemple :

Blake2_128("Alice") = 0x113538518418f8abb2791957045177a0

Impossible de déduire “Alice” à partir de 0x113538518418f8abb2791957045177a0 qui est un hash.

Blake2_128Concat est énumérable

C’est pour cela que l’équipe Substrate a pondu le concept d’algorithmes de hachage transparents : l’idée est tout simplement d’adjoindre la valeur originelle au hash :

Blake2_128Concat("Alice") = 0x113538518418f8abb2791957045177a014416c696365

On retrouve :

  • Le hash : 113538518418f8abb2791957045177a0
  • La valeur originelle : 14416c696365 (valeur hexadécimale de la chaîne “Alice”, vérifiez)

De cette manière, à partir d’un hash de Blake2_128Concat on sait retrouver la valeur originelle et, par conséquent, à partir d’un préfixe d’une Map dans le Storage on sait lister toutes les entrées hashées de la Map et en déduire leur valeur originelle respective.

Application sur IdentitiesNames

En changeant Blake2_128 par Blake2_128Concat, je peux lister les pseudos stockés dans la ĞDev locale :

 Identity.IdentitiesNames = [
   ("Alice", ())
   ("Charlie", ())
   ("Bob", ())
   ("Dave", ())
 ]

:question: Pourquoi avoir utilisé Blake2_128 et non pas sa version concat ? A priori, la réponse est ici : V2s: Comment utiliser les extrinsics pour la wot? - #16 by elois
Ceci dit, dans son raisonnement Eloïs ne prenait en compte que l’exécution du Runtime et pas les tests que l’on pourrait avoir besoin de réaliser.

:question: et pour IdentityIndexOf ? La raison ne me saute pas aux yeux, d’autant que la clé est l’AccountId, tout comme PendingNewAccounts qui lui est bien en Blake2_128Concat.
Je plaiderais plus pour l’erreur que la raison ici.

Impacts 1 : Pas de migration facile de la ĞDev

Comme il n’est pas possible de déduire la valeur originelle à partir d’un hash de Blake2_128, pour la ĞDev actuelle si je voulais effectuer cette modification, il faudrait que je connaisse à l’avance chacun des pseudos utilisés et les associer au hash correspondant trouvé dans le Storage et mettre les nouvelles valeurs à l’occasion d’un Runtime Upgrade.

Ce serait possible et intéressant, mais vu que nous allons de toute façon reboot la ĞDev, je préfère juste préparer une MR à merger pour le prochain reboot et continuer mon travail sur le Golden Testing.

Impact 2 : sanity_check

A priori nous aurons une erreur de contrôle sur l’assertion blake2_128_owner_key == &blake2_128(idty_value.owner_key.as_slice()). Pour l’instant je n’ai pas creusé cette partie, peut-être le ferais-je pour la MR.


A noter enfin que Gavin Wood lui-même a fait un ticket en ce sens pour Substate afin de remplacer l’utilisation par défaut à l’époque de Blake2-256 par Blake2-256Concat, jugée suffisante et moins contraignante.

5 Likes