Skip to content

Commit

Permalink
k256+p256: move Scalar impl blocks to top of module (#516)
Browse files Browse the repository at this point in the history
Reorders the impl blocks containing inherent constants/methods to the
top of the module, following suit with how the `affine` and `projective`
modules have been reorganized.
  • Loading branch information
tarcieri authored Jan 17, 2022
1 parent 39b9001 commit f0f7477
Show file tree
Hide file tree
Showing 2 changed files with 278 additions and 278 deletions.
272 changes: 136 additions & 136 deletions k256/src/arithmetic/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,141 +77,6 @@ const FRAC_MODULUS_2: U256 = ORDER.shr_vartime(1);
#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
pub struct Scalar(U256);

impl Field for Scalar {
fn random(rng: impl RngCore) -> Self {
// Uses rejection sampling as the default random generation method,
// which produces a uniformly random distribution of scalars.
//
// This method is not constant time, but should be secure so long as
// rejected RNG outputs are unrelated to future ones (which is a
// necessary property of a `CryptoRng`).
//
// With an unbiased RNG, the probability of failing to complete after 4
// iterations is vanishingly small.
Self::generate_vartime(rng)
}

fn zero() -> Self {
Self::ZERO
}

fn one() -> Self {
Self::ONE
}

#[must_use]
fn square(&self) -> Self {
Scalar::square(self)
}

#[must_use]
fn double(&self) -> Self {
self.add(self)
}

fn invert(&self) -> CtOption<Self> {
Scalar::invert(self)
}

/// Tonelli-Shank's algorithm for q mod 16 = 1
/// <https://eprint.iacr.org/2012/685.pdf> (page 12, algorithm 5)
#[allow(clippy::many_single_char_names)]
fn sqrt(&self) -> CtOption<Self> {
// Note: `pow_vartime` is constant-time with respect to `self`
let w = self.pow_vartime(&[
0x777fa4bd19a06c82,
0xfd755db9cd5e9140,
0xffffffffffffffff,
0x1ffffffffffffff,
]);

let mut v = Self::S;
let mut x = *self * w;
let mut b = x * w;
let mut z = Self::root_of_unity();

for max_v in (1..=Self::S).rev() {
let mut k = 1;
let mut tmp = b.square();
let mut j_less_than_v = Choice::from(1);

for j in 2..max_v {
let tmp_is_one = tmp.ct_eq(&Self::one());
let squared = Self::conditional_select(&tmp, &z, tmp_is_one).square();
tmp = Self::conditional_select(&squared, &tmp, tmp_is_one);
let new_z = Self::conditional_select(&z, &squared, tmp_is_one);
j_less_than_v &= !j.ct_eq(&v);
k = u32::conditional_select(&j, &k, tmp_is_one);
z = Self::conditional_select(&z, &new_z, j_less_than_v);
}

let result = x * z;
x = Self::conditional_select(&result, &x, b.ct_eq(&Self::one()));
z = z.square();
b *= z;
v = k;
}

CtOption::new(x, x.square().ct_eq(self))
}
}

impl PrimeField for Scalar {
type Repr = FieldBytes;

const NUM_BITS: u32 = 256;
const CAPACITY: u32 = 255;
const S: u32 = 6;

/// Attempts to parse the given byte array as an SEC1-encoded scalar.
///
/// Returns None if the byte array does not contain a big-endian integer in the range
/// [0, p).
fn from_repr(bytes: FieldBytes) -> CtOption<Self> {
let inner = U256::from_be_byte_array(bytes);
CtOption::new(Self(inner), inner.ct_lt(&Secp256k1::ORDER))
}

fn to_repr(&self) -> FieldBytes {
self.to_bytes()
}

fn is_odd(&self) -> Choice {
self.0.is_odd()
}

fn multiplicative_generator() -> Self {
7u64.into()
}

fn root_of_unity() -> Self {
Scalar::from_repr(arr![u8;
0x0c, 0x1d, 0xc0, 0x60, 0xe7, 0xa9, 0x19, 0x86, 0xdf, 0x98, 0x79, 0xa3, 0xfb, 0xc4,
0x83, 0xa8, 0x98, 0xbd, 0xea, 0xb6, 0x80, 0x75, 0x60, 0x45, 0x99, 0x2f, 0x4b, 0x54,
0x02, 0xb0, 0x52, 0xf2
])
.unwrap()
}
}

#[cfg(feature = "bits")]
#[cfg_attr(docsrs, doc(cfg(feature = "bits")))]
impl PrimeFieldBits for Scalar {
#[cfg(target_pointer_width = "32")]
type ReprBits = [u32; 8];

#[cfg(target_pointer_width = "64")]
type ReprBits = [u64; 4];

fn to_le_bits(&self) -> ScalarBits {
self.into()
}

fn char_le_bits() -> ScalarBits {
ORDER.to_uint_array().into()
}
}

impl Scalar {
/// Zero scalar.
pub const ZERO: Self = Self(U256::ZERO);
Expand Down Expand Up @@ -281,7 +146,7 @@ impl Scalar {
let x56 = x28.pow2k(28).mul(&x28);

#[rustfmt::skip]
let res = x56
let res = x56
.pow2k(56).mul(&x56)
.pow2k(14).mul(&x14)
.pow2k(3).mul(&x_101)
Expand Down Expand Up @@ -357,6 +222,141 @@ impl Scalar {
}
}

impl Field for Scalar {
fn random(rng: impl RngCore) -> Self {
// Uses rejection sampling as the default random generation method,
// which produces a uniformly random distribution of scalars.
//
// This method is not constant time, but should be secure so long as
// rejected RNG outputs are unrelated to future ones (which is a
// necessary property of a `CryptoRng`).
//
// With an unbiased RNG, the probability of failing to complete after 4
// iterations is vanishingly small.
Self::generate_vartime(rng)
}

fn zero() -> Self {
Self::ZERO
}

fn one() -> Self {
Self::ONE
}

#[must_use]
fn square(&self) -> Self {
Scalar::square(self)
}

#[must_use]
fn double(&self) -> Self {
self.add(self)
}

fn invert(&self) -> CtOption<Self> {
Scalar::invert(self)
}

/// Tonelli-Shank's algorithm for q mod 16 = 1
/// <https://eprint.iacr.org/2012/685.pdf> (page 12, algorithm 5)
#[allow(clippy::many_single_char_names)]
fn sqrt(&self) -> CtOption<Self> {
// Note: `pow_vartime` is constant-time with respect to `self`
let w = self.pow_vartime(&[
0x777fa4bd19a06c82,
0xfd755db9cd5e9140,
0xffffffffffffffff,
0x1ffffffffffffff,
]);

let mut v = Self::S;
let mut x = *self * w;
let mut b = x * w;
let mut z = Self::root_of_unity();

for max_v in (1..=Self::S).rev() {
let mut k = 1;
let mut tmp = b.square();
let mut j_less_than_v = Choice::from(1);

for j in 2..max_v {
let tmp_is_one = tmp.ct_eq(&Self::one());
let squared = Self::conditional_select(&tmp, &z, tmp_is_one).square();
tmp = Self::conditional_select(&squared, &tmp, tmp_is_one);
let new_z = Self::conditional_select(&z, &squared, tmp_is_one);
j_less_than_v &= !j.ct_eq(&v);
k = u32::conditional_select(&j, &k, tmp_is_one);
z = Self::conditional_select(&z, &new_z, j_less_than_v);
}

let result = x * z;
x = Self::conditional_select(&result, &x, b.ct_eq(&Self::one()));
z = z.square();
b *= z;
v = k;
}

CtOption::new(x, x.square().ct_eq(self))
}
}

impl PrimeField for Scalar {
type Repr = FieldBytes;

const NUM_BITS: u32 = 256;
const CAPACITY: u32 = 255;
const S: u32 = 6;

/// Attempts to parse the given byte array as an SEC1-encoded scalar.
///
/// Returns None if the byte array does not contain a big-endian integer in the range
/// [0, p).
fn from_repr(bytes: FieldBytes) -> CtOption<Self> {
let inner = U256::from_be_byte_array(bytes);
CtOption::new(Self(inner), inner.ct_lt(&Secp256k1::ORDER))
}

fn to_repr(&self) -> FieldBytes {
self.to_bytes()
}

fn is_odd(&self) -> Choice {
self.0.is_odd()
}

fn multiplicative_generator() -> Self {
7u64.into()
}

fn root_of_unity() -> Self {
Scalar::from_repr(arr![u8;
0x0c, 0x1d, 0xc0, 0x60, 0xe7, 0xa9, 0x19, 0x86, 0xdf, 0x98, 0x79, 0xa3, 0xfb, 0xc4,
0x83, 0xa8, 0x98, 0xbd, 0xea, 0xb6, 0x80, 0x75, 0x60, 0x45, 0x99, 0x2f, 0x4b, 0x54,
0x02, 0xb0, 0x52, 0xf2
])
.unwrap()
}
}

#[cfg(feature = "bits")]
#[cfg_attr(docsrs, doc(cfg(feature = "bits")))]
impl PrimeFieldBits for Scalar {
#[cfg(target_pointer_width = "32")]
type ReprBits = [u32; 8];

#[cfg(target_pointer_width = "64")]
type ReprBits = [u64; 4];

fn to_le_bits(&self) -> ScalarBits {
self.into()
}

fn char_le_bits() -> ScalarBits {
ORDER.to_uint_array().into()
}
}

impl DefaultIsZeroes for Scalar {}

impl From<u32> for Scalar {
Expand Down
Loading

0 comments on commit f0f7477

Please sign in to comment.