use super::curve::Curve;
use super::field::limbs_of;
use super::group::Table;
use crate::math::numbers::Number;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
pub struct Point<'c, C: Curve> {
curve: &'c C,
pub(super) limbs: Vec<u64>,
}
impl<'c, C: Curve> Point<'c, C> {
#[inline]
pub(super) fn from_limbs(curve: &'c C, limbs: Vec<u64>) -> Self {
Point { curve, limbs }
}
#[inline(always)]
pub(super) fn belongs_to(&self, curve: &C) -> bool {
core::ptr::eq(self.curve, curve) || self.curve.same_curve(curve)
}
#[inline(always)]
#[track_caller]
pub(super) fn check_curve(&self, curve: &C) {
if !self.belongs_to(curve) {
different_curves();
}
}
#[inline]
pub fn curve(&self) -> &'c C {
self.curve
}
pub fn is_identity(&self) -> bool {
self.curve.is_identity_limbs(&self.limbs)
}
pub fn coordinates(&self) -> Option<(Number, Number)> {
self.curve
.coordinates_limbs(&[&self.limbs])
.pop()
.unwrap_or(None)
}
pub fn coordinates_of(points: &[Point<'c, C>]) -> Vec<Option<(Number, Number)>> {
let Some(first) = points.first() else {
return Vec::new();
};
let stored: Vec<&[u64]> = points
.iter()
.map(|p| {
p.check_curve(first.curve);
&p.limbs[..]
})
.collect();
first.curve.coordinates_limbs(&stored)
}
pub fn double(&self) -> Self {
let mut r = self.clone();
self.curve.double_limbs(&mut r.limbs);
r
}
pub fn compress(&self) -> Vec<u8> {
let xy = self.coordinates();
self.curve.encode(xy.as_ref().map(|(x, y)| (x, y)), true)
}
pub fn to_bytes(&self) -> Vec<u8> {
let xy = self.coordinates();
self.curve.encode(xy.as_ref().map(|(x, y)| (x, y)), false)
}
pub fn prepare(&self, bits: usize) -> Prepared<'c, C> {
Prepared {
curve: self.curve,
table: self.curve.prepare_limbs(&self.limbs, bits),
point: self.limbs.clone(),
}
}
}
#[cold]
#[inline(never)]
#[track_caller]
fn different_curves() -> ! {
panic!("the points are on different curves")
}
pub struct Prepared<'c, C: Curve> {
curve: &'c C,
table: Table,
point: Vec<u64>,
}
impl<'c, C: Curve> Prepared<'c, C> {
pub fn mul(&self, k: &Number) -> Point<'c, C> {
let scalar = limbs_of(k);
let mut limbs = self.point.clone();
if k.bits() as usize <= self.table.bits {
self.curve
.prepared_limbs(&mut limbs, &self.table, &scalar, k.is_negative());
} else {
self.curve.mul_limbs(&mut limbs, &scalar, k.is_negative());
}
Point::from_limbs(self.curve, limbs)
}
}
impl<C: Curve> Clone for Point<'_, C> {
fn clone(&self) -> Self {
Point {
curve: self.curve,
limbs: self.limbs.clone(),
}
}
fn clone_from(&mut self, source: &Self) {
self.curve = source.curve;
self.limbs.clone_from(&source.limbs);
}
}
impl<C: Curve> PartialEq for Point<'_, C> {
#[track_caller]
fn eq(&self, other: &Self) -> bool {
other.check_curve(self.curve);
self.curve.equal_limbs(&self.limbs, &other.limbs)
}
}
impl<C: Curve> Eq for Point<'_, C> {}
impl<C: Curve> Hash for Point<'_, C> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.coordinates().hash(state);
}
}
impl<C: Curve> fmt::Debug for Point<'_, C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl<C: Curve> fmt::Display for Point<'_, C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.coordinates() {
Some((x, y)) => write!(f, "({x}, {y})"),
None => f.write_str("infinity"),
}
}
}
impl<'c, C: Curve> Neg for &Point<'c, C> {
type Output = Point<'c, C>;
fn neg(self) -> Point<'c, C> {
-self.clone()
}
}
impl<'c, C: Curve> Neg for Point<'c, C> {
type Output = Point<'c, C>;
fn neg(mut self) -> Point<'c, C> {
self.curve.neg_limbs(&mut self.limbs);
self
}
}
macro_rules! operators {
($trait:ident, $method:ident, $assign:ident, $assign_method:ident, $limbs:ident) => {
impl<'c, C: Curve> $assign<&Point<'c, C>> for Point<'c, C> {
#[track_caller]
fn $assign_method(&mut self, rhs: &Point<'c, C>) {
rhs.check_curve(self.curve);
self.curve.$limbs(&mut self.limbs, &rhs.limbs);
}
}
impl<'c, C: Curve> $assign<Point<'c, C>> for Point<'c, C> {
#[track_caller]
fn $assign_method(&mut self, rhs: Point<'c, C>) {
self.$assign_method(&rhs);
}
}
impl<'c, C: Curve> $trait<&Point<'c, C>> for Point<'c, C> {
type Output = Point<'c, C>;
#[track_caller]
fn $method(mut self, rhs: &Point<'c, C>) -> Point<'c, C> {
self.$assign_method(rhs);
self
}
}
impl<'c, C: Curve> $trait<Point<'c, C>> for Point<'c, C> {
type Output = Point<'c, C>;
#[track_caller]
fn $method(self, rhs: Point<'c, C>) -> Point<'c, C> {
self.$method(&rhs)
}
}
impl<'c, C: Curve> $trait<&Point<'c, C>> for &Point<'c, C> {
type Output = Point<'c, C>;
#[track_caller]
fn $method(self, rhs: &Point<'c, C>) -> Point<'c, C> {
self.clone().$method(rhs)
}
}
impl<'c, C: Curve> $trait<Point<'c, C>> for &Point<'c, C> {
type Output = Point<'c, C>;
#[track_caller]
fn $method(self, rhs: Point<'c, C>) -> Point<'c, C> {
self.clone().$method(&rhs)
}
}
};
}
operators!(Add, add, AddAssign, add_assign, add_limbs);
operators!(Sub, sub, SubAssign, sub_assign, sub_limbs);
impl<C: Curve> MulAssign<&Number> for Point<'_, C> {
fn mul_assign(&mut self, k: &Number) {
self.curve
.mul_limbs(&mut self.limbs, &limbs_of(k), k.is_negative());
}
}
impl<C: Curve> MulAssign<Number> for Point<'_, C> {
fn mul_assign(&mut self, k: Number) {
*self *= &k;
}
}
impl<'c, C: Curve> Mul<&Number> for Point<'c, C> {
type Output = Point<'c, C>;
fn mul(mut self, k: &Number) -> Point<'c, C> {
self *= k;
self
}
}
impl<'c, C: Curve> Mul<Number> for Point<'c, C> {
type Output = Point<'c, C>;
fn mul(self, k: Number) -> Point<'c, C> {
self * &k
}
}
impl<'c, C: Curve> Mul<&Number> for &Point<'c, C> {
type Output = Point<'c, C>;
fn mul(self, k: &Number) -> Point<'c, C> {
self.clone() * k
}
}
impl<'c, C: Curve> Mul<Number> for &Point<'c, C> {
type Output = Point<'c, C>;
fn mul(self, k: Number) -> Point<'c, C> {
self.clone() * &k
}
}
impl<'c, C: Curve> Mul<&Point<'c, C>> for &Number {
type Output = Point<'c, C>;
fn mul(self, p: &Point<'c, C>) -> Point<'c, C> {
p * self
}
}
impl<'c, C: Curve> Mul<Point<'c, C>> for &Number {
type Output = Point<'c, C>;
fn mul(self, p: Point<'c, C>) -> Point<'c, C> {
p * self
}
}
impl<'c, C: Curve> Mul<&Point<'c, C>> for Number {
type Output = Point<'c, C>;
fn mul(self, p: &Point<'c, C>) -> Point<'c, C> {
p * &self
}
}
impl<'c, C: Curve> Mul<Point<'c, C>> for Number {
type Output = Point<'c, C>;
fn mul(self, p: Point<'c, C>) -> Point<'c, C> {
p * &self
}
}