Skip to content

Integrate EFF Large Wordlist for Random Wallet Name Generation #14

@BasiruAbdul1992

Description

@BasiruAbdul1992

Replace Current Wordlist with EFF Large Wordlist and Improve Entropy

✅ Replace the hardcoded kNames, k1, and k2
✅ Use the EFF Diceware wordlist
✅ Remove weak Random() in favor of Random.secure()
✅ Load the wordlist from an asset file (assets/eff_wordlist.txt) to reduce code bloat and improve maintainability

Currently, random wallet name generation is limited by a small hardcoded wordlist and uses a non-secure random generator, which leads to predictable or repeated names. Using the EFF Diceware wordlist drastically improves entropy and randomness, enhancing wallet name security and uniqueness.

The EFF wordlist file does not need any modifications for the code snippet to work.

You can download the EFF wordlist directly with:

curl -O https://www.eff.org/files/2016/07/18/eff_large_wordlist.txt
  • Add asset in pubspec.yaml:
flutter:
  assets:
    - assets/eff_wordlist.txt

Update lib/utilities/name_generator.dart:

/*
 * This file is part of Stack Wallet.
 * 
 * Copyright (c) 2023 Cypher Stack
 * All Rights Reserved.
 * The code is distributed under GPLv3 license, see LICENSE file for details.
 * 
 */

import 'dart:math';
import 'package:flutter/services.dart' show rootBundle;

class NameGenerator {
  final Set<String> _usedNames = {};
  final Set<String> _availableNames = {};
  final Random _rand = Random.secure();
  List<String> _wordList = [];
  bool _loaded = false;
  int _count = 0;

  /// Must be called once before using [generate()]
  Future<void> load() async {
    if (_loaded) return;

    final raw = await rootBundle.loadString('assets/eff_wordlist.txt');
    _wordList = raw
        .split('\n')
        .where((line) => line.trim().isNotEmpty)
        .map((line) => line.split('\t')[1]) // second column is the word
        .toList();

    _populateNames();
    _loaded = true;
  }

  void _populateNames() {
    _availableNames.clear();
    for (int i = 0; i < _wordList.length; i++) {
      final w1 = _wordList[i];
      final w2 = _wordList[_rand.nextInt(_wordList.length)];
      _availableNames.add('$w1 $w2');
    }
    _availableNames.removeAll(_usedNames);
  }

  String generate({required Set<String> namesToExclude}) {
    if (!_loaded) {
      throw Exception('Call await load() before using generate()');
    }

    _usedNames.addAll(namesToExclude);
    _availableNames.removeAll(_usedNames);

    if (_availableNames.isEmpty) {
      _count++;
      _populateNames(); // refill with new combos
    }

    final name = _availableNames.elementAt(_rand.nextInt(_availableNames.length));
    _usedNames.add(name);
    return _count > 0 ? "$name $_count" : name;
  }
}

⚙️ Entropy Comparison: Old vs EFF Wordlist

System Words Used Total Combinations Approx. Entropy (bits)
Original (k1 × k2) 20 × 20 400 ~8.64 bits
EFF Diceware 7,776 × 7,776 60,466,176 ~25.5 bits

This proposed change will make wallet name generator much more random and secure, reduce hardcoded clutter, and follow best practices for randomness in Flutter.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions