Skip to content

Commit

Permalink
sec1: migrate from generic-array to hybrid-array
Browse files Browse the repository at this point in the history
The RustCrypto/traits crates are now using `hybrid-array`, which
features a mostly safe implementation that natively leverages const
generics as much as possible.
  • Loading branch information
tarcieri committed Jan 4, 2024
1 parent 9b65d8b commit 1bdb7f7
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 40 deletions.
11 changes: 10 additions & 1 deletion Cargo.lock

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

4 changes: 2 additions & 2 deletions sec1/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ rust-version = "1.70"
[dependencies]
base16ct = { version = "0.2", optional = true, default-features = false }
der = { version = "=0.8.0-pre", optional = true, features = ["oid"] }
generic-array = { version = "0.14.7", optional = true, default-features = false }
hybrid-array = { version = "=0.2.0-pre.8", optional = true, default-features = false }
pkcs8 = { version = "=0.11.0-pre", optional = true, default-features = false }
serdect = { version = "=0.3.0-pre", optional = true, default-features = false, features = ["alloc"] }
subtle = { version = "2", optional = true, default-features = false }
Expand All @@ -35,7 +35,7 @@ std = ["alloc", "der?/std"]

der = ["dep:der", "zeroize"]
pem = ["alloc", "der/pem", "pkcs8/pem"]
point = ["dep:base16ct", "dep:generic-array"]
point = ["dep:base16ct", "dep:hybrid-array"]
serde = ["dep:serdect"]
zeroize = ["dep:zeroize", "der?/zeroize"]

Expand Down
2 changes: 1 addition & 1 deletion sec1/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub use crate::error::{Error, Result};
pub use crate::point::EncodedPoint;

#[cfg(feature = "point")]
pub use generic_array::typenum::consts;
pub use hybrid_array::typenum::consts;

#[cfg(feature = "der")]
pub use crate::{parameters::EcParameters, private_key::EcPrivateKey, traits::DecodeEcPrivateKey};
Expand Down
72 changes: 36 additions & 36 deletions sec1/src/point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ use core::{
cmp::Ordering,
fmt::{self, Debug},
hash::{Hash, Hasher},
ops::Add,
ops::{Add, Sub},
str,
};
use generic_array::{
use hybrid_array::{
typenum::{U1, U24, U28, U32, U48, U66},
ArrayLength, GenericArray,
Array, ArraySize,
};

#[cfg(feature = "alloc")]
Expand All @@ -34,20 +34,20 @@ use zeroize::Zeroize;
/// Trait for supported modulus sizes which precomputes the typenums for
/// various point encodings so they don't need to be included as bounds.
// TODO(tarcieri): replace this all with const generic expressions.
pub trait ModulusSize: 'static + ArrayLength<u8> + Copy + Debug {
pub trait ModulusSize: 'static + ArraySize + Copy + Debug {
/// Size of a compressed point for the given elliptic curve when encoded
/// using the SEC1 `Elliptic-Curve-Point-to-Octet-String` algorithm
/// (including leading `0x02` or `0x03` tag byte).
type CompressedPointSize: 'static + ArrayLength<u8> + Copy + Debug;
type CompressedPointSize: 'static + ArraySize + Copy + Debug;

/// Size of an uncompressed point for the given elliptic curve when encoded
/// using the SEC1 `Elliptic-Curve-Point-to-Octet-String` algorithm
/// (including leading `0x04` tag byte).
type UncompressedPointSize: 'static + ArrayLength<u8> + Copy + Debug;
type UncompressedPointSize: 'static + ArraySize + Copy + Debug;

/// Size of an untagged point for given elliptic curve, i.e. size of two
/// serialized base field elements.
type UntaggedPointSize: 'static + ArrayLength<u8> + Copy + Debug;
type UntaggedPointSize: 'static + ArraySize + Copy + Debug + Sub<Self, Output = Self>;
}

