Skip to content

Commit f4efa31

Browse files
authored
Merge pull request #136 from LLFourn/implement-ord-for-point-and-scalar
Implement Ord and Partial Ord on scalar and point
2 parents 9657d8c + 887135e commit f4efa31

File tree

12 files changed

+69
-26
lines changed

12 files changed

+69
-26
lines changed

Diff for: CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88
- Allow `Zero` points to serialize
99
- Remove requirement of `CryptoRng` everywhere
1010
- Rename `from_scalar_mul` to `even_y_from_scalar_mul` to be more explicit
11-
- Remove `XOnly` in favor of `Point<EvenY>`
11+
- Remove `XOnly` in favour of `Point<EvenY>`
1212
- Replace `.mark` system with methods for changing each marker type.
1313
- Make `From<u32>` for `Scalar` regardless of secrecy
1414
- Merge `AddTag` and `Tagged` into one trait `Tag`
1515
- Add `NonceRng` impls for `RefCell` and `Mutex`
16+
- Add `Ord` and `PartialOrd` implementations for Scalar and Point
1617

1718
## 0.7.1
1819

Diff for: schnorr_fun/src/frost.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,7 @@ impl<H: Digest<OutputSize = U32> + Clone, NG> Frost<H, NG> {
722722
.non_zero()
723723
.unwrap_or_else(|| {
724724
// Use the same trick as the MuSig spec
725-
G.clone().normalize()
725+
G.normalize()
726726
})
727727
.into_point_with_even_y();
728728

Diff for: schnorr_fun/src/musig.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ impl<H: Digest<OutputSize = U32> + Clone, NG> MuSig<H, Schnorr<H, NG>> {
479479
.unwrap_or_else(|| {
480480
// if final nonce is zero we set it to generator as in MuSig spec
481481
debug_assert!(G.is_y_even());
482-
G.clone().normalize()
482+
G.normalize()
483483
})
484484
.into_point_with_even_y();
485485

Diff for: secp256kfun/src/backend/k256_impl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ use crate::{
66
use core::ops::Neg;
77
use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq};
88

9-
pub static G_TABLE: ProjectivePoint = ProjectivePoint::GENERATOR;
109
pub static G_POINT: ProjectivePoint = ProjectivePoint::GENERATOR;
1110
pub type Point = ProjectivePoint;
11+
// We don't implement multiplication tables yet
1212
pub type BasePoint = ProjectivePoint;
1313

1414
impl BackendScalar for Scalar {

Diff for: secp256kfun/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ pub extern crate proptest;
6868
///[_SEC 2: Recommended Elliptic Curve Domain Parameters_]: https://www.secg.org/sec2-v2.pdf
6969
///[`BasePoint`]: crate::marker::BasePoint
7070
pub static G: &'static Point<marker::BasePoint, marker::Public, marker::NonZero> =
71-
&Point::from_inner(backend::G_POINT, marker::BasePoint(backend::G_TABLE));
71+
&Point::from_inner(backend::G_POINT, marker::BasePoint);
7272

7373
// it is applied to nonce generators too so export at root
7474
pub use hash::Tag;

Diff for: secp256kfun/src/marker/point_type.rs

+8-12
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
///
99
/// [`Point<T,S,Z>`]: crate::Point
1010
/// [`G`]: crate::G
11-
pub trait PointType: Sized + Clone + Copy + 'static {
11+
pub trait PointType:
12+
Sized + Clone + Copy + PartialEq + Eq + core::hash::Hash + Ord + PartialOrd
13+
{
1214
/// The point type returned from the negation of a point of this type.
1315
type NegationType: Default;
1416

@@ -18,7 +20,7 @@ pub trait PointType: Sized + Clone + Copy + 'static {
1820

1921
/// A Fully Normalized Point. Internally `Normal` points are represented using
2022
/// _affine_ coordinates with fully normalized `x` and `y` field elements.
21-
#[derive(Default, Debug, Clone, Copy)]
23+
#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
2224
#[cfg_attr(feautre = "serde", derive(serde::Serialize, serde::Deserialize))]
2325
pub struct Normal;
2426
/// A Non-normalized Point. Usually, represented as three field elements three field elements:
@@ -37,15 +39,15 @@ pub struct Normal;
3739
///
3840
/// [`normalize`]: crate::Point::normalize
3941
40-
#[derive(Default, Debug, Clone, Copy)]
42+
#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
4143
pub struct NonNormal;
4244

4345
/// Backwards compatibility type alias.
4446
#[deprecated(note = "use NonNormal instead")]
4547
pub type Jacobian = NonNormal;
4648

4749
/// A [`Normal`] point whose `y` coordinate is known to be even.
48-
#[derive(Default, Debug, Clone, Copy)]
50+
#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
4951
#[cfg_attr(feautre = "serde", derive(serde::Serialize, serde::Deserialize))]
5052
pub struct EvenY;
5153

@@ -56,22 +58,16 @@ pub struct EvenY;
5658
/// At the time of writing no pre-computation is done.
5759
///
5860
/// [`G`]: crate::G
59-
#[derive(Clone, Copy)]
60-
pub struct BasePoint(pub(crate) crate::backend::BasePoint);
61+
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
62+
pub struct BasePoint;
6163

6264
/// A marker trait that indicates a `PointType` uses a affine internal representation.
6365
pub trait Normalized: PointType {}
6466

65-
pub(crate) trait NotBasePoint: Default {}
66-
6767
impl Normalized for EvenY {}
6868
impl Normalized for Normal {}
6969
impl Normalized for BasePoint {}
7070

71-
impl NotBasePoint for NonNormal {}
72-
impl NotBasePoint for EvenY {}
73-
impl NotBasePoint for Normal {}
74-
7571
impl<N: Normalized> PointType for N {
7672
type NegationType = Normal;
7773

Diff for: secp256kfun/src/marker/secrecy.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,16 @@
3131
/// [`Point`]: crate::marker::Public
3232
/// [`Scalar`s]: crate::Scalar
3333
/// [`Point`s]: crate::Point
34-
pub trait Secrecy: Default + Clone + PartialEq + Copy + 'static {}
34+
pub trait Secrecy: Default + Clone + PartialEq + Eq + Copy + 'static + Ord + PartialOrd {}
3535

3636
/// Indicates that the value is secret and therefore makes core operations
3737
/// executed on it to use _constant time_ versions of the operations.
38-
#[derive(Debug, Clone, Default, PartialEq, Copy)]
38+
#[derive(Debug, Clone, Default, PartialEq, Eq, Copy, Ord, PartialOrd)]
3939
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
4040
pub struct Secret;
4141

4242
/// Indicates that variable time operations may be used on the value.
43-
#[derive(Debug, Clone, Default, PartialEq, Copy, Eq, Hash)]
43+
#[derive(Debug, Clone, Default, PartialEq, Eq, Copy, Hash, Ord, PartialOrd)]
4444
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
4545
pub struct Public;
4646

Diff for: secp256kfun/src/marker/zero_choice.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/// Something marked with Zero might be `0` i.e. the additive identity
2-
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
2+
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Ord, PartialOrd)]
33
#[cfg_attr(feautre = "serde", derive(serde::Serialize, serde::Deserialize))]
44
pub struct Zero;
55

66
/// Something marked with `NonZero` is guaranteed not to be 0.
7-
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
7+
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Ord, PartialOrd)]
88
#[cfg_attr(feautre = "serde", derive(serde::Serialize, serde::Deserialize))]
99
pub struct NonZero;
1010

@@ -16,11 +16,13 @@ pub trait ZeroChoice:
1616
Default
1717
+ Clone
1818
+ PartialEq
19+
+ Eq
1920
+ Copy
2021
+ DecideZero<NonZero>
2122
+ DecideZero<Zero>
22-
+ Eq
2323
+ core::hash::Hash
24+
+ Ord
25+
+ PartialOrd
2426
+ 'static
2527
{
2628
/// Returns whether the type is `Zero`

Diff for: secp256kfun/src/op.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
//! use secp256kfun::{marker::*, op, Scalar, G};
1616
//! let x = Scalar::random(&mut rand::thread_rng());
1717
//! let X1 = op::scalar_mul_point(&x, G); // fast
18-
//! let H = &G.clone().normalize(); // scrub `BasePoint` marker
18+
//! let H = &G.normalize(); // scrub `BasePoint` marker
1919
//! let X2 = op::scalar_mul_point(&x, &H); // slow
2020
//! assert_eq!(X1, X2);
2121
//! ```

Diff for: secp256kfun/src/point.rs

+14
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,20 @@ impl core::hash::Hash for Point<EvenY, Public, NonZero> {
327327
}
328328
}
329329

330+
impl<T1: Normalized, S1, Z1, T2: Normalized, S2, Z2> PartialOrd<Point<T2, S2, Z2>>
331+
for Point<T1, S1, Z1>
332+
{
333+
fn partial_cmp(&self, other: &Point<T2, S2, Z2>) -> Option<core::cmp::Ordering> {
334+
Some(self.to_bytes().cmp(&other.to_bytes()))
335+
}
336+
}
337+
338+
impl<T1: Normalized, S1, Z1> Ord for Point<T1, S1, Z1> {
339+
fn cmp(&self, other: &Point<T1, S1, Z1>) -> core::cmp::Ordering {
340+
self.to_bytes().cmp(&other.to_bytes())
341+
}
342+
}
343+
330344
impl<S, Z, T: Normalized> Point<T, S, Z> {
331345
/// Converts the point to its compressed encoding as specified by [_Standards for Efficient Cryptography_].
332346
///

Diff for: secp256kfun/src/scalar.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ use rand_core::RngCore;
4949
/// [`Secrecy`]: crate::marker::Secrecy
5050
/// [`Secret`]: crate::marker::Secret
5151
/// [`ZeroChoice]: crate::marker::ZeroChoice
52-
#[derive(Eq)]
5352
pub struct Scalar<S = Secret, Z = NonZero>(pub(crate) backend::Scalar, PhantomData<(Z, S)>);
5453

5554
impl<Z> Copy for Scalar<Public, Z> {}
@@ -291,6 +290,8 @@ impl<Z1, Z2, S1, S2> PartialEq<Scalar<S2, Z2>> for Scalar<S1, Z1> {
291290
}
292291
}
293292

293+
impl<Z, S> Eq for Scalar<Z, S> {}
294+
294295
impl<S> From<u32> for Scalar<S, Zero> {
295296
fn from(int: u32) -> Self {
296297
Self::from_inner(backend::BackendScalar::from_u32(int))
@@ -405,6 +406,18 @@ impl<SL, SR, ZR: ZeroChoice> MulAssign<&Scalar<SR, ZR>> for Scalar<SL, Zero> {
405406
}
406407
}
407408

409+
impl<S1, Z1, S2, Z2> PartialOrd<Scalar<S2, Z2>> for Scalar<S1, Z1> {
410+
fn partial_cmp(&self, other: &Scalar<S2, Z2>) -> Option<core::cmp::Ordering> {
411+
Some(self.to_bytes().cmp(&other.to_bytes()))
412+
}
413+
}
414+
415+
impl<S, Z> Ord for Scalar<S, Z> {
416+
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
417+
self.to_bytes().cmp(&other.to_bytes())
418+
}
419+
}
420+
408421
#[cfg(test)]
409422
mod test {
410423
use super::*;

Diff for: secp256kfun/tests/against_c_lib.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
#![allow(non_snake_case)]
2+
#![cfg(feature = "proptest")]
23
#[cfg(not(target_arch = "wasm32"))]
34
mod against_c_lib {
45
use proptest::prelude::*;
56
use secp256k1::{PublicKey, SecretKey, SECP256K1 as SECP};
6-
use secp256kfun::{g, op::double_mul, s, Scalar, G};
7+
use secp256kfun::{g, op::double_mul, s, Point, Scalar, G};
78

89
proptest! {
910
#[test]
@@ -121,5 +122,21 @@ mod against_c_lib {
121122
let scalar = Scalar::from_bytes_mod_order(bytes.clone());
122123
prop_assert_eq!(&(-scalar).to_bytes()[..], &sk[..]);
123124
}
125+
126+
#[test]
127+
fn point_ord(point1 in any::<Point>(), point2 in any::<Point>()) {
128+
prop_assert_eq!(
129+
point1.cmp(&point2),
130+
PublicKey::from(point1).cmp(&PublicKey::from(point2))
131+
);
132+
}
133+
134+
#[test]
135+
fn scalar_ord(scalar1 in any::<Scalar>(), scalar2 in any::<Scalar>()) {
136+
prop_assert_eq!(
137+
scalar1.cmp(&scalar2),
138+
SecretKey::from(scalar1).cmp(&SecretKey::from(scalar2))
139+
);
140+
}
124141
}
125142
}

0 commit comments

Comments
 (0)