generateDewif method
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);
}