Last week, I built a small Solana wallet script where I could create, export, save, and reload a keypair.
Here's the link of the script for reference: Github
It all started with this line:
const wallet = await generateKeyPairSigner({ extractable: true });
When I tried exporting the private key:
await crypto.subtle.exportKey("pkcs8", wallet.keyPair.privateKey);
I learned two important things:
1. Why extractable: true is required
If the key is not extractable:
exportKey simply fails
The private key stays locked inside the crypto subsystem
You cannot save or reuse the wallet
So without extractable: true, the wallet is temporary (in-memory only).
2. Why "pkcs8" and not "raw"?
This part was subtle but important.
"pkcs8" is the standard format for exporting private keys
It wraps the key with metadata (algorithm, structure, etc.)
The Web Crypto API only allows private keys to be exported in PKCS#8 format
If you try:
crypto.subtle.exportKey("raw", wallet.keyPair.privateKey);
It will fail.
Because:
"raw" format is only valid for public keys
Private keys require a structured, secure encoding → hence PKCS#8
🧩 What I Did Next
After exporting in PKCS#8, I extracted the actual 32-byte private key:
const privateKeyBytes = new Uint8Array(pkcs8Buffer.slice(-32));
Then combined it with the public key:
`const keyPairBytes = new Uint8Array(64);
keyPairBytes.set(privateKeyBytes, 0);
keyPairBytes.set(publicKeyBytes, 32);`
This gave me the standard 64-byte Solana keypair, which I could:
Save to a file
Reload later
⚖️ Big Takeaway
This small detail clarified a bigger concept for me:
extractable: true → enables portability (save, backup, restore)
"pkcs8" → the only valid way to export private keys
"raw" → only works for public keys
Top comments (0)