bip32-ed25519-dart

Pub Version (stable) Pub Version (including pre-releases) Dart Test CI Publish to pub.dev

The Dart implementation of the BIP32-Ed25519 the deterministic key generation scheme for Edward25519 curve

API Interfaces

TBD

Key Types

  • ED25519 (RFC 8032) Keys
    • the generated ed25519 signing key is 64-byte long and is created by the concatenation of the ED25519 seed (private key) and the generated public key.
    • the private key a.k.a seed is a 32-byte long cryptographically secure random data.
  • ED25519 Extended Keys
    • the private key is a 64-byte long cryptographically secure random data, and it can be interpreted as the SHA512 hashed and clear/set bit of an ED25519 seed or the first 32-byte (the seed part) of the ED25519 secret/private key.
    • they also can be interpreted as standalone keys, though brute-force is required for retrieving the ED25519 seed from an extended key.
    • The clears are set based on the RFC8032 specification.
    • an Extended key's left 32-byte is equivalent /w a X25519 (for EcDH) private key.
  • BIP32-ED25519 Keys
    • BIP32-ED25519 derivation requires that the 3rd bit of the 31th bytes of an ED25519 Extended key must be cleared.
    • This means that every BIP32-ED2559 signing key is valid Extended ED25519 key,
    • but half of the ED25519 Extended and therefore half of the ED25519 keys are not compatible /w BIP32-ED25519 keys.
Key ID Constructors Comment Constraints
ed25519e_sk ExtendedPrivateKey.generate() All keys are valid, and will set the bits based on RFC8032 N/A
ExtendedPrivateKey.fromSeed(32) All keys are valid, and will set the bits based on RFC8032 check length
ExtendedPrivateKey.decode('ed25519e_sk') Will throw excpetions if the bits are not set. check length and bits
ExtendedPrivateKey(64) Will throw excpetions if the bits are not set. check length and bits
public => _public() returns /w an ed25519_pk verifying key It's an expensive operation and should be created when it's first referenced
sign(message) returns /w a signature N/A
verify(sm, sig) Simply verify by it's public key. check sm messages and signature length
ed25519_pk VerifyKey(32) All keys are valid. check length
verify(sm, sig) check length(s)
verify(sm || sig) check length(s)
ed25519bip32_sk ExtendedBip32PrivateKey.generate() All keys are valid, and will set the bits based on Bip32-Ed25519 N/A
ExtendedBip32Private.normalizeBytes(96) All keys are valid, and will set the bits based on Bip32-Ed25519 check length
ExtendedBip32Private.fromVerifiedBytes(96) All keys should be valid but we cannot validate it. It's expensive to check the public key
ExtendedBip32PrivateKey.decode('ed25519bip32_sk') Will throw excpetions if the bits are not set. check length and bits
ExtendedBip32PrivateKey(96) Will throw excpetions if the bits are not set. check length and bits
ExtendedBip32Private.fromExtended(sk64, cc32) Will throw excpetions if the bits are not set. check length and bits
public => _public() Inherited from ExtendedPrivateKey It's an expensive operation and should be created when it's first referenced
sign(message) Inherited from ExtendedPrivateKey check length(s)
verify(sm, sig) Inherited from ExtendedPrivateKey check sm messages and signature length
verify(sm || sig) Inherited from ExtendedPrivateKey check length(s)
derive(index) Inherited from ExtendedPrivateKey check index
chainCode => ChainCode(suffix) Returns /w a chain code value object check length(s)
getExtended => ExtendedPrivateKey.fromValidBytes(64) Returns and extended key as every Bip32-Ed25519 is a valid Extended Ed25519 key
ed25519bip32_pk ExtendedBip32PublicKey(64) All keys are valid check length(s)
ExtendedBip32PublicKey.fromKey(pk32, cc32) All keys are valid check length(s)
verify(sm, sig) Inherited from VerifyKey check length(s)
verify(sm || sig) Inherited from VerifyKey check length(s)
derive(index) Inherited from VerifyKey check index range
chainCode => ChainCode(suffix) Returns /w a chain code value object check length
getExtended => ExtendedPublicKey.fromValidBytes(prefix) Returns and extended key as every Bip32-Ed25519 is a valid Extended Ed25519 key It's cheap operation

