Skip to main content

Accounts & PQC signing

QoreChain accounts are derived from a single BIP-39 mnemonic. The same mnemonic yields a native, an EVM, and an SVM account via independent derivation paths.

HD derivation

import {
generateMnemonic,
validateMnemonic,
deriveNativeAccount,
deriveEvmAccount,
deriveSvmAccount,
} from "@qorechain/sdk";

const mnemonic = generateMnemonic(); // 12 words; pass 256 for 24 words

const native = await deriveNativeAccount(mnemonic);
console.log(native.address); // "qor1..." (secp256k1, bech32)

const evm = await deriveEvmAccount(mnemonic);
console.log(evm.address); // "0x..." (EIP-55 checksummed)

const svm = await deriveSvmAccount(mnemonic);
console.log(svm.address); // base58 ed25519 public key

The mnemonic is validated (words and checksum) before any key is derived, so a typo raises rather than silently producing a wrong account. You can validate explicitly with validateMnemonic(mnemonic).

Derivation schemes

TypeCurvePathAddress
nativesecp256k1m/44'/118'/0'/0/{i}bech32 qor of ripemd160(sha256(pubkey))
evmsecp256k1m/44'/60'/0'/0/{i}0x + keccak256(pubkey)[-20:], EIP-55
svmed25519m/44'/501'/{i}'/0'base58 of the 32-byte public key

Pass an account index to derive additional accounts. In TypeScript:

const second = await deriveNativeAccount(mnemonic, { accountIndex: 1 });

In Python/Go/Rust the index is a positional argument (derive_native_account(mnemonic, 1) / DeriveNativeAccount(mnemonic, 1) / derive_native_account(&mnemonic, 1)).

Known-answer note

The derivation schemes are deterministic and covered by known-answer tests across all four SDKs, so the same mnemonic produces identical addresses in TypeScript, Python, Go, and Rust. This lets you derive in one language and verify in another.

Post-quantum cryptography (PQC)

QoreChain supports ML-DSA-87 (Dilithium-5, FIPS 204) signatures. The SDK exposes the primitives directly.

import {
generatePqcKeypair,
pqcSign,
pqcVerify,
ML_DSA_87_PUBLIC_KEY_LENGTH,
ML_DSA_87_SIGNATURE_LENGTH,
} from "@qorechain/sdk";

const keypair = generatePqcKeypair();
const message = new TextEncoder().encode("hello");

const signature = pqcSign(keypair.secretKey, message);
const ok = pqcVerify(keypair.publicKey, message, signature);

The exported length constants (ML_DSA_87_PUBLIC_KEY_LENGTH, ML_DSA_87_SECRET_KEY_LENGTH, ML_DSA_87_SIGNATURE_LENGTH, ML_DSA_87_SEED_LENGTH) let you validate buffer sizes.

Underneath, the PQC primitives come from qorechain-pqc — the open-source, standards-only library that wraps audited FIPS-204/203/202 implementations behind one consistent API in six languages (JavaScript/TypeScript, Rust, Go, C, Python, Java). Reach for it directly when you need the raw primitives or hybridSignBytes framing outside the SDK.

Pluggable signers

For composition, the SDK provides a Signer abstraction plus PqcSigner and HybridSigner implementations, and a SignatureMode enum. Use these when you want to plug PQC signing into your own flow rather than calling the primitives directly.

Hybrid signing

A hybrid transaction carries both a classical secp256k1 signature and an ML-DSA-87 signature, so it remains valid under classical verification while gaining post-quantum protection. The post-quantum part travels as a PQCHybridSignature extension on the transaction.

Hybrid signing is required on the cosmos path

As of the current chain version (v3.1.77), the network default is hybrid_signature_mode = required with allow_classical_fallback = false. Hybrid signing via buildHybridTx (with includePqcPublicKey) is mandatory for cosmos-path transactions — classical-only cosmos transactions are rejected on-chain. EVM transactions use a separate eth_secp256k1 path and are unaffected.

import {
buildHybridTx,
deriveNativeAccount,
directSignerFromPrivateKey,
} from "@qorechain/sdk";

const account = await deriveNativeAccount(mnemonic);
const signer = await directSignerFromPrivateKey(account.privateKey, "qor");

// buildHybridTx assembles a tx with BOTH a classical signature and an
// ML-DSA-87 signature attached as a PQCHybridSignature extension.
// (See packages/ts and the pqc-hybrid-sign example for the full call.)

On-chain prerequisite

Before a hybrid transaction will PQC-verify on-chain, the signer's PQC public key must be registered via the chain's MsgRegisterPQCKeyunless you set includePqcPublicKey: true, which embeds the key in the extension so the chain can auto-register it on first use.

Hybrid tx contract (high level)

The transaction is signed classically over the standard sign bytes (which exclude the PQC extension), and the ML-DSA-87 signature is computed and attached as the PQCHybridSignature extension. Because the classical sign bytes exclude the extension, the classical signature stays valid whether or not a verifier understands the PQC part. The lower-level helpers (encodeHybridExtension, attachHybridExtension, buildHybridSignatureExtension, HYBRID_SIG_TYPE_URL) and the end-to-end builders (buildHybridTx, signAndBroadcastHybrid) are exported for advanced use.

Hybrid transaction submission is the required path on the live network for cosmos transactions. The local sign/verify primitives and tx-building helpers are available today.

Algorithm identifiers

The SDK exports algorithm IDs and helpers for protocol-level work: AlgorithmUnspecified, AlgorithmDilithium5, AlgorithmMLKEM1024, algorithmName(id), and isSignatureAlgorithm(id).