Skip to content

Commit 33f0baa

Browse files
committed
arithmetic: Make Montgomery API more flexible.
Change the computation of `R` and `RR` to support writing the value to a larger output buffer, to support future refactorings.
1 parent 12a93c2 commit 33f0baa

File tree

7 files changed

+128
-15
lines changed

7 files changed

+128
-15
lines changed

src/arithmetic/bigint/exp.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ fn elem_exp_consttime_inner<N, M, const STORAGE_LIMBS: usize>(
150150
|init, uninit| {
151151
let r: Result<&mut [Limb], LimbSliceError> = match init.len() {
152152
// table[0] = base**0 (i.e. 1).
153-
0 => Ok(One::fillR(uninit, m)?),
153+
0 => Ok(One::write_mont_identity(&mut uninit.into_cursor(), m)?),
154154

155155
// table[1] = base*R == (base/R * RRR)/R
156156
1 => limbs_mul_mont(
@@ -282,6 +282,8 @@ fn elem_exp_consttime_inner<N, M, const STORAGE_LIMBS: usize>(
282282
let (acc, rest) = state.split_at_mut(m_len);
283283
let (base_cached, m_cached) = rest.split_at_mut(m_len);
284284

285+
let mut acc = polyfill::slice::Uninit::from(acc);
286+
285287
// "To improve cache locality" according to upstream.
286288
let (m_cached, _) = polyfill::slice::Uninit::from(m_cached)
287289
.write_copy_of_slice(m.limbs())?
@@ -327,7 +329,7 @@ fn elem_exp_consttime_inner<N, M, const STORAGE_LIMBS: usize>(
327329
// All entries in `table` will be Montgomery encoded.
328330

329331
// t0 = table[0] = base**0 (i.e. 1).
330-
let t0 = One::fillR(acc.as_mut().into(), m)?;
332+
let t0 = One::write_mont_identity(&mut acc.reborrow_mut().into_cursor(), m)?;
331333
scatter5(t0, table, LeakyWindow5::_0)?;
332334

333335
// acc = base**1 (i.e. base).

src/arithmetic/bigint/modulus/one.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::{
2424
cpu,
2525
error::LenMismatchError,
2626
limb::{self, LIMB_BITS},
27-
polyfill,
27+
polyfill::slice::Cursor,
2828
};
2929
use core::mem::size_of;
3030

@@ -45,14 +45,16 @@ impl<M, E> One<M, E> {
4545
}
4646

4747
impl<M> One<M, R> {
48-
pub(in super::super) fn fillR<'r>(
49-
out: polyfill::slice::Uninit<'r, Limb>,
48+
/// Writes the value of the Montgomery multiplication identity `R` for `m` to
49+
/// `out`.
50+
pub(in super::super) fn write_mont_identity<'r>(
51+
out: &mut Cursor<'r, Limb>,
5052
m: &Mont<'_, M>,
5153
) -> Result<&'r mut [Limb], LenMismatchError> {
5254
let r = m.limbs().len() * LIMB_BITS;
5355

5456
// out = 2**r - m where m = self.
55-
let out = limb::limbs_negative_odd(out, m.limbs())?;
57+
let out = limb::write_negative_assume_odd(out, m.limbs())?;
5658

5759
let lg_m = m.len_bits().as_bits();
5860
let leading_zero_bits_in_m = r - lg_m;
@@ -101,7 +103,7 @@ impl<M> One<M, RR> {
101103
let m = &Mont::from_parts_unchecked_less_safe(m, &n0, cpu);
102104

103105
let mut acc = out
104-
.write_fully_with(|out| One::fillR(out, m))
106+
.write_fully_with(|uninit| One::write_mont_identity(&mut uninit.into_cursor(), m))
105107
.map(Elem::<M, R>::assume_in_range_and_encoded_less_safe)?;
106108

107109
// 2**t * R can be calculated by t doublings starting with R.

src/limb.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::{
2222
bb, c,
2323
error::{self, LenMismatchError},
2424
polyfill::{
25-
slice::{AliasingSlices, InOut, Uninit},
25+
slice::{AliasingSlices, Cursor, InOut},
2626
sliceutil, usize_from_u32, ArrayFlatMap, StartMutPtr,
2727
},
2828
window5::Window5,
@@ -333,20 +333,22 @@ pub(crate) fn limbs_double_mod(r: &mut [Limb], m: &[Limb]) -> Result<(), LenMism
333333
}
334334

335335
// *r = -a, assuming a is odd.
336-
pub(crate) fn limbs_negative_odd<'r>(
337-
r: Uninit<'r, Limb>,
336+
pub(crate) fn write_negative_assume_odd<'r>(
337+
r: &mut Cursor<'r, Limb>,
338338
a: &[Limb],
339339
) -> Result<&'r mut [Limb], LenMismatchError> {
340340
// Two's complement step 1: flip all the bits.
341341
// The compiler should optimize this to vectorized (a ^ !0).
342342
let r = r
343343
.write_iter(a.iter().map(|&a| !a))
344-
.uninit_empty()?
345344
.src_empty()?
346345
.into_written();
347346
// Two's complement step 2: Add one. Since `a` is odd, `r` is even. Thus we
348347
// can use a bitwise or for addition.
349-
r[0] |= 1;
348+
let Some(least_significant_limb) = r.get_mut(0) else {
349+
return Err(LenMismatchError::new(a.len()));
350+
};
351+
*least_significant_limb |= 1;
350352
Ok(r)
351353
}
352354

src/polyfill.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ mod start_ptr;
9898
mod test;
9999

100100
mod uninit_slice;
101+
mod uninit_slice_cursor;
101102
mod unwrap_const;
102103

103104
pub use self::{

src/polyfill/slice.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use crate::polyfill::{StartMutPtr, StartPtr};
2727
pub(crate) use super::{
2828
aliasing_slices::{AliasSrc, AliasingSlices, InOut},
2929
uninit_slice::{AliasedUninit, Uninit},
30+
uninit_slice_cursor::Cursor,
3031
};
3132

3233
#[allow(dead_code)]

src/polyfill/uninit_slice.rs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
#[allow(unused_imports)]
1616
use crate::polyfill::prelude::*;
1717

18-
use super::start_ptr::{StartMutPtr, StartPtr};
18+
use super::{
19+
start_ptr::{StartMutPtr, StartPtr},
20+
uninit_slice_cursor::Cursor,
21+
};
1922
use crate::{error::LenMismatchError, polyfill};
2023
use core::{
2124
marker::PhantomData,
@@ -53,11 +56,25 @@ impl<E> StartMutPtr for &mut Uninit<'_, E> {
5356
}
5457

5558
impl<'target, E> Uninit<'target, E> {
59+
pub fn into_cursor(self) -> Cursor<'target, E> {
60+
Cursor::new(self)
61+
}
62+
5663
pub fn len(&self) -> usize {
5764
self.target.len()
5865
}
5966

60-
pub(super) fn split_off_mut(&mut self, range: RangeTo<usize>) -> Option<Uninit<'target, E>> {
67+
#[allow(dead_code)]
68+
pub fn reborrow_mut(&mut self) -> Uninit<'_, E> {
69+
Uninit {
70+
target: self.target,
71+
}
72+
}
73+
74+
pub(super) fn split_off_mut<'s>(
75+
&'s mut self,
76+
range: RangeTo<usize>,
77+
) -> Option<Uninit<'target, E>> {
6178
if self.target.len() < range.end {
6279
return None;
6380
}
@@ -74,7 +91,26 @@ impl<'target, E: Copy> Uninit<'target, E> {
7491
self,
7592
src: &[E],
7693
) -> Result<WriteResult<'target, E, Self, ()>, LenMismatchError> {
77-
self.write_iter(src.iter().copied()).src_empty()
94+
self.write_copy_of_slice_(src)
95+
.map_err(|uninit| LenMismatchError::new(uninit.len()))
96+
}
97+
98+
pub fn write_copy_of_slice_(
99+
mut self,
100+
src: &[E],
101+
) -> Result<WriteResult<'target, E, Self, ()>, Self> {
102+
let Some(mut dst) = self.split_off_mut(..src.len()) else {
103+
return Err(self);
104+
};
105+
let written = unsafe {
106+
ptr::copy_nonoverlapping(src.as_ptr(), dst.start_mut_ptr(), src.len());
107+
dst.assume_init()
108+
};
109+
Ok(WriteResult {
110+
written,
111+
dst_leftover: self,
112+
src_leftover: (),
113+
})
78114
}
79115

80116
pub fn write_iter<Src: IntoIterator<Item = E>>(
@@ -264,6 +300,7 @@ impl<'written, E, Dst, Src> WriteResult<'written, E, Dst, Src> {
264300
}
265301

266302
impl<'written, E, Src> WriteResult<'written, E, Uninit<'written, E>, Src> {
303+
#[allow(dead_code)]
267304
#[inline(always)]
268305
pub fn uninit_empty(self) -> Result<WriteResult<'written, E, (), Src>, LenMismatchError> {
269306
let (res, dst_leftover) = self.take_uninit();
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright 2025 Brian Smith.
2+
//
3+
// Permission to use, copy, modify, and/or distribute this software for any
4+
// purpose with or without fee is hereby granted, provided that the above
5+
// copyright notice and this permission notice appear in all copies.
6+
//
7+
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8+
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9+
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10+
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11+
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12+
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13+
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14+
15+
#[allow(unused_imports)]
16+
use crate::polyfill::prelude::*;
17+
18+
use super::uninit_slice::{Uninit, WriteResult};
19+
use crate::error::LenMismatchError;
20+
use core::mem;
21+
22+
pub struct Cursor<'buf, E> {
23+
uninit: Uninit<'buf, E>,
24+
}
25+
26+
impl<'buf, E> Cursor<'buf, E> {
27+
pub(super) const fn new(uninit: Uninit<'buf, E>) -> Self {
28+
Self { uninit }
29+
}
30+
31+
#[allow(dead_code)]
32+
pub fn write_copy_of_slice(&mut self, src: &[E]) -> Result<&'buf mut [E], LenMismatchError>
33+
where
34+
E: Copy,
35+
{
36+
match mem::take(&mut self.uninit).write_copy_of_slice_(src) {
37+
Ok(w) => {
38+
let (res, uninit) = w.take_uninit();
39+
self.uninit = uninit;
40+
Ok(res.into_written())
41+
}
42+
Err(uninit) => {
43+
self.uninit = uninit;
44+
Err(LenMismatchError::new(self.uninit.len()))
45+
}
46+
}
47+
}
48+
49+
pub fn write_iter<'s, Src: IntoIterator<Item = E>>(
50+
&'s mut self,
51+
src: Src,
52+
) -> WriteResult<'buf, E, (), Src::IntoIter>
53+
where
54+
E: Copy,
55+
{
56+
// TODO: Deal with panics.
57+
let uninit = mem::replace(&mut self.uninit, Uninit::from([].as_mut_slice()));
58+
let (res, uninit) = uninit.write_iter(src).take_uninit();
59+
self.uninit = uninit;
60+
res
61+
}
62+
}
63+
64+
impl<'buf, E> From<Uninit<'buf, E>> for Cursor<'buf, E> {
65+
fn from(uninit: Uninit<'buf, E>) -> Self {
66+
Self::new(uninit)
67+
}
68+
}

0 commit comments

Comments
 (0)