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::{Secp256k1Coord, Secp256k1Point, Secp256k1Scalar},
24 EncodedPoint, Secp256k1,
25};
26
27pub type FieldBytes = elliptic_curve::FieldBytes<Secp256k1>;
33
34impl FieldBytesEncoding<Secp256k1> 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 Secp256k1Point {
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 Secp256k1Point {}
57
58impl ConditionallySelectable for Secp256k1Point {
59 fn conditional_select(
60 a: &Secp256k1Point,
61 b: &Secp256k1Point,
62 choice: Choice,
63 ) -> Secp256k1Point {
64 Secp256k1Point::from_xy_unchecked(
65 Secp256k1Coord::conditional_select(
66 <Self as WeierstrassPoint>::x(a),
67 <Self as WeierstrassPoint>::x(b),
68 choice,
69 ),
70 Secp256k1Coord::conditional_select(a.y(), b.y(), choice),
71 )
72 }
73}
74
75impl ConstantTimeEq for Secp256k1Point {
76 fn ct_eq(&self, other: &Secp256k1Point) -> Choice {
77 <Self as WeierstrassPoint>::x(self).ct_eq(<Self as WeierstrassPoint>::x(other))
78 & self.y().ct_eq(other.y())
79 }
80}
81
82impl Default for Secp256k1Point {
83 fn default() -> Self {
84 <Self as WeierstrassPoint>::IDENTITY
85 }
86}
87
88impl DefaultIsZeroes for Secp256k1Point {}
89
90impl Sum for Secp256k1Point {
91 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
92 iter.fold(<Self as WeierstrassPoint>::IDENTITY, |a, b| a + b)
93 }
94}
95
96impl<'a> Sum<&'a Secp256k1Point> for Secp256k1Point {
97 fn sum<I: Iterator<Item = &'a Secp256k1Point>>(iter: I) -> Self {
98 iter.cloned().sum()
99 }
100}
101
102impl Mul<Secp256k1Scalar> for Secp256k1Point {
103 type Output = Secp256k1Point;
104
105 fn mul(self, other: Secp256k1Scalar) -> Secp256k1Point {
106 Secp256k1::msm(&[other], &[self])
107 }
108}
109
110impl Mul<&Secp256k1Scalar> for &Secp256k1Point {
111 type Output = Secp256k1Point;
112
113 fn mul(self, other: &Secp256k1Scalar) -> Secp256k1Point {
114 Secp256k1::msm(&[*other], &[*self])
115 }
116}
117
118impl Mul<&Secp256k1Scalar> for Secp256k1Point {
119 type Output = Secp256k1Point;
120
121 fn mul(self, other: &Secp256k1Scalar) -> Secp256k1Point {
122 Secp256k1::msm(&[*other], &[self])
123 }
124}
125
126impl MulAssign<Secp256k1Scalar> for Secp256k1Point {
127 fn mul_assign(&mut self, rhs: Secp256k1Scalar) {
128 *self = Secp256k1::msm(&[rhs], &[*self]);
129 }
130}
131
132impl MulAssign<&Secp256k1Scalar> for Secp256k1Point {
133 fn mul_assign(&mut self, rhs: &Secp256k1Scalar) {
134 *self = Secp256k1::msm(&[*rhs], &[*self]);
135 }
136}
137
138impl elliptic_curve::Group for Secp256k1Point {
139 type Scalar = Secp256k1Scalar;
140
141 fn random(mut _rng: impl RngCore) -> Self {
142 unimplemented!()
144 }
145
146 fn identity() -> Self {
147 <Self as WeierstrassPoint>::IDENTITY
148 }
149
150 fn generator() -> Self {
151 Self::GENERATOR
152 }
153
154 fn is_identity(&self) -> Choice {
155 (<Self as openvm_ecc_guest::Group>::is_identity(self) as u8).into()
156 }
157
158 #[must_use]
159 fn double(&self) -> Self {
160 self + self
161 }
162}
163
164impl elliptic_curve::group::Curve for Secp256k1Point {
165 type AffineRepr = Secp256k1Point;
166
167 fn to_affine(&self) -> Secp256k1Point {
168 *self
169 }
170}
171
172impl LinearCombination for Secp256k1Point {
173 fn lincomb(x: &Self, k: &Self::Scalar, y: &Self, l: &Self::Scalar) -> Self {
174 Secp256k1::msm(&[*k, *l], &[*x, *y])
175 }
176}
177
178impl MulByGenerator for Secp256k1Point {}
180
181impl DecompressPoint<Secp256k1> for Secp256k1Point {
182 fn decompress(x_bytes: &FieldBytes, y_is_odd: Choice) -> CtOption<Self> {
184 use openvm_ecc_guest::weierstrass::FromCompressed;
185
186 let x = Secp256k1Coord::from_be_bytes_unchecked(x_bytes.as_slice());
187 let rec_id = y_is_odd.unwrap_u8();
188 CtOption::new(x, (x.is_reduced() as u8).into()).and_then(|x| {
189 let y = <Secp256k1Point as FromCompressed<Secp256k1Coord>>::decompress(x, &rec_id);
190 match y {
191 Some(point) => CtOption::new(point, 1.into()),
192 None => CtOption::new(Secp256k1Point::default(), 0.into()),
193 }
194 })
195 }
196}
197
198impl DecompactPoint<Secp256k1> for Secp256k1Point {
200 fn decompact(x_bytes: &FieldBytes) -> CtOption<Self> {
201 Self::decompress(x_bytes, Choice::from(0))
202 }
203}
204
205impl FromEncodedPoint<Secp256k1> for Secp256k1Point {
206 fn from_encoded_point(encoded_point: &EncodedPoint) -> CtOption<Self> {
212 match openvm_ecc_guest::ecdsa::VerifyingKey::<Secp256k1>::from_sec1_bytes(
213 encoded_point.as_bytes(),
214 ) {
215 Ok(verifying_key) => CtOption::new(*verifying_key.as_affine(), 1.into()),
216 Err(_) => CtOption::new(Secp256k1Point::default(), 0.into()),
217 }
218 }
219}
220
221impl ToEncodedPoint<Secp256k1> for Secp256k1Point {
222 fn to_encoded_point(&self, compress: bool) -> EncodedPoint {
223 EncodedPoint::conditional_select(
224 &EncodedPoint::from_affine_coordinates(
225 &<Self as WeierstrassPoint>::x(self).to_be_bytes().into(),
226 &<Self as WeierstrassPoint>::y(self).to_be_bytes().into(),
227 compress,
228 ),
229 &EncodedPoint::identity(),
230 elliptic_curve::Group::is_identity(self),
231 )
232 }
233}
234
235impl TryFrom<EncodedPoint> for Secp256k1Point {
236 type Error = elliptic_curve::Error;
237
238 fn try_from(point: EncodedPoint) -> elliptic_curve::Result<Secp256k1Point> {
239 Secp256k1Point::try_from(&point)
240 }
241}
242
243impl TryFrom<&EncodedPoint> for Secp256k1Point {
244 type Error = elliptic_curve::Error;
245
246 fn try_from(point: &EncodedPoint) -> elliptic_curve::Result<Secp256k1Point> {
247 Option::from(Secp256k1Point::from_encoded_point(point)).ok_or(elliptic_curve::Error)
248 }
249}
250
251impl From<Secp256k1Point> for EncodedPoint {
252 fn from(affine_point: Secp256k1Point) -> EncodedPoint {
253 EncodedPoint::from(&affine_point)
254 }
255}
256
257impl From<&Secp256k1Point> for EncodedPoint {
258 fn from(affine_point: &Secp256k1Point) -> EncodedPoint {
259 affine_point.to_encoded_point(true)
260 }
261}