k256/arithmetic/field/
field_5x52.rs

1//! Field element modulo the curve internal modulus using 64-bit limbs.
2//! Inspired by the implementation in <https://github.com/bitcoin-core/secp256k1>
3
4use crate::FieldBytes;
5use elliptic_curve::{
6    subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
7    zeroize::Zeroize,
8};
9
10/// Scalars modulo SECP256k1 modulus (2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1).
11/// Uses 5 64-bit limbs (little-endian), where in the normalized form
12/// first 4 contain 52 bits of the value each, and the last one contains 48 bits.
13/// CurveArithmetic operations can be done without modulo reduction for some time,
14/// using the remaining overflow bits.
15#[derive(Clone, Copy, Debug)]
16pub struct FieldElement5x52(pub(crate) [u64; 5]);
17
18impl FieldElement5x52 {
19    /// Zero element.
20    pub const ZERO: Self = Self([0, 0, 0, 0, 0]);
21
22    /// Multiplicative identity.
23    pub const ONE: Self = Self([1, 0, 0, 0, 0]);
24
25    /// Attempts to parse the given byte array as an SEC1-encoded field element.
26    /// Does not check the result for being in the correct range.
27    pub(crate) const fn from_bytes_unchecked(bytes: &[u8; 32]) -> Self {
28        let w0 = (bytes[31] as u64)
29            | ((bytes[30] as u64) << 8)
30            | ((bytes[29] as u64) << 16)
31            | ((bytes[28] as u64) << 24)
32            | ((bytes[27] as u64) << 32)
33            | ((bytes[26] as u64) << 40)
34            | (((bytes[25] & 0xFu8) as u64) << 48);
35
36        let w1 = ((bytes[25] >> 4) as u64)
37            | ((bytes[24] as u64) << 4)
38            | ((bytes[23] as u64) << 12)
39            | ((bytes[22] as u64) << 20)
40            | ((bytes[21] as u64) << 28)
41            | ((bytes[20] as u64) << 36)
42            | ((bytes[19] as u64) << 44);
43
44        let w2 = (bytes[18] as u64)
45            | ((bytes[17] as u64) << 8)
46            | ((bytes[16] as u64) << 16)
47            | ((bytes[15] as u64) << 24)
48            | ((bytes[14] as u64) << 32)
49            | ((bytes[13] as u64) << 40)
50            | (((bytes[12] & 0xFu8) as u64) << 48);
51
52        let w3 = ((bytes[12] >> 4) as u64)
53            | ((bytes[11] as u64) << 4)
54            | ((bytes[10] as u64) << 12)
55            | ((bytes[9] as u64) << 20)
56            | ((bytes[8] as u64) << 28)
57            | ((bytes[7] as u64) << 36)
58            | ((bytes[6] as u64) << 44);
59
60        let w4 = (bytes[5] as u64)
61            | ((bytes[4] as u64) << 8)
62            | ((bytes[3] as u64) << 16)
63            | ((bytes[2] as u64) << 24)
64            | ((bytes[1] as u64) << 32)
65            | ((bytes[0] as u64) << 40);
66
67        Self([w0, w1, w2, w3, w4])
68    }
69
70    /// Attempts to parse the given byte array as an SEC1-encoded field element.
71    ///
72    /// Returns None if the byte array does not contain a big-endian integer in the range
73    /// [0, p).
74    #[inline]
75    pub fn from_bytes(bytes: &FieldBytes) -> CtOption<Self> {
76        let res = Self::from_bytes_unchecked(bytes.as_ref());
77        let overflow = res.get_overflow();
78        CtOption::new(res, !overflow)
79    }
80
81    pub const fn from_u64(val: u64) -> Self {
82        let w0 = val & 0xFFFFFFFFFFFFF;
83        let w1 = val >> 52;
84        Self([w0, w1, 0, 0, 0])
85    }
86
87    /// Returns the SEC1 encoding of this field element.
88    pub fn to_bytes(self) -> FieldBytes {
89        let mut ret = FieldBytes::default();
90        ret[0] = (self.0[4] >> 40) as u8;
91        ret[1] = (self.0[4] >> 32) as u8;
92        ret[2] = (self.0[4] >> 24) as u8;
93        ret[3] = (self.0[4] >> 16) as u8;
94        ret[4] = (self.0[4] >> 8) as u8;
95        ret[5] = self.0[4] as u8;
96        ret[6] = (self.0[3] >> 44) as u8;
97        ret[7] = (self.0[3] >> 36) as u8;
98        ret[8] = (self.0[3] >> 28) as u8;
99        ret[9] = (self.0[3] >> 20) as u8;
100        ret[10] = (self.0[3] >> 12) as u8;
101        ret[11] = (self.0[3] >> 4) as u8;
102        ret[12] = ((self.0[2] >> 48) as u8 & 0xFu8) | ((self.0[3] as u8 & 0xFu8) << 4);
103        ret[13] = (self.0[2] >> 40) as u8;
104        ret[14] = (self.0[2] >> 32) as u8;
105        ret[15] = (self.0[2] >> 24) as u8;
106        ret[16] = (self.0[2] >> 16) as u8;
107        ret[17] = (self.0[2] >> 8) as u8;
108        ret[18] = self.0[2] as u8;
109        ret[19] = (self.0[1] >> 44) as u8;
110        ret[20] = (self.0[1] >> 36) as u8;
111        ret[21] = (self.0[1] >> 28) as u8;
112        ret[22] = (self.0[1] >> 20) as u8;
113        ret[23] = (self.0[1] >> 12) as u8;
114        ret[24] = (self.0[1] >> 4) as u8;
115        ret[25] = ((self.0[0] >> 48) as u8 & 0xFu8) | ((self.0[1] as u8 & 0xFu8) << 4);
116        ret[26] = (self.0[0] >> 40) as u8;
117        ret[27] = (self.0[0] >> 32) as u8;
118        ret[28] = (self.0[0] >> 24) as u8;
119        ret[29] = (self.0[0] >> 16) as u8;
120        ret[30] = (self.0[0] >> 8) as u8;
121        ret[31] = self.0[0] as u8;
122        ret
123    }
124
125    /// Adds `x * (2^256 - modulus)`.
126    fn add_modulus_correction(&self, x: u64) -> Self {
127        // add (2^256 - modulus) * x to the first limb
128        let t0 = self.0[0] + x * 0x1000003D1u64;
129
130        // Propagate excess bits up the limbs
131        let t1 = self.0[1] + (t0 >> 52);
132        let t0 = t0 & 0xFFFFFFFFFFFFFu64;
133
134        let t2 = self.0[2] + (t1 >> 52);
135        let t1 = t1 & 0xFFFFFFFFFFFFFu64;
136
137        let t3 = self.0[3] + (t2 >> 52);
138        let t2 = t2 & 0xFFFFFFFFFFFFFu64;
139
140        let t4 = self.0[4] + (t3 >> 52);
141        let t3 = t3 & 0xFFFFFFFFFFFFFu64;
142
143        Self([t0, t1, t2, t3, t4])
144    }
145
146    /// Subtracts the overflow in the last limb and return it with the new field element.
147    /// Equivalent to subtracting a multiple of 2^256.
148    fn subtract_modulus_approximation(&self) -> (Self, u64) {
149        let x = self.0[4] >> 48;
150        let t4 = self.0[4] & 0x0FFFFFFFFFFFFu64; // equivalent to self -= 2^256 * x
151        (Self([self.0[0], self.0[1], self.0[2], self.0[3], t4]), x)
152    }
153
154    /// Checks if the field element is greater or equal to the modulus.
155    fn get_overflow(&self) -> Choice {
156        let m = self.0[1] & self.0[2] & self.0[3];
157        let x = (self.0[4] >> 48 != 0)
158            | ((self.0[4] == 0x0FFFFFFFFFFFFu64)
159                & (m == 0xFFFFFFFFFFFFFu64)
160                & (self.0[0] >= 0xFFFFEFFFFFC2Fu64));
161        Choice::from(x as u8)
162    }
163
164    /// Brings the field element's magnitude to 1, but does not necessarily normalize it.
165    pub fn normalize_weak(&self) -> Self {
166        // Reduce t4 at the start so there will be at most a single carry from the first pass
167        let (t, x) = self.subtract_modulus_approximation();
168
169        // The first pass ensures the magnitude is 1, ...
170        let res = t.add_modulus_correction(x);
171
172        // ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element)
173        debug_assert!(res.0[4] >> 49 == 0);
174
175        res
176    }
177
178    /// Fully normalizes the field element.
179    /// That is, first four limbs are at most 52 bit large, the last limb is at most 48 bit large,
180    /// and the value is less than the modulus.
181    pub fn normalize(&self) -> Self {
182        let res = self.normalize_weak();
183
184        // At most a single final reduction is needed;
185        // check if the value is >= the field characteristic
186        let overflow = res.get_overflow();
187
188        // Apply the final reduction (for constant-time behaviour, we do it always)
189        let res_corrected = res.add_modulus_correction(1u64);
190        // Mask off the possible multiple of 2^256 from the final reduction
191        let (res_corrected, x) = res_corrected.subtract_modulus_approximation();
192
193        // If the last limb didn't carry to bit 48 already,
194        // then it should have after any final reduction
195        debug_assert!(x == (overflow.unwrap_u8() as u64));
196
197        Self::conditional_select(&res, &res_corrected, overflow)
198    }
199
200    /// Checks if the field element becomes zero if normalized.
201    pub fn normalizes_to_zero(&self) -> Choice {
202        let res = self.normalize_weak();
203
204        let t0 = res.0[0];
205        let t1 = res.0[1];
206        let t2 = res.0[2];
207        let t3 = res.0[3];
208        let t4 = res.0[4];
209
210        // z0 tracks a possible raw value of 0, z1 tracks a possible raw value of the modulus
211        let z0 = t0 | t1 | t2 | t3 | t4;
212        let z1 = (t0 ^ 0x1000003D0u64) & t1 & t2 & t3 & (t4 ^ 0xF000000000000u64);
213
214        Choice::from(((z0 == 0) | (z1 == 0xFFFFFFFFFFFFFu64)) as u8)
215    }
216
217    /// Determine if this `FieldElement5x52` is zero.
218    ///
219    /// # Returns
220    ///
221    /// If zero, return `Choice(1)`.  Otherwise, return `Choice(0)`.
222    pub fn is_zero(&self) -> Choice {
223        Choice::from(((self.0[0] | self.0[1] | self.0[2] | self.0[3] | self.0[4]) == 0) as u8)
224    }
225
226    /// Determine if this `FieldElement5x52` is odd in the SEC1 sense: `self mod 2 == 1`.
227    ///
228    /// # Returns
229    ///
230    /// If odd, return `Choice(1)`.  Otherwise, return `Choice(0)`.
231    pub fn is_odd(&self) -> Choice {
232        (self.0[0] as u8 & 1).into()
233    }
234
235    /// The maximum number `m` for which `0xFFFFFFFFFFFFF * 2 * (m + 1) < 2^64`
236    #[cfg(debug_assertions)]
237    pub const fn max_magnitude() -> u32 {
238        2047u32
239    }
240
241    /// Returns -self, treating it as a value of given magnitude.
242    /// The provided magnitude must be equal or greater than the actual magnitude of `self`.
243    /// Raises the magnitude by 1.
244    pub const fn negate(&self, magnitude: u32) -> Self {
245        let m = (magnitude + 1) as u64;
246        let r0 = 0xFFFFEFFFFFC2Fu64 * 2 * m - self.0[0];
247        let r1 = 0xFFFFFFFFFFFFFu64 * 2 * m - self.0[1];
248        let r2 = 0xFFFFFFFFFFFFFu64 * 2 * m - self.0[2];
249        let r3 = 0xFFFFFFFFFFFFFu64 * 2 * m - self.0[3];
250        let r4 = 0x0FFFFFFFFFFFFu64 * 2 * m - self.0[4];
251        Self([r0, r1, r2, r3, r4])
252    }
253
254    /// Returns self + rhs mod p.
255    /// Sums the magnitudes.
256    pub const fn add(&self, rhs: &Self) -> Self {
257        Self([
258            self.0[0] + rhs.0[0],
259            self.0[1] + rhs.0[1],
260            self.0[2] + rhs.0[2],
261            self.0[3] + rhs.0[3],
262            self.0[4] + rhs.0[4],
263        ])
264    }
265
266    /// Multiplies by a single-limb integer.
267    /// Multiplies the magnitude by the same value.
268    pub const fn mul_single(&self, rhs: u32) -> Self {
269        let rhs_u64 = rhs as u64;
270        Self([
271            self.0[0] * rhs_u64,
272            self.0[1] * rhs_u64,
273            self.0[2] * rhs_u64,
274            self.0[3] * rhs_u64,
275            self.0[4] * rhs_u64,
276        ])
277    }
278
279    #[inline(always)]
280    fn mul_inner(&self, rhs: &Self) -> Self {
281        /*
282        `square()` is just `mul()` with equal arguments. Rust compiler is smart enough
283        to do all the necessary optimizations for this case, but it needs to have this information
284        inside a function. If a function is just *called* with the same arguments,
285        this information cannot be used, so the function must be inlined while using the same arguments.
286
287        Now `mul()` is quite long and therefore expensive to inline. So we have an inner (inlined)
288        function, that is used inside `mul()` and `square()`, and when it is used with the same
289        arguments in `square()`, compiler is able to use that fact after inlining.
290        */
291
292        let a0 = self.0[0] as u128;
293        let a1 = self.0[1] as u128;
294        let a2 = self.0[2] as u128;
295        let a3 = self.0[3] as u128;
296        let a4 = self.0[4] as u128;
297        let b0 = rhs.0[0] as u128;
298        let b1 = rhs.0[1] as u128;
299        let b2 = rhs.0[2] as u128;
300        let b3 = rhs.0[3] as u128;
301        let b4 = rhs.0[4] as u128;
302        let m = 0xFFFFFFFFFFFFFu128;
303        let r = 0x1000003D10u128;
304
305        debug_assert!(a0 >> 56 == 0);
306        debug_assert!(a1 >> 56 == 0);
307        debug_assert!(a2 >> 56 == 0);
308        debug_assert!(a3 >> 56 == 0);
309        debug_assert!(a4 >> 52 == 0);
310
311        debug_assert!(b0 >> 56 == 0);
312        debug_assert!(b1 >> 56 == 0);
313        debug_assert!(b2 >> 56 == 0);
314        debug_assert!(b3 >> 56 == 0);
315        debug_assert!(b4 >> 52 == 0);
316
317        // [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n.
318        // for 0 <= x <= 4, px is a shorthand for sum(a[i]*b[x-i], i=0..x).
319        // for 4 <= x <= 8, px is a shorthand for sum(a[i]*b[x-i], i=(x-4)..4)
320        // Note that [x 0 0 0 0 0] = [x*r].
321
322        let mut d = a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
323        debug_assert!(d >> 114 == 0);
324        // [d 0 0 0] = [p3 0 0 0]
325        let mut c = a4 * b4;
326        debug_assert!(c >> 112 == 0);
327        // [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0]
328        d += (c & m) * r;
329        c >>= 52;
330        debug_assert!(d >> 115 == 0);
331        debug_assert!(c >> 60 == 0);
332        let c64 = c as u64;
333        // [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0]
334        let t3 = (d & m) as u64;
335        d >>= 52;
336        debug_assert!(t3 >> 52 == 0);
337        debug_assert!(d >> 63 == 0);
338        let d64 = d as u64;
339        // [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0]
340
341        d = d64 as u128 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
342        debug_assert!(d >> 115 == 0);
343        // [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0]
344        d += c64 as u128 * r;
345        debug_assert!(d >> 116 == 0);
346        // [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0]
347        let t4 = (d & m) as u64;
348        d >>= 52;
349        debug_assert!(t4 >> 52 == 0);
350        debug_assert!(d >> 64 == 0);
351        let d64 = d as u64;
352        // [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0]
353        let tx = t4 >> 48;
354        let t4 = t4 & ((m as u64) >> 4);
355        debug_assert!(tx >> 4 == 0);
356        debug_assert!(t4 >> 48 == 0);
357        // [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0]
358
359        c = a0 * b0;
360        debug_assert!(c >> 112 == 0);
361        // [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0]
362        d = d64 as u128 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1;
363        debug_assert!(d >> 115 == 0);
364        // [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0]
365        let u0 = (d & m) as u64;
366        d >>= 52;
367        debug_assert!(u0 >> 52 == 0);
368        debug_assert!(d >> 63 == 0);
369        let d64 = d as u64;
370        // [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0]
371        // [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0]
372        let u0 = (u0 << 4) | tx;
373        debug_assert!(u0 >> 56 == 0);
374        // [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0]
375        c += u0 as u128 * ((r as u64) >> 4) as u128;
376        debug_assert!(c >> 115 == 0);
377        // [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0]
378        let r0 = (c & m) as u64;
379        c >>= 52;
380        debug_assert!(r0 >> 52 == 0);
381        debug_assert!(c >> 61 == 0);
382        let c64 = c as u64;
383        // [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0]
384
385        c = c64 as u128 + a0 * b1 + a1 * b0;
386        debug_assert!(c >> 114 == 0);
387        // [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0]
388        d = d64 as u128 + a2 * b4 + a3 * b3 + a4 * b2;
389        debug_assert!(d >> 114 == 0);
390        // [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0]
391        c += (d & m) * r;
392        d >>= 52;
393        debug_assert!(c >> 115 == 0);
394        debug_assert!(d >> 62 == 0);
395        let d64 = d as u64;
396        // [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0]
397        let r1 = (c & m) as u64;
398        c >>= 52;
399        debug_assert!(r1 >> 52 == 0);
400        debug_assert!(c >> 63 == 0);
401        let c64 = c as u64;
402        // [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0]
403
404        c = c64 as u128 + a0 * b2 + a1 * b1 + a2 * b0;
405        debug_assert!(c >> 114 == 0);
406        // [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0]
407        d = d64 as u128 + a3 * b4 + a4 * b3;
408        debug_assert!(d >> 114 == 0);
409        // [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0]
410        c += (d & m) * r;
411        d >>= 52;
412        debug_assert!(c >> 115 == 0);
413        debug_assert!(d >> 62 == 0);
414        let d64 = d as u64;
415        // [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0]
416
417        // [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0]
418        let r2 = (c & m) as u64;
419        c >>= 52;
420        debug_assert!(r2 >> 52 == 0);
421        debug_assert!(c >> 63 == 0);
422        let c64 = c as u64;
423        // [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0]
424        c = c64 as u128 + (d64 as u128) * r + t3 as u128;
425        debug_assert!(c >> 100 == 0);
426        // [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0]
427        let r3 = (c & m) as u64;
428        c >>= 52;
429        debug_assert!(r3 >> 52 == 0);
430        debug_assert!(c >> 48 == 0);
431        let c64 = c as u64;
432        // [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0]
433        c = c64 as u128 + t4 as u128;
434        debug_assert!(c >> 49 == 0);
435        // [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0]
436        let r4 = c as u64;
437        debug_assert!(r4 >> 49 == 0);
438        // [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0]
439
440        Self([r0, r1, r2, r3, r4])
441    }
442
443    /// Returns self * rhs mod p
444    /// Brings the magnitude to 1 (but doesn't normalize the result).
445    /// The magnitudes of arguments should be <= 8.
446    #[inline(always)]
447    pub fn mul(&self, rhs: &Self) -> Self {
448        self.mul_inner(rhs)
449    }
450
451    /// Returns self * self
452    /// Brings the magnitude to 1 (but doesn't normalize the result).
453    /// The magnitudes of arguments should be <= 8.
454    pub fn square(&self) -> Self {
455        self.mul_inner(self)
456    }
457}
458
459impl Default for FieldElement5x52 {
460    fn default() -> Self {
461        Self::ZERO
462    }
463}
464
465impl ConditionallySelectable for FieldElement5x52 {
466    #[inline(always)]
467    fn conditional_select(
468        a: &FieldElement5x52,
469        b: &FieldElement5x52,
470        choice: Choice,
471    ) -> FieldElement5x52 {
472        FieldElement5x52([
473            u64::conditional_select(&a.0[0], &b.0[0], choice),
474            u64::conditional_select(&a.0[1], &b.0[1], choice),
475            u64::conditional_select(&a.0[2], &b.0[2], choice),
476            u64::conditional_select(&a.0[3], &b.0[3], choice),
477            u64::conditional_select(&a.0[4], &b.0[4], choice),
478        ])
479    }
480}
481
482impl ConstantTimeEq for FieldElement5x52 {
483    fn ct_eq(&self, other: &Self) -> Choice {
484        self.0[0].ct_eq(&other.0[0])
485            & self.0[1].ct_eq(&other.0[1])
486            & self.0[2].ct_eq(&other.0[2])
487            & self.0[3].ct_eq(&other.0[3])
488            & self.0[4].ct_eq(&other.0[4])
489    }
490}
491
492impl Zeroize for FieldElement5x52 {
493    fn zeroize(&mut self) {
494        self.0.zeroize();
495    }
496}
497
498#[cfg(test)]
499mod tests {
500    use super::FieldElement5x52;
501
502    #[test]
503    fn overflow_check_after_weak_normalize() {
504        // A regression test for a missing condition in `get_overflow()`.
505        // The condition was only missing in the 32-bit case,
506        // but we're adding a 64-bit testcase nevertheless.
507        //
508        // In `normalize()`, after the `normalize_weak()` call,
509        // the excess bit from the limb 0 is propagated all the way to the last limb.
510        // This constitutes an overflow, since the last bit becomes equal to (1 << 22),
511        // that is 23 bits in total.
512        // When `get_overflow()` is called afterwards, this was not detected,
513        // since the corresponding condition (checking for the last limb being > 22 bits)
514        // was missing.
515        // This resulted in a debug assert firing later.
516        //
517        // This is essentially 2^256
518        let z = FieldElement5x52([
519            (1 << 52), // an excess bit here
520            // the remaining full-sized limbs are at top normalized capacity
521            (1 << 52) - 1,
522            (1 << 52) - 1,
523            (1 << 52) - 1,
524            // the last limb is also at top normalized capacity
525            (1 << 48) - 1,
526        ]);
527
528        // Used to fail here (debug_assert firing because overflow happened at an unexpected place):
529        let z_normalized = z.normalize();
530
531        // Properly normalized result, just to be sure
532        // The initial number is 2^256, so the result is 0x1000003d1
533        let z_reference = FieldElement5x52([0x1000003d1, 0, 0, 0, 0]);
534
535        assert_eq!(z_normalized.0, z_reference.0);
536    }
537}