Skip to main content

elliptic_curve/
field.rs

1//! Field element encoding support.
2
3use crate::Curve;
4use array::{Array, typenum::Unsigned};
5use bigint::{ArrayEncoding, ByteOrder, Encoding};
6
7/// Size of serialized field elements of this elliptic curve.
8pub type FieldBytesSize<C> = <C as Curve>::FieldBytesSize;
9
10/// Byte representation of a base/scalar field element of a given curve.
11pub type FieldBytes<C> = Array<u8, FieldBytesSize<C>>;
12
13/// Decode the provided [`FieldBytes`] as an integer.
14///
15/// Note that the resulting integer is the raw representation of the given `bytes` and is not
16/// reduced by any modulus.
17pub fn bytes_to_uint<C: Curve>(bytes: &FieldBytes<C>) -> C::Uint {
18    C::Uint::from_slice_truncated(bytes, modulus_bits::<C>(), C::FIELD_ENDIANNESS)
19}
20
21/// Encode the provided integer as [`FieldBytes`].
22///
23/// Note that the output may be truncated if it overflows the width of [`FieldBytes`].
24pub fn uint_to_bytes<C: Curve>(uint: &C::Uint) -> FieldBytes<C> {
25    let field_bytes_len = FieldBytesSize::<C>::USIZE;
26    let uint_bytes_len = <<C as Curve>::Uint as ArrayEncoding>::ByteSize::USIZE;
27    debug_assert!(field_bytes_len <= uint_bytes_len);
28
29    let mut field_bytes = FieldBytes::<C>::default();
30    match C::FIELD_ENDIANNESS {
31        ByteOrder::BigEndian => {
32            let offset = uint_bytes_len.saturating_sub(field_bytes_len);
33            field_bytes.copy_from_slice(&uint.to_be_byte_array()[offset..]);
34        }
35        ByteOrder::LittleEndian => {
36            field_bytes.copy_from_slice(&uint.to_le_byte_array()[..field_bytes_len]);
37        }
38    }
39
40    field_bytes
41}
42
43// TODO(tarcieri): store full bit precision of the modulus on `Curve`
44#[allow(clippy::cast_possible_truncation)]
45const fn modulus_bits<C: Curve>() -> u32 {
46    (FieldBytesSize::<C>::USIZE * 8) as u32
47}