Vai al contenuto

Bitcoin

LastWord: an auditable offline BIP-39 checksum assistant built around a PIC

A technical overview of LastWord, a standalone device that lets you audit the entropy-to-word mapping of a BIP-39 seed phrase step by step and compute the final checksum word offline.

Bitcoin BIP-39 PIC Embedded Hardware Security

A while ago I started working on a small hardware project called LastWord.

The idea is simple: build a very small device that helps create a BIP-39 mnemonic without generating entropy on its own, and above all in a way that can be audited step by step by the user.

The project is available on GitHub:

https://github.com/gianlucag/LastWord

LastWord prototype

Why I built it

If you want to create a Bitcoin seed phrase starting from entropy you generated yourself, for example with coin flips or dice rolls, many hardware wallets can already do something along those lines.

The problem is that in most cases you still have to trust the device to correctly transform your entropy bits into BIP-39 words.

That is exactly the part I wanted to make visible.

With LastWord, while you feed entropy into the device, it shows the current 11-bit group being assembled, and when that group is complete it shows both the decimal index and the corresponding BIP-39 word.

This is the key point of the whole project.

I did not want a black box saying “trust me, your seed is correct”. I wanted a small machine that makes the conversion process inspectable, boring and deterministic.

The only operation that is not practical to perform by hand is the final SHA-256 step used to derive the checksum bits for the last word. That part is delegated to the device. Everything else can be independently checked by the user against a standard BIP-39 wordlist.

What LastWord is, and what it is not

LastWord is not a random number generator.

It does not create entropy for the user. It does not try to be a full hardware wallet. It does not connect to USB, Wi-Fi or any network. It does not store seed phrases persistently.

It is simply a checksum assistant for entropy generated externally by the user.

The workflow is:

  1. generate entropy yourself;
  2. enter that entropy into LastWord;
  3. verify how each 11-bit group maps to a BIP-39 word;
  4. let the device compute the final checksum portion of the last word;
  5. independently verify the completed mnemonic on any standard BIP-39 wallet if desired.

That constraint is intentional. I wanted a small tool that does one thing and does it transparently.

Hardware choices

The hardware is intentionally minimal:

  • Microchip PIC18F47K42
  • HD44780-compatible 2x16 LCD
  • two push buttons

No touchscreen, no keyboard, no storage, no complex UI.

Here is the circuit assembled on a breadboard, with the PICkit programmer connected:

LastWord breadboard prototype with PIC microcontroller, LCD and programmer

This is the current hardware diagram shown in the repository:

LastWord schematic

The prototype is built on perfboard, and I actually like that it looks like a practical tool rather than a polished consumer product. The project is closer to the spirit of “small dedicated instrument” than “finished gadget”.

The choice of a PIC microcontroller is also very deliberate. I already had experience with PIC devices, so it was natural to use a platform I knew well instead of pulling in a much larger ecosystem. For this kind of project, simplicity matters more than fashion.

The core design idea: auditability

In BIP-39, every word except the last one is derived from an 11-bit value coming directly from entropy.

That means there is a very concrete transformation happening:

entropy bits -> 11-bit groups -> decimal index -> BIP-39 word

This is the exact transformation that LastWord exposes to the user.

During input, the display follows a compact layout like this:

+----------------+
|W07 11000______ |
|<input controls>|
+----------------+

The top line shows the current word being assembled and the bits collected so far.

When a full 11-bit group is complete, the device pauses and shows the result:

+----------------+
|W07 11000010110 |
|1558 security   |
+----------------+

So the user can see all three levels at once:

  • the binary value;
  • the decimal index;
  • the actual BIP-39 word.

That single screen is probably the whole point of the project.

The repository also includes screenshots from the emulator and the real UI. For example, this is a word currently being assembled:

Word in progress

And this is the screen shown when the 11-bit group is complete:

Completed word

Entropy input modes

LastWord currently supports three ways of entering entropy.

1. Coin flips

This is the most direct mode.

The mapping is:

Heads -> 0
Tails -> 1

Each button press directly appends one bit.

This mode is conceptually simple and easy to audit, but of course it assumes you are happy with the fairness of the physical coin you are using.

2. Von Neumann coin mode

This mode is more interesting.

Here, coin flips are processed in pairs according to Von Neumann’s extractor:

HH -> discard
HT -> 0
TH -> 1
TT -> discard

Under the standard assumptions of independence and identical bias, this removes bias from a non-perfect coin. In other words, you no longer need to assume a perfectly fair 50/50 coin.

I had discussed this idea earlier as a possible improvement, and in the current repository it is already implemented.

This is one of the nicest aspects of the project: the entropy still comes from the user, while the device applies a deterministic extraction rule that can be explained in one minute and checked by anyone.

3. Dice rolls

The third mode accepts results from a six-sided die.

The mapping used is:

1 -> 00
2 -> 01
3 -> 10
4 -> 11
5 -> discard
6 -> discard

This is simple and practical. Four outcomes are used to encode two bits, while two outcomes are discarded.

There is also a subtle but important rule in the implementation: a single die roll is never allowed to spill over across two different BIP-39 words. If only one bit is needed to complete the current 11-bit group, only the first bit is used and the second one is dropped.

That is the kind of small design choice that keeps the process conceptually clean.

The last word

The name LastWord obviously comes from the final BIP-39 word.

The last word is special because it contains both user-supplied entropy bits and checksum bits derived from SHA-256.

Depending on the mnemonic length, the split is:

12 words: EEEEEEE|CCCC
18 words: EEEEE|CCCCCC
24 words: EEE|CCCCCCCC

Where:

E = entropy bit supplied by the user
C = checksum bit calculated by the device

This is exactly where the device becomes useful.

Everything up to that point can in principle be checked manually and compared against the wordlist. The final checksum extraction from SHA-256 is the only part that is annoying enough to justify a dedicated tool.

After all entropy has been entered, LastWord computes SHA-256 offline and fills in the checksum portion of the final word.

That final result can then be independently verified later with any BIP-39-compatible wallet.

Firmware and development workflow

The repository is laid out in a straightforward way:

firmware/   Firmware source code
hardware/   Schematics and PCB files
images/     Prototype and hardware images
scripts/    Utility scripts

There are also two build entry points:

./build_emulator.sh
./build_pic18.sh

The first one builds a PC emulator, which is extremely useful during development because it lets me test the UI logic and the entropy-processing flow without having to reflash the microcontroller every single time.

The second builds the actual firmware image for the PIC:

lastword.hex

I like this split a lot. For a small embedded project, having an emulator is a luxury, but also a very pragmatic one.

Why not just use a hardware wallet?

This is probably the most obvious question.

The short answer is that this project is not really competing with hardware wallets.

A hardware wallet is meant to store keys and sign transactions. LastWord is meant to make one very specific part of mnemonic creation auditable.

Even if a wallet lets you enter your own entropy, it usually does not show the full conversion from raw entropy bits to 11-bit word indices in a way you can inspect line by line.

https://github.com/gianlucag/LastWord