Key Standardization

KeyPair key verifyKey encryptionKey publicKey rawKey Comment
ed25519 ed25519_sk ed25519_pk N/A verifyKey ed25519_sk This is the 32-byte long seed
ed25519_skpk ed25519_pk N/A verifyKey ed25519_sk rawKey is the 32-byte long seed
ed25519_pk ed25519_pk N/A verifyKey ed25519_pk rawKey is the key itself
Extended Ed25519 ed25519_esk ed25519_pk x25519_sk verifyKey ed25519_esk rawKey is the key itself
ed25519_pk ed25519_pk x25519_pk verifyKey ed25519_pk rawKey is the key itself
Bip32-Ed25519 ed25519_eskcc ed25519_pkcc x25519_sk verifyKey ed25519_esk rawKey a valid extended key
ed25519_pkcc ed25519_pkcc x25519_pk verifyKey ed25519_pk rawKeys is a valid Ed25519 signing key
X25519 x25519_sk N/A x25519_pk encryptionKey x25519_sk rawKey is the key itself
x25519_pk N/A x25519_pk encryptionKey x25519_pk rawKey is the key itself

ED25519 Keys

The ed25519 is an Elliptic Curve Digital Signature Algortithm using curve25519 by Dan Bernstein, Niels Duif, Tanja Lange, Peter Schwabe, and Bo-Yin Yang.

The key is 64-byte long and contains the the 32-byte long seed a.k.a private key that is used for generate the secret key and public key.

ED25519 Extended keys

The 64-byte long extended keys contains either - only the 64-byte long secret key. - or the 64-byte long extended private key and the 32-byte public key similar to the normal ED25519 key whihc contains the 32-byte private key (seed) and the 32-byte long private key.

Though, pinenacl-dart's extended interface expecting a concatenated secret and public key. It's due to the assumption that the public key is already known (no scalar_base multiplication is needed for retrieveing the key)

The message signing and signature verifying is compatible /w ED25519.

BIP32-ED25519 Keys

The 96-byte long BIP32-ED25519 keys contains a ed25519e_sk and the chain code. The message signing and signature verifying is compatible /w ED25519.

References

Restrictions

In Cardano blockchain, the keys are derived by the BIP32-ED25519 specification.

The BIP32-ED25519, in addition to the ED25519 (RFC 8032), needs the 3rd bit cleared of the 31th byte.

Therefore, the half of the ED25519 Extended secret keys and therefore the half of the ED25519 private keys are not compatible /w BIP32-ED25519.

To overcome of this restriction, different wallet implementation decided to generate their master node/root key differently (as BIP32-ED25519 specification only requires that bit cleared on the master node/root key as the derived keys would have that bit cleared in the derivation functions anyway).

Some of them (such as Yoroi), just clear that additional 3rd bit, while others (such as the old Daedalus) are hashing the corresponding master key until they find a compatible key, and when it's found, they set and clear the bits as specified in the RFC 8032.

Resolution

There can be different type of resolutions. The most proper way would be: generate only a BIP32-ED25519 compatible 24-word mnemonics and therefore a 256-bit long master secret for new wallets and discard others (as it's is specified in the Bip32-Ed25519 paper). Then use that 256-bit master secret as k specified in BIP32-ED25519.

Drawback of this is that half of the already existing user's mnemonics are not compatible, therefore they need either to move to a new wallet or using some out-dated master-key generation algorithm. The other disadvantege of this is that it would impact the plausible-deniability feature, meaning by when a BIP32-ED25519 compatible 256-bit long seed is generated from a 24-word mnemonic with using an additional password/passphrase by BIP-0039, it could happen that the other seed generated from the same mnemonic, but with no or some different passhprase, would not be BIP-ED25519 compatible.