Skip to content

Commit 1056cb2

Browse files
authored
primefield: add monty_field_reduce! (#1585)
Adds a macro for writing `Reduce` impls for `Curve::Uint` and for the associated `Array<u8, _>` for serialized field elements. For some reason this macro doesn't work in cases where there are also `Reduce<Array<u8, _>>` impls defined for e.g. `hash2curve` and its says the impls conflict, when the only difference is the macro uses a type alias. It's also not working on P-224 for some reason, like it's miscomputing the byte size? Where it does work, it nicely cleans up the scalar implementation.
1 parent 976f07b commit 1056cb2

File tree

6 files changed

+68
-114
lines changed

6 files changed

+68
-114
lines changed

bignp256/src/arithmetic/scalar.rs

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,12 @@
1717
mod scalar_impl;
1818

1919
use self::scalar_impl::*;
20-
use crate::{BignP256, FieldBytes, ORDER_HEX, U256};
20+
use crate::{BignP256, ORDER_HEX, U256};
2121
use elliptic_curve::{
22-
Curve as _, FieldBytesEncoding,
23-
bigint::Limb,
22+
Curve as _,
2423
ff::PrimeField,
25-
ops::Reduce,
2624
scalar::{FromUintUnchecked, IsHigh},
27-
subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, CtOption},
25+
subtle::{Choice, ConstantTimeEq, ConstantTimeGreater, CtOption},
2826
};
2927

3028
#[cfg(doc)]
@@ -65,6 +63,12 @@ primefield::fiat_monty_field_arithmetic! {
6563
selectnz: fiat_bignp256_scalar_selectznz
6664
}
6765

66+
primefield::monty_field_reduce! {
67+
name: Scalar,
68+
params: ScalarParams,
69+
uint: U256,
70+
}
71+
6872
elliptic_curve::scalar_impls!(BignP256, Scalar);
6973

7074
impl AsRef<Scalar> for Scalar {
@@ -88,22 +92,6 @@ impl IsHigh for Scalar {
8892
}
8993
}
9094

91-
impl Reduce<U256> for Scalar {
92-
fn reduce(w: &U256) -> Self {
93-
let (r, underflow) = w.borrowing_sub(&BignP256::ORDER, Limb::ZERO);
94-
let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8);
95-
Self::from_uint_unchecked(U256::conditional_select(w, &r, !underflow))
96-
}
97-
}
98-
99-
impl Reduce<FieldBytes> for Scalar {
100-
#[inline]
101-
fn reduce(bytes: &FieldBytes) -> Self {
102-
let w = <U256 as FieldBytesEncoding<BignP256>>::decode_field_bytes(bytes);
103-
Self::reduce(&w)
104-
}
105-
}
106-
10795
#[cfg(test)]
10896
mod tests {
10997
use super::{Scalar, U256};

bp256/src/arithmetic/scalar.rs

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,11 @@
2222
#[allow(dead_code)] // TODO(tarcieri): remove this when we can use `const _` to silence warnings
2323
mod scalar_impl;
2424

25-
use crate::{BrainpoolP256r1, BrainpoolP256t1, FieldBytes, ORDER, ORDER_HEX, U256};
25+
use crate::{BrainpoolP256r1, BrainpoolP256t1, ORDER, ORDER_HEX, U256};
2626
use elliptic_curve::{
27-
bigint::{ArrayEncoding, Limb},
2827
ff::PrimeField,
29-
ops::Reduce,
3028
scalar::{FromUintUnchecked, IsHigh},
31-
subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, CtOption},
29+
subtle::{Choice, ConstantTimeEq, ConstantTimeGreater, CtOption},
3230
};
3331

3432
#[cfg(not(bp256_backend = "bignum"))]
@@ -80,6 +78,12 @@ primefield::fiat_monty_field_arithmetic! {
8078
selectnz: fiat_bp256_scalar_selectznz
8179
}
8280

81+
primefield::monty_field_reduce! {
82+
name: Scalar,
83+
params: ScalarParams,
84+
uint: U256,
85+
}
86+
8387
elliptic_curve::scalar_impls!(BrainpoolP256r1, Scalar);
8488
elliptic_curve::scalar_impls!(BrainpoolP256t1, Scalar);
8589

@@ -104,21 +108,6 @@ impl IsHigh for Scalar {
104108
}
105109
}
106110

