tevador / polyseed

Mnemonic seed library for Monero and other CryptoNote-based currencies.
GNU Lesser General Public License v3.0
44 stars 4 forks source link

KDF choice questions #8

Closed Monero-HackerIndustrial closed 7 months ago

Monero-HackerIndustrial commented 1 year ago

Hello, I am the developer for monerosigner, a monero fork of seedsigner (A DIY hardware wallet built around pi zero).

The generation of new seeds in my project will use dice rolls as an option for entropy generation of new seeds. In the bitcoin space there is a standard under bip39 for raw entropy to seed. There is no equivalent standard for monero. Since I am still early in the process I wanted to get your input as polyseed is slightly based off the bip39 KDF.

Here is a work in progress repo for dice roll entropy to monero seed: https://github.com/Monero-HackerIndustrial/MoneroDice-WalletGen I avoided the simple "rolls to bytes, then hash" and instead opted for key derivation similar to bip39. Below is the first version to my entropy to monero seed:

#the new way uses the key derivation of
# https://github.com/diybitcoinhardware/embit/blob/2bf81739eb5f01f8ad59d23c492fd9d9564eed48/src/embit/bip39.py#L86
PBKDF2_ROUNDS = 2048
#password used for the salt (a sha256sum )
password = hashlib.sha256(dice_rolls.encode()).digest()
entropy_bytes  = hashlib.pbkdf2_hmac(
        "sha512",
        dice_rolls.encode("utf-8"),
        password,
        PBKDF2_ROUNDS,
        32,
    )

hex = entropy_bytes

hex = hex.hex()
s = Seed(hex)
phrase = s.phrase
public_address = s.public_address()

I am relying on the monero python library which handles encoding the hex seed into a seed phrase. That part is documented and standardized in multiple libraries and clients.

Since there was no BIP39 equivalent standard in monero for raw hex entropy to key derivation I used BIP39 as inspiration.

I took a look at polyseed and noticed some similar ideas.

Polyseed was designed for the 128-bit security level. This corresponds to the security of the ed25519 elliptic curve, which requires about 2126 operations to break a key.

The private key is derived from the 150-bit secret seed using PBKDF2-HMAC-SHA256 with 10000 iterations. The KDF parameters were selected to allow for the key to be derived by hardware wallets. Key generation is domain-separated by the wallet birthday month, seed features and the coin flag.

The size of the secret seed and the domain separation parameters provide a comfortable security margin against multi-target attacks.

My version and Polyseed use similar key derivations except for 2 differences. sha256 vs sha512

of iterations

10000 vs 2048 The salt being the reserved/feature bits.

Is there an advantage to using PBKDF2-HMAC-SHA256 vs PBKDF2-HMAC-SHA512? Bip39 uses sha512 as the kdf. I was basing my choice off of it. Was there a specific design choice in using sha256 for polyseed?

You mentioned

The KDF parameters were selected to allow for the key to be derived by hardware wallets. Could you elaborate a bit on this? Is it because the sha256 hardware chips are more common and makes it easier when building embedded systems?

While I am asking I also wanted to get your input on the dice roll entropy.

The script generates 100 dice rolls for a little bit over 256 bit entropy. Based on some Math from coldcard, a d6 dice provides 2.585 bits of additional entropy per roll This means: 50 rolls for 128 bit 99 rolls for 256 bit.

Thank you for your help in advance

tevador commented 1 year ago

Was there a specific design choice in using sha256 for polyseed?

Yes, several reasons:

  1. SHA256 targets the 128-bit security level, which matches polyseed. SHA-512 is for the 256-bit security level.
  2. SHA256 runs much faster on 32-bit hardware, which is common in embedded devices such as hardware wallets.
  3. Some x86 and ARM CPUs have hardware support for SHA-256, but not for SHA-512.

Polyseed will be integrated into Monero soon. If you want to make it easier to support the seed format in the future, I recommend using PBKDF2-HMAC-SHA256. Your diceware routine can be easily integrated with polyseed by injecting it into the randbytes dependency.