Current mainnet identity:
network_name = mainnetaddress_hrp = scnetwork_id = fe561911730912cced1e83bc273fab13genesis_hash = eaae655a1eec3c876bd2e66d899fc8da93d205a5df36a2665f736387aa3cb78a
This document describes the live finalis-core key and address model.
It is intentionally practical:
- what a private key is in this codebase
- how a public key is derived
- how an address is generated
- what cryptographic primitives are used
- what script/address types are currently live
In the live codebase, a wallet / validator private key is an Ed25519 raw 32-byte private seed.
Current implementation:
Important detail:
- the code stores and signs with the raw 32-byte Ed25519 private input
- it is not a WIF string
- it is not a secp256k1 scalar
- it is not a BIP32/BIP39 HD wallet path
So, in finalis-core, a “private key” means:
Ed25519 raw private key material, 32 bytes
The public key is the 32-byte Ed25519 raw public key derived from that private seed.
Live type:
PubKey32 = bytes[32]
The live keypair flow is:
private_key_32 -> Ed25519 keypair -> public_key_32
The live signature primitive is:
Ed25519
Used for:
- transaction signatures
- vote signatures
- proposal signatures
- validator join proof-of-possession
- availability/BPoAR operator-signed records where applicable
The implementation uses OpenSSL Ed25519 raw-key APIs.
The currently live user-facing address type is:
P2PKH
That means the address identifies:
HASH160(pubkey)
where:
HASH160(x) = RIPEMD160(SHA256(x))
Current hash helpers:
The live address derivation path is:
private_key_32
-> public_key_32
-> pubkey_hash_20 = HASH160(public_key_32)
-> address = encode_p2pkh(hrp, pubkey_hash_20)
This is exactly how the validator keystore and CLI derive addresses.
The current supported address HRPs are:
scfor mainnet-style addressestscfor test/dev-style addresses
Any other HRP is currently rejected by the live address encoder/validator.
The live address format is a custom Bech32-like text form, but it is not standard SegWit Bech32.
Structure:
<hrp> "1" <base32(data)>
where data is:
payload || checksum[0..3]
and:
payload = addr_type_byte || pubkey_hash_20
Current live values:
addr_type_byte = 0x00for P2PKHpayloadlength = 21 bytes- checksum length = 4 bytes
- total pre-base32 data length = 25 bytes
The base32 alphabet is:
abcdefghijklmnopqrstuvwxyz234567
Important boundary:
- this is not Bitcoin Base58Check
- this is not standard Bech32 witness-version encoding
- integrators should use the repository encoder/validator rather than assuming compatibility with external wallet libraries
The live address checksum is:
checksum = first_4_bytes( SHA256d( hrp || 0x00 || payload ) )
where:
SHA256d(x) = SHA256(SHA256(x))
So checksum verification is deterministic and tied to both:
- the HRP
- the payload bytes
The live P2PKH output script is:
OP_DUP
OP_HASH160
PUSH20 <pubkey_hash_20>
OP_EQUALVERIFY
OP_CHECKSIG
Byte form:
76 a9 14 <20-byte pubkey hash> 88 ac
Current helper:
Exchanges and wallet integrations should rely on:
validate_addressnormalized_addressscript_pubkey_hexscripthash_hex
from the live lightserver surface.
Do not reimplement address parsing with generic assumptions if you can avoid it.
The correct integration rule is:
address string
-> validate_address
-> normalized_address + script_pubkey_hex + scripthash_hex
This transparent address flow does not decode confidential request URIs or wallet-local confidential account state.
The lightserver uses scripthash_hex for history and UTXO lookups.
Current live derivation is:
scripthash_hex = SHA256(script_pubkey)
This is what exchanges should use with:
get_history_pageget_utxos
The current live model does not provide:
- confidential receive request URI decoding through
validate_address - confidential account import/export through the transparent address parser
- transparent-style public address expansion for confidential outputs
Confidential note:
-
the wallet may use local confidential request URI formats such as
scconfreq1:... -
those are wallet/product surfaces, not part of the transparent address model documented here
-
Base58 legacy addresses
-
secp256k1 account addresses
-
EVM-style
keccak(pubkey)addresses -
HD derivation standardization in the protocol itself
-
multisig address encoding
-
Taproot / SegWit witness versioning
There are other script forms in the chain for validator registration and mint flows, but ordinary user-facing addresses are currently P2PKH only.
Private keys:
- must be treated as raw signing authority
- are sufficient to spend ordinary P2PKH outputs controlled by that key
- also matter for validator/operator actions where the same key material is used
Operationally:
- never expose raw private key bytes in logs
- never assume a generic wallet import/export format is compatible
- always normalize and validate addresses before use
- always derive exchange or operator wallet history from finalized
scripthash_hexlookups, not from string comparison alone
Live finalis-core address identity is:
Ed25519 keypair
-> HASH160(pubkey)
-> custom hrp + separator + base32(payload || 4-byte sha256d checksum)
-> P2PKH script
If you need to integrate safely:
- generate Ed25519 keys
- derive address from
HASH160(pubkey) - validate with live RPC
- use
script_pubkey_hex/scripthash_hexfor finalized accounting