Convert salt+password G1v1 to Substrate decoded seed

Une étape importante de cette migration va être la migration des comptes G1 vers des Mnemonic.

Maintenant que la GD3 permet de migrer son identité vers une autre clé, je vais pouvoir attaquer ce workflow:

  • Une le premier coffre Ğecko créé, proposer d’importer un ancien compte (je vais le nommer compte Cesium pour le moment faute de mieux, mais il va falloir trouver la bonne terminologie pour les gens, G1v1 peut être je ne sais pas).
  • Convertir le SALT+PASSWORD renseigné par l’utilisateur en Seed Substrate (need help)
  • Importer temporairement cette seed dans le format substrate standard via la lib polkadotjs
  • Proposer l’adresse de destination cible parmi les portefeuilles du coffre actuel
  • Après validation, vider le compte Cs vers le portefeuille choisi, et si une identité est lié à ce compte, la migrer également

A priori, la seul étape où j’aimerai bien avoir quelques conseils pour m’aiguiller c’est le passage salt+pwd vers seed format attendu par substrate.

Pour le moment je suis bloqué à cette étape (pseudocode):

id = 'tata'
pwd = 'toto'
scrypt -> seed en Uint8List: [52, 97, 48, 215, 139, 186, 204, 149, 245, 139, 202, 64, 133, 4, 155, 16, 48, 185, 225, 197, 10, 234, 82, 112, 76, 5, 255, 100, 105, 36, 198, 118]
encoded: '346130d78bbacc95f58bca4085049b1030b9e1c50aea52704c05ff646924c676'
newAddress = api.keyring.addressFromRawSeed(ss58, cryptoType: CryptoType.ed25519, encoded);
print(newAddress) -> null

Je ne sais pas comment passer de ce Uint8List vers la string « rawSeed » attendu par la lib polkadot.js.

Je vais continuer de creuser le sujet mais si parmi vous certains on déjà étudié la question ou savent décrire précisément le détail technique précis de ces étapes, je ne dis pas non (c’est certainement tout bête mais je suis pas encore pro crypto).

ping @kimamila @cgeek @tuxmain @Moul @vit

2 « J'aime »

Dans la doc actuelle de polkadot-api je ne trouve pas de fonction addressFromRawSeed, il semble que ça n’existe plus, d’après la doc actuelle tu devrais plutôt essayer quelque chose comme ça:

import { Keyring } from '@polkadot/api';
import { u8aToHex } from '@polkadot/util';

const keyring = new Keyring({ type: 'ed25519' });
const pair = keyring.addFromUri(u8aToHex(seed));

seed est ton Uint8List.

1 « J'aime »

Ok je crois que j’y suis presque, si j’ai bon, l’address ss58=42 de tata/toto est: 5HPgviQ8cBDcTpjSkKXjHDe2YxEzwob7ZmxHrUcSLsmP9f4w

Tu confirmes ?

J’avais juste oublié que la rawSeed est composé de 64 bytes qui sont en faite privateKey+pubkey encodé, donc j’ai pris les 32 premier bytes.

Avec les 32 dernier bytes ça donne l’adresse 5Ej6ocZKm2p9iZ2xzyGySRV9Fu94AprTdcqiLRiA6DBRs2oa mais je ne pense pas que ce soit ça.

Non non la seed c’est bien 32 octets uniquement, c’est ta lib scrypt qui est mal réglée où que tu utilises mal, scrypt doit te retourner 32 octets précisément. Il y a souvent un paramètre dkLen à set à 32.

Dans Tikka, je fais ça sans problème grâce à l’'API substrate-interface pour Python :

keypair = Keypair.create_from_seed(
            seed_hex=seed_hex,
            ss58_format=self.currencies.get_current().ss58_format,
            crypto_type=KeypairType.ED25519,
        )

Effectivement, il te faut la seed V1 (en python l’api l’a veut en hexa…) et zou il me fait une Keypair substrate. Il me faudra implémenter le transfert vers un compte mnemonic dérivé en « //0 », car pour l’instant j’ai juste un compte racine brut.

Quand tu aura résolu tes soucis de type dans l’api JS, tu pourra vérifier que le compte V1 « test »/« test » te donne bien l’addresse V1 et V2 :

adresse base58 V1 : « DCovzCEnQm9GUWe6mr8u42JR1JAuoj3HbQUGdCkfTzSr »
adresse ss58 V2 : « 5GAT6CJW8yVKwUuQc7sM5Kk9GZVTpbZYk9PfjNXtvnNgAJZ1 »

Attention, ss58format=42, cryptotype=Keypair.ED25519 pour l’adresse V2.

Voir ce post :

4 « J'aime »

Eurka, j’ai finit par y arriver en dart:

Future csToV2(String salt, String password) async {
    final scrypt = pc.KeyDerivator('scrypt');

    scrypt.init(
      pc.ScryptParameters(
        4096,
        16,
        1,
        32,
        Uint8List.fromList(salt.codeUnits),
      ),
    );
    final rawSeed = scrypt.process(Uint8List.fromList(password.codeUnits));
    final rawSeedString = HEX.encode(rawSeed);

    final newAddress = await sdk.api.keyring.addressFromRawSeed(ss58,
        cryptoType: CryptoType.ed25519, rawSeed: '0x$rawSeedString');

    log.d('address: ${newAddress.address}');
  }

Il fallait que je rajoute 0x devant rawSeedString sinon il était interprété comme une string utf8, donc 64 bytes au lieux de 32…

csToV2('test', 'test');
-> address: 5GAT6CJW8yVKwUuQc7sM5Kk9GZVTpbZYk9PfjNXtvnNgAJZ1
5 « J'aime »

25 messages ont été scindés en un nouveau sujet : Migrate identity (identity.changeOwnerKey())

ok, de mon côté j’arrive aussi à me connecter à Duniter v2s via les un salt+password :

import {keyring} from "@polkadot/ui-keyring";
const scrypt = require('scrypt-async');

// (...)
const salt = 'test';
const password = 'test';
const meta = {name: 'Account Duniter v1'};

const rawSeedString = await new Promise((resolve) => {
  scrypt(data.password, data.salt, {
    N: 4096,
    r: 16,
    p: 1,
    dkLen: 32, // Seed length
    encoding: 'hex'
  }, (result) => resolve(result));
});

keyring.setSS58Format(42); // SS58 format

const {pair, json} = await keyring.addUri(`0x${rawSeedString}`, password, meta, 'ed25519');  

console.info('Account address -> ' + json.address); // = 5GAT6CJW8yVKwUuQc7sM5Kk9GZVTpbZYk9PfjNXtvnNgAJZ1

Merci pour le partage !

2 « J'aime »