Skip to content

Commit c89eac2

Browse files
committed
Add constant-time trait bounds
1 parent 017bb2c commit c89eac2

File tree

4 files changed

+40
-10
lines changed

4 files changed

+40
-10
lines changed

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ rand_core = { version = "0.6" , default-features = false}
2424
serde = { version = "1.0", optional = true }
2525
sha3 = { version = "0.10", default-features = false }
2626
snafu = { version = "0.7", default-features = false}
27+
subtle = { verion = "2.5.0", default-features = false }
2728
zeroize = {version = "1" , default-features = false}
2829

2930
[dev-dependencies]
@@ -48,6 +49,7 @@ std = [
4849
"serde?/std",
4950
"sha3/std",
5051
"snafu/std",
52+
"subtle/std",
5153
"tari_utilities/std",
5254
"zeroize/std",
5355
]
@@ -61,4 +63,4 @@ crate-type = ["lib", "cdylib"]
6163
[[bench]]
6264
name = "benches"
6365
path = "benches/mod.rs"
64-
harness = false
66+
harness = false

src/dhke.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ use crate::keys::PublicKey;
1818
/// The result of a Diffie-Hellman key exchange
1919
#[derive(Zeroize, ZeroizeOnDrop)]
2020
pub struct DiffieHellmanSharedSecret<P>(P)
21-
where P: Zeroize;
21+
where P: PublicKey;
2222

2323
impl<P> DiffieHellmanSharedSecret<P>
2424
where
25-
P: PublicKey + Zeroize,
25+
P: PublicKey,
2626
for<'a> &'a <P as PublicKey>::K: Mul<&'a P, Output = P>,
2727
{
2828
/// Perform a Diffie-Hellman key exchange
@@ -36,6 +36,20 @@ where
3636
}
3737
}
3838

39+
impl<P> Eq for DiffieHellmanSharedSecret<P>
40+
where
41+
P: PublicKey,
42+
{}
43+
44+
impl<P> PartialEq for DiffieHellmanSharedSecret<P>
45+
where
46+
P: PublicKey,
47+
{
48+
fn eq(&self, other: &DiffieHellmanSharedSecret<P>) -> bool {
49+
self.0.ct_eq(&other.0).into()
50+
}
51+
}
52+
3953
#[cfg(test)]
4054
mod test {
4155
use rand_core::OsRng;

src/keys.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use core::ops::Add;
1010

1111
use rand_core::{CryptoRng, RngCore};
12+
use subtle::ConstantTimeEq;
1213
use tari_utilities::{ByteArray, ByteArrayError};
1314
use zeroize::{Zeroize, ZeroizeOnDrop};
1415

@@ -27,7 +28,7 @@ use zeroize::{Zeroize, ZeroizeOnDrop};
2728
/// let p = RistrettoPublicKey::from_secret_key(&k);
2829
/// ```
2930
pub trait SecretKey:
30-
ByteArray + Clone + PartialEq + Eq + Add<Output = Self> + Default + Zeroize + ZeroizeOnDrop
31+
ByteArray + Clone + ConstantTimeEq + PartialEq + Eq + Add<Output = Self> + Default + Zeroize + ZeroizeOnDrop
3132
{
3233
/// The length of the byte encoding of a key, in bytes
3334
const KEY_LEN: usize;
@@ -54,7 +55,7 @@ pub trait SecretKey:
5455
/// implementations need to implement this trait for them to be used in Tari.
5556
///
5657
/// See [SecretKey](trait.SecretKey.html) for an example.
57-
pub trait PublicKey: ByteArray + Add<Output = Self> + Clone + PartialOrd + Ord + Default + Zeroize {
58+
pub trait PublicKey: ByteArray + ConstantTimeEq + PartialEq + Eq + Add<Output = Self> + Clone + PartialOrd + Ord + Default + Zeroize {
5859
/// The length of the byte encoding of a key, in bytes
5960
const KEY_LEN: usize;
6061

src/ristretto/ristretto_keys.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
//! The Tari-compatible implementation of Ristretto based on the curve25519-dalek implementation
55
use alloc::{string::ToString, vec::Vec};
6+
use subtle::ConstantTimeEq;
67
use core::{
78
borrow::Borrow,
89
cmp::Ordering,
@@ -51,7 +52,7 @@ use crate::{
5152
/// let _k2 = RistrettoSecretKey::from_hex(&"100000002000000030000000040000000");
5253
/// let _k3 = RistrettoSecretKey::random(&mut rng);
5354
/// ```
54-
#[derive(Eq, Clone, Default, Zeroize, ZeroizeOnDrop)]
55+
#[derive(Clone,Default, Zeroize, ZeroizeOnDrop)]
5556
pub struct RistrettoSecretKey(pub(crate) Scalar);
5657

5758
#[cfg(feature = "borsh")]
@@ -132,12 +133,20 @@ impl Hash for RistrettoSecretKey {
132133
}
133134
}
134135

136+
impl ConstantTimeEq for RistrettoSecretKey {
137+
fn ct_eq(&self, other: &Self) -> subtle::Choice {
138+
self.0.ct_eq(&other.0)
139+
}
140+
}
141+
135142
impl PartialEq for RistrettoSecretKey {
136143
fn eq(&self, other: &Self) -> bool {
137-
self.0.eq(&other.0)
144+
self.ct_eq(&other).into()
138145
}
139146
}
140147

148+
impl Eq for RistrettoSecretKey {}
149+
141150
//---------------------------------- RistrettoSecretKey Debug --------------------------------------------//
142151
impl fmt::Debug for RistrettoSecretKey {
143152
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -423,6 +432,12 @@ impl fmt::Display for RistrettoPublicKey {
423432
}
424433
}
425434

435+
impl ConstantTimeEq for RistrettoPublicKey {
436+
fn ct_eq(&self, other: &Self) -> subtle::Choice {
437+
self.point.ct_eq(&other.point)
438+
}
439+
}
440+
426441
impl RistrettoPublicKey {
427442
// Formats a 64 char hex string to a given width.
428443
// If w >= 64, we pad the result.
@@ -471,9 +486,7 @@ impl fmt::Debug for RistrettoPublicKey {
471486

472487
impl PartialEq for RistrettoPublicKey {
473488
fn eq(&self, other: &RistrettoPublicKey) -> bool {
474-
// Although this is slower than `self.compressed == other.compressed`, expanded point comparison is an equal
475-
// time comparison
476-
self.point == other.point
489+
self.ct_eq(other).into()
477490
}
478491
}
479492

0 commit comments

Comments
 (0)