FIO Public/Private Keys
FIO Private Key
Private Key Generation
Private key generation in the SDKs is available for testing purposes only. Do not generate private keys for production application using these methods. Instead pass securely generated private keys or seed phrase to the SDK constructor.
Derivation Path
FIO Chain is registered at index 235/0x800000eb
on the SLIP-44
FIO Private Keys follow Wallet Import Format (WIF) standard and public keys follow well-known base58 encoding with FIO prefix, for example:
FIO7tkpmicyK2YWShSKef6B9XXqBN6LpDJo69oRDfhn67CEnj3L2G
For those who have integrated EOSIO, FIO public keys follows the same format, except the prefix is FIO instead of EOS.
The derivation path for FIO is:
"44'/235'/0'/0/0"
To test your FIO key derivation, use this mnemonic phrase:
valley alien library bread worry brother bundle hammer loyal barely dune brave
This is the expected Private Key for address_index 0:
5Kbb37EAqQgZ9vWUHoPiC2uXYhyGSFNbL6oiDp24Ea1ADxV1qnu
This is the expected Public Key for address_index 0:
FIO5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575o
To obtain a private key from a seed phrase, you can use the BIP 39 tool by Ian Coleman as described in this video.
FIO Private Key Wallet Import Format (WIF)
FIO private keys are Wallet Import Format (WIF) encoded. WIF is an encoding for a private EDSA key. FIO uses the same version, checksum, and encoding scheme as the Bitcoin WIF addresses and should be compatible with existing libraries.
This is an example of a FIO WIF Private Key:
5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAbuatmU
This encoding is good for:
- Copy and Pasting private keys (ensures the entire key is copied)
- Including keys in text or user editable file formats
- Shortening the key-length
This encoding is not good for:
- Writing keys down by hand (even a single upper / lowercase mistake can cause a major problem)
- Binary or computer storage where code handles the key and data is already checked
Considerations:
- If a key could be written down or re-keyed, the BIP39 Mnemonic Code standard is a better option to use.
- It is a good idea to always label a WIF key using the word "Private" or "Private Key".
WIF encoded FIO Private Key checksum validation
-
Start with the WIF encoded Private Key.
5Kbb37EAqQgZ9vWUHoPiC2uXYhyGSFNbL6oiDp24Ea1ADxV1qnu
-
Base58 decode the WIF string (shown as HEX here).
80ea8eb60b7e5868e218f248e032769020b4fea5dcfd02f2992861eaf4fb534854163733c6
-
Slice the decoded WIF into the versioned key and the checksum (last 4 bytes).
80ea8eb60b7e5868e218f248e032769020b4fea5dcfd02f2992861eaf4fb534854
163733c6
-
Perform a binary SHA-256 hash on the versioned key.
a34bb90a0d35e01df7901fb9cd32688a65349086a00cbde4106fff7b60b43ecc
-
Perform another binary SHA-256 hash on result of SHA-256 hash.
163733c6bdfb1a755b2498ba7f03d47be5f04823738541b889a8f26777e2cf93
-
Take the first 4 bytes of the second SHA-256 hash, this is the checksum.
163733c6
-
Make sure the checksum in steps 3 and 6 match.
WIF encoded FIO Private Key checksum validation example
The following is a JavaScript implementation of this checksum algorithm and may be used to checksum FIO WIF private keys
const assert = require('assert')
const base58 = require('bs58')
const createHash = require('create-hash')
// 1. Start with the Wallet Import Private Key.
let privateKey = '5Kbb37EAqQgZ9vWUHoPiC2uXYhyGSFNbL6oiDp24Ea1ADxV1qnu';
// 2. Base58 decode the WIF string (shown as HEX here). Returns a buffer.
privateKey = base58.decode(privateKey);
// 3. Slice the decoded WIF into the versioned key and the checksum (last 4 bytes).
checksum1 = privateKey.slice(-4)
privateKey = privateKey.slice(0,-4)
// 4. Perform a binary SHA-256 hash on the versioned key.
privateKey = createHash('sha256').update(privateKey).digest()
// 5. Perform another binary SHA-256 hash on result of SHA-256 hash.
privateKey = createHash('sha256').update(privateKey).digest()
// 6. Take the first 4 bytes of the second SHA-256 hash, this is the checksum.
checksum2 = privateKey.slice(0,4)
// 7. Make sure the checksum in steps 3 and 6 match.
assert(checksum2 = checksum1, 'Checksum failed!')
FIO Public Key
FIO, like EOSIO, uses the base58 cryptographic hash function to encode raw public keys.
FIO Public Key checksum validation
-
Start with a FIO Public Key Key.
FIO5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575o
-
Strip off the initial "FIO" string.
5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575o
-
Base58 decode the public key.
0271195c66ec2799e436757a70cd8431d4b17733a097b18a5f7f1b6b085978ff0f343fc54e
-
Trim off the last 4 checksum bytes and you are left with a 33 byte compressed public key.
0271195c66ec2799e436757a70cd8431d4b17733a097b18a5f7f1b6b085978ff0f
343fc54e
-
Perform a RIPEMD-160 hash on the key.
343fc54e7a93a7328cdf47bdad878bef36049315
-
Take the first 4 bytes of the hash, this is the checksum.
343fc54e
-
Make sure the checksum in steps 4 and 6 match.
FIO Public Key checksum validation example
The following is a JavaScript implementation of this checksum algorithm and may be used to checksum FIO Public keys
const assert = require('assert')
const base58 = require('bs58')
const createHash = require('create-hash')
// 1. Start with a FIO Public Key Key.
let publicKey = 'FIO5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575o';
// 2. Strip off the initial "FIO" string.
publicKey = publicKey.slice(3)
// 3. Base58 decode the public key.
publicKey = base58.decode(publicKey);
// 4. Trim off the last 4 checksum bytes and you are left with a 33 byte compressed public key.
checksum1 = publicKey.slice(-4)
publicKey = publicKey.slice(0,-4)
// 5. Perform a RIPEMD-160 hash on the key.
publicKey = createHash('rmd160').update(publicKey).digest()
// 6. Take the first 4 bytes of the hash, this is the checksum.
checksum2 = publicKey.slice(0,4)
// 7. Make sure the checksum in steps 3 and 6 match.
assert(checksum2 = checksum1, 'Checksum failed!')
FIO Public Key checksum validation using the fiojs library
This example uses the fiojs library to validate a FIO public key.
const { Ecc } = require('@fioprotocol/fiojs');
const ecurve = require('ecurve');
const secp256k1 = ecurve.getCurveByName('secp256k1');
const validPublicKey = 'FIO5ReMUvFM9X12eSuAR4QKjHsGJ6qponQP36xtV7WZLPBG35dJTr'
const invalidPublicKey = 'FIO5ReMUvFM9X12eSufe4QKjHsGJ6qponQP36xtV7WZLPBG35dJTr'
const invalidPublicKey2 = 'FIO5ReMUvFM9X12eSufe4QKjHsGJ6qponQP36xtWZLPBG35dJTr'
async function main () {
console.log("\n1. Check if valid:", validPublicKey)
let isValid = await isPubKeyValid(validPublicKey)
console.log ("Validation result:", isValid)
console.log("\n2. Check if valid:", validPublicKey)
isValid = await isPubKeyValid(invalidPublicKey)
console.log ("Validation result:", isValid)
console.log("\n3. Check if valid:", invalidPublicKey2)
isValid = await isPubKeyValid(invalidPublicKey2)
console.log ("Validation result:", isValid)
}
async function isPubKeyValid(publicKey) {
if (publicKey.length !== 53) return false
// return Ecc.isValidPublic(publicKey)
const PUB_KEY_PREFIX = 'FIO'
if (publicKey.substr(0, 3) !== PUB_KEY_PREFIX) return false
const base58Substr = publicKey.substr(PUB_KEY_PREFIX.length);
try {
const buffer = Ecc.key_utils.checkDecode(base58Substr)
ecurve.Point.decodeFrom(secp256k1, buffer)
} catch (e) {
console.error(e);
return false
}
return true
}
main()
Updated 3 days ago