macro_rules! impl_modulus_size {
Expand All @@ -72,7 +72,7 @@ pub struct EncodedPoint<Size>
where
Size: ModulusSize,
{
bytes: GenericArray<u8, Size::UncompressedPointSize>,
bytes: Array<u8, Size::UncompressedPointSize>,
}

#[allow(clippy::len_without_is_empty)]
Expand Down Expand Up @@ -103,24 +103,24 @@ where
return Err(Error::PointEncoding);
}

let mut bytes = GenericArray::default();
let mut bytes = Array::default();
bytes[..expected_len].copy_from_slice(input);
Ok(Self { bytes })
}

/// Decode elliptic curve point from raw uncompressed coordinates, i.e.
/// encoded as the concatenated `x || y` coordinates with no leading SEC1
/// tag byte (which would otherwise be `0x04` for an uncompressed point).
pub fn from_untagged_bytes(bytes: &GenericArray<u8, Size::UntaggedPointSize>) -> Self {
let (x, y) = bytes.split_at(Size::to_usize());
Self::from_affine_coordinates(x.into(), y.into(), false)
pub fn from_untagged_bytes(bytes: &Array<u8, Size::UntaggedPointSize>) -> Self {
let (x, y) = bytes.split_ref();
Self::from_affine_coordinates(x, y, false)
}

/// Encode an elliptic curve point from big endian serialized coordinates
/// (with optional point compression)
pub fn from_affine_coordinates(
x: &GenericArray<u8, Size>,
y: &GenericArray<u8, Size>,
x: &Array<u8, Size>,
y: &Array<u8, Size>,
compress: bool,
) -> Self {
let tag = if compress {
Expand All @@ -129,7 +129,7 @@ where
Tag::Uncompressed
};

let mut bytes = GenericArray::default();
let mut bytes = Array::default();
bytes[0] = tag.into();
bytes[1..(Size::to_usize() + 1)].copy_from_slice(x);

Expand Down Expand Up @@ -200,27 +200,28 @@ where
return Coordinates::Identity;
}

let (x, y) = self.bytes[1..].split_at(Size::to_usize());
let (x_bytes, y_bytes) = self.bytes[1..].split_at(Size::to_usize());
let x = Array::ref_from_slice(x_bytes);

if self.is_compressed() {
Coordinates::Compressed {
x: x.into(),
x,
y_is_odd: self.tag() as u8 & 1 == 1,
}
} else if self.is_compact() {
Coordinates::Compact { x: x.into() }
} else {
Coordinates::Uncompressed {
x: x.into(),
y: y.into(),
x,
y: Array::ref_from_slice(y_bytes),
}
}
}

