区块链【免费下载链接】cosmos-sdkFramework for building performant, customizable blockchains with native interoperability项目地址https://gitcode.com/gh_mirrors/co/cosmos-sdk点击查看免费下载本指南以 Cosmos SDK 内置的账户与公钥体系为核心对应官方文档 docs/docs/learn/beginner/03-accounts.md系统讲解账户的构成、HD 钱包的 BIP32/BIP44 派生过程、三类链上地址的 Bech32 编码规则以及Keyring密钥管理器的核心接口与扩展方式。读完本文你将掌握 Cosmos SDK 中从「助记词 → 私钥 → 公钥 → 地址」的完整链路理解各密钥方案的适用场景并具备为 Keyring 注册自定义签名算法如 secp256r1的实战能力。账户定义公钥、私钥与地址的三角关系在 Cosmos SDK 中一个account账户本质上是一对密钥公钥PubKey与私钥PrivKey。PubKey可以被派生哈希出各种Addresses这些地址用于在应用内标识用户及其他参与方。Addresses同时与 message 关联用于标识消息的发送者。PrivKey用于生成数字签名以证明某个与该PrivKey关联的Address确实批准了给定的message。从源码结构看这一对密钥类型在 crypto/types/types.go 中定义PubKey接口扩展了proto.Message因为公钥需要被持久化到 store 中并提供Address()、Bytes()、VerifySignature(msg, sig []byte) bool、Type()等方法PrivKey接口扩展proto.Message与LedgerPrivKey提供Sign(msg []byte) ([]byte, error)与PubKey()等方法。HD 钱包从助记词到多层账户的 BIP32/BIP44 派生对于 HDHierarchical Deterministic分层确定性密钥派生Cosmos SDK 采用 BIP32 标准。BIP32 允许用户创建 BIP44 规范所定义的 HD 钱包——即一组由同一个初始秘密种子派生出的账户集合。一个种子通常由12 或 24 个单词的助记词mnemonic生成。利用单向密码学函数同一个种子可以派生任意数量的PrivKey再由PrivKey派生PubKey。助记词是最敏感的信息——只要助记词被妥善保存私钥就能随时重新生成。下图完整展示了从助记词到各个账户地址的分层派生关系Account 0 Account 1 Account 2 ------------------ ------------------ ------------------ | | | | | | | Address 0 | | Address 1 | | Address 2 | | ^ | | ^ | | ^ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Public key 0 | | Public key 1 | | Public key 2 | | ^ | | ^ | | ^ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Private key 0 | | Private key 1 | | Private key 2 | | ^ | | ^ | | ^ | ------------------ ------------------ ------------------ | | | | | | | | | -------------------------------------------------------------------- | | ------------------ | | | Master PrivKey | | | ------------------- | | ------------------ | | | Mnemonic (Seed) | | | -------------------从源码层面看BIP44 路径的解析与派生实现在 crypto/hd/hdpath.goNewParamsFromPathcrypto/hd/hdpath.go#L30-L101将形如m/44/118/0/0/0的路径拆分为 purpose、coinType、account、change、addressIndex 五个字段并严格校验首字段必须为44第二、三字段必须是 hardened带后缀第四、五字段不能 hardenedchange 只能是 0 或 1ComputeMastersFromSeed使用 HMAC-SHA512 与Bitcoin seed曲线标识符从种子计算主私钥与链码DerivePrivateKeyForPath沿路径逐级执行derivePrivateKey其中 hardened 派生在索引上加上0x80000000并使用私钥本身参与 HMAC非 hardened 派生则使用压缩公钥参与。在 Cosmos SDK 中密钥由名为Keyring的对象统一存储与管理。数字签名与支持的密钥方案用户认证的主要方式是数字签名用户用自己的私钥签署交易验证方用对应的公钥验签。为了在链上进行签名验证公钥会随同其他交易校验所需数据一起存储在一个Account对象中。在节点中所有数据均使用 Protocol Buffers 序列化存储。Cosmos SDK 支持以下用于创建数字签名的密钥方案地址长度字节公钥长度字节用于交易认证用于共识CometBFTsecp256k12033yesnosecp256r13233yesnotm-ed25519-- 不使用 --32noyes几点说明secp256k1实现位于 crypto/keys/secp256k1是最常用的账户签名算法secp256r1NIST P-256 曲线实现位于 crypto/keys/secp256r1同样可用于交易认证tm-ed25519实现位于 crypto/keys/ed25519仅用于共识验证不作为普通用户交易签名方案。需要留意版本差异当前仓库的 crypto/hd/algo.go#L13-L29 还定义了bls12_381与ml_dsa_65NIST ML-DSA-65FIPS 204 后量子签名方案等PubKeyType其中 ML-DSA-65 已可用于软件 Keyring 的账户密钥生成。地址体系AccAddress、ValAddress 与 ConsAddressAddresses与PubKey都是标识应用中参与方的公开信息而Account用于存储认证信息其基本实现是BaseAccount对象。每个账户用Address一串从公钥派生的字节序列来标识。Cosmos SDK 定义了3 种地址类型用于指明账户的使用场景AccAddress标识用户即message的发送者ValAddress标识验证人操作者validator operatorConsAddress标识参与共识的验证人节点验证人节点使用ed25519曲线派生。这三种类型都实现Address接口见 types/address.go#L126-L134// Address is a common interface for different types of addresses used by the SDK type Address interface { Equals(Address) bool Empty() bool Marshal() ([]byte, error) MarshalJSON() ([]byte, error) Bytes() []byte String() string Format(s fmt.State, verb rune) }在 types/address.go#L136-L141 中AccAddress、ValAddress、ConsAddress三个类型均被断言实现了该接口。地址构造算法定义于 ADR-28从公钥pub获取账户地址的标准写法是sdk.AccAddress(pub.Address().Bytes())值得注意的是Marshal()与Bytes()返回的都是地址的原始[]byte形式——Marshal()的存在只是为了满足 Protobuf 兼容性要求。Bech32 编码与地址前缀在与用户交互时地址使用 Bech32。Bech32 是与区块链交互时唯一支持的地址格式其人类可读部分HRP即 Bech32 前缀用于标识地址类型地址 Bech32 前缀AccountscosmosValidator OperatorcosmosvaloperConsensus Nodescosmosvalcons从前缀定义源码types/address.go#L38-L76可以看到这些前缀的拼接规则主前缀cosmosBech32MainPrefix加上valoper/valcons等子前缀例如Bech32PrefixValAddr Bech32MainPrefix PrefixValidator PrefixOperator。同时 SDK 还定义了对应的公钥前缀cosmospub、cosmosvaloperpub、cosmosvalconspub用于 Bech32 编码公钥。AccAddressFromBech32types/address.go#L193-L212则是反向解析先用当前配置中的账户前缀通过GetFromBech32解码再调用VerifyAddressFormat校验长度不能为空、不能超过address.MaxAddrLen。此外 types/address.go#L100-L123 显示 SDK 为三类地址分别维护了 LRU 缓存账户地址 60000 条、验证人与共识地址各 500 条用于加速高频的地址字符串化操作。公钥Public KeysCosmos SDK 中的公钥由cryptotypes.PubKey接口定义。由于公钥需要存入 storecryptotypes.PubKey扩展了proto.Message接口见 crypto/types/types.go#L8-L17// PubKey defines a public key and extends proto.Message. type PubKey interface { proto.Message Address() Address Bytes() []byte VerifySignature(msg, sig []byte) bool Equals(PubKey) bool Type() string }secp256k1与secp256r1使用压缩格式序列化若y坐标是两个与x坐标相关联的值中字典序较大的那个首字节为0x02否则首字节为0x03该前缀之后紧跟x坐标。公钥不用于引用账户或用户一般来说也不在构造交易消息时使用少数例外MsgCreateValidator、Validator与Multisig消息。在与用户交互时PubKey使用 Protobuf JSON 格式化ProtoMarshalJSON函数见 codec/json.go。CLI 中的实际输出结构定义在 client/keys/output.go#L23-L39即KeyOutput结构体它包含name、type、address、pubkey以及可选的mnemonic字段其中pubkey通过codectypes.NewAnyWithValue(pk)与codec.ProtoMarshalJSON编码为 JSON。Keyring密钥管理器Keyring是存储与管理账户的对象其实现遵循Keyring接口见 crypto/keyring/keyring.go#L58-L106。默认实现来自第三方库99designs/keyring。从 crypto/keyring/keyring.go#L31-L39 可以看到Keyring 支持多种后端backend后端常量值说明BackendFilefile文件系统存储BackendOSos操作系统原生密钥环BackendKWalletkwalletKDE Wallet 服务BackendPasspasspass 密码管理器BackendTesttest测试用后端BackendMemorymemory内存后端NewInMemory适合测试核心方法剖析Sign(uid string, msg []byte, signMode signing.SignMode) ([]byte, types.PubKey, error)只负责对msg字节进行签名。调用方必须先把交易准备并编码为规范的[]byte形式。由于 Protobuf 本身不确定ADR-020 决定用于签名的规范payload是SignDoc结构体并使用 ADR-027 所述方法做确定性编码。signMode参数控制使用哪种签名模式例如SIGN_MODE_DIRECT或SIGN_MODE_LEGACY_AMINO_JSON从而决定msg字节如何产生。SignDoc的定义见 proto/cosmos/tx/v1beta1/tx.proto#L50-L67// SignDoc is the type used for generating sign bytes for SIGN_MODE_DIRECT. message SignDoc { // body_bytes is protobuf serialization of a TxBody that matches the // representation in TxRaw. bytes body_bytes 1; // auth_info_bytes is a protobuf serialization of an AuthInfo that matches the // representation in TxRaw. bytes auth_info_bytes 2; // chain_id is the unique identifier of the chain this transaction targets. // It prevents signed transactions from being used on another chain by an // attacker string chain_id 3; // account_number is the account number of the account in state uint64 account_number 4; }注意Cosmos SDK 默认不实现签名验证验签被推迟到anteHandler中执行。从 crypto/keyring/keyring.go#L398-L429 的实现可以看到Sign的三种分支local类型密钥直接调用priv.Sign(msg)ledger类型调用SignWithLedger交给硬件钱包multi/offline类型无本地私钥返回ErrOfflineSign。NewAccount(uid, mnemonic, bip39Passphrase, hdPath string, algo SignatureAlgo) (*Record, error)基于 BIP44 路径创建新账户并持久化到磁盘。私钥绝不会以明文存储而是先用口令passphrase加密实现见 crypto/armor.go其中EncryptArmorPrivKey使用 bcrypt 或 argon2 等 KDF 派生密钥后加密为 ASCII armor 格式。在该方法中密钥类型与序号指的是 BIP44 派生路径中用于从助记词派生出私钥/公钥的分段例如0、1、2……。使用相同的助记词与派生路径必然生成相同的PrivKey、PubKey与Address。Keyring 支持以下密钥算法以当前仓库 crypto/keyring/keyring.go#L209-L215 的默认注册为准secp256k1ml_dsa_65后量子签名方案 ML-DSA-65软件 Keyring 可用Ledger 等硬件钱包暂不支持说明原文档基于 v0.53.0所列的默认算法为secp256k1与ed25519当前仓库默认注册表为hd.Secp256k1与hd.MlDsa65且 Ledger 后端仅支持secp256k1。请以你所基于的 SDK 版本实际代码为准。ExportPrivKeyArmor(uid, encryptPassphrase string) (armor string, err error)使用给定口令将私钥导出为 ASCII-armored 加密格式。之后既可以用ImportPrivKey(uid, armor, passphrase string)重新导入 Keyring也可以调用UnarmorDecryptPrivKey(armorStr string, passphrase string)解密得到原始私钥。实现见 crypto/keyring/keyring.go#L283-L291先通过ExportPrivateKeyObject取出私钥对象再调用crypto.EncryptArmorPrivKey加密。另外NewMnemoniccrypto/keyring/keyring.go#L558-L589会直接从系统熵生成默认 24 词助记词defaultEntropySize再由助记词派生并持久化密钥若bip39Passphrase为空则使用DefaultBIP39Passphrase。为 Keyring 创建新的密钥类型要新增一种可供 Keyring 使用的密钥类型必须实现keyring.SignatureAlgo接口见 crypto/keyring/signing_algorithms.go#L11-L16// SignatureAlgo defines the interface for a keyring supported algorithm. type SignatureAlgo interface { Name() hd.PubKeyType Derive() hd.DeriveFn Generate() hd.GenerateFn }其中Name()以hd.PubKeyType返回算法名Derive()与Generate()必须分别返回如下类型的函数见 crypto/hd/algo.go#L28-L37type ( DeriveFn func(mnemonic, bip39Passphrase, hdPath string) ([]byte, error) GenerateFn func(bz []byte) types.PrivKey )实现好keyring.SignatureAlgo后需要把它加入 Keyring 的 supported algos 列表。为了简洁新密钥类型的实现应放在crypto/hd包内可参考 crypto/hd/algo.go 中secp256k1Algo的现成实现如Secp256k1 secp256k1Algo{}与Derive/Generate方法。以 secp256r1 为例的完整实现以下演示如何实现 secp256r1 算法来自原文档的官方示例路径标注亦沿用文档。首先需要在 secp256r1 包中新增一个从秘密数值创建私钥的函数// cosmos-sdk/crypto/keys/secp256r1/privkey.go // NewPrivKeyFromSecret creates a private key derived from the secret number // represented in big-endian. The secret must be a valid ECDSA field element. func NewPrivKeyFromSecret(secret []byte) (*PrivKey, error) { var d new(big.Int).SetBytes(secret) if d.Cmp(secp256r1.Params().N) 1 { return nil, errorsmod.Wrap(errors.ErrInvalidRequest, secret not in the curve base field) } sk : new(ecdsa.PrivKey) return PrivKey{ecdsaSK{*sk}}, nil }然后实现secp256r1Algo// cosmos-sdk/crypto/hd/secp256r1Algo.go package hd import ( github.com/cosmos/go-bip39 github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1 github.com/cosmos/cosmos-sdk/crypto/types ) // Secp256r1Type uses the secp256r1 ECDSA parameters. const Secp256r1Type PubKeyType(secp256r1) var Secp256r1 secp256r1Algo{} type secp256r1Algo struct{} func (s secp256r1Algo) Name() PubKeyType { return Secp256r1Type } // Derive derives and returns the secp256r1 private key for the given seed and HD path. func (s secp256r1Algo) Derive() DeriveFn { return func(mnemonic string, bip39Passphrase, hdPath string) ([]byte, error) { seed, err : bip39.NewSeedWithErrorChecking(mnemonic, bip39Passphrase) if err ! nil { return nil, err } masterPriv, ch : ComputeMastersFromSeed(seed) if len(hdPath) 0 { return masterPriv[:], nil } derivedKey, err : DerivePrivateKeyForPath(masterPriv, ch, hdPath) return derivedKey, err } } // Generate generates a secp256r1 private key from the given bytes. func (s secp256r1Algo) Generate() GenerateFn { return func(bz []byte) types.PrivKey { key, err : secp256r1.NewPrivKeyFromSecret(bz) if err ! nil { panic(err) } return key } }最后把该算法注册进 Keyring 的 supported algos 列表// cosmos-sdk/crypto/keyring/keyring.go func newKeystore(kr keyring.Keyring, cdc codec.Codec, backend string, opts ...Option) keystore { // Default options for keybase, these can be overwritten using the // Option function options : Options{ SupportedAlgos: SigningAlgoList{hd.Secp256k1, hd.Secp256r1}, // added here SupportedAlgosLedger: SigningAlgoList{hd.Secp256k1}, } ...注册完成后创建密钥时用--algo标志指定算法即可simd keys add myKey --algo secp256r1对应的 CLI 标志定义在 client/flags/flags.go#L77FlagKeyType key-type默认值为secp256k1见 client/keys/add.go#L94用户在keys add时通过--key-type/--algo选择算法SDK 再用keyring.NewSigningAlgoFromString从受支持算法列表中解析client/keys/add.go#L151-L152。小结账户 一对密钥PubKey派生地址并标识消息发送者PrivKey生成数字签名完成认证两者由 crypto/types/types.go 中接口统一定义。HD 派生助记词 → 种子 → BIP44 路径逐级派生私钥/公钥/地址路径解析与派生逻辑见 crypto/hd/hdpath.go。三类地址AccAddress用户、ValAddress验证人操作者、ConsAddress共识节点统一实现 types/address.go 中的Address接口交互时以 Bech32 编码并携带不同前缀。Keyring 管理密钥支持file/os/memory/test等多种后端Sign处理规范化的SignDoc字节私钥以口令加密后落盘验签则交由anteHandler在链上完成。可扩展性实现keyring.SignatureAlgoName/Derive/Generate三方法并注册到 supported algos即可通过 CLI 的--algo标志启用新的签名算法。建议进阶阅读Anatomy of a Cosmos SDK Application 了解应用整体结构messages 概念 理解地址在消息路由中的作用ADR-028 掌握地址构造算法的完整规范。赞分享区块链【免费下载链接】cosmos-sdkFramework for building performant, customizable blockchains with native interoperability项目地址https://gitcode.com/gh_mirrors/co/cosmos-sdk点击查看免费下载相关推荐以太坊密码学全解析从密钥派生、Keccak-256 地址到 BLS 签名聚合与 KZG 承诺以太坊密码学全解析从密钥派生、Keccak 256 地址到 BLS 签名聚合与 KZG 承诺 本文基于《Mastering Ethereum精通以太坊第文档教程区块链Cosmos SDK 密钥环(Keyring)配置与使用指南Cosmos SDK 密钥环 Keyring 配置与使用指南 密钥环概述 在Cosmos SDK构建的区块链应用中密钥环 Keyring 是管理公私钥对的核心区块链Diem 账户体系详解地址推导、认证密钥、资源结构与账户角色Diem 账户体系详解地址推导、认证密钥、资源结构与账户角色 本篇技术指南以 Diem 开发者文档《Accounts》为核心系统讲解 Diem 区块链的账户区块链金融科技上一篇GTA5防护增强工具YimMenu新手安全使用完全指南下一篇Duktape 贡献指南从 Fork 分支到合并的完整实践流程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?