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
5 changes: 2 additions & 3 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,5 @@ unused_qualifications = "warn"
crypto-common = { path = "crypto-common" }
digest = { path = "digest" }
signature = { path = "signature" }

crypto-bigint = { git = "https://github.com/RustCrypto/crypto-bigint" }
2 changes: 1 addition & 1 deletion elliptic-curve/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ representing various elliptic curve forms, scalars, points, and public/secret ke

[dependencies]
array = { package = "hybrid-array", version = "0.4", default-features = false, features = ["zeroize"] }
bigint = { package = "crypto-bigint", version = "0.7", default-features = false, features = ["hybrid-array", "rand_core", "subtle", "zeroize"] }
bigint = { package = "crypto-bigint", version = "0.7.4", default-features = false, features = ["hybrid-array", "rand_core", "subtle", "zeroize"] }
base16ct = "1"
common = { package = "crypto-common", version = "0.2", features = ["rand_core"] }
rand_core = { version = "0.10", default-features = false }
Expand Down
5 changes: 1 addition & 4 deletions elliptic-curve/src/dev/mock_curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
//! generically over curves without having to pull in a complete curve implementation.

use crate::{
BatchNormalize, Curve, CurveAffine, CurveArithmetic, CurveGroup, FieldBytesEncoding, Generate,
PrimeCurve,
BatchNormalize, Curve, CurveAffine, CurveArithmetic, CurveGroup, Generate, PrimeCurve,
array::typenum::U32,
bigint::{Limb, Odd, U256, modular::Retrieve},
ctutils,
Expand Down Expand Up @@ -350,8 +349,6 @@ impl Retrieve for Scalar {
}
}

impl FieldBytesEncoding<MockCurve> for U256 {}

