1use alloc::vec::Vec;
2use core::{cmp::Ordering, ops::ShrAssign};
3
4use elliptic_curve::{
5 bigint::{ArrayEncoding, Encoding, U256},
6 ops::{Invert, Reduce},
7 rand_core::RngCore,
8 scalar::{FromUintUnchecked, IsHigh},
9 subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
10 zeroize::DefaultIsZeroes,
11 Field, PrimeField, ScalarPrimitive,
12};
13use hex_literal::hex;
14use openvm_algebra_guest::IntMod;
15
16use crate::{
17 internal::{seven_le, Secp256k1Scalar},
18 point::FieldBytes,
19 Secp256k1, ORDER_HEX,
20};
21
22impl Secp256k1Scalar {
23 pub fn to_bytes(&self) -> FieldBytes {
25 self.to_be_bytes().into()
26 }
27}
28impl Copy for Secp256k1Scalar {}
31
32impl From<u64> for Secp256k1Scalar {
33 fn from(value: u64) -> Self {
34 Self::from_u64(value)
35 }
36}
37
38impl Default for Secp256k1Scalar {
39 fn default() -> Self {
40 <Self as IntMod>::ZERO
41 }
42}
43
44impl ConstantTimeEq for Secp256k1Scalar {
46 fn ct_eq(&self, other: &Self) -> Choice {
47 self.as_le_bytes().ct_eq(other.as_le_bytes())
48 }
49}
50
51impl ConditionallySelectable for Secp256k1Scalar {
52 fn conditional_select(
53 a: &Secp256k1Scalar,
54 b: &Secp256k1Scalar,
55 choice: Choice,
56 ) -> Secp256k1Scalar {
57 Secp256k1Scalar::from_le_bytes_unchecked(
58 &a.as_le_bytes()
59 .iter()
60 .zip(b.as_le_bytes().iter())
61 .map(|(a, b)| u8::conditional_select(a, b, choice))
62 .collect::<Vec<_>>(),
63 )
64 }
65}
66
67impl Field for Secp256k1Scalar {
68 const ZERO: Self = <Self as IntMod>::ZERO;
69 const ONE: Self = <Self as IntMod>::ONE;
70
71 fn random(mut _rng: impl RngCore) -> Self {
72 unimplemented!()
73 }
74
75 #[must_use]
76 fn square(&self) -> Self {
77 self * self
78 }
79
80 #[must_use]
81 fn double(&self) -> Self {
82 self + self
83 }
84
85 fn invert(&self) -> CtOption<Self> {
86 self.assert_reduced();
88 let is_zero = self.ct_eq(&<Self as IntMod>::ZERO);
89 CtOption::new(
90 <Secp256k1Scalar as openvm_algebra_guest::Field>::invert(self),
91 !is_zero,
92 )
93 }
94
95 #[allow(clippy::many_single_char_names)]
96 fn sqrt(&self) -> CtOption<Self> {
97 match <Self as openvm_algebra_guest::Sqrt>::sqrt(self) {
98 Some(sqrt) => CtOption::new(sqrt, 1.into()),
99 None => CtOption::new(<Self as Field>::ZERO, 0.into()),
100 }
101 }
102
103 fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
104 ff::helpers::sqrt_ratio_generic(num, div)
105 }
106}
107
108impl PrimeField for Secp256k1Scalar {
109 type Repr = FieldBytes;
110
111 const MODULUS: &'static str = ORDER_HEX;
112 const NUM_BITS: u32 = 256;
113 const CAPACITY: u32 = 255;
114 const TWO_INV: Self = Self::from_const_bytes(hex!(
115 "a1201b68462fe9df1d50a457736e575dffffffffffffffffffffffffffffff7f"
116 ));
117 const MULTIPLICATIVE_GENERATOR: Self = Self::from_const_bytes(seven_le());
118 const S: u32 = 6;
119 const ROOT_OF_UNITY: Self = Self::from_const_bytes(hex!(
120 "f252b002544b2f9945607580b6eabd98a883c4fba37998df8619a9e760c01d0c"
121 ));
122 const ROOT_OF_UNITY_INV: Self = Self::from_const_bytes(hex!(
123 "1c0d4f88a030fbb6c313a40a9175a27772bb8c5bc7b0c7ef96702df181e13afd"
124 ));
125 const DELTA: Self = Self::from_const_bytes(hex!(
126 "0176bbc0c81794191e34e180e7783bd6c86145fe21bc0c000000000000000000"
127 ));
128
129 fn from_repr(bytes: FieldBytes) -> CtOption<Self> {
134 let ret = Self::from_be_bytes_unchecked(bytes.as_slice());
135 CtOption::new(ret, (ret.is_reduced() as u8).into())
136 }
137
138 fn to_repr(&self) -> FieldBytes {
140 *FieldBytes::from_slice(&self.to_be_bytes())
141 }
142
143 fn is_odd(&self) -> Choice {
144 (self.as_le_bytes()[0] & 1).into()
145 }
146}
147
148impl ShrAssign<usize> for Secp256k1Scalar {
149 fn shr_assign(&mut self, _rhs: usize) {
150 unimplemented!()
152 }
153}
154
155impl Reduce<U256> for Secp256k1Scalar {
156 type Bytes = FieldBytes;
157
158 fn reduce(w: U256) -> Self {
159 <Self as openvm_algebra_guest::Reduce>::reduce_le_bytes(&w.to_le_bytes())
160 }
161
162 #[inline]
163 fn reduce_bytes(bytes: &FieldBytes) -> Self {
164 Self::reduce(U256::from_be_byte_array(*bytes))
165 }
166}
167
168impl PartialOrd for Secp256k1Scalar {
169 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
171 self.assert_reduced();
172 other.assert_reduced();
173 Some(
174 self.to_be_bytes()
175 .iter()
176 .zip(other.to_be_bytes().iter())
177 .map(|(a, b)| a.cmp(b))
178 .find(|ord| *ord != Ordering::Equal)
179 .unwrap_or(Ordering::Equal),
180 )
181 }
182}
183
184impl IsHigh for Secp256k1Scalar {
185 fn is_high(&self) -> Choice {
186 ((self + self < *self) as u8).into()
190 }
191}
192
193impl Invert for Secp256k1Scalar {
194 type Output = CtOption<Self>;
195
196 fn invert(&self) -> CtOption<Self> {
197 <Self as Field>::invert(self)
198 }
199}
200
201impl FromUintUnchecked for Secp256k1Scalar {
202 type Uint = U256;
203
204 fn from_uint_unchecked(uint: Self::Uint) -> Self {
205 Self::from_le_bytes_unchecked(&uint.to_le_bytes())
206 }
207}
208
209impl From<ScalarPrimitive<Secp256k1>> for Secp256k1Scalar {
210 fn from(scalar: ScalarPrimitive<Secp256k1>) -> Self {
211 Self::from_le_bytes_unchecked(&scalar.as_uint().to_le_bytes())
212 }
213}
214
215impl From<Secp256k1Scalar> for ScalarPrimitive<Secp256k1> {
216 fn from(scalar: Secp256k1Scalar) -> ScalarPrimitive<Secp256k1> {
217 ScalarPrimitive::from_slice(&scalar.to_be_bytes()).unwrap()
218 }
219}
220
221impl DefaultIsZeroes for Secp256k1Scalar {}
222
223impl AsRef<Secp256k1Scalar> for Secp256k1Scalar {
224 fn as_ref(&self) -> &Secp256k1Scalar {
225 self
226 }
227}
228
229impl From<Secp256k1Scalar> for U256 {
230 fn from(scalar: Secp256k1Scalar) -> Self {
231 U256::from_be_slice(&scalar.to_be_bytes())
232 }
233}
234
235impl From<Secp256k1Scalar> for FieldBytes {
236 fn from(scalar: Secp256k1Scalar) -> Self {
237 *FieldBytes::from_slice(&scalar.to_be_bytes())
238 }
239}