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
ecdsa: implement RustCrypto/traits#223 updates
Updates usages of the `elliptic-curve` crate API
  • Loading branch information
tarcieri committed Jul 27, 2020
commit 7ba2cbf60e71feda7b9c6f6aadbd1444ec7bd6e3
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

85 changes: 47 additions & 38 deletions ecdsa/src/asn1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
// <https://www.bearssl.org/gitweb/?p=BearSSL;a=blob;f=src/ec/ecdsa_rta.c>

use crate::{
generic_array::{ArrayLength, GenericArray},
generic_array::{typenum::Unsigned, ArrayLength, GenericArray},
Error,
};
use core::{
convert::{TryFrom, TryInto},
fmt,
ops::{Add, Range},
};
use elliptic_curve::{consts::U9, ScalarBytes};
use elliptic_curve::{consts::U9, weierstrass::Curve, ScalarBytes};

/// Maximum overhead of an ASN.1 DER-encoded ECDSA signature for a given curve:
/// 9-bytes.
Expand All @@ -34,10 +34,11 @@ use elliptic_curve::{consts::U9, ScalarBytes};
pub type MaxOverhead = U9;

/// Maximum size of an ASN.1 DER encoded signature for the given elliptic curve.
pub type MaxSize<ScalarSize> = <<ScalarSize as Add>::Output as Add<MaxOverhead>>::Output;
pub type MaxSize<C> =
<<<C as elliptic_curve::Curve>::ElementSize as Add>::Output as Add<MaxOverhead>>::Output;

/// Byte array containing a serialized ASN.1 signature
type DocumentBytes<ScalarSize> = GenericArray<u8, MaxSize<ScalarSize>>;
type DocumentBytes<C> = GenericArray<u8, MaxSize<C>>;

/// ASN.1 `INTEGER` tag
const INTEGER_TAG: u8 = 0x02;
Expand All @@ -48,14 +49,15 @@ const SEQUENCE_TAG: u8 = 0x30;
/// ASN.1 DER-encoded signature.
///
/// Generic over the scalar size of the elliptic curve.
pub struct Signature<ScalarSize>
pub struct Signature<C>
where
ScalarSize: Add + ArrayLength<u8>,
MaxSize<ScalarSize>: ArrayLength<u8>,
<ScalarSize as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
C: Curve,
C::ElementSize: Add + ArrayLength<u8>,
MaxSize<C>: ArrayLength<u8>,
<C::ElementSize as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
{
/// ASN.1 DER-encoded signature data
bytes: DocumentBytes<ScalarSize>,
bytes: DocumentBytes<C>,

/// Range of the `r` value within the signature
r_range: Range<usize>,
Expand All @@ -64,11 +66,12 @@ where
s_range: Range<usize>,
}

impl<ScalarSize> signature::Signature for Signature<ScalarSize>
impl<C> signature::Signature for Signature<C>
where
ScalarSize: Add + ArrayLength<u8>,
MaxSize<ScalarSize>: ArrayLength<u8>,
<ScalarSize as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
C: Curve,
C::ElementSize: Add + ArrayLength<u8>,
MaxSize<C>: ArrayLength<u8>,
<C::ElementSize as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
{
/// Parse an ASN.1 DER-encoded ECDSA signature from a byte slice
fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
Expand All @@ -77,23 +80,24 @@ where
}

#[allow(clippy::len_without_is_empty)]
impl<ScalarSize> Signature<ScalarSize>
impl<C> Signature<C>
where
ScalarSize: Add + ArrayLength<u8>,
MaxSize<ScalarSize>: ArrayLength<u8>,
<ScalarSize as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
C: Curve,
C::ElementSize: Add + ArrayLength<u8>,
MaxSize<C>: ArrayLength<u8>,
<C::ElementSize as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
{
/// Get the length of the signature in bytes
pub fn len(&self) -> usize {
self.s_range.end
}

/// Create an ASN.1 DER encoded signature from the `r` and `s` scalars
pub(crate) fn from_scalars(r: &ScalarBytes<ScalarSize>, s: &ScalarBytes<ScalarSize>) -> Self {
pub(crate) fn from_scalars(r: &ScalarBytes<C>, s: &ScalarBytes<C>) -> Self {
let r_len = int_length(r);
let s_len = int_length(s);
let scalar_size = ScalarSize::to_usize();
let mut bytes = DocumentBytes::<ScalarSize>::default();
let scalar_size = C::ElementSize::to_usize();
let mut bytes = DocumentBytes::<C>::default();

// SEQUENCE header
bytes[0] = SEQUENCE_TAG as u8;
Expand Down Expand Up @@ -132,22 +136,24 @@ where
}
}

impl<ScalarSize> AsRef<[u8]> for Signature<ScalarSize>
impl<C> AsRef<[u8]> for Signature<C>
where
ScalarSize: Add + ArrayLength<u8>,
MaxSize<ScalarSize>: ArrayLength<u8>,
<ScalarSize as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
C: Curve,
C::ElementSize: Add + ArrayLength<u8>,
MaxSize<C>: ArrayLength<u8>,
<C::ElementSize as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
{
fn as_ref(&self) -> &[u8] {
&self.bytes.as_slice()[..self.len()]
}
}

impl<ScalarSize> fmt::Debug for Signature<ScalarSize>
impl<C> fmt::Debug for Signature<C>
where
ScalarSize: Add + ArrayLength<u8>,
MaxSize<ScalarSize>: ArrayLength<u8>,
<ScalarSize as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
C: Curve,
C::ElementSize: Add + ArrayLength<u8>,
MaxSize<C>: ArrayLength<u8>,
<C::ElementSize as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("asn1::Signature")
Expand All @@ -157,11 +163,12 @@ where
}
}

