如何用Rust泛型统一ECDSA签名曲线的实现?
问题:泛型ECDSA签名结构体构建失败
需求描述
需要构建一个可存储、支持序列化/反序列化的ECDSA签名结构体,作为更大结构的组成部分,该结构体可根据用户输入选择NIST P-256、NIST P-384或secp256k1曲线,且不想为每个支持的曲线单独编写结构体和实现逻辑。
尝试的泛型代码
#![allow(dead_code, unused_imports)] use ecdsa::{signature::Signer, SigningKey}; use elliptic_curve::{PublicKey, SecretKey}; use k256::Secp256k1; use p256::NistP256; use p384::NistP384; use rand_core::OsRng; #[derive(Debug)] pub struct Signature<T> { signature: ecdsa::Signature<T>, } impl<T> Signature<T> { pub fn sign(secret_key: SecretKey<T>, message: &[u8]) -> Signature<T> { let signature = SigningKey::from(&secret_key).sign(&message); Signature { signature } } } fn main() { let key: SecretKey<NistP256> = SecretKey::random(&mut OsRng); let sig: Signature<NistP256> = Signature::sign(key, "foo".as_bytes()); dbg!(sig); }
编译错误信息
error[E0277]: the trait bound `T: elliptic_curve::Curve` is not satisfied --> src/main.rs:16:29 | 16 | pub fn sign(secret_key: SecretKey<T>, message: &[u8]) -> Signature<T> { | ^^^^^^^^^^^^ the trait `elliptic_curve::Curve` is not implemented for `T` | note: required by a bound in `SecretKey` --> /home/xxx/.cargo/registry/src/github.com-1ecc6299db9ec823/elliptic-curve-0.12.3/src/secret_key.rs:84:25 | 84 | pub struct SecretKey<C: Curve> { | ^^^^^ required by this bound in `SecretKey` help: consider restricting type parameter `T` | 15 | impl<T: elliptic_curve::Curve> Signature<T> { | +++++++++++++++++++++++ error[E0277]: the trait bound `T: ecdsa::PrimeCurve` is not satisfied --> src/main.rs:12:16 | 12 | signature: ecdsa::Signature<T>, | ^^^^^^^^^^^^^^^^^^^ the trait `ecdsa::PrimeCurve` is not implemented for `T` | note: required by a bound in `ecdsa::Signature` --> /home/xxx/.cargo/registry/src/github.com-1ecc6299db9ec823/ecdsa-0.14.4/src/lib.rs:132:25 | 132 | pub struct Signature<C: PrimeCurve> | ^^^^^^^^^^ required by this bound in `ecdsa::Signature` help: consider restricting type parameter `T` | 11 | pub struct Signature<T: ecdsa::PrimeCurve> { | +++++++++++++++++++
单曲线可运行代码
针对NistP256单独编写的可正常运行代码:
#![allow(dead_code, unused_imports)] use ecdsa::{signature::Signer, SigningKey}; use elliptic_curve::{PublicKey, SecretKey}; use k256::Secp256k1; use p256::NistP256; use p384::NistP384; use rand_core::OsRng; #[derive(Debug)] pub struct Signature { signature: ecdsa::Signature<NistP256>, } impl Signature { pub fn sign(secret_key: SecretKey<NistP256>, message: &[u8]) -> Self { let signature = SigningKey::from(&secret_key).sign(&message); Self { signature } } } fn main() { let key: SecretKey<NistP256> = SecretKey::random(&mut OsRng); let sig: Signature = Signature::sign(key, "foo".as_bytes()); dbg!(sig); }
解决方案
错误的核心原因是泛型参数T缺少必要的 trait 约束。Rust泛型默认没有任何约束,编译器无法推断T满足SecretKey和ecdsa::Signature的类型要求,必须显式声明约束条件:
- 给
Signature<T>结构体的泛型T加上ecdsa::PrimeCurve约束,因为ecdsa::Signature<C>要求曲线类型C实现该trait; - 给impl块的泛型T加上
elliptic_curve::Curve和ecdsa::signature::Signer<ecdsa::Signature<T>>约束,前者是SecretKey<T>的必要条件,后者保证SigningKey可以对消息签名。
修改后的完整代码:
#![allow(dead_code, unused_imports)] use ecdsa::{signature::Signer, SigningKey, PrimeCurve}; use elliptic_curve::{Curve, PublicKey, SecretKey}; use k256::Secp256k1; use p256::NistP256; use p384::NistP384; use rand_core::OsRng; #[derive(Debug)] pub struct Signature<T: PrimeCurve> { signature: ecdsa::Signature<T>, } impl<T> Signature<T> where T: Curve + PrimeCurve, SigningKey<T>: Signer<ecdsa::Signature<T>>, { pub fn sign(secret_key: SecretKey<T>, message: &[u8]) -> Signature<T> { let signature = SigningKey::from(&secret_key).sign(&message); Signature { signature } } } fn main() { // 测试NIST P-256 let key_p256: SecretKey<NistP256> = SecretKey::random(&mut OsRng); let sig_p256: Signature<NistP256> = Signature::sign(key_p256, "foo".as_bytes()); dbg!(sig_p256); // 测试secp256k1 let key_k256: SecretKey<Secp256k1> = SecretKey::random(&mut OsRng); let sig_k256: Signature<Secp256k1> = Signature::sign(key_k256, "bar".as_bytes()); dbg!(sig_k256); // 测试NIST P-384 let key_p384: SecretKey<NistP384> = SecretKey::random(&mut OsRng); let sig_p384: Signature<NistP384> = Signature::sign(key_p384, "baz".as_bytes()); dbg!(sig_p384); }
如果需要支持序列化/反序列化,只需给Signature<T>添加#[derive(Serialize, Deserialize)],并在Cargo.toml中为各个曲线库启用serde特性(例如p256 = { version = "0.12", features = ["serde"] })。
内容的提问来源于stack exchange,提问作者Jason Belich
相关产品推荐
相关产品推荐

