Skip to content

Commit 3f03b40

Browse files
authored
elliptic-curve: factor out FieldBytesEncoding trait (RustCrypto#1235)
Extracts a trait to be impl'd on `Curve::Uint` which provides curve-specific rules for how field elements should be encoded as bytes. These rules include both endianness and how to pad/truncate bytes to match the size of the integer (which may be larger than the size of the field modulus, to be a multiple of the limb size)
1 parent c0c4701 commit 3f03b40

File tree

4 files changed

+52
-32
lines changed

4 files changed

+52
-32
lines changed

elliptic-curve/src/dev.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
sec1::{CompressedPoint, FromEncodedPoint, ToEncodedPoint},
1616
subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
1717
zeroize::DefaultIsZeroes,
18-
Curve, CurveArithmetic, PrimeCurve,
18+
Curve, CurveArithmetic, FieldBytesEncoding, PrimeCurve,
1919
};
2020
use core::{
2121
iter::{Product, Sum},
@@ -339,6 +339,8 @@ impl Reduce<U256> for Scalar {
339339
}
340340
}
341341

342+
impl FieldBytesEncoding<MockCurve> for U256 {}
343+
342344
impl From<u64> for Scalar {
343345
fn from(n: u64) -> Scalar {
344346
Self(n.into())

elliptic-curve/src/field.rs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,50 @@
11
//! Field elements.
22
3-
use crate::Curve;
4-
use generic_array::GenericArray;
3+
use crate::{
4+
bigint::{ArrayEncoding, ByteArray, Integer},
5+
Curve,
6+
};
7+
use generic_array::{typenum::Unsigned, GenericArray};
58

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

912
/// Byte representation of a base/scalar field element of a given curve.
1013
pub type FieldBytes<C> = GenericArray<u8, FieldBytesSize<C>>;
14+
15+
/// Trait for decoding/encoding `Curve::Uint` from/to [`FieldBytes`] using
16+
/// curve-specific rules.
17+
///
18+
/// Namely a curve's modulus may be smaller than the big integer type used to
19+
/// internally represent field elements (since the latter are multiples of the
20+
/// limb size), such as in the case of curves like NIST P-224 and P-521, and so
21+
/// it may need to be padded/truncated to the right length.
22+
///
23+
/// Additionally, different curves have different endianness conventions, also
24+
/// captured here.
25+
pub trait FieldBytesEncoding<C>: ArrayEncoding + Integer
26+
where
27+
C: Curve,
28+
{
29+
/// Decode unsigned integer from serialized field element.
30+
///
31+
/// The default implementation assumes a big endian encoding.
32+
fn decode_field_bytes(field_bytes: &FieldBytes<C>) -> Self {
33+
debug_assert!(field_bytes.len() <= Self::ByteSize::USIZE);
34+
let mut byte_array = ByteArray::<Self>::default();
35+
byte_array[..field_bytes.len()].copy_from_slice(field_bytes);
36+
Self::from_be_byte_array(byte_array)
37+
}
38+
39+
/// Encode unsigned integer into serialized field element.
40+
///
41+
/// The default implementation assumes a big endian encoding.
42+
fn encode_field_bytes(&self) -> FieldBytes<C> {
43+
let mut field_bytes = FieldBytes::<C>::default();
44+
debug_assert!(field_bytes.len() <= Self::ByteSize::USIZE);
45+
46+
let len = field_bytes.len();
47+
field_bytes.copy_from_slice(&self.to_be_byte_array()[..len]);
48+
field_bytes
49+
}
50+
}

elliptic-curve/src/lib.rs

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ mod voprf;
105105

106106
pub use crate::{
107107
error::{Error, Result},
108-
field::{FieldBytes, FieldBytesSize},
108+
field::{FieldBytes, FieldBytesEncoding, FieldBytesSize},
109109
scalar::ScalarPrimitive,
110110
secret_key::SecretKey,
111111
};
@@ -140,8 +140,7 @@ use core::{
140140
fmt::Debug,
141141
ops::{Add, ShrAssign},
142142
};
143-
use crypto_bigint::{ArrayEncoding, ByteArray};
144-
use generic_array::{typenum::Unsigned, ArrayLength};
143+
use generic_array::ArrayLength;
145144

146145
/// Algorithm [`ObjectIdentifier`][`pkcs8::ObjectIdentifier`] for elliptic
147146
/// curve public key cryptography (`id-ecPublicKey`).
@@ -167,7 +166,7 @@ pub trait Curve: 'static + Copy + Clone + Debug + Default + Eq + Ord + Send + Sy
167166
type FieldBytesSize: ArrayLength<u8> + Add + Eq;
168167

169168
/// Integer type used to represent field elements of this elliptic curve.
170-
type Uint: ArrayEncoding
169+
type Uint: bigint::ArrayEncoding
171170
+ bigint::AddMod<Output = Self::Uint>
172171
+ bigint::Encoding
173172
+ bigint::Integer
@@ -176,33 +175,12 @@ pub trait Curve: 'static + Copy + Clone + Debug + Default + Eq + Ord + Send + Sy
176175
+ bigint::RandomMod
177176
+ bigint::SubMod<Output = Self::Uint>
178177
+ zeroize::Zeroize
178+
+ FieldBytesEncoding<Self>
179179
+ ShrAssign<usize>;
180180

181181
/// Order of this elliptic curve, i.e. number of elements in the scalar
182182
/// field.
183183
const ORDER: Self::Uint;
184-
185-
/// Decode unsigned integer from serialized field element.
186-
///
187-
/// The default implementation assumes a big endian encoding.
188-
fn decode_field_bytes(field_bytes: &FieldBytes<Self>) -> Self::Uint {
189-
debug_assert!(field_bytes.len() <= <Self::Uint as ArrayEncoding>::ByteSize::USIZE);
190-
let mut byte_array = ByteArray::<Self::Uint>::default();
191-
byte_array[..field_bytes.len()].copy_from_slice(field_bytes);
192-
Self::Uint::from_be_byte_array(byte_array)
193-
}
194-
195-
/// Encode unsigned integer into serialized field element.
196-
///
197-
/// The default implementation assumes a big endian encoding.
198-
fn encode_field_bytes(uint: &Self::Uint) -> FieldBytes<Self> {
199-
let mut field_bytes = FieldBytes::<Self>::default();
200-
debug_assert!(field_bytes.len() <= <Self::Uint as ArrayEncoding>::ByteSize::USIZE);
201-
202-
let len = field_bytes.len();
203-
field_bytes.copy_from_slice(&uint.to_be_byte_array()[..len]);
204-
field_bytes
205-
}
206184
}
207185

208186
/// Marker trait for elliptic curves with prime order.

elliptic-curve/src/scalar/primitive.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
bigint::{prelude::*, Limb, NonZero},
55
scalar::FromUintUnchecked,
66
scalar::IsHigh,
7-
Curve, Error, FieldBytes, Result,
7+
Curve, Error, FieldBytes, FieldBytesEncoding, Result,
88
};
99
use base16ct::HexDisplay;
1010
use core::{
@@ -78,7 +78,7 @@ where
7878

7979
/// Decode [`ScalarPrimitive`] from a serialized field element
8080
pub fn from_bytes(bytes: &FieldBytes<C>) -> CtOption<Self> {
81-
Self::new(C::decode_field_bytes(bytes))
81+
Self::new(C::Uint::decode_field_bytes(bytes))
8282
}
8383

8484
/// Decode [`ScalarPrimitive`] from a big endian byte slice.
@@ -117,7 +117,7 @@ where
117117

118118
/// Encode [`ScalarPrimitive`] as a serialized field element.
119119
pub fn to_bytes(&self) -> FieldBytes<C> {
120-
C::encode_field_bytes(&self.inner)
120+
self.inner.encode_field_bytes()
121121
}
122122

123123
/// Convert to a `C::Uint`.

0 commit comments

Comments
 (0)