bigint: Split Nonnegative into its own module.

Clarify that `Nonnegative` values are immutable by enforcing this
through the module system.

Some read-only to-be-refactored-away methods of `Nonnegative` stay in
`bigint` to avoid moving them back-and-forth later.

`git diff HEAD^1:src/arithmetic/bigint.rs src/arithmetic/nonnegative.rs`
This commit is contained in:
Brian Smith 2022-11-28 18:01:28 -08:00
parent f8ea7829bd
commit e8da038f27
3 changed files with 84 additions and 48 deletions

View File

@ -1,4 +1,4 @@
// Copyright 2017 Brian Smith.
// Copyright 2017-2023 Brian Smith.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
@ -19,3 +19,6 @@ pub mod constant;
pub mod bigint;
pub mod montgomery;
#[cfg(feature = "alloc")]
mod nonnegative;

View File

@ -1,4 +1,4 @@
// Copyright 2015-2016 Brian Smith.
// Copyright 2015-2023 Brian Smith.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
@ -36,13 +36,14 @@
//! [Static checking of units in Servo]:
//! https://blog.mozilla.org/research/2014/06/23/static-checking-of-units-in-servo/
pub(crate) use super::nonnegative::Nonnegative;
use crate::{
arithmetic::montgomery::*,
bits, bssl, c, cpu, error,
limb::{self, Limb, LimbMask, LIMB_BITS, LIMB_BYTES},
polyfill::{u64_from_usize, LeadingZerosStripped},
};
use alloc::{borrow::ToOwned as _, boxed::Box, vec, vec::Vec};
use alloc::{borrow::ToOwned as _, boxed::Box, vec};
use core::{
marker::PhantomData,
num::NonZeroU64,
@ -293,7 +294,7 @@ impl<M> Modulus<M> {
cpu_features: cpu::Features,
) -> Result<(Self, bits::BitLength), error::KeyRejected> {
let limbs = BoxedLimbs {
limbs: n.limbs.into_boxed_slice(),
limbs: n.into_limbs(),
m: PhantomData,
};
Self::from_boxed_limbs(limbs, cpu_features)
@ -1133,50 +1134,21 @@ pub fn elem_verify_equal_consttime<M, E>(
}
}
/// Nonnegative integers.
pub struct Nonnegative {
limbs: Vec<Limb>,
}
// TODO: Move these methods from `Nonnegative` to `Modulus`.
impl Nonnegative {
pub fn from_be_bytes_with_bit_length(
input: untrusted::Input,
) -> Result<(Self, bits::BitLength), error::Unspecified> {
let mut limbs = vec![0; (input.len() + LIMB_BYTES - 1) / LIMB_BYTES];
// Rejects empty inputs.
limb::parse_big_endian_and_pad_consttime(input, &mut limbs)?;
while limbs.last() == Some(&0) {
let _ = limbs.pop();
}
let r_bits = limb::limbs_minimal_bits(&limbs);
Ok((Self { limbs }, r_bits))
}
#[inline]
pub fn is_odd(&self) -> bool {
limb::limbs_are_even_constant_time(&self.limbs) != LimbMask::True
}
pub fn verify_less_than(&self, other: &Self) -> Result<(), error::Unspecified> {
if !greater_than(other, self) {
return Err(error::Unspecified);
}
Ok(())
}
pub fn to_elem<M>(&self, m: &Modulus<M>) -> Result<Elem<M, Unencoded>, error::Unspecified> {
self.verify_less_than_modulus(m)?;
let mut r = m.zero();
r.limbs[0..self.limbs.len()].copy_from_slice(&self.limbs);
r.limbs[0..self.limbs().len()].copy_from_slice(self.limbs());
Ok(r)
}
pub fn verify_less_than_modulus<M>(&self, m: &Modulus<M>) -> Result<(), error::Unspecified> {
if self.limbs.len() > m.limbs.len() {
if self.limbs().len() > m.limbs.len() {
return Err(error::Unspecified);
}
if self.limbs.len() == m.limbs.len() {
if limb::limbs_less_than_limbs_consttime(&self.limbs, &m.limbs) != LimbMask::True {
if self.limbs().len() == m.limbs.len() {
if limb::limbs_less_than_limbs_consttime(self.limbs(), &m.limbs) != LimbMask::True {
return Err(error::Unspecified);
}
}
@ -1184,15 +1156,6 @@ impl Nonnegative {
}
}
// Returns a > b.
fn greater_than(a: &Nonnegative, b: &Nonnegative) -> bool {
if a.limbs.len() == b.limbs.len() {
limb::limbs_less_than_limbs_vartime(&b.limbs, &a.limbs)
} else {
a.limbs.len() > b.limbs.len()
}
}
#[derive(Clone)]
#[repr(transparent)]
struct N0([Limb; 2]);
@ -1516,7 +1479,7 @@ mod tests {
num_limbs,
m: PhantomData,
});
limbs[0..value.limbs.len()].copy_from_slice(&value.limbs);
limbs[0..value.limbs().len()].copy_from_slice(value.limbs());
Elem {
limbs,
encoding: PhantomData,

View File

@ -0,0 +1,70 @@
// Copyright 2015-2023 Brian Smith.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use crate::{
bits, error,
limb::{self, Limb, LimbMask, LIMB_BYTES},
};
use alloc::{boxed::Box, vec, vec::Vec};
/// Nonnegative integers.
pub(crate) struct Nonnegative {
limbs: Vec<Limb>,
}
impl Nonnegative {
pub fn from_be_bytes_with_bit_length(
input: untrusted::Input,
) -> Result<(Self, bits::BitLength), error::Unspecified> {
let mut limbs = vec![0; (input.len() + LIMB_BYTES - 1) / LIMB_BYTES];
// Rejects empty inputs.
limb::parse_big_endian_and_pad_consttime(input, &mut limbs)?;
while limbs.last() == Some(&0) {
let _ = limbs.pop();
}
let r_bits = limb::limbs_minimal_bits(&limbs);
Ok((Self { limbs }, r_bits))
}
#[inline]
pub fn is_odd(&self) -> bool {
limb::limbs_are_even_constant_time(&self.limbs) != LimbMask::True
}
pub fn verify_less_than(&self, other: &Self) -> Result<(), error::Unspecified> {
if !greater_than(other, self) {
return Err(error::Unspecified);
}
Ok(())
}
#[inline]
pub fn limbs(&self) -> &[Limb] {
&self.limbs
}
#[inline]
pub fn into_limbs(self) -> Box<[Limb]> {
self.limbs.into_boxed_slice()
}
}
// Returns a > b.
fn greater_than(a: &Nonnegative, b: &Nonnegative) -> bool {
if a.limbs.len() == b.limbs.len() {
limb::limbs_less_than_limbs_vartime(&b.limbs, &a.limbs)
} else {
a.limbs.len() > b.limbs.len()
}
}