use super::curve::{Curve, CurveError};
use super::field::limbs_of;
use super::group::Table;
use super::point::Point;
use crate::math::numbers::Number;
use core::ops::Deref;
use std::sync::OnceLock;
pub struct Domain<C: Curve> {
curve: C,
generator: Vec<u64>,
order: Number,
cofactor: Number,
table: OnceLock<Table>,
}
impl<C: Curve> Domain<C> {
pub fn new(
curve: C,
x: &Number,
y: &Number,
order: &Number,
cofactor: &Number,
) -> Result<Domain<C>, CurveError> {
let generator = {
let g = curve.point(x, y).map_err(|_| CurveError::NotOnCurve)?;
if !order.is_positive() || !(&g * order).is_identity() {
return Err(CurveError::WrongOrder);
}
g.limbs.clone()
};
Ok(Domain {
curve,
generator,
order: order.clone(),
cofactor: cofactor.clone(),
table: OnceLock::new(),
})
}
pub fn generator(&self) -> Point<'_, C> {
Point::from_limbs(&self.curve, self.generator.clone())
}
pub fn order(&self) -> &Number {
&self.order
}
pub fn cofactor(&self) -> &Number {
&self.cofactor
}
pub fn mul_generator(&self, k: &Number) -> Point<'_, C> {
let table = self.table();
let k = k.rem_euclid(&self.order);
let mut limbs = vec![0; self.generator.len()];
self.curve
.prepared_limbs(&mut limbs, table, &limbs_of(&k), false);
Point::from_limbs(&self.curve, limbs)
}
pub fn mul_add<'c>(&'c self, a: &Number, b: &Number, point: &Point<'c, C>) -> Point<'c, C> {
point.check_curve(&self.curve);
self.mul_generator(a) + point * b
}
pub fn in_subgroup(&self, point: &Point<'_, C>) -> bool {
point.belongs_to(&self.curve) && (point * &self.order).is_identity()
}
pub fn clear_cofactor<'c>(&self, point: &Point<'c, C>) -> Point<'c, C> {
point.check_curve(&self.curve);
point * &self.cofactor
}
fn table(&self) -> &Table {
self.table.get_or_init(|| {
self.curve
.prepare_limbs(&self.generator, self.order.bits() as usize)
})
}
}
impl<C: Curve> Deref for Domain<C> {
type Target = C;
fn deref(&self) -> &C {
&self.curve
}
}