generateDewif method

Future<NewWallet> generateDewif(
  1. String mnemonic,
  2. String password, {
  3. String lang = 'english',
  4. int dewifCurrencyCode = DEWIF_CURRENCY_CODE_G1,
  5. int dewifVersion = DEWIF_VERSION,
  6. bool testRfc = false,
})

Return the base64 DEWIF string generated from given mnemonic and password. You can optionnaly specify a custom parameters, as language for mnemonic (default is enhlish) More detail in the Duniter RFC13: https://git.duniter.org/documents/rfcs/blob/master/rfc/0013_Duniter_Encrypted_Wallet_Import_Format.md

Implementation

Future<NewWallet> generateDewif(String mnemonic, String password,
    {String lang = 'english',
    int dewifCurrencyCode = DEWIF_CURRENCY_CODE_G1,
    int dewifVersion = DEWIF_VERSION,
    bool testRfc = false}) async {
  mnemonic = mnemonic.replaceAll('é', 'é');
  mnemonic = mnemonic.replaceAll('è', 'è');
  if (testRfc) print(mnemonic);

  const int log_n = 14;

  var nonce = randomByte(12);

  // To test RFC
  if (testRfc) nonce = 'c54299ae71fe2a4ecdc7d58a';

  // Header is data version + currency code on 4 bytes
  final header = (dewifVersion.toRadixString(16).padLeft(8, '0') +
      dewifCurrencyCode.toRadixString(16).padLeft(8, '0'));

  // Start data with header + log_n + used algorithm code + nonce
  var data = header +
      log_n.toRadixString(16).padLeft(2, '0') +
      DEWIF_ALGORITHM_CODE_BIP32_ED25519.toRadixString(16).padLeft(2, '0') +
      nonce;

  // Salt is sha256("dewif" || nonce || passphrase)
  final salt =
      sha256("dewif".codeUnits + HEX.decode(nonce) + password.codeUnits);

  final scrypt = KeyDerivator('scrypt');
  scrypt.init(
    ScryptParameters(
      pow(2, log_n).toInt(), //16384
      16,
      1,
      42,
      salt.toUint8List(),
    ),
  );
  final scryptedPassword = scrypt.process(password.codeUnits.toUint8List());

  final entropyMnemonic =
      HEX.decode(bip39.mnemonicToEntropy(mnemonic, language: lang));

  var entropyPadding = randomByte(32 - entropyMnemonic.length);

  // To test RFC
  if (testRfc) entropyPadding = 'aa083bd16c8317121d34b5aed1c1420a';

  final languageCode = DEWIF_MNEMONIC_LANGUAGES.keys
      .firstWhere((k) => DEWIF_MNEMONIC_LANGUAGES[k] == lang);

  final checksum = sha256(HEX.decode(nonce) +
          [languageCode] +
          [entropyMnemonic.length] +
          entropyMnemonic)
      .sublist(0, 8);

  final dataToEncrypt = languageCode.toRadixString(16) +
      entropyMnemonic.length.toRadixString(16) +
      HEX.encode(entropyMnemonic) +
      entropyPadding +
      HEX.encode(checksum);

  final encryptedData = byteXor(
      Uint8List.fromList(HEX.decode(dataToEncrypt)), scryptedPassword);

  data = data + HEX.encode(encryptedData);
  final base64Data = base64.encode(HEX.decode(data));

  //To test RFC
  if (testRfc &&
      base64Data ==
          'AAAAARAAAAEOAcVCma5x/ipOzcfViufNdfj5k4Sl5zdrHLf9PPGDkH1Pz3y8tFrx/jZZcJd92LIk+EWIrjxiSw==') {
    print('Data is conform to RFC !');
  }

  // Show me everything
  // print('\nVersion: ' + dewifVersion.toRadixString(16));
  // print('log N: ' + log_n.toRadixString(16));
  // print('Algorithm: ' + DEWIF_ALGORITHM_CODE_BIP32_ED25519.toRadixString(16));
  // print('Nonce: ' + nonce);
  // print('Language: ' + languageCode.toRadixString(16));
  // print('Entropy length: ' + entropyMnemonic.length.toRadixString(16));
  // print('Entropy Mnemonic: ' + HEX.encode(entropyMnemonic));
  // print('Entropy padding: ' + entropyPadding);
  // print('Checksum: ' + HEX.encode(checksum));
  // print(data);

  return NewWallet._(base64Data, password);
}