Skip to content

Commit 59f2370

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 3f21398 commit 59f2370

File tree

7 files changed

+99
-17
lines changed

7 files changed

+99
-17
lines changed

src/arithmetic/bigint/exp.rs

Lines changed: 5 additions & 3 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,11 +329,11 @@ 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).
334-
let acc = polyfill::slice::Uninit::from(acc)
336+
let acc = acc
335337
.write_copy_of_slice(base_cached)?
336338
.uninit_empty()?
337339
.into_written();

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: 33 additions & 4 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::from(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
}
@@ -71,10 +88,21 @@ impl<'target, E> Uninit<'target, E> {
7188
impl<'target, E: Copy> Uninit<'target, E> {
7289
#[allow(dead_code)]
7390
pub fn write_copy_of_slice(
74-
self,
91+
mut self,
7592
src: &[E],
7693
) -> Result<WriteResult<'target, E, Self, ()>, LenMismatchError> {
77-
self.write_iter(src.iter().copied()).src_empty()
94+
let Some(mut dst) = self.split_off_mut(..src.len()) else {
95+
return Err(LenMismatchError::new(self.len()));
96+
};
97+
let written = unsafe {
98+
ptr::copy_nonoverlapping(src.as_ptr(), dst.start_mut_ptr(), src.len());
99+
dst.assume_init()
100+
};
101+
Ok(WriteResult {
102+
written,
103+
dst_leftover: self,
104+
src_leftover: (),
105+
})
78106
}
79107

80108
pub fn write_iter<Src: IntoIterator<Item = E>>(
@@ -264,6 +292,7 @@ impl<'written, E, Dst, Src> WriteResult<'written, E, Dst, Src> {
264292
}
265293

266294
impl<'written, E, Src> WriteResult<'written, E, Uninit<'written, E>, Src> {
295+
#[allow(dead_code)]
267296
#[inline(always)]
268297
pub fn uninit_empty(self) -> Result<WriteResult<'written, E, (), Src>, LenMismatchError> {
269298
let (res, dst_leftover) = self.take_uninit();
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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 core::mem;
20+
21+
pub struct Cursor<'buf, E> {
22+
uninit: Uninit<'buf, E>,
23+
}
24+
25+
impl<'buf, E> Cursor<'buf, E> {
26+
pub fn write_iter<'s, Src: IntoIterator<Item = E>>(
27+
&'s mut self,
28+
src: Src,
29+
) -> WriteResult<'buf, E, (), Src::IntoIter>
30+
where
31+
E: Copy,
32+
{
33+
// TODO: Deal with panics.
34+
let uninit = mem::replace(&mut self.uninit, Uninit::from([].as_mut_slice()));
35+
let (res, uninit) = uninit.write_iter(src).take_uninit();
36+
self.uninit = uninit;
37+
res
38+
}
39+
}
40+
41+
impl<'buf, E> From<Uninit<'buf, E>> for Cursor<'buf, E> {
42+
fn from(uninit: Uninit<'buf, E>) -> Self {
43+
Self { uninit }
44+
}
45+
}

0 commit comments

Comments
 (0)