crypto_bigint/uint/boxed/
sqrt.rs1use crate::{BoxedUint, CheckedSquareRoot, Choice, CtOption, FloorSquareRoot, NonZero};
4
5impl BoxedUint {
6 #[deprecated(since = "0.7.0", note = "please use `floor_sqrt` instead")]
10 #[must_use]
11 pub fn sqrt(&self) -> Self {
12 self.floor_sqrt()
13 }
14
15 #[must_use]
20 pub fn floor_sqrt(&self) -> Self {
21 let mut root = self.clone();
22 root.floor_sqrt_assign();
23 root
24 }
25
26 #[deprecated(since = "0.7.0", note = "please use `floor_sqrt_vartime` instead")]
32 #[must_use]
33 pub fn sqrt_vartime(&self) -> Self {
34 self.floor_sqrt_vartime()
35 }
36
37 #[must_use]
44 pub fn floor_sqrt_vartime(&self) -> Self {
45 let mut root = self.clone();
46 root.floor_sqrt_assign_vartime();
47 root
48 }
49
50 #[must_use]
54 pub fn wrapping_sqrt(&self) -> Self {
55 self.floor_sqrt()
56 }
57
58 #[must_use]
64 pub fn wrapping_sqrt_vartime(&self) -> Self {
65 self.floor_sqrt_vartime()
66 }
67
68 #[must_use]
71 pub fn checked_sqrt(&self) -> CtOption<Self> {
72 let mut root = self.clone();
73 let exact = root.floor_sqrt_assign();
74 CtOption::new(root, exact)
75 }
76
77 #[must_use]
82 pub fn checked_sqrt_vartime(&self) -> Option<Self> {
83 let mut root = self.clone();
84 if root.floor_sqrt_assign_vartime() {
85 Some(root)
86 } else {
87 None
88 }
89 }
90
91 fn floor_sqrt_assign(&mut self) -> Choice {
94 let size = self.nlimbs();
95 let mut buf = Self::zero_with_precision(self.bits_precision() * 2);
96 self.as_mut_uint_ref()
97 .sqrt_assign(buf.as_mut_uint_ref().split_at_mut(size))
98 }
99
100 pub fn floor_sqrt_assign_vartime(&mut self) -> bool {
105 let size = self.nlimbs();
106 let mut buf = Self::zero_with_precision(self.bits_precision() * 2);
107 self.as_mut_uint_ref()
108 .sqrt_assign_vartime(buf.as_mut_uint_ref().split_at_mut(size))
109 }
110}
111
112impl CheckedSquareRoot for BoxedUint {
113 type Output = Self;
114
115 fn checked_sqrt(&self) -> CtOption<Self::Output> {
116 self.checked_sqrt()
117 }
118
119 fn checked_sqrt_vartime(&self) -> Option<Self::Output> {
120 self.checked_sqrt_vartime()
121 }
122}
123
124impl FloorSquareRoot for BoxedUint {
125 fn floor_sqrt(&self) -> Self {
126 self.floor_sqrt()
127 }
128
129 fn floor_sqrt_vartime(&self) -> Self {
130 self.floor_sqrt_vartime()
131 }
132}
133
134impl CheckedSquareRoot for NonZero<BoxedUint> {
135 type Output = Self;
136
137 fn checked_sqrt(&self) -> CtOption<Self> {
138 self.as_ref().checked_sqrt().map(NonZero::new_unchecked)
139 }
140
141 fn checked_sqrt_vartime(&self) -> Option<Self> {
142 self.as_ref()
143 .checked_sqrt_vartime()
144 .map(NonZero::new_unchecked)
145 }
146}
147
148impl FloorSquareRoot for NonZero<BoxedUint> {
149 fn floor_sqrt(&self) -> Self {
150 NonZero::new_unchecked(self.as_ref().floor_sqrt())
151 }
152
153 fn floor_sqrt_vartime(&self) -> Self {
154 NonZero::new_unchecked(self.as_ref().floor_sqrt_vartime())
155 }
156}
157
158#[cfg(test)]
159#[allow(clippy::integer_division_remainder_used, reason = "test")]
160mod tests {
161 use crate::{BoxedUint, CheckedSquareRoot, FloorSquareRoot, Limb};
162
163 #[cfg(feature = "rand_core")]
164 use {
165 crate::RandomBits,
166 chacha20::ChaCha8Rng,
167 rand_core::{Rng, SeedableRng},
168 };
169
170 #[test]
171 fn edge() {
172 assert_eq!(
173 BoxedUint::zero_with_precision(256).floor_sqrt(),
174 BoxedUint::zero_with_precision(256)
175 );
176 assert_eq!(
177 BoxedUint::one_with_precision(256).floor_sqrt(),
178 BoxedUint::one_with_precision(256)
179 );
180 let mut half = BoxedUint::zero_with_precision(256);
181 for i in 0..half.limbs.len() / 2 {
182 half.limbs[i] = Limb::MAX;
183 }
184 let u256_max = BoxedUint::max(256);
185 assert_eq!(u256_max.floor_sqrt(), half);
186
187 assert_eq!(
191 BoxedUint::from_be_hex("055fa39422bd9f281762946e056535badbf8a6864d45fa3d", 192)
192 .unwrap()
193 .floor_sqrt(),
194 BoxedUint::from_be_hex("0000000000000000000000002516f0832a538b2d98869e21", 192)
195 .unwrap(),
196 );
197 assert_eq!(
198 BoxedUint::from_be_hex("055fa39422bd9f281762946e056535badbf8a6864d45fa3d", 192)
199 .unwrap()
200 .floor_sqrt_vartime(),
201 BoxedUint::from_be_hex("0000000000000000000000002516f0832a538b2d98869e21", 192)
202 .unwrap()
203 );
204
205 assert_eq!(
207 BoxedUint::from_be_hex(
208 "4bb750738e25a8f82940737d94a48a91f8cd918a3679ff90c1a631f2bd6c3597",
209 256
210 )
211 .unwrap()
212 .floor_sqrt(),
213 BoxedUint::from_be_hex(
214 "000000000000000000000000000000008b3956339e8315cff66eb6107b610075",
215 256
216 )
217 .unwrap()
218 );
219 assert_eq!(
220 BoxedUint::from_be_hex(
221 "4bb750738e25a8f82940737d94a48a91f8cd918a3679ff90c1a631f2bd6c3597",
222 256
223 )
224 .unwrap()
225 .floor_sqrt_vartime(),
226 BoxedUint::from_be_hex(
227 "000000000000000000000000000000008b3956339e8315cff66eb6107b610075",
228 256
229 )
230 .unwrap()
231 );
232 }
233
234 #[test]
235 fn edge_vartime() {
236 assert_eq!(
237 BoxedUint::zero_with_precision(256).floor_sqrt_vartime(),
238 BoxedUint::zero_with_precision(256)
239 );
240 assert_eq!(
241 BoxedUint::one_with_precision(256).floor_sqrt_vartime(),
242 BoxedUint::one_with_precision(256)
243 );
244 let mut half = BoxedUint::zero_with_precision(256);
245 for i in 0..half.limbs.len() / 2 {
246 half.limbs[i] = Limb::MAX;
247 }
248 let u256_max = !BoxedUint::zero_with_precision(256);
249 assert_eq!(u256_max.floor_sqrt_vartime(), half);
250 }
251
252 #[test]
253 fn simple() {
254 let tests = [
255 (4u8, 2u8),
256 (9, 3),
257 (16, 4),
258 (25, 5),
259 (36, 6),
260 (49, 7),
261 (64, 8),
262 (81, 9),
263 (100, 10),
264 (121, 11),
265 (144, 12),
266 (169, 13),
267 ];
268 for (a, e) in &tests {
269 let l = BoxedUint::from(*a);
270 let r = BoxedUint::from(*e);
271 assert_eq!(l.floor_sqrt(), r);
272 assert_eq!(l.floor_sqrt_vartime(), r);
273 assert_eq!(
274 CheckedSquareRoot::checked_sqrt(&l).into_option().as_ref(),
275 Some(&r)
276 );
277 assert_eq!(
278 CheckedSquareRoot::checked_sqrt_vartime(&l).as_ref(),
279 Some(&r)
280 );
281 let nz_l = l.as_nz_vartime().unwrap();
282 let nz_r = r.to_nz().unwrap();
283 assert_eq!(FloorSquareRoot::floor_sqrt(nz_l), nz_r);
284 assert_eq!(FloorSquareRoot::floor_sqrt_vartime(nz_l), nz_r);
285 assert_eq!(
286 CheckedSquareRoot::checked_sqrt(nz_l).into_option().as_ref(),
287 Some(&nz_r)
288 );
289 assert_eq!(
290 CheckedSquareRoot::checked_sqrt_vartime(nz_l).as_ref(),
291 Some(&nz_r)
292 );
293 }
294 }
295
296 #[test]
297 fn nonsquares() {
298 assert_eq!(BoxedUint::from(2u8).floor_sqrt(), BoxedUint::from(1u8));
299 assert!(!BoxedUint::from(2u8).checked_sqrt().is_some().to_bool());
300 assert_eq!(BoxedUint::from(3u8).floor_sqrt(), BoxedUint::from(1u8));
301 assert!(!BoxedUint::from(3u8).checked_sqrt().is_some().to_bool());
302 assert_eq!(BoxedUint::from(5u8).floor_sqrt(), BoxedUint::from(2u8));
303 assert_eq!(BoxedUint::from(6u8).floor_sqrt(), BoxedUint::from(2u8));
304 assert_eq!(BoxedUint::from(7u8).floor_sqrt(), BoxedUint::from(2u8));
305 assert_eq!(BoxedUint::from(8u8).floor_sqrt(), BoxedUint::from(2u8));
306 assert_eq!(BoxedUint::from(10u8).floor_sqrt(), BoxedUint::from(3u8));
307 }
308
309 #[test]
310 fn nonsquares_vartime() {
311 assert_eq!(
312 BoxedUint::from(2u8).floor_sqrt_vartime(),
313 BoxedUint::from(1u8)
314 );
315 assert!(BoxedUint::from(2u8).checked_sqrt_vartime().is_none());
316 assert_eq!(
317 BoxedUint::from(3u8).floor_sqrt_vartime(),
318 BoxedUint::from(1u8)
319 );
320 assert!(BoxedUint::from(3u8).checked_sqrt_vartime().is_none());
321 assert_eq!(
322 BoxedUint::from(5u8).floor_sqrt_vartime(),
323 BoxedUint::from(2u8)
324 );
325 assert_eq!(
326 BoxedUint::from(6u8).floor_sqrt_vartime(),
327 BoxedUint::from(2u8)
328 );
329 assert_eq!(
330 BoxedUint::from(7u8).floor_sqrt_vartime(),
331 BoxedUint::from(2u8)
332 );
333 assert_eq!(
334 BoxedUint::from(8u8).floor_sqrt_vartime(),
335 BoxedUint::from(2u8)
336 );
337 assert_eq!(
338 BoxedUint::from(10u8).floor_sqrt_vartime(),
339 BoxedUint::from(3u8)
340 );
341 }
342
343 #[cfg(feature = "rand_core")]
344 #[test]
345 fn fuzz() {
346 use crate::ConcatenatingSquare;
347
348 let mut rng = ChaCha8Rng::from_seed([7u8; 32]);
349 let rounds = if cfg!(miri) { 10 } else { 50 };
350 for _ in 0..rounds {
351 let t = u64::from(rng.next_u32());
352 let s = BoxedUint::from(t);
353 let s2 = s.checked_mul(&s).unwrap();
354 assert_eq!(s2.floor_sqrt(), s);
355 assert_eq!(s2.floor_sqrt_vartime(), s);
356 assert!(CheckedSquareRoot::checked_sqrt(&s2).is_some().to_bool());
357 assert!(CheckedSquareRoot::checked_sqrt_vartime(&s2).is_some());
358 }
359
360 for _ in 0..rounds {
361 let s = BoxedUint::random_bits(&mut rng, 512);
362 let mut s2 = BoxedUint::zero_with_precision(512);
363 s2.limbs[..s.limbs.len()].copy_from_slice(&s.limbs);
364 assert_eq!(s.concatenating_square().floor_sqrt(), s2);
365 assert_eq!(s.concatenating_square().floor_sqrt_vartime(), s2);
366 }
367 }
368}