Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 33 additions & 12 deletions ecdsa/src/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,28 @@ pub struct TestVector {
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! new_signing_test {
($vectors:expr) => {
($curve:path, $vectors:expr) => {
use core::convert::TryInto;
use $crate::generic_array::GenericArray;
use $crate::{
elliptic_curve::{Arithmetic, FromBytes},
generic_array::GenericArray,
hazmat::SignPrimitive,
};

#[test]
fn ecdsa_signing() {
for vector in $vectors {
let d = Scalar::from_bytes(vector.d.try_into().unwrap()).unwrap();
let k = Scalar::from_bytes(vector.k.try_into().unwrap()).unwrap();
let sig = d
.try_sign_prehashed(&k, GenericArray::from_slice(vector.m))
let d = <$curve as Arithmetic>::Scalar::from_bytes(vector.d.try_into().unwrap())
.unwrap();

let k = <$curve as Arithmetic>::Scalar::from_bytes(vector.k.try_into().unwrap())
.unwrap();

let z = <$curve as Arithmetic>::Scalar::from_bytes(vector.m.try_into().unwrap())
.unwrap();

let sig = d.try_sign_prehashed(&k, &z).unwrap();

assert_eq!(vector.r, sig.r().as_slice());
assert_eq!(vector.s, sig.s().as_slice());
}
Expand All @@ -55,8 +64,14 @@ macro_rules! new_signing_test {
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! new_verification_test {
($vectors:expr) => {
use $crate::elliptic_curve::sec1::EncodedPoint;
($curve:path, $vectors:expr) => {
use core::convert::TryInto;
use $crate::{
elliptic_curve::{sec1::EncodedPoint, Arithmetic, FromBytes},
generic_array::GenericArray,
hazmat::VerifyPrimitive,
Signature,
};

#[test]
fn ecdsa_verify_success() {
Expand All @@ -67,14 +82,17 @@ macro_rules! new_verification_test {
false,
);

let q: AffinePoint = q_encoded.decode().unwrap();
let q: <$curve as Arithmetic>::AffinePoint = q_encoded.decode().unwrap();

let z = <$curve as Arithmetic>::Scalar::from_bytes(vector.m.try_into().unwrap())
.unwrap();

let sig = Signature::from_scalars(
GenericArray::from_slice(vector.r),
GenericArray::from_slice(vector.s),
);

let result = q.verify_prehashed(GenericArray::from_slice(vector.m), &sig);
let result = q.verify_prehashed(&z, &sig);
assert!(result.is_ok());
}
}
Expand All @@ -88,15 +106,18 @@ macro_rules! new_verification_test {
false,
);

let q: AffinePoint = q_encoded.decode().unwrap();
let q: <$curve as Arithmetic>::AffinePoint = q_encoded.decode().unwrap();

let z = <$curve as Arithmetic>::Scalar::from_bytes(vector.m.try_into().unwrap())
.unwrap();

// Flip a bit in `s`
let mut s_tweaked = GenericArray::clone_from_slice(vector.s);
s_tweaked[0] ^= 1;

let sig = Signature::from_scalars(GenericArray::from_slice(vector.r), &s_tweaked);

let result = q.verify_prehashed(GenericArray::from_slice(vector.m), &sig);
let result = q.verify_prehashed(&z, &sig);
assert!(result.is_err());
}
}
Expand Down
16 changes: 7 additions & 9 deletions ecdsa/src/hazmat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@

use crate::{Signature, SignatureSize};
use core::borrow::Borrow;
use elliptic_curve::{
generic_array::ArrayLength, ops::Invert, weierstrass::Curve, Arithmetic, ElementBytes,
};
use elliptic_curve::{generic_array::ArrayLength, ops::Invert, weierstrass::Curve, Arithmetic};
use signature::Error;

#[cfg(feature = "digest")]
Expand All @@ -36,12 +34,12 @@ where
/// Accepts the following arguments:
///
/// - `ephemeral_scalar`: ECDSA `k` value. MUST BE UNIFORMLY RANDOM!!!
/// - `hashed_msg`: hashed message digest to be signed.
/// - `hashed_msg`: scalar computed from a hashed message digest to be signed.
/// MUST BE OUTPUT OF A CRYPTOGRAPHICALLY SECURE DIGEST ALGORITHM!!!
fn try_sign_prehashed<K: Borrow<C::Scalar> + Invert<Output = C::Scalar>>(
&self,
ephemeral_scalar: &K,
hashed_msg: &ElementBytes<C>,
hashed_msg: &C::Scalar,
) -> Result<Signature<C>, Error>;
}

Expand All @@ -64,7 +62,7 @@ where
fn try_sign_recoverable_prehashed<K: Borrow<C::Scalar> + Invert<Output = C::Scalar>>(
&self,
ephemeral_scalar: &K,
hashed_msg: &ElementBytes<C>,
hashed_msg: &C::Scalar,
) -> Result<Self::RecoverableSignature, Error>;
}

Expand All @@ -77,7 +75,7 @@ where
fn try_sign_prehashed<K: Borrow<C::Scalar> + Invert<Output = C::Scalar>>(
&self,
ephemeral_scalar: &K,
hashed_msg: &ElementBytes<C>,
hashed_msg: &C::Scalar,
) -> Result<Signature<C>, Error> {
self.try_sign_recoverable_prehashed(ephemeral_scalar, hashed_msg)
.map(Into::into)
Expand All @@ -91,7 +89,7 @@ where
/// particular curve's `AffinePoint` type.
pub trait VerifyPrimitive<C>
where
C: Curve,
C: Curve + Arithmetic,
SignatureSize<C>: ArrayLength<u8>,
{
/// Verify the prehashed message against the provided signature
Expand All @@ -103,7 +101,7 @@ where
/// - `signature`: signature to be verified against the key and message
fn verify_prehashed(
&self,
hashed_msg: &ElementBytes<C>,
hashed_msg: &C::Scalar,
signature: &Signature<C>,
) -> Result<(), Error>;
}
Expand Down
2 changes: 1 addition & 1 deletion ecdsa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![forbid(unsafe_code)]
#![warn(missing_docs, rust_2018_idioms, intra_doc_link_resolution_failure)]
#![warn(missing_docs, rust_2018_idioms)]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png",
html_root_url = "https://docs.rs/ecdsa/0.7.2"
Expand Down
67 changes: 33 additions & 34 deletions ecdsa/src/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,35 @@

// TODO(tarcieri): support for hardware crypto accelerators

mod rfc6979;
pub mod rfc6979;

use crate::{
hazmat::{DigestPrimitive, SignPrimitive},
Error, Signature, SignatureSize,
};
use elliptic_curve::{
generic_array::ArrayLength, ops::Invert, scalar::NonZeroScalar, weierstrass::Curve,
zeroize::Zeroize, Arithmetic, ElementBytes, FromBytes, FromDigest, SecretKey,
zeroize::Zeroize, Arithmetic, FromBytes, FromDigest, SecretKey,
};
use signature::{
digest::{BlockInput, Digest, FixedOutput, Reset, Update},
DigestSigner,
};

#[cfg(feature = "rand")]
use signature::{
rand_core::{CryptoRng, RngCore},
RandomizedDigestSigner, RandomizedSigner,
use {
elliptic_curve::ElementBytes,
signature::{
rand_core::{CryptoRng, RngCore},
RandomizedDigestSigner, RandomizedSigner,
},
};

/// ECDSA signer
pub struct Signer<C>
where
C: Curve + Arithmetic,
C::Scalar: Invert<Output = C::Scalar> + SignPrimitive<C> + Zeroize,
C::Scalar: FromDigest<C> + Invert<Output = C::Scalar> + SignPrimitive<C> + Zeroize,
SignatureSize<C>: ArrayLength<u8>,
{
secret_scalar: NonZeroScalar<C>,
Expand All @@ -39,7 +42,7 @@ where
impl<C> Signer<C>
where
C: Curve + Arithmetic,
C::Scalar: Invert<Output = C::Scalar> + SignPrimitive<C> + Zeroize,
C::Scalar: FromDigest<C> + Invert<Output = C::Scalar> + SignPrimitive<C> + Zeroize,
SignatureSize<C>: ArrayLength<u8>,
{
/// Create a new signer
Expand All @@ -48,9 +51,7 @@ where

// TODO(tarcieri): replace with into conversion when available (see subtle#73)
if scalar.is_some().into() {
Ok(Self {
secret_scalar: scalar.unwrap(),
})
Ok(Self::from(scalar.unwrap()))
} else {
Err(Error::new())
}
Expand All @@ -61,31 +62,25 @@ impl<C, D> DigestSigner<D, Signature<C>> for Signer<C>
where
C: Curve + Arithmetic,
C::Scalar: FromDigest<C> + Invert<Output = C::Scalar> + SignPrimitive<C> + Zeroize,
D: BlockInput<BlockSize = C::ElementSize>
+ FixedOutput<OutputSize = C::ElementSize>
+ Clone
+ Default
+ Reset
+ Update,
ElementBytes<C>: Zeroize,
D: FixedOutput<OutputSize = C::ElementSize> + BlockInput + Clone + Default + Reset + Update,
SignatureSize<C>: ArrayLength<u8>,
{
/// Sign message prehash using a deterministic ephemeral scalar (`k`)
/// computed using the algorithm described in RFC 6979 (Section 3.2):
/// <https://tools.ietf.org/html/rfc6979#section-3>
fn try_sign_digest(&self, digest: D) -> Result<Signature<C>, Error> {
let ephemeral_scalar = rfc6979::generate_k(&self.secret_scalar, digest.clone(), &[]);
let msg_scalar = C::Scalar::from_digest(digest);

self.secret_scalar
.as_ref()
.try_sign_prehashed(ephemeral_scalar.as_ref(), &digest.finalize())
.try_sign_prehashed(ephemeral_scalar.as_ref(), &msg_scalar)
}
}

impl<C> signature::Signer<Signature<C>> for Signer<C>
where
C: Curve + Arithmetic + DigestPrimitive,
C::Scalar: Invert<Output = C::Scalar> + SignPrimitive<C> + Zeroize,
C::Scalar: FromDigest<C> + Invert<Output = C::Scalar> + SignPrimitive<C> + Zeroize,
SignatureSize<C>: ArrayLength<u8>,
Self: DigestSigner<C::Digest, Signature<C>>,
{
Expand All @@ -100,13 +95,7 @@ impl<C, D> RandomizedDigestSigner<D, Signature<C>> for Signer<C>
where
C: Curve + Arithmetic,
C::Scalar: FromDigest<C> + Invert<Output = C::Scalar> + SignPrimitive<C> + Zeroize,
D: BlockInput<BlockSize = C::ElementSize>
+ FixedOutput<OutputSize = C::ElementSize>
+ Clone
+ Default
+ Reset
+ Update,
ElementBytes<C>: Zeroize,
D: FixedOutput<OutputSize = C::ElementSize> + BlockInput + Clone + Default + Reset + Update,
SignatureSize<C>: ArrayLength<u8>,
{
/// Sign message prehash using an ephemeral scalar (`k`) derived according
Expand All @@ -123,9 +112,10 @@ where
let ephemeral_scalar =
rfc6979::generate_k(&self.secret_scalar, digest.clone(), &added_entropy);

let msg_scalar = C::Scalar::from_digest(digest);

self.secret_scalar
.as_ref()
.try_sign_prehashed(ephemeral_scalar.as_ref(), &digest.finalize())
.try_sign_prehashed(ephemeral_scalar.as_ref(), &msg_scalar)
}
}

Expand All @@ -134,7 +124,7 @@ where
impl<C> RandomizedSigner<Signature<C>> for Signer<C>
where
C: Curve + Arithmetic + DigestPrimitive,
C::Scalar: Invert<Output = C::Scalar> + SignPrimitive<C> + Zeroize,
C::Scalar: FromDigest<C> + Invert<Output = C::Scalar> + SignPrimitive<C> + Zeroize,
SignatureSize<C>: ArrayLength<u8>,
Self: RandomizedDigestSigner<C::Digest, Signature<C>>,
{
Expand All @@ -147,11 +137,21 @@ where
}
}

impl<C> Zeroize for Signer<C>
impl<C> From<NonZeroScalar<C>> for Signer<C>
where
C: Curve + Arithmetic,
C::Scalar: Invert<Output = C::Scalar> + SignPrimitive<C> + Zeroize,
C::Scalar: FromDigest<C> + Invert<Output = C::Scalar> + SignPrimitive<C> + Zeroize,
SignatureSize<C>: ArrayLength<u8>,
{
fn from(secret_scalar: NonZeroScalar<C>) -> Self {
Self { secret_scalar }
}
}

impl<C> Zeroize for Signer<C>
where
C: Curve + Arithmetic,
C::Scalar: FromDigest<C> + Invert<Output = C::Scalar> + SignPrimitive<C> + Zeroize,
SignatureSize<C>: ArrayLength<u8>,
{
fn zeroize(&mut self) {
Expand All @@ -162,8 +162,7 @@ where
impl<C> Drop for Signer<C>
where
C: Curve + Arithmetic,
C::Scalar: Invert<Output = C::Scalar> + SignPrimitive<C> + Zeroize,

C::Scalar: FromDigest<C> + Invert<Output = C::Scalar> + SignPrimitive<C> + Zeroize,
SignatureSize<C>: ArrayLength<u8>,
{
fn drop(&mut self) {
Expand Down
Loading