107-
impl Reduce<U256> for Scalar {
108-
fn reduce(w: &U256) -> Self {
109-
let (r, underflow) = w.borrowing_sub(&ORDER, Limb::ZERO);
110-
let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8);
111-
Self::from_uint_unchecked(U256::conditional_select(w, &r, !underflow))
112-
}
113-
}
114-
115-
impl Reduce<FieldBytes> for Scalar {
116-
#[inline]
117-
fn reduce(bytes: &FieldBytes) -> Self {
118-
Self::reduce(&U256::from_be_byte_array(*bytes))
119-
}
120-
}
121-
122111
#[cfg(test)]
123112
mod tests {
124113
use super::{Scalar, U256};

bp384/src/arithmetic/scalar.rs

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,11 @@
2222
#[allow(dead_code)] // TODO(tarcieri): remove this when we can use `const _` to silence warnings
2323
mod scalar_impl;
2424

25-
use crate::{BrainpoolP384r1, BrainpoolP384t1, FieldBytes, ORDER, ORDER_HEX, U384};
25+
use crate::{BrainpoolP384r1, BrainpoolP384t1, ORDER, ORDER_HEX, U384};
2626
use elliptic_curve::{
27-
bigint::{ArrayEncoding, Limb},
2827
ff::PrimeField,
29-
ops::Reduce,
3028
scalar::{FromUintUnchecked, IsHigh},
31-
subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, CtOption},
29+
subtle::{Choice, ConstantTimeEq, ConstantTimeGreater, CtOption},
3230
};
3331

3432
#[cfg(not(bp384_backend = "bignum"))]
@@ -50,7 +48,7 @@ primefield::monty_field_element! {
5048
name: Scalar,
5149
params: ScalarParams,
5250
uint: U384,
53-
doc: "Element in the brainpoolP256 scalar field modulo n"
51+
doc: "Element in the brainpoolP384 scalar field modulo n"
5452
}
5553

5654
#[cfg(bp384_backend = "bignum")]
@@ -80,6 +78,12 @@ primefield::fiat_monty_field_arithmetic! {
8078
selectnz: fiat_bp384_scalar_selectznz
8179
}
8280

81+
primefield::monty_field_reduce! {
82+
name: Scalar,
83+
params: ScalarParams,
84+
uint: U384,
85+
}
86+
8387
elliptic_curve::scalar_impls!(BrainpoolP384r1, Scalar);
8488
elliptic_curve::scalar_impls!(BrainpoolP384t1, Scalar);
8589

@@ -104,21 +108,6 @@ impl IsHigh for Scalar {
104108
}
105109
}
106110

107-
impl Reduce<U384> for Scalar {
108-
fn reduce(w: &U384) -> Self {
109-
let (r, underflow) = w.borrowing_sub(&ORDER, Limb::ZERO);
110-
let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8);
111-
Self::from_uint_unchecked(U384::conditional_select(w, &r, !underflow))
112-
}
113-
}
114-
115-
impl Reduce<FieldBytes> for Scalar {
116-
#[inline]
117-
fn reduce(bytes: &FieldBytes) -> Self {
118-
Self::reduce(&U384::from_be_byte_array(*bytes))
119-
}
120-
}
121-
122111
#[cfg(test)]
123112
mod tests {
124113
use super::{Scalar, U384};

p192/src/arithmetic/scalar.rs

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,12 @@
2222
mod scalar_impl;
2323

2424
use self::scalar_impl::*;
25-
use crate::{FieldBytes, FieldBytesEncoding, NistP192, ORDER_HEX, U192};
25+
use crate::{NistP192, ORDER_HEX, U192};
2626
use elliptic_curve::{
2727
Curve as _,
28-
bigint::Limb,
2928
ff::PrimeField,
30-
ops::Reduce,
3129
scalar::{FromUintUnchecked, IsHigh},
32-
subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, CtOption},
30+
subtle::{Choice, ConstantTimeEq, ConstantTimeGreater, CtOption},
3331
};
3432

3533
#[cfg(feature = "serde")]
@@ -76,6 +74,12 @@ primefield::fiat_monty_field_arithmetic! {
7674
selectnz: fiat_p192_scalar_selectznz
7775
}
7876

77+
primefield::monty_field_reduce! {
78+
name: Scalar,
79+
params: ScalarParams,
80+
uint: U192,
81+
}
82+
7983
elliptic_curve::scalar_impls!(NistP192, Scalar);
8084

8185
impl AsRef<Scalar> for Scalar {
@@ -99,22 +103,6 @@ impl IsHigh for Scalar {
99103
}
100104
}
101105

102-
impl Reduce<U192> for Scalar {
103-
fn reduce(w: &U192) -> Self {
104-
let (r, underflow) = w.borrowing_sub(&NistP192::ORDER, Limb::ZERO);
105-
let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8);
106-
Self::from_uint_unchecked(U192::conditional_select(w, &r, !underflow))
107-
}
108-
}
109-
110-
impl Reduce<FieldBytes> for Scalar {
111-
#[inline]
112-
fn reduce(bytes: &FieldBytes) -> Self {
113-
let w = <U192 as FieldBytesEncoding<NistP192>>::decode_field_bytes(bytes);
114-
Self::reduce(&w)
115-
}
116-
}
117-
118106
#[cfg(feature = "serde")]
119107
impl Serialize for Scalar {
120108
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

primefield/src/macros.rs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -354,20 +354,6 @@ macro_rules! monty_field_element {
354354
}
355355
}
356356

