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