What library does Trezor use?

Good afternoon.
More than two days ago I created a topic with my question, but still no answer :frowning:
There is a research in the network that some wallets use Libbitcoin Explorer (bx) library for entropy generation and in it directly the Mersenne Twister(MT) PRNG method, which uses only 32 bits instead of 128.
I would like to know what method the Trezor wallet uses to do this.
Have a nice day!

@matejcik Hi, can you help with a query?


First of all, Trezor is not affected by this problem, because we actually think things through when doing cryptography :slight_smile: (a mistake like this stretches the Hanlon’s Razor to its limit)

For cryptographic operations, we use a custom open-source library, trezor-crypto, which you can find here: https://github.com/trezor/trezor-firmware/tree/master/crypto

Seed generation in particular, however, is not part of the library. Trezor actually does something rather clever: it takes the entropy from two independent sources. One of them is the internal TRNG of the STM32 chip. The other is your computer.

When generating seed, Trezor asks the host computer to provide 256 bits of randomness. These are then mixed with 256 bits of internally generated randomness via SHA256. That means that:

  • even if the internal TRNG is broken or backdoored, your seed still has enough entropy from the external random bits, and
  • even if your PC is infected by malware and someone knows the external random bits, they still can’t regenerate your seed because there’s additional 256 bits mixed in internally.

Your seed would only be vulnerable if the same entity both had malware on your PC, and backdoored the internal TRNG, and could pair this information.


But my Trezor Model T has 12 words in seed phrase, will the generation method be the same as with 256 bits or is the generation for 128 bits different in some other way?

It’s the same, always 256 bits internal + 256 bits from host. This gets mixed down into 256 input bits, and then your seed takes the first N out of that – 128 for a 12-word seed, full 256 for a 24-word one.

Entropy and hashing works like this:

For simplicity, “entropy” here means “number of bits that the attacker needs to try,” i.e., those that were actually generated randomly, as opposed to by a broken or malicious process.

(Consider, for example, that the internal TRNG is broken, and always responds with either all-ones or all-zeroes. This TRNG is still giving me 1 bit of entropy – an attacker that knows all the external bits still needs to try 2 different seeds, one with all-zeroes internal bits, and other with all-ones. Even if the TRNG is biased and returns all-zeroes with 80 % probability, we could calculate the fractional entropy that I’m getting from it.)

So, at input, we have 256 bits coming from the host PC and 256 bits from the internal generator. In the best possible world, all those 512 bits were generated randomly, and our input has full 512 bits of entropy.
But let’s say that the attacker is in control of the external entropy. We are still getting 512 total bits, but 256 of those are fully known to the attacker. There is “only” 256 good bits of entropy remaining.

Now, we hash the input together.
The nice property of SHA-256 is that every bit of the input affects the whole output. You can imagine this as if every incoming bit “shakes up” the internal state in an unpredictable way.
So even if, say, the attacker gives you 100 000 bits, and you can only insert 256 random ones in certain places, this still means that the internal state was “shaken up” 256 times unpredictably. Exactly the same as if the 256 random bits are the only input.

If the attacker wants to figure out the value of the result, they still need to try every combination of the 256 bits that they don’t know.

(A fun corollary: let’s say that both the internal TRNG and the host PC random number generator is biased, and instead of 256 bits, only give you 140 bits of actual entropy. Due to the SHA-256 combining them, the resulting value again has the maximum possible 256 bits of entropy, some of it “coming from” the internal part and the other from the external part.)

So in the end you have 256 secret bits, with hopefully 256 bits of entropy between them. Another nice property of hashing with SHA-256 is that the output entropy is uniformly distributed. Means that the first 128 bits are “exactly as random” as the last 128. Because the whole internal state gets “shaken up” every time, this means that the first half gets shaken up exactly as much as the second half.

(Interestingly, this means that even if I start out with only 128 bits of entropy in the 256-bit output, when I take the first half, it has the full 128 bits of entropy.
The second half also has 128 bits of entropy, but it’s the same entropy. If you flip a coin and look at what’s on the top, you got one bit. If you look at what’s at the bottom, you also got one bit of data. Either is good, but they depend on each other. You don’t get two bits by looking first at the top and then at the bottom.
Similarly: the attacker needs to try 2^128 options to guess your 128-bit first half, but they get the 128-bit second half “for free” together with it.)

That is, the generation method does not change with the number of words in the seed phrase
For generation of 12 and 24 words TRNG + entropy generated by device and then another 256 bits from SHA256 are used.
And for 12 words seed phrase will take the first 128 bits from the generated result
Did I understand you correctly?

1 Like