1use core::{
2 iter::Sum,
3 ops::{Mul, MulAssign},
4};
5
6use elliptic_curve::{
7 bigint::{ArrayEncoding, U256},
8 ops::{LinearCombination, MulByGenerator},
9 point::{AffineCoordinates, DecompactPoint, DecompressPoint},
10 rand_core::RngCore,
11 sec1::{FromEncodedPoint, ToEncodedPoint},
12 subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
13 zeroize::DefaultIsZeroes,
14 FieldBytesEncoding,
15};
16use openvm_algebra_guest::IntMod;
17use openvm_ecc_guest::{
18 weierstrass::{IntrinsicCurve, WeierstrassPoint},
19 CyclicGroup,
20};
21
22use crate::{
23 internal::{P256Coord, P256Point, P256Scalar},
24 EncodedPoint, NistP256,
25};
26
27pub type FieldBytes = elliptic_curve::FieldBytes<NistP256>;
33
34impl FieldBytesEncoding<NistP256> for U256 {
35 fn decode_field_bytes(field_bytes: &FieldBytes) -> Self {
36 U256::from_be_byte_array(*field_bytes)
37 }
38
39 fn encode_field_bytes(&self) -> FieldBytes {
40 self.to_be_byte_array()
41 }
42}
43
44impl AffineCoordinates for P256Point {
45 type FieldRepr = FieldBytes;
46
47 fn x(&self) -> FieldBytes {
48 *FieldBytes::from_slice(&<Self as WeierstrassPoint>::x(self).to_be_bytes())
49 }
50
51 fn y_is_odd(&self) -> Choice {
52 (self.y().as_le_bytes()[0] & 1).into()
53 }
54}
55
56impl Copy for P256Point {}
57
58impl ConditionallySelectable for P256Point {
59 fn conditional_select(a: &P256Point, b: &P256Point, choice: Choice) -> P256Point {
60 P256Point::from_xy_unchecked(
61 P256Coord::conditional_select(
62 <Self as WeierstrassPoint>::x(a),
63 <Self as WeierstrassPoint>::x(b),
64 choice,
65 ),
66 P256Coord::conditional_select(a.y(), b.y(), choice),
67 )
68 }
69}
70
71impl ConstantTimeEq for P256Point {
72 fn ct_eq(&self, other: &P256Point) -> Choice {
73 <Self as WeierstrassPoint>::x(self).ct_eq(<Self as WeierstrassPoint>::x(other))
74 & self.y().ct_eq(other.y())
75 }
76}
77
78impl Default for P256Point {
79 fn default() -> Self {
80 <Self as WeierstrassPoint>::IDENTITY
81 }
82}
83
84impl DefaultIsZeroes for P256Point {}
85
86impl Sum for P256Point {
87 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
88 iter.fold(<Self as WeierstrassPoint>::IDENTITY, |a, b| a + b)
89 }
90}
91
92impl<'a> Sum<&'a P256Point> for P256Point {
93 fn sum<I: Iterator<Item = &'a P256Point>>(iter: I) -> Self {
94 iter.cloned().sum()
95 }
96}
97
98impl Mul<P256Scalar> for P256Point {
99 type Output = P256Point;
100
101 fn mul(self, other: P256Scalar) -> P256Point {
102 NistP256::msm(&[other], &[self])
103 }
104}
105
106impl Mul<&P256Scalar> for &P256Point {
107 type Output = P256Point;
108
109 fn mul(self, other: &P256Scalar) -> P256Point {
110 NistP256::msm(&[*other], &[*self])
111 }
112}
113
114impl Mul<&P256Scalar> for P256Point {
115 type Output = P256Point;
116
117 fn mul(self, other: &P256Scalar) -> P256Point {
118 NistP256::msm(&[*other], &[self])
119 }
120}
121
122impl MulAssign<P256Scalar> for P256Point {
123 fn mul_assign(&mut self, rhs: P256Scalar) {
124 *self = NistP256::msm(&[rhs], &[*self]);
125 }
126}
127
128impl MulAssign<&P256Scalar> for P256Point {
129 fn mul_assign(&mut self, rhs: &P256Scalar) {
130 *self = NistP256::msm(&[*rhs], &[*self]);
131 }
132}
133
134impl elliptic_curve::Group for P256Point {
135 type Scalar = P256Scalar;
136
137 fn random(mut _rng: impl RngCore) -> Self {
138 unimplemented!()
140 }
141
142 fn identity() -> Self {
143 <Self as WeierstrassPoint>::IDENTITY
144 }
145
146 fn generator() -> Self {
147 Self::GENERATOR
148 }
149
150 fn is_identity(&self) -> Choice {
151 (<Self as openvm_ecc_guest::Group>::is_identity(self) as u8).into()
152 }
153
154 #[must_use]
155 fn double(&self) -> Self {
156 self + self
157 }
158}
159
160impl elliptic_curve::group::Curve for P256Point {
161 type AffineRepr = P256Point;
162
163 fn to_affine(&self) -> P256Point {
164 *self
165 }
166}
167
168impl LinearCombination for P256Point {
169 fn lincomb(x: &Self, k: &Self::Scalar, y: &Self, l: &Self::Scalar) -> Self {
170 NistP256::msm(&[*k, *l], &[*x, *y])
171 }
172}
173
174impl MulByGenerator for P256Point {}
176
177impl DecompressPoint<NistP256> for P256Point {
178 fn decompress(x_bytes: &FieldBytes, y_is_odd: Choice) -> CtOption<Self> {
180 use openvm_ecc_guest::weierstrass::FromCompressed;
181
182 let x = P256Coord::from_be_bytes_unchecked(x_bytes.as_slice());
183 let rec_id = y_is_odd.unwrap_u8();
184 CtOption::new(x, (x.is_reduced() as u8).into()).and_then(|x| {
185 let y = <P256Point as FromCompressed<P256Coord>>::decompress(x, &rec_id);
186 match y {
187 Some(point) => CtOption::new(point, 1.into()),
188 None => CtOption::new(P256Point::default(), 0.into()),
189 }
190 })
191 }
192}
193
194impl DecompactPoint<NistP256> for P256Point {
195 fn decompact(x_bytes: &FieldBytes) -> CtOption<Self> {
196 Self::decompress(x_bytes, Choice::from(0))
197 }
198}
199
200impl FromEncodedPoint<NistP256> for P256Point {
201 fn from_encoded_point(encoded_point: &EncodedPoint) -> CtOption<Self> {
207 match openvm_ecc_guest::ecdsa::VerifyingKey::<NistP256>::from_sec1_bytes(
208 encoded_point.as_bytes(),
209 ) {
210 Ok(verifying_key) => CtOption::new(*verifying_key.as_affine(), 1.into()),
211 Err(_) => CtOption::new(P256Point::default(), 0.into()),
212 }
213 }
214}
215
216impl ToEncodedPoint<NistP256> for P256Point {
217 fn to_encoded_point(&self, compress: bool) -> EncodedPoint {
218 EncodedPoint::conditional_select(
219 &EncodedPoint::from_affine_coordinates(
220 &<Self as WeierstrassPoint>::x(self).to_be_bytes().into(),
221 &<Self as WeierstrassPoint>::y(self).to_be_bytes().into(),
222 compress,
223 ),
224 &EncodedPoint::identity(),
225 elliptic_curve::Group::is_identity(self),
226 )
227 }
228}
229
230impl TryFrom<EncodedPoint> for P256Point {
231 type Error = elliptic_curve::Error;
232
233 fn try_from(point: EncodedPoint) -> elliptic_curve::Result<P256Point> {
234 P256Point::try_from(&point)
235 }
236}
237
238impl TryFrom<&EncodedPoint> for P256Point {
239 type Error = elliptic_curve::Error;
240
241 fn try_from(point: &EncodedPoint) -> elliptic_curve::Result<P256Point> {
242 Option::from(P256Point::from_encoded_point(point)).ok_or(elliptic_curve::Error)
243 }
244}
245
246impl From<P256Point> for EncodedPoint {
247 fn from(affine_point: P256Point) -> EncodedPoint {
248 EncodedPoint::from(&affine_point)
249 }
250}
251
252impl From<&P256Point> for EncodedPoint {
253 fn from(affine_point: &P256Point) -> EncodedPoint {
254 affine_point.to_encoded_point(true)
255 }
256}