use core::fmt;
#[doc(inline)]
pub use crate::core::coords::{Parity, Sign};
use crate::{
core::{ByteArray, Curve},
errors::InvalidCoordinate,
Scalar,
};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Coordinates<E: Curve> {
pub x: Coordinate<E>,
pub y: Coordinate<E>,
}
#[derive(Clone)]
pub struct Coordinate<E: Curve>(E::CoordinateArray);
impl<E: Curve> Coordinate<E> {
#[inline(always)]
pub fn as_be_bytes(&self) -> &[u8] {
self.0.as_ref()
}
pub fn from_be_bytes(bytes: &[u8]) -> Result<Self, InvalidCoordinate> {
let mut coord = E::CoordinateArray::zeroes();
if coord.as_ref().len() != bytes.len() {
return Err(InvalidCoordinate);
}
coord.as_mut().copy_from_slice(bytes);
Ok(Self(coord))
}
pub fn to_scalar(&self) -> Scalar<E> {
Scalar::from_be_bytes_mod_order(self.as_be_bytes())
}
pub fn new(bytes: E::CoordinateArray) -> Self {
Self(bytes)
}
pub fn as_array(&self) -> &E::CoordinateArray {
&self.0
}
}
impl<E: Curve> AsRef<[u8]> for Coordinate<E> {
#[inline(always)]
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl<E: Curve> AsMut<[u8]> for Coordinate<E> {
fn as_mut(&mut self) -> &mut [u8] {
self.0.as_mut()
}
}
impl<E: Curve> Default for Coordinate<E> {
fn default() -> Self {
Self(ByteArray::zeroes())
}
}
impl<E: Curve> fmt::Debug for Coordinate<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut tuple = f.debug_tuple("Coordinate");
#[cfg(feature = "alloc")]
{
tuple.field(&hex::encode(self.as_be_bytes()));
}
tuple.finish()
}
}
impl<E: Curve> PartialEq for Coordinate<E> {
fn eq(&self, other: &Self) -> bool {
self.as_be_bytes() == other.as_be_bytes()
}
}
impl<E: Curve> Eq for Coordinate<E> {}
impl<E: Curve> PartialOrd for Coordinate<E> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<E: Curve> Ord for Coordinate<E> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.as_be_bytes().cmp(other.as_be_bytes())
}
}
impl<E: Curve> core::hash::Hash for Coordinate<E> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.as_be_bytes().hash(state);
}
}
mod sealed {
pub trait Sealed {}
impl<E: crate::core::Curve> Sealed for crate::Point<E> {}
impl<E: crate::core::Curve> Sealed for crate::NonZero<crate::Point<E>> {}
}
pub trait HasAffineX<E: Curve>: sealed::Sealed {
fn x(&self) -> Option<Coordinate<E>>;
}
pub trait HasAffineY<E: Curve>: sealed::Sealed {
fn y(&self) -> Option<Coordinate<E>>;
}
pub trait HasAffineXAndParity<E: Curve>: HasAffineX<E>
where
Self: Sized,
{
fn x_and_parity(&self) -> Option<(Coordinate<E>, Parity)>;
fn from_x_and_parity(x: &Coordinate<E>, y_parity: Parity) -> Option<Self>;
}
pub trait HasAffineXY<E: Curve>: HasAffineX<E> + HasAffineY<E>
where
Self: Sized,
{
fn coords(&self) -> Option<Coordinates<E>>;
fn from_coords(coords: &Coordinates<E>) -> Option<Self>;
}
pub trait AlwaysHasAffineX<E: Curve>: sealed::Sealed {
fn x(&self) -> Coordinate<E>;
}
pub trait AlwaysHasAffineY<E: Curve>: sealed::Sealed {
fn y(&self) -> Coordinate<E>;
}
pub trait AlwaysHasAffineYAndSign<E: Curve>: AlwaysHasAffineY<E>
where
Self: Sized,
{
fn y_and_sign(&self) -> (Sign, Coordinate<E>);
fn from_y_and_sign(x_sign: Sign, y: &Coordinate<E>) -> Option<Self>;
}
pub trait AlwaysHasAffineXY<E: Curve>: AlwaysHasAffineX<E> + AlwaysHasAffineY<E> + Sized {
fn from_coords(coords: &Coordinates<E>) -> Option<Self>;
}