Skip to content

Commit c55e966

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

File tree

4 files changed

+35
-10
lines changed

4 files changed

+35
-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: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,19 @@
1111
1212
use core::ops::Mul;
1313

14+
use subtle::{Choice, ConstantTimeEq};
1415
use zeroize::{Zeroize, ZeroizeOnDrop};
1516

1617
use crate::keys::PublicKey;
1718

1819
/// The result of a Diffie-Hellman key exchange
19-
#[derive(Zeroize, ZeroizeOnDrop)]
20+
#[derive(PartialEq, Eq, Zeroize, ZeroizeOnDrop)]
2021
pub struct DiffieHellmanSharedSecret<P>(P)
21-
where P: Zeroize;
22+
where P: PublicKey;
2223

2324
impl<P> DiffieHellmanSharedSecret<P>
2425
where
25-
P: PublicKey + Zeroize,
26+
P: PublicKey,
2627
for<'a> &'a <P as PublicKey>::K: Mul<&'a P, Output = P>,
2728
{
2829
/// Perform a Diffie-Hellman key exchange
@@ -36,6 +37,14 @@ where
3637
}
3738
}
3839

40+
impl<P> ConstantTimeEq for DiffieHellmanSharedSecret<P>
41+
where P: PublicKey
42+
{
43+
fn ct_eq(&self, other: &DiffieHellmanSharedSecret<P>) -> Choice {
44+
self.0.ct_eq(&other.0)
45+
}
46+
}
47+
3948
#[cfg(test)]
4049
mod test {
4150
use rand_core::OsRng;

src/keys.rs

Lines changed: 5 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,9 @@ 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:
59+
ByteArray + ConstantTimeEq + PartialEq + Eq + Add<Output = Self> + Clone + PartialOrd + Ord + Default + Zeroize
60+
{
5861
/// The length of the byte encoding of a key, in bytes
5962
const KEY_LEN: usize;
6063

src/ristretto/ristretto_keys.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use curve25519_dalek::{
2121
use digest::{consts::U64, Digest};
2222
use once_cell::sync::OnceCell;
2323
use rand_core::{CryptoRng, RngCore};
24+
use subtle::ConstantTimeEq;
2425
use tari_utilities::{hex::Hex, ByteArray, ByteArrayError, Hashable};
2526
use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
2627

@@ -132,9 +133,15 @@ 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

@@ -423,6 +430,12 @@ impl fmt::Display for RistrettoPublicKey {
423430
}
424431
}
425432

433+
impl ConstantTimeEq for RistrettoPublicKey {
434+
fn ct_eq(&self, other: &Self) -> subtle::Choice {
435+
self.point.ct_eq(&other.point)
436+
}
437+
}
438+
426439
impl RistrettoPublicKey {
427440
// Formats a 64 char hex string to a given width.
428441
// If w >= 64, we pad the result.
@@ -471,9 +484,7 @@ impl fmt::Debug for RistrettoPublicKey {
471484

472485
impl PartialEq for RistrettoPublicKey {
473486
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
487+
self.ct_eq(other).into()
477488
}
478489
}
479490

0 commit comments

Comments
 (0)