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