了解 secp256k1 与 多签钱包

发布: (2026年2月13日 GMT+8 01:11)
9 分钟阅读
原文: Dev.to

Source: Dev.to

理解 secp256k1 与多签钱包的封面图片

“我们需要的是一种基于密码学证明而非信任的电子支付系统。” — 中本聪

每天,数以百万计的交易在比特币和以太坊网络中流动。然而,令人惊讶的是,真正理解支撑这一切的密码学基础——secp256k1(为两条区块链提供动力的椭圆曲线)的开发者寥寥无几。

在构建我的 Rust 多签钱包 时,我意识到大多数开发者(包括我自己起初)都把椭圆曲线密码学当作黑盒。我们只会导入库、调用函数,并相信魔法会自行发生。

本文将改变这种现状。我们将揭开 secp256k1 的神秘面纱,探讨多签钱包的工作原理,并说明为什么 Rust 是构建密码系统的完美语言。

区块链统计数据

什么是 secp256k1?

secp256k1 是一个椭圆曲线,由以下简单方程(在有限域上)定义:

y² = x³ + 7

这个看似简单的方程产生了一条具有卓越特性的曲线:

  • 点加法 – 你可以“相加”曲线上的两个点得到第三个点。
  • 标量乘法 – 将一个点乘以整数会得到另一个点。
  • 单向函数 – 从私钥 → 公钥的转换很容易;而逆向过程在计算上是不可行的。

Elliptic Curve Visualization

为什么选择这条曲线?

比特币的创始人选择 secp256k1 有以下几个原因:

  • 效率 – 方程 y² = x³ + 7 没有 x 项,使得模运算更快。
  • 安全性 – 256 位的密钥空间提供约 2²⁵⁶ 个可能的密钥(比可观测宇宙中的原子还多)。
  • 非 NSA – 与某些 NIST 曲线不同,secp256k1 的参数并非由任何政府机构挑选。

Source:

如何使用密码学密钥

How Cryptography Works

私钥

256 位随机数,例如:

0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b

公钥

通过标量乘法得到曲线上的一点:

PublicKey = PrivateKey × G

其中 G 是生成点(secp256k1 上的固定点)。

地址

  1. 使用 SHA‑256 对公钥进行哈希,然后再使用 RIPEMD‑160。
  2. 添加版本字节和校验和。
  3. 编码(通常为 Base58Check) → 你的钱包地址。

多签钱包:共享所有权

什么是多签钱包?

需要 M out of N(M 署名中的 N)签名才能授权交易的钱包。

示例

M‑of‑N用例
2‑of‑3公司钱包(CEO、CFO、CTO——任意两人即可批准)
3‑of‑5DAO 金库(多数批准)
1‑of‑2个人备份(主钥匙 + 恢复钥匙)

Multisig transaction

为什么多签很重要

  • 安全性 – 没有单点故障;丢失一把钥匙不会危及资金。
  • 治理 – 重大决策需要共识。
  • 最小化信任 – 无需信任单一方。
  • 恢复 – 内置钥匙丢失的恢复机制。

用 Rust 构建:为什么?

Rust 不仅仅是一门流行的语言——它几乎是为密码学而生的。

// Rust's type system prevents common crypto bugs
pub struct PrivateKey([u8; 32]); // Exactly 32 bytes, no more, no less

impl PrivateKey {
    // Ownership system ensures keys aren't accidentally copied
    pub fn sign(&self, message: &[u8]) -> Signature {
        // Compile‑time guarantee of memory safety:
        // - No buffer overflows
        // - No use‑after‑free
    }
}

// Error handling forces you to deal with failures
match wallet.verify_signature(&tx, &sig) {
    Ok(valid) => { /* proceed */ }
    Err(e)   => { /* must handle error */ }
}

Rust 在密码学中的关键优势

  • 内存安全 – 防止缓冲区溢出、悬空指针和数据竞争。
  • 零成本抽象 – 高层次的易用性而没有运行时开销。
  • 强类型系统 – 防止混淆密钥、签名、哈希等。
  • 显式错误处理 – 强制开发者处理失败情况,减少静默错误。
  • Cargo 与 Crates.io – 轻松的依赖管理和可复现的构建(对安全审计至关重要)。

