这是每位 Solana 开发者都该收藏的 密钥管理手册。无论你用 JavaScript、Python、Rust 还是命令行,都能 5 分钟完成密钥生成、助记词备份、钱包连接及签名验证。
关键词:Solana密钥对、Solana钱包、密钥生成、助记词、Vanity地址、钱包连接、签名验证、ed25519
1. 速通核心概念:什么是密钥对与钱包?
- 密钥对 = 私钥 + 公钥
- 钱包 = 把密钥对包装成人类可用的 UI 并加一层安全逻辑
- 开发时可直接用代码生成密钥对;生产环境请用户授权现有钱包即可,绝不要暴露私钥。
2. 一键生成新密钥对
JavaScript(TypeScript)
import { Keypair } from "@solana/web3.js";
(async () => {
const keypair = Keypair.generate();
})();Python
from solders.keypair import Keypair
keypair = Keypair()
print(keypair.pubkey())Rust
use solana_sdk::signature::Keypair;
fn main() {
let wallet = Keypair::new();
println!("{:?}", wallet.pubkey());
}CLI(官方工具)
$ solana-keygen new
# 屏幕会显示助记词及公钥 9ZNTfG4NyQgxy2SWjSiQoUyBPEvXT2xo7fKc5hPYYJ7bC++(libsolana)
需链接 openssl、sodium
auto key_pair = Keypair::generate();
std::cout << key_pair.public_key.to_base58() << std::endl;3. 如何从已有密钥恢复
3.1 通过原始字节数组
const keypair = Keypair.fromSecretKey(
Uint8Array.from([174, 47, …, 135])
);3.2 通过 Base58 字符串
import bs58 from "bs58";
const keypair = Keypair.fromSecretKey(
bs58.decode("5MaiiCavjCmn9Hs1o3eznqDEhRwxo7pXiAYez7keQUviUkauRiTMD8DrESdrNjN8zd9mTmVhRvBJeg5vhyvgrAhG")
);所有语言均支持 bytes / Base58 互相转换,牢记 Base58 即常见的私钥格式。
4. 验证密钥对是否正确
快速比对「私钥推算出的公钥」与「手动填入的公钥」是否一致:
const publicKey = new PublicKey("24PNhTaNtomHhoy3fTRaMhAFCRj4uHqhZEEoWrKDbR5p");
console.log(keypair.publicKey.toBase58() === publicKey.toBase58()); // trueCLI 亦有单行校验:
$ solana-keygen verify prompt://5. 判断公钥是否可掌控(isOnCurve)
并非所有公钥背后都存在私钥。程序派生地址(PDA)就不在 ed25519 曲线上。
console.log(PublicKey.isOnCurve(pubkey.toBytes())); // true/false返回值 false 代表无对应私钥,无法直接签名,多用于程序控制地址。
6. 助记词:让备份更人类友好
6.1 一键生成助记词
import * as bip39 from "bip39";
const mnemonic = bip39.generateMnemonic(); // 12/24 个英文单词6.2 从助记词复原 Solana 钱包
单账号(BIP39)
// mnemonic → seed → keypair
const seed = bip39.mnemonicToSeedSync("pill tomorrow foster ...");
const keypair = Keypair.fromSeed(seed.slice(0, 32));HD 多账号(BIP44)
路径:m/44'/501'/i'/0',i 是索引。
for (let i = 0; i < 10; i++) {
const path = `m/44'/501'/${i}'/0'`;
const childKeypair = Keypair.fromSeed(hd.derive(path).privateKey);
console.log(`${path} → ${childKeypair.publicKey.toBase58()}`);
}CLI 也支持一句:
$ solana-keygen recover 'prompt:?key=0/0'7. 打造个性化 Vaniy 地址
Vanity 地址是指定前缀的公钥,例如 “elv1s...”。核心思路:大量暴力重试。
let kp;
do {
kp = Keypair.generate();
} while (!kp.publicKey.toBase58().startsWith("elv1s"));⚠️ 前缀越长,计算量指数级上升;推荐使用官方 CLI 原生版本,速度远快于脚本。
8. 签名 & 验证:钱包的核心功能
const signature = nacl.sign.detached(messageBytes, keypair.secretKey);
const verified = nacl.sign.detached.verify(messageBytes, signature, keypair.publicKey.toBytes());
console.log(verified); // truePython、Rust、C++ 皆提供 sign_message / verify 类似 API。
👉 想直接测试线上钱包,点我跳转
9. 前端集成钱包:React、Vue、Svelte 示例
9.1 React(wallet-adapter-react)
- 安装依赖
yarn add @solana/wallet-adapter-react @solana/wallet-adapter-react-ui \
@solana/wallet-adapter-base @solana/wallet-adapter-wallets- 创建 Provider 包装器
import { ConnectionProvider, WalletProvider } from "@solana/wallet-adapter-react";
import { WalletModalProvider } from "@solana/wallet-adapter-react-ui";
import { PhantomWalletAdapter } from "@solana/wallet-adapter-wallets";
const wallets = useMemo(() => [new PhantomWalletAdapter()], []);
const network = WalletAdapterNetwork.Devnet;
<ConnectionProvider endpoint={clusterApiUrl(network)}>
<WalletProvider wallets={wallets} autoConnect>
<WalletModalProvider>
{/* App goes here */}
</WalletModalProvider>
</WalletProvider>
</ConnectionProvider>- 连接状态监测
const { wallet } = useWallet();
const { setVisible } = useWalletModal();
<button onClick={() => setVisible(true)}>
{wallet ? wallet.publicKey.toString() : "Connect Wallet"}
</button>9.2 Vue(solana-wallets-vue)
npm i solana-wallets-vue @solana/wallet-adapter-wallets配置:
import { initWallet } from "solana-wallets-vue";
initWallet({ wallets: [new PhantomWalletAdapter()] });组件中使用:
<template>
<wallet-multi-button />
<p v-if="connected">{{ wallet.publicKey }}</p>
</template>
<script setup>
import { useWallet } from "solana-wallets-vue";
const { connected, wallet } = useWallet();
</script>9.3 Svelte(svelte-on-solana)
npm i @svelte-on-solana/wallet-adapter-core \
@svelte-on-solana/wallet-adapter-ui @solana/wallet-adapter-wallets<script>
import { walletStore } from "@svelte-on-solana/wallet-adapter-core";
import { WalletProvider, WalletMultiButton } from "@svelte-on-solana/wallet-adapter-ui";
</script>
<WalletProvider {wallets} network="devnet" localStorageKey="walletAdapter">
<WalletMultiButton />
{#if $walletStore?.connected}
<p>公钥: {$walletStore.publicKey}</p>
{/if}
</WalletProvider>常见问题 FAQ
Q1:在浏览器里直接生成密钥安全吗?
不安全。生产环境请使用已连接的钱包扩展,私钥永不离开用户本地设备。
Q2:助记词和私钥有什么关系?
助记词通过 一次性熵种子 → 私钥。同一助记词 + 相同派生路径 → 完全相同的私钥/公钥对。
Q3:程序派生地址(PDA)能否拿来收款?
可以!PDA 可被程序可控但人类无法签名,常用来当作映射、Vault 或程序账户。
Q4:Vanity 地址可以缩短计算时间吗?
只能多线程或高性能机器,Solana CLI 已做汇编层优化;云 GPU 枚举前缀存在被托管风险。
Q5:为何连接钱包后请求已经 Sign 但交易一直失败?
检查链上账号 token 余额、网络 RPC 延迟、或交易指令参数,前端签名不等于交易成功。
Q6:移动端 webview 内钱包连接失败怎么办?
部分钱包扩展在移动端不支持注入,请集成 浏览器钱包适配器 fallback 或使用 wallet-standard 兼容性方案。