如何使用Generics统一签名曲线



我希望构建一个结构,将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);
}

我不想为我想要支持的所有曲线创建structs和impl,然后想办法将它们统一到最终的结构中。

因此,要么我在概念上对泛型有根本性的错误,要么RustCrypto签名板条箱的实现足够奇怪,以至于它们不可能是泛型的。

我哪里做错了?

感谢Rustlang论坛,我最终提出了以下内容:

基本上每一个通用上游代码都提到,你也必须提到。。。Rust目前不执行隐式泛型边界。

#![allow(dead_code, unused_imports)]
use ecdsa::{
hazmat::{DigestPrimitive, SignPrimitive},
signature::{DigestSigner, Signer},
PrimeCurve, SignatureSize, SigningKey,
};
use elliptic_curve::{
generic_array::ArrayLength, Curve, ProjectiveArithmetic, ScalarArithmetic, SecretKey,
};
use k256::Secp256k1;
use p256::NistP256;
use p384::NistP384;
use rand_core::OsRng;
#[derive(Debug)]
pub struct Signature<T: Curve + PrimeCurve>
where
SignatureSize<T>: ArrayLength<u8>,
{
signature: ecdsa::Signature<T>,
}
impl<T> Signature<T>
where
T: PrimeCurve,
SignatureSize<T>: ArrayLength<u8>,
{
pub fn sign(secret_key: SecretKey<T>, message: &[u8]) -> Signature<T>
where
T: PrimeCurve + ScalarArithmetic + ProjectiveArithmetic + DigestPrimitive,
T::Scalar: SignPrimitive<T>,
SigningKey<T>: DigestSigner<T::Digest, ecdsa::Signature<T>>,
{
let signing_key = SigningKey::from(&secret_key);
let signature = signing_key.sign(&message);
Self { signature }
}
}
fn main() {
let key: SecretKey<Secp256k1> = SecretKey::random(&mut OsRng);
let sig: Signature<Secp256k1> = Signature::sign(key, "foo".as_bytes());
dbg!(sig);
}

最新更新