有了这些特性,Rust 让你能够自信地实现 secp256k1 操作和多签逻辑,因为编译器会为你把关。

祝编码愉快,愿你的密钥永远保密!

零成本抽象

高级代码编译为快速的汇编代码。

显式错误处理

加密失败不可忽视。

无垃圾回收

可预测的性能,没有意外的暂停。

用 Rust 构建:核心架构

以下是一个典型的 Rust 多签钱包结构示例。它展示了关键概念——完整实现位于我的 GitHub 仓库 中,包含了事务排队、增强的序列化以及更健壮的错误处理等附加功能:

// Core data structures
pub struct MultisigWallet {
    pub threshold: usize,        // M in M‑of‑N
    pub signers: Vec<PublicKey>, // N public keys
    pub nonce: u64,              // Prevent replay attacks
}

pub struct Transaction {
    pub to: Address,
    pub amount: u64,
    pub nonce: u64,
}

// The critical signing and verification functions
impl MultisigWallet {
    pub fn create_signature(
        &self,
        tx: &Transaction,
        private_key: &PrivateKey,
    ) -> Result<Signature, Error> {
        // Hash the transaction
        let msg_hash = hash_transaction(tx);

        // Sign with secp256k1
        sign_ecdsa(&msg_hash, private_key)
    }

    pub fn verify_and_execute(
        &mut self,
        tx: &Transaction,
        signatures: Vec<Signature>,
    ) -> Result<(), Error> {
        // Verify we have enough signatures
        if signatures.len() < self.threshold {
            return Err(Error::InsufficientSignatures);
        }

        // Verify each signature is from a valid signer
        let msg_hash = hash_transaction(tx);

        for sig in signatures.iter().take(self.threshold) {
            let pub_key = recover_public_key(&msg_hash, sig)?;

            if !self.signers.contains(&pub_key) {
                return Err(Error::UnauthorizedSigner);
            }
        }

        // Execute transaction
        self.execute_transaction(tx)
    }
}

我面临的挑战

1. 签名验证的边缘情况

挑战: 如果同一密钥签名两次会怎样?如果签名顺序错误会怎样?

解决方案: 从每个签名中恢复公钥并与签名者列表进行比对。使用 HashSet 来防止重复签名。

2. 交易重放攻击

挑战: 没有 nonce,攻击者可能会重放旧的有效交易。

解决方案: 包含一个随每笔交易递增的 nonce。旧的交易将失效。

3. 密钥序列化

挑战: 公钥可以是压缩的(33 bytes)或未压缩的(65 bytes)。

解决方案: 为保持一致性始终使用压缩格式。Rust 的类型系统有助于强制执行这一点。

我学到的

  • 密码学毫不宽容: 一个字节错误 = 完全失败。Rust 的严格性是特性,而非缺陷。
  • 测试至关重要: 使用已知向量、模糊测试和基于属性的测试。
  • 理解胜过记忆: 知道 secp256k1 为什么有效,使调试变得极其容易。
  • 错误处理即安全: 每个 Result 若处理不当都是潜在漏洞。

关键要点

关键要点

亲自尝试

完整实现已开源并有文档说明。您将看到:

  • 完整的 secp256k1 签名创建与验证。
  • M‑of‑N 多签钱包实现。
  • 交易序列化与哈希。
  • 全面的错误处理。
  • 包含已知向量的测试套件。

如果您觉得这有帮助,请留下评论或反馈。有任何问题?发现 bug?想要贡献?

打开 issue 或 PR —— 让我们一起构建安全的加密系统吧! 🦀

0 浏览
Back to Blog

相关文章

阅读更多 »

Rari – 基于 Rust 的 React 框架

文章:Rari – Rust 驱动的 React 框架 https://rari.build/ 评论:Hacker News 讨论 https://news.ycombinator.com/item?id=46993596 33 点,17 条评论…