impl From<u64> for Scalar {
fn from(n: u64) -> Scalar {
Self(n.into())
Expand Down
68 changes: 32 additions & 36 deletions elliptic-curve/src/field.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,47 @@
//! Field elements.
//! Field element encoding support.

use crate::{
Curve,
bigint::{ArrayEncoding, ByteArray, Integer},
};
use crate::Curve;
use array::{Array, typenum::Unsigned};
use bigint::{ArrayEncoding, ByteOrder, Encoding};

/// Size of serialized field elements of this elliptic curve.
pub type FieldBytesSize<C> = <C as Curve>::FieldBytesSize;

/// Byte representation of a base/scalar field element of a given curve.
pub type FieldBytes<C> = Array<u8, FieldBytesSize<C>>;

/// Trait for decoding/encoding `Curve::Uint` from/to [`FieldBytes`] using
/// curve-specific rules.
/// Decode the provided [`FieldBytes`] as an integer.
///
/// Namely a curve's modulus may be smaller than the big integer type used to
/// internally represent field elements (since the latter are multiples of the
/// limb size), such as in the case of curves like NIST P-224 and P-521, and so
/// it may need to be padded/truncated to the right length.
/// Note that the resulting integer is the raw representation of the given `bytes` and is not
/// reduced by any modulus.
pub fn bytes_to_uint<C: Curve>(bytes: &FieldBytes<C>) -> C::Uint {
C::Uint::from_slice_truncated(bytes, modulus_bits::<C>(), C::FIELD_ENDIANNESS)
}

/// Encode the provided integer as [`FieldBytes`].
///
/// Additionally, different curves have different endianness conventions, also
/// captured here.
pub trait FieldBytesEncoding<C>: ArrayEncoding + Integer
where
C: Curve,
{
/// Decode unsigned integer from serialized field element.
///
/// The default implementation assumes a big endian encoding.
fn decode_field_bytes(field_bytes: &FieldBytes<C>) -> Self {
debug_assert!(field_bytes.len() <= Self::ByteSize::USIZE);
let mut byte_array = ByteArray::<Self>::default();
let offset = Self::ByteSize::USIZE.saturating_sub(field_bytes.len());
byte_array[offset..].copy_from_slice(field_bytes);
Self::from_be_byte_array(byte_array)
/// Note that the output may be truncated if it overflows the width of [`FieldBytes`].
pub fn uint_to_bytes<C: Curve>(uint: &C::Uint) -> FieldBytes<C> {
let field_bytes_len = FieldBytesSize::<C>::USIZE;
let uint_bytes_len = <<C as Curve>::Uint as ArrayEncoding>::ByteSize::USIZE;
debug_assert!(field_bytes_len <= uint_bytes_len);

let mut field_bytes = FieldBytes::<C>::default();
match C::FIELD_ENDIANNESS {
ByteOrder::BigEndian => {
let offset = uint_bytes_len.saturating_sub(field_bytes_len);
field_bytes.copy_from_slice(&uint.to_be_byte_array()[offset..]);
}
ByteOrder::LittleEndian => {
field_bytes.copy_from_slice(&uint.to_le_byte_array()[..field_bytes_len]);
}
}

/// Encode unsigned integer into serialized field element.
///
/// The default implementation assumes a big endian encoding.
fn encode_field_bytes(&self) -> FieldBytes<C> {
let mut field_bytes = FieldBytes::<C>::default();
debug_assert!(field_bytes.len() <= Self::ByteSize::USIZE);
field_bytes
}

let offset = Self::ByteSize::USIZE.saturating_sub(field_bytes.len());
field_bytes.copy_from_slice(&self.to_be_byte_array()[offset..]);
field_bytes
}
// TODO(tarcieri): store full bit precision of the modulus on `Curve`
#[allow(clippy::cast_possible_truncation)]
const fn modulus_bits<C: Curve>() -> u32 {
(FieldBytesSize::<C>::USIZE * 8) as u32
}
11 changes: 6 additions & 5 deletions elliptic-curve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ extern crate alloc;
#[cfg(feature = "std")]
extern crate std;

pub mod field;
pub mod point;
pub mod scalar;

Expand All @@ -77,7 +78,6 @@ pub mod ops;
pub mod sec1;

mod error;
mod field;
mod macros;
mod secret_key;

Expand All @@ -88,14 +88,13 @@ mod public_key;

pub use crate::{
error::{Error, Result},
field::{FieldBytes, FieldBytesEncoding, FieldBytesSize},
field::{FieldBytes, FieldBytesSize},
scalar::ScalarValue,
secret_key::SecretKey,
};
pub use array;
pub use array::typenum::consts;
pub use bigint;
pub use bigint::ctutils;
pub use bigint::{self, ByteOrder, ctutils};
pub use common;
pub use common::Generate;
pub use rand_core;
Expand Down Expand Up @@ -163,11 +162,13 @@ pub trait Curve: 'static + Copy + Clone + Debug + Default + Eq + Ord + Send + Sy
+ bigint::RandomMod
+ bigint::Unsigned
+ zeroize::Zeroize
+ FieldBytesEncoding<Self>
+ ShrAssign<usize>;

/// Order of this curve's prime order subgroup, i.e. number of elements in the scalar field.
const ORDER: Odd<Self::Uint>;

/// Endianness used for serializing field elements of this curve.
const FIELD_ENDIANNESS: ByteOrder = ByteOrder::BigEndian;
}

/// Marker trait for elliptic curves with prime order.
Expand Down
7 changes: 4 additions & 3 deletions elliptic-curve/src/scalar/value.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
//! Integer values within the range of a given [`Curve`]'s scalar modulus.

use crate::{
Curve, Error, FieldBytes, FieldBytesEncoding, Result,
Curve, Error, FieldBytes, Result,
array::Array,
bigint::{AddMod, ConstOne, ConstZero, Integer, Limb, NegMod, Odd, RandomMod, SubMod, Zero},
ctutils::{self, CtEq, CtGt, CtLt, CtSelect},
field,
scalar::{FromUintUnchecked, IsHigh},
};
use base16ct::HexDisplay;
Expand Down Expand Up @@ -74,7 +75,7 @@ where

/// Decode [`ScalarValue`] from a serialized field element
pub fn from_bytes(bytes: &FieldBytes<C>) -> CtOption<Self> {
Self::new(C::Uint::decode_field_bytes(bytes))
Self::new(field::bytes_to_uint::<C>(bytes))
}

/// Decode [`ScalarValue`] from a big endian byte slice.
Expand Down Expand Up @@ -114,7 +115,7 @@ where

/// Encode [`ScalarValue`] as a serialized field element.
pub fn to_bytes(&self) -> FieldBytes<C> {
self.inner.encode_field_bytes()
field::uint_to_bytes::<C>(&self.inner)
}

/// Convert to a `C::Uint`.
Expand Down
Loading