ec/
curve_jacobi_intersection.rs1use core::fmt;
21use fp::field_ops::{FieldOps, FieldRandom};
22
23use crate::curve_ops::Curve;
24use crate::curve_weierstrass::WeierstrassCurve;
25use crate::point_jacobi_intersection::JacobiIntersectionPoint;
26
27#[derive(Debug, Clone, PartialEq, Eq)]
40pub struct JacobiIntersectionCurve<F: FieldOps> {
41 pub a: F,
43}
44
45impl<F> fmt::Display for JacobiIntersectionCurve<F>
46where
47 F: FieldOps + fmt::Display,
48{
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 if f.alternate() {
51 write!(
52 f,
53 "JacobiIntersectionCurve {{\n s^2 + c^2 = 1\n a s^2 + d^2 = 1\n a = {}\n}}",
54 self.a
55 )
56 } else {
57 write!(f, "s^2 + c^2 = 1, {} s^2 + d^2 = 1", self.a)
58 }
59 }
60}
61
62impl<F: FieldOps + FieldRandom> JacobiIntersectionCurve<F> {
63 pub fn new(a: F) -> Self {
65 assert!(
66 F::characteristic()[0] != 2,
67 "Jacobi intersections require char(F) != 2"
68 );
69 assert!(Self::is_smooth(&a), "singular Jacobi intersection");
70 Self { a }
71 }
72
73 pub fn is_smooth(a: &F) -> bool {
75 *a != F::zero() && *a != F::one()
76 }
77
78 pub fn contains(&self, s: &F, c: &F, d: &F) -> bool {
80 let s2 = <F as FieldOps>::square(s);
81 let c2 = <F as FieldOps>::square(c);
82 let d2 = <F as FieldOps>::square(d);
83
84 s2 + c2 == F::one() && self.a * s2 + d2 == F::one()
85 }
86
87 pub fn a_invariants(&self) -> [F; 1] {
90 [self.a]
91 }
92
93 pub fn random_point(&self, rng: &mut (impl rand::CryptoRng + rand::Rng)) -> JacobiIntersectionPoint<F> {
100 loop {
101 let s = F::random(rng);
102 let s2 = <F as FieldOps>::square(&s);
103
104 let c2 = F::one() - s2;
105 let d2 = F::one() - self.a * s2;
106
107 if let (Some(c), Some(d)) = (c2.sqrt().into_option(), d2.sqrt().into_option()) {
108 let p = JacobiIntersectionPoint::new(s, c, d);
109 debug_assert!(self.is_on_curve(&p));
110 return p;
111 }
112 }
113 }
114
115 pub fn to_weierstrass_curve(&self) -> WeierstrassCurve<F> {
118 let two = <F as FieldOps>::double(&F::one());
119 WeierstrassCurve::new(
120 F::zero(),
121 two - self.a,
122 F::zero(),
123 F::one() - self.a,
124 F::zero(),
125 )
126 }
127}
128
129impl<F: FieldOps + FieldRandom> Curve for JacobiIntersectionCurve<F> {
130 type BaseField = F;
131 type Point = JacobiIntersectionPoint<F>;
132
133 fn is_on_curve(&self, point: &Self::Point) -> bool {
134 self.contains(&point.s, &point.c, &point.d)
135 }
136
137 fn random_point(&self, rng: &mut (impl rand::CryptoRng + rand::Rng)) -> Self::Point {
138 JacobiIntersectionCurve::random_point(self, rng)
139 }
140
141 fn j_invariant(&self) -> F {
142 self.to_weierstrass_curve().j_invariant()
143 }
144
145 fn a_invariants(&self) -> Vec<Self::BaseField> {
146 JacobiIntersectionCurve::a_invariants(self).to_vec()
147 }
148}