impl<ScalarSize> TryFrom<&[u8]> for Signature<ScalarSize>
impl<C> TryFrom<&[u8]> for Signature<C>
where
ScalarSize: Add + ArrayLength<u8>,
MaxSize<ScalarSize>: ArrayLength<u8>,
<ScalarSize as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
C: Curve,
C::ElementSize: Add + ArrayLength<u8>,
MaxSize<C>: ArrayLength<u8>,
<C::ElementSize as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
{
type Error = Error;

Expand Down Expand Up @@ -198,20 +205,20 @@ where
}

// First INTEGER (r)
let r_range = parse_int(&bytes[offset..], ScalarSize::to_usize())?;
let r_range = parse_int(&bytes[offset..], C::ElementSize::to_usize())?;
let r_start = offset.checked_add(r_range.start).unwrap();
let r_end = offset.checked_add(r_range.end).unwrap();

// Second INTEGER (s)
let s_range = parse_int(&bytes[r_end..], ScalarSize::to_usize())?;
let s_range = parse_int(&bytes[r_end..], C::ElementSize::to_usize())?;
let s_start = r_end.checked_add(s_range.start).unwrap();
let s_end = r_end.checked_add(s_range.end).unwrap();

if s_end != bytes.as_ref().len() {
return Err(Error::new());
}

let mut byte_arr = DocumentBytes::<ScalarSize>::default();
let mut byte_arr = DocumentBytes::<C>::default();
byte_arr[..s_end].copy_from_slice(bytes.as_ref());