/// Get the x-coordinate for this [`EncodedPoint`].
///
/// Returns `None` if this point is the identity point.
pub fn x(&self) -> Option<&GenericArray<u8, Size>> {
pub fn x(&self) -> Option<&Array<u8, Size>> {
match self.coordinates() {
Coordinates::Identity => None,
Coordinates::Compressed { x, .. } => Some(x),
Expand All @@ -232,7 +233,7 @@ where
/// Get the y-coordinate for this [`EncodedPoint`].
///
/// Returns `None` if this point is compressed or the identity point.
pub fn y(&self) -> Option<&GenericArray<u8, Size>> {
pub fn y(&self) -> Option<&Array<u8, Size>> {
match self.coordinates() {
Coordinates::Compressed { .. } | Coordinates::Identity => None,
Coordinates::Uncompressed { y, .. } => Some(y),
Expand All @@ -255,10 +256,10 @@ where
impl<Size> ConditionallySelectable for EncodedPoint<Size>
where
Size: ModulusSize,
<Size::UncompressedPointSize as ArrayLength<u8>>::ArrayType: Copy,
<Size::UncompressedPointSize as ArraySize>::ArrayType<u8>: Copy,
{
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
let mut bytes = GenericArray::default();
let mut bytes = Array::default();

for (i, byte) in bytes.iter_mut().enumerate() {
*byte = u8::conditional_select(&a.bytes[i], &b.bytes[i], choice);
Expand All @@ -271,7 +272,7 @@ where
impl<Size> Copy for EncodedPoint<Size>
where
Size: ModulusSize,
<Size::UncompressedPointSize as ArrayLength<u8>>::ArrayType: Copy,
<Size::UncompressedPointSize as ArraySize>::ArrayType<u8>: Copy,
{
}

Expand Down Expand Up @@ -382,7 +383,7 @@ where
type Err = Error;

fn from_str(hex: &str) -> Result<Self> {
let mut buf = GenericArray::<u8, Size::UncompressedPointSize>::default();
let mut buf = Array::<u8, Size::UncompressedPointSize>::default();
base16ct::mixed::decode(hex, &mut buf)
.map_err(|_| Error::PointEncoding)
.and_then(Self::from_bytes)
Expand Down Expand Up @@ -426,13 +427,13 @@ pub enum Coordinates<'a, Size: ModulusSize> {
/// Compact curve point
Compact {
/// x-coordinate
x: &'a GenericArray<u8, Size>,
x: &'a Array<u8, Size>,
},

/// Compressed curve point
Compressed {
/// x-coordinate
x: &'a GenericArray<u8, Size>,
x: &'a Array<u8, Size>,

/// Is the y-coordinate odd?
y_is_odd: bool,
Expand All @@ -441,10 +442,10 @@ pub enum Coordinates<'a, Size: ModulusSize> {
/// Uncompressed curve point
Uncompressed {
/// x-coordinate
x: &'a GenericArray<u8, Size>,
x: &'a Array<u8, Size>,

/// y-coordinate
y: &'a GenericArray<u8, Size>,
y: &'a Array<u8, Size>,
},
}

Expand Down Expand Up @@ -556,8 +557,8 @@ impl From<Tag> for u8 {
mod tests {
use super::{Coordinates, Tag};
use core::str::FromStr;
use generic_array::{typenum::U32, GenericArray};
use hex_literal::hex;
use hybrid_array::typenum::U32;

#[cfg(feature = "alloc")]
use alloc::string::ToString;
Expand Down Expand Up @@ -600,7 +601,7 @@ mod tests {

assert_eq!(
compressed_even_y.x().unwrap(),
&hex!("0100000000000000000000000000000000000000000000000000000000000000").into()
&hex!("0100000000000000000000000000000000000000000000000000000000000000")
);
assert_eq!(compressed_even_y.y(), None);

Expand All @@ -625,7 +626,7 @@ mod tests {

assert_eq!(
compressed_odd_y.x().unwrap(),
&hex!("0200000000000000000000000000000000000000000000000000000000000000").into()
&hex!("0200000000000000000000000000000000000000000000000000000000000000")
);
assert_eq!(compressed_odd_y.y(), None);
}
Expand All @@ -649,11 +650,11 @@ mod tests {

assert_eq!(
uncompressed_point.x().unwrap(),
&hex!("1111111111111111111111111111111111111111111111111111111111111111").into()
&hex!("1111111111111111111111111111111111111111111111111111111111111111")
);
assert_eq!(
uncompressed_point.y().unwrap(),
&hex!("2222222222222222222222222222222222222222222222222222222222222222").into()
&hex!("2222222222222222222222222222222222222222222222222222222222222222")
);
}

Expand Down Expand Up @@ -701,8 +702,7 @@ mod tests {
#[test]
fn from_untagged_point() {
let untagged_bytes = hex!("11111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222");
let uncompressed_point =
EncodedPoint::from_untagged_bytes(GenericArray::from_slice(&untagged_bytes[..]));
let uncompressed_point = EncodedPoint::from_untagged_bytes(&untagged_bytes.into());
assert_eq!(uncompressed_point.as_bytes(), &UNCOMPRESSED_BYTES[..]);
}

Expand Down

0 comments on commit 1bdb7f7

Please sign in to comment.