1use core::{fmt::{Debug, Formatter}, ops::Add};
2
3use dashu::integer::UBig;
4use solana_nostd_secp256k1_recover::secp256k1_recover;
5
6#[cfg(feature="big-mod-exp")]
7use solana_nostd_big_mod_exp::big_mod_exp;
8
9
10use crate::{CompressedPoint, Curve, Secp256k1Error, Secp256k1Point};
11
12pub const SEC1_OCTET_UNCOMPRESSED: u8 = 0x04;
13
14#[derive(PartialEq, Eq, Clone, Copy)]
15pub struct UncompressedPoint(pub [u8; Self::SIZE]);
16
17impl Secp256k1Point for UncompressedPoint {
18 const SIZE: usize = 64;
19
20 fn is_odd(&self) -> bool {
21 self.0[63] & 1 != 0
22 }
23
24 fn is_even(&self) -> bool {
25 self.0[63] & 1 != 1
26 }
27
28 fn x(&self) -> [u8; 32] {
29 [
30 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], self.0[7],
31 self.0[8], self.0[9], self.0[10], self.0[11], self.0[12], self.0[13], self.0[14],
32 self.0[15], self.0[16], self.0[17], self.0[18], self.0[19], self.0[20], self.0[21],
33 self.0[22], self.0[23], self.0[24], self.0[25], self.0[26], self.0[27], self.0[28],
34 self.0[29], self.0[30], self.0[31],
35 ]
36 }
37
38 fn y(&self) -> [u8; 32] {
39 [
40 self.0[32], self.0[33], self.0[34], self.0[35], self.0[36], self.0[37], self.0[38],
41 self.0[39], self.0[40], self.0[41], self.0[42], self.0[43], self.0[44], self.0[45],
42 self.0[46], self.0[47], self.0[48], self.0[49], self.0[50], self.0[51], self.0[52],
43 self.0[53], self.0[54], self.0[55], self.0[56], self.0[57], self.0[58], self.0[59],
44 self.0[60], self.0[61], self.0[62], self.0[63],
45 ]
46 }
47
48 #[cfg(feature="big-mod-exp")]
49 fn lift_x(x: &[u8; 32]) -> Result<Self, Secp256k1Error> {
50 let x_3 = (&UBig::from_be_bytes(x).pow(3) + UBig::from_word(7)) % &UBig::from_be_bytes(&Curve::P);
52 let y = big_mod_exp(&x_3.to_be_bytes(), &Curve::P_1_4, &Curve::P);
54 if (&UBig::from_be_bytes(&y).pow(2) % &UBig::from_be_bytes(&Curve::P)) != x_3 {
55 return Err(Secp256k1Error::InvalidYCoordinate);
56 }
57 let mut x_y = [0u8; 64];
58 x_y[..32].clone_from_slice(x);
59 x_y[32..].clone_from_slice(&y);
60 Ok(Self(x_y))
61 }
62
63 #[cfg(feature="big-mod-exp")]
64 fn lift_x_unchecked(x: &[u8; 32]) -> Self {
65 let x_3 = (&UBig::from_be_bytes(x).pow(3) + UBig::from_word(7)) % &UBig::from_be_bytes(&Curve::P);
67 let y = big_mod_exp(&x_3.to_be_bytes(), &Curve::P_1_4, &Curve::P);
69 let mut x_y = [0u8; 64];
70 x_y[..32].clone_from_slice(x);
71 x_y[32..].clone_from_slice(&y);
72 Self(x_y)
73 }
74
75 #[cfg(not(feature="big-mod-exp"))]
76 fn lift_x(x: &[u8; 32]) -> Result<Self, Secp256k1Error> {
77 Curve::lift_x(x)
78 }
79
80 #[cfg(not(feature="big-mod-exp"))]
81 fn lift_x_unchecked(x: &[u8; 32]) -> Self {
82 Curve::lift_x_unchecked(x)
83 }
84
85 fn invert(&mut self) {
86 let y = (UBig::from_be_bytes(&Curve::P) - UBig::from_be_bytes(&self.y())).to_be_bytes();
87 self.0[32..64].clone_from_slice(&[0u8;32]);
88 self.0[64-y.len()..].clone_from_slice(&y);
89 }
90
91 fn compress(&self) -> CompressedPoint {
92 CompressedPoint::from(*self)
93 }
94
95 fn decompress(&self) -> UncompressedPoint {
96 *self
97 }
98
99 fn tweak(&self, tweak: [u8; 32]) -> Result<Self, Secp256k1Error> {
100 let z_scalar = ((UBig::from_be_bytes(&Curve::negate_n(&self.x())) * UBig::from_be_bytes(&tweak)) % UBig::from_be_bytes(&Curve::N)).to_be_bytes();
102
103 let mut z = [0u8; 32];
105 z[32 - z_scalar.len()..].copy_from_slice(&z_scalar);
106
107 let s: [u8; 64] = [
108 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], self.0[7],
109 self.0[8], self.0[9], self.0[10], self.0[11], self.0[12], self.0[13], self.0[14], self.0[15],
110 self.0[16], self.0[17], self.0[18], self.0[19], self.0[20], self.0[21], self.0[22], self.0[23],
111 self.0[24], self.0[25], self.0[26], self.0[27], self.0[28], self.0[29], self.0[30], self.0[31],
112 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], self.0[7],
113 self.0[8], self.0[9], self.0[10], self.0[11], self.0[12], self.0[13], self.0[14], self.0[15],
114 self.0[16], self.0[17], self.0[18], self.0[19], self.0[20], self.0[21], self.0[22], self.0[23],
115 self.0[24], self.0[25], self.0[26], self.0[27], self.0[28], self.0[29], self.0[30], self.0[31],
116 ];
117
118 Ok(UncompressedPoint(secp256k1_recover(&z, self.is_odd(), &s)?))
120 }
121}
122
123impl Add<UncompressedPoint> for UncompressedPoint {
124 type Output = UncompressedPoint;
125
126 fn add(self, rhs: UncompressedPoint) -> Self::Output {
127 let rhs: UncompressedPoint = rhs.decompress();
128 let p = UBig::from_be_bytes(&Curve::P); let x_p = UBig::from_be_bytes(&self.x());
132 let y_p = UBig::from_be_bytes(&self.y());
133 let x_q = UBig::from_be_bytes(&rhs.x());
134 let y_q = UBig::from_be_bytes(&rhs.y());
135
136 let inv = Curve::mod_inv_p(&(&x_q - &x_p).to_be_bytes()).expect("This shouldn't fail");
138 let inv = UBig::from_be_bytes(&inv);
139
140 let m = (&y_q + &p - &y_p) * inv % &p;
142
143 let xr = (&m * &m + &p - &x_p - &x_q) % &p;
145
146 let yr = (&m * (&x_p + &p - &xr) + &p - &y_p) % &p;
148
149 let mut result_x = [0u8; 32];
151 let mut result_y = [0u8; 32];
152 result_x.copy_from_slice(&xr.to_be_bytes());
153 result_y.copy_from_slice(&yr.to_be_bytes());
154
155 let mut result = [0u8; 64];
157 result[..32].copy_from_slice(&result_x);
158 result[32..].copy_from_slice(&result_y);
159
160 UncompressedPoint(result)
161 }
162}
163
164impl Add<CompressedPoint> for UncompressedPoint {
165 type Output = UncompressedPoint;
166
167 fn add(self, rhs: CompressedPoint) -> Self::Output {
168 self.add(rhs.decompress())
169 }
170}
171
172impl Debug for UncompressedPoint {
173 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
174 for byte in &self.0 {
175 write!(f, "{:02X}", byte)?;
176 }
177 Ok(())
178 }
179}
180
181impl UncompressedPoint {
182 pub fn to_sec1_bytes(&self) -> [u8; 65] {
183 [
184 SEC1_OCTET_UNCOMPRESSED,
185 self.0[0],
186 self.0[1],
187 self.0[2],
188 self.0[3],
189 self.0[4],
190 self.0[5],
191 self.0[6],
192 self.0[7],
193 self.0[8],
194 self.0[9],
195 self.0[10],
196 self.0[11],
197 self.0[12],
198 self.0[13],
199 self.0[14],
200 self.0[15],
201 self.0[16],
202 self.0[17],
203 self.0[18],
204 self.0[19],
205 self.0[20],
206 self.0[21],
207 self.0[22],
208 self.0[23],
209 self.0[24],
210 self.0[25],
211 self.0[26],
212 self.0[27],
213 self.0[28],
214 self.0[29],
215 self.0[30],
216 self.0[31],
217 self.0[32],
218 self.0[33],
219 self.0[34],
220 self.0[35],
221 self.0[36],
222 self.0[37],
223 self.0[38],
224 self.0[39],
225 self.0[40],
226 self.0[41],
227 self.0[42],
228 self.0[43],
229 self.0[44],
230 self.0[45],
231 self.0[46],
232 self.0[47],
233 self.0[48],
234 self.0[49],
235 self.0[50],
236 self.0[51],
237 self.0[52],
238 self.0[53],
239 self.0[54],
240 self.0[55],
241 self.0[56],
242 self.0[57],
243 self.0[58],
244 self.0[59],
245 self.0[60],
246 self.0[61],
247 self.0[62],
248 self.0[63],
249 ]
250 }
251}
252
253impl TryFrom<CompressedPoint> for UncompressedPoint {
254 type Error = Secp256k1Error;
255
256 fn try_from(x: CompressedPoint) -> Result<Self, Secp256k1Error> {
257 let mut point = UncompressedPoint::lift_x(&x.x())?;
258 if point.is_odd() != x.is_odd() {
259 point.invert();
260 }
261 Ok(point)
262 }
263}
264
265impl From<[u8; 65]> for UncompressedPoint {
266 fn from(p: [u8; 65]) -> Self {
267 let mut s = [0u8; 64];
268 s.clone_from_slice(&p[1..]);
269 UncompressedPoint(s)
270 }
271}
272
273impl TryFrom<[u8; 32]> for UncompressedPoint {
274 type Error = Secp256k1Error;
275
276 fn try_from(scalar: [u8; 32]) -> Result<Self, Self::Error> {
277 Curve::mul_g(&scalar)
278 }
279}