Ok(Signature {
Expand Down Expand Up @@ -311,16 +318,18 @@ fn trim_zeroes(mut bytes: &[u8], scalar_size: usize) -> Result<usize, Error> {

#[cfg(test)]
mod tests {
use elliptic_curve::{consts::U32, weierstrass::Curve};
use elliptic_curve::consts::U32;
use signature::Signature as _;

#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)]
pub struct ExampleCurve;

impl Curve for ExampleCurve {
type ScalarSize = U32;
impl elliptic_curve::Curve for ExampleCurve {
type ElementSize = U32;
}

impl elliptic_curve::weierstrass::Curve for ExampleCurve {}

type Signature = crate::Signature<ExampleCurve>;

const EXAMPLE_SIGNATURE: [u8; 64] = [
Expand Down
6 changes: 3 additions & 3 deletions ecdsa/src/hazmat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ where
&self,
ephemeral_scalar: &Self::Scalar,
masking_scalar: Option<&Self::Scalar>,
hashed_msg: &ScalarBytes<C::ScalarSize>,
hashed_msg: &ScalarBytes<C>,
) -> Result<Signature<C>, Error>;
}

Expand All @@ -66,7 +66,7 @@ where
/// - `signature`: signature to be verified against the key and message
fn verify_prehashed(
&self,
hashed_msg: &ScalarBytes<C::ScalarSize>,
hashed_msg: &ScalarBytes<C>,
signature: &Signature<C>,
) -> Result<(), Error>;
}
Expand All @@ -92,7 +92,7 @@ pub trait DigestPrimitive: Curve {
#[cfg(feature = "digest")]
impl<C: DigestPrimitive> PrehashSignature for Signature<C>
where
<C::ScalarSize as core::ops::Add>::Output: ArrayLength<u8>,
<C::ElementSize as core::ops::Add>::Output: ArrayLength<u8>,
{
type Digest = C::Digest;
}
42 changes: 21 additions & 21 deletions ecdsa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ use elliptic_curve::ScalarBytes;
use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};

/// Size of a fixed sized signature for the given elliptic curve.
pub type SignatureSize<C> = <<C as Curve>::ScalarSize as Add>::Output;
pub type SignatureSize<C> = <<C as elliptic_curve::Curve>::ElementSize as Add>::Output;

/// Fixed-size byte array containing an ECDSA signature
pub type SignatureBytes<C> = GenericArray<u8, SignatureSize<C>>;
Expand Down Expand Up @@ -86,9 +86,9 @@ where
SignatureSize<C>: ArrayLength<u8>,
{
/// Create a [`Signature`] from the serialized `r` and `s` components
pub fn from_scalars(r: &ScalarBytes<C::ScalarSize>, s: &ScalarBytes<C::ScalarSize>) -> Self {
pub fn from_scalars(r: &ScalarBytes<C>, s: &ScalarBytes<C>) -> Self {
let mut bytes = SignatureBytes::<C>::default();
let scalar_size = C::ScalarSize::to_usize();
let scalar_size = C::ElementSize::to_usize();
bytes[..scalar_size].copy_from_slice(r.as_slice());
bytes[scalar_size..].copy_from_slice(s.as_slice());
Signature { bytes }
Expand All @@ -97,31 +97,31 @@ where
/// Parse a signature from ASN.1 DER
pub fn from_asn1(bytes: &[u8]) -> Result<Self, Error>
where
C::ScalarSize: Add + ArrayLength<u8>,
asn1::MaxSize<C::ScalarSize>: ArrayLength<u8>,
<C::ScalarSize as Add>::Output: Add<asn1::MaxOverhead> + ArrayLength<u8>,
C::ElementSize: Add + ArrayLength<u8>,
asn1::MaxSize<C>: ArrayLength<u8>,
<C::ElementSize as Add>::Output: Add<asn1::MaxOverhead> + ArrayLength<u8>,
{
asn1::Signature::<C::ScalarSize>::try_from(bytes).map(Into::into)
asn1::Signature::<C>::try_from(bytes).map(Into::into)
}

/// Serialize this signature as ASN.1 DER
pub fn to_asn1(&self) -> asn1::Signature<C::ScalarSize>
pub fn to_asn1(&self) -> asn1::Signature<C>
where
C::ScalarSize: Add + ArrayLength<u8>,
asn1::MaxSize<C::ScalarSize>: ArrayLength<u8>,
<C::ScalarSize as Add>::Output: Add<asn1::MaxOverhead> + ArrayLength<u8>,
C::ElementSize: Add + ArrayLength<u8>,
asn1::MaxSize<C>: ArrayLength<u8>,
<C::ElementSize as Add>::Output: Add<asn1::MaxOverhead> + ArrayLength<u8>,
{
asn1::Signature::from_scalars(self.r(), self.s())
}

/// Get the `r` component of this signature
pub fn r(&self) -> &ScalarBytes<C::ScalarSize> {
ScalarBytes::from_slice(&self.bytes[..C::ScalarSize::to_usize()])
pub fn r(&self) -> &ScalarBytes<C> {
ScalarBytes::<C>::from_slice(&self.bytes[..C::ElementSize::to_usize()])
}

/// Get the `s` component of this signature
pub fn s(&self) -> &ScalarBytes<C::ScalarSize> {
ScalarBytes::from_slice(&self.bytes[C::ScalarSize::to_usize()..])
pub fn s(&self) -> &ScalarBytes<C> {
ScalarBytes::<C>::from_slice(&self.bytes[C::ElementSize::to_usize()..])
}
}

Expand Down Expand Up @@ -174,16 +174,16 @@ where
}
}

impl<C> From<asn1::Signature<C::ScalarSize>> for Signature<C>
impl<C> From<asn1::Signature<C>> for Signature<C>
where
C: Curve,
C::ScalarSize: Add + ArrayLength<u8>,
asn1::MaxSize<C::ScalarSize>: ArrayLength<u8>,
<C::ScalarSize as Add>::Output: Add<asn1::MaxOverhead> + ArrayLength<u8>,
C::ElementSize: Add + ArrayLength<u8>,
asn1::MaxSize<C>: ArrayLength<u8>,
<C::ElementSize as Add>::Output: Add<asn1::MaxOverhead> + ArrayLength<u8>,
{
fn from(doc: asn1::Signature<C::ScalarSize>) -> Signature<C> {
fn from(doc: asn1::Signature<C>) -> Signature<C> {
let mut bytes = SignatureBytes::<C>::default();
let scalar_size = C::ScalarSize::to_usize();
let scalar_size = C::ElementSize::to_usize();
let r_begin = scalar_size.checked_sub(doc.r().len()).unwrap();
let s_begin = bytes.len().checked_sub(doc.s().len()).unwrap();

Expand Down