357-
// TODO(tarcieri): write `Reduce` impls
358-
// impl $crate::bigint::Reduce<$uint> for $fe {
359-
// fn reduce(w: &$uint) -> Self {
360-
// Self($crate::MontyFieldElement::<$params, { <$params>::LIMBS }>::reduce(w))
361-
// }
362-
// }
363-
//
364-
// impl $crate::bigint::Reduce<$crate::MontyFieldBytes<$params, { <$params>::LIMBS }>> for $fe {
365-
// #[inline]
366-
// fn reduce(bytes: &$crate::MontyFieldBytes<$params, { <$params>::LIMBS }>) -> Self {
367-
// Self($crate::MontyFieldElement::<$params, { <$params>::LIMBS }>::reduce(bytes))
368-
// }
369-
// }
370-
371357
$crate::field_op!($fe, Add, add, add);
372358
$crate::field_op!($fe, Sub, sub, sub);
373359
$crate::field_op!($fe, Mul, mul, multiply);
@@ -729,6 +715,32 @@ macro_rules! monty_field_arithmetic {
729715
};
730716
}
731717

718+
/// Write `Reduce` impls for a particular field implementation which delegate to
719+
/// `MontyFieldElement`.
720+
#[macro_export]
721+
macro_rules! monty_field_reduce {
722+
(
723+
name: $fe:tt,
724+
params: $params:ty,
725+
uint: $uint:path,
726+
) => {
727+
impl $crate::bigint::Reduce<$uint> for $fe {
728+
fn reduce(w: &$uint) -> Self {
729+
Self($crate::MontyFieldElement::<$params, { <$params>::LIMBS }>::reduce(w))
730+
}
731+
}
732+
733+
impl $crate::bigint::Reduce<$crate::MontyFieldBytes<$params, { <$params>::LIMBS }>>
734+
for $fe
735+
{
736+
#[inline]
737+
fn reduce(bytes: &$crate::MontyFieldBytes<$params, { <$params>::LIMBS }>) -> Self {
738+
Self($crate::MontyFieldElement::<$params, { <$params>::LIMBS }>::reduce(bytes))
739+
}
740+
}
741+
};
742+
}
743+
732744
/// Emit a `core::ops` trait wrapper for an inherent method which is expected to be provided by a
733745
/// backend arithmetic implementation (e.g. `fiat-crypto`)
734746
#[macro_export]

sm2/src/arithmetic/scalar.rs

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,12 @@ use fiat_crypto::sm2_scalar_32::*;
1515
#[cfg(target_pointer_width = "64")]
1616
use fiat_crypto::sm2_scalar_64::*;
1717

18-
use crate::{FieldBytes, FieldBytesEncoding, ORDER_HEX, Sm2, U256};
18+
use crate::{ORDER_HEX, Sm2, U256};
1919
use elliptic_curve::{
2020
Curve as _,
21-
bigint::Limb,
2221
ff::PrimeField,
23-
ops::Reduce,
2422
scalar::{FromUintUnchecked, IsHigh},
25-
subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, CtOption},
23+
subtle::{Choice, ConstantTimeEq, ConstantTimeGreater, CtOption},
2624
};
2725

2826
#[cfg(feature = "serde")]
@@ -69,6 +67,12 @@ primefield::fiat_monty_field_arithmetic! {
6967
selectnz: fiat_sm2_scalar_selectznz
7068
}
7169

70+
primefield::monty_field_reduce! {
71+
name: Scalar,
72+
params: ScalarParams,
73+
uint: U256,
74+
}
75+
7276
elliptic_curve::scalar_impls!(Sm2, Scalar);
7377

7478
impl AsRef<Scalar> for Scalar {
@@ -92,22 +96,6 @@ impl IsHigh for Scalar {
9296
}
9397
}
9498

95-
impl Reduce<U256> for Scalar {
96-
fn reduce(w: &U256) -> Self {
97-
let (r, underflow) = w.borrowing_sub(&Sm2::ORDER, Limb::ZERO);
98-
let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8);
99-
Self::from_uint_unchecked(U256::conditional_select(w, &r, !underflow))
100-
}
101-
}
102-
103-
impl Reduce<FieldBytes> for Scalar {
104-
#[inline]
105-
fn reduce(bytes: &FieldBytes) -> Self {
106-
let w = <U256 as FieldBytesEncoding<Sm2>>::decode_field_bytes(bytes);
107-
Self::reduce(&w)
108-
}
109-
}
110-
11199
#[cfg(feature = "serde")]
112100
impl Serialize for Scalar {
113101
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

0 commit comments

Comments
 (0)