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 #[must_use]
68 fn square(&self) -> Self {
69 self * self
70 }
71
72 #[must_use]
73 fn double(&self) -> Self {
74 self + self
75 }
76
77 fn invert(&self) -> CtOption<Self> {
78 self.assert_reduced();
80 let is_zero = self.ct_eq(&<Self as IntMod>::ZERO);
81 CtOption::new(
82 <P256Scalar as openvm_algebra_guest::Field>::invert(self),
83 !is_zero,
84 )
85 }
86
87 #[allow(clippy::many_single_char_names)]
88 fn sqrt(&self) -> CtOption<Self> {
89 match <Self as openvm_algebra_guest::Sqrt>::sqrt(self) {
90 Some(sqrt) => CtOption::new(sqrt, 1.into()),
91 None => CtOption::new(<Self as Field>::ZERO, 0.into()),
92 }
93 }
94
95 fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
96 ff::helpers::sqrt_ratio_generic(num, div)
97 }
98}
99
100const fn seven_le() -> [u8; 32] {
101 let mut buf = [0u8; 32];
102 buf[0] = 7;
103 buf
104}
105
106impl PrimeField for P256Scalar {
107 type Repr = FieldBytes;
108
109 const MODULUS: &'static str = ORDER_HEX;
110 const NUM_BITS: u32 = 256;
111 const CAPACITY: u32 = 255;
112 const TWO_INV: Self = Self::from_const_bytes(hex!(
113 "a992317e61e5dc7942cf8bd3567d73deffffffffffffff7f00000080ffffff7f"
114 ));
115 const MULTIPLICATIVE_GENERATOR: Self = Self::from_const_bytes(seven_le());
116 const S: u32 = 4;
117 const ROOT_OF_UNITY: Self = Self::from_const_bytes(hex!(
118 "02661eb4fbd79205af8d3704d0ca4615fc3d2a84ce7a80ba9209772a067fc9ff"
119 ));
120 const ROOT_OF_UNITY_INV: Self = Self::from_const_bytes(hex!(
121 "6437c757067f9c3737414c797c11ace3ae1c135804fa45c62a6fd462556aa6a0"
122 ));
123 const DELTA: Self = Self::from_const_bytes(hex!(
124 "817d05a5391e0000000000000000000000000000000000000000000000000000"
125 ));
126
127 fn from_repr(bytes: FieldBytes) -> CtOption<Self> {
132 let ret = Self::from_be_bytes_unchecked(bytes.as_slice());
133 CtOption::new(ret, (ret.is_reduced() as u8).into())
134 }
135
136 fn to_repr(&self) -> FieldBytes {
138 *FieldBytes::from_slice(&self.to_be_bytes())
139 }
140
141 fn is_odd(&self) -> Choice {
142 (self.as_le_bytes()[0] & 1).into()
143 }
144}
145
146impl ShrAssign<usize> for P256Scalar {
147 fn shr_assign(&mut self, _rhs: usize) {
148 unimplemented!()
150 }
151}
152
153impl Reduce<U256> for P256Scalar {
154 type Bytes = FieldBytes;
155
156 fn reduce(w: U256) -> Self {
157 <Self as openvm_algebra_guest::Reduce>::reduce_le_bytes(&w.to_le_bytes())
158 }
159
160 #[inline]
161 fn reduce_bytes(bytes: &FieldBytes) -> Self {
162 Self::reduce(U256::from_be_byte_array(*bytes))
163 }
164}
165
166impl PartialOrd for P256Scalar {
167 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
169 self.assert_reduced();
170 other.assert_reduced();
171 Some(
172 self.to_be_bytes()
173 .iter()
174 .zip(other.to_be_bytes().iter())
175 .map(|(a, b)| a.cmp(b))
176 .find(|ord| *ord != Ordering::Equal)
177 .unwrap_or(Ordering::Equal),
178 )
179 }
180}
181
182impl IsHigh for P256Scalar {
183 fn is_high(&self) -> Choice {
184 ((self + self < *self) as u8).into()
188 }
189}
190
191impl Invert for P256Scalar {
192 type Output = CtOption<Self>;
193
194 fn invert(&self) -> CtOption<Self> {
195 <Self as Field>::invert(self)
196 }
197}
198
199impl FromUintUnchecked for P256Scalar {
200 type Uint = U256;
201
202 fn from_uint_unchecked(uint: Self::Uint) -> Self {
203 Self::from_le_bytes_unchecked(&uint.to_le_bytes())
204 }
205}
206
207impl From<ScalarPrimitive<NistP256>> for P256Scalar {
208 fn from(scalar: ScalarPrimitive<NistP256>) -> Self {
209 Self::from_le_bytes_unchecked(&scalar.as_uint().to_le_bytes())
210 }
211}
212
213impl From<P256Scalar> for ScalarPrimitive<NistP256> {
214 fn from(scalar: P256Scalar) -> ScalarPrimitive<NistP256> {
215 ScalarPrimitive::from_slice(&scalar.to_be_bytes()).unwrap()
216 }
217}
218
219impl DefaultIsZeroes for P256Scalar {}
220
221impl AsRef<P256Scalar> for P256Scalar {
222 fn as_ref(&self) -> &P256Scalar {
223 self
224 }
225}
226
227impl From<P256Scalar> for U256 {
228 fn from(scalar: P256Scalar) -> Self {
229 U256::from_be_slice(&scalar.to_be_bytes())
230 }
231}
232
233impl From<P256Scalar> for FieldBytes {
234 fn from(scalar: P256Scalar) -> Self {
235 *FieldBytes::from_slice(&scalar.to_be_bytes())
236 }
237}