Skip to content

Commit b5eef74

Browse files
authored
Merge branch 'main' into ramfox/flakey-test-simple-node-id
2 parents 72aec29 + b2a55bf commit b5eef74

File tree

17 files changed

+365
-242
lines changed

17 files changed

+365
-242
lines changed

Cargo.lock

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

iroh-base/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ serde = { version = "1", features = ["derive", "rc"] }
2626
snafu = { version = "0.8.5", features = ["rust_1_81"], optional = true }
2727
n0-snafu = "0.2.2"
2828
nested_enum_utils = "0.2.0"
29+
zeroize = { version = "1.8.2", optional = true, features = ["derive"] }
30+
zeroize_derive = { version = "1.4.2", optional = true } # needed for minimal versions
2931

3032
[dev-dependencies]
3133
postcard = { version = "1", features = ["use-std"] }
@@ -47,6 +49,8 @@ key = [
4749
"dep:snafu",
4850
"dep:data-encoding",
4951
"dep:rand_core",
52+
"dep:zeroize",
53+
"dep:zeroize_derive",
5054
"relay",
5155
]
5256
relay = [

iroh-base/src/key.rs

Lines changed: 75 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@
33
use std::{
44
borrow::Borrow,
55
cmp::{Ord, PartialOrd},
6-
fmt::{Debug, Display},
6+
fmt::{self, Debug, Display},
77
hash::Hash,
88
ops::Deref,
99
str::FromStr,
1010
};
1111

1212
use curve25519_dalek::edwards::CompressedEdwardsY;
13-
pub use ed25519_dalek::{Signature, SignatureError};
1413
use ed25519_dalek::{SigningKey, VerifyingKey};
1514
use nested_enum_utils::common_fields;
1615
use rand_core::CryptoRng;
@@ -100,24 +99,22 @@ impl<'de> Deserialize<'de> for PublicKey {
10099
}
101100

102101
impl PublicKey {
102+
/// The length of an ed25519 `PublicKey`, in bytes.
103+
pub const LENGTH: usize = ed25519_dalek::PUBLIC_KEY_LENGTH;
104+
103105
/// Get this public key as a byte array.
104106
pub fn as_bytes(&self) -> &[u8; 32] {
105107
self.0.as_bytes()
106108
}
107109

108-
/// Returns the [`VerifyingKey`] for this `PublicKey`.
109-
pub fn public(&self) -> VerifyingKey {
110-
VerifyingKey::from_bytes(self.0.as_bytes()).expect("already verified")
111-
}
112-
113110
/// Construct a `PublicKey` from a slice of bytes.
114111
///
115112
/// # Warning
116113
///
117114
/// This will return a [`SignatureError`] if the bytes passed into this method do not represent
118115
/// a valid `ed25519_dalek` curve point. Will never fail for bytes return from [`Self::as_bytes`].
119116
/// See [`VerifyingKey::from_bytes`] for details.
120-
pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, SignatureError> {
117+
pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, KeyParsingError> {
121118
let key = VerifyingKey::from_bytes(bytes)?;
122119
let y = CompressedEdwardsY(key.to_bytes());
123120
Ok(Self(y))
@@ -129,7 +126,9 @@ impl PublicKey {
129126
///
130127
/// Returns `Ok(())` if the signature is valid, and `Err` otherwise.
131128
pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> {
132-
self.public().verify_strict(message, signature)
129+
self.as_verifying_key()
130+
.verify_strict(message, &signature.0)
131+
.map_err(|_| SignatureSnafu.build())
133132
}
134133

135134
/// Convert to a hex string limited to the first 5 bytes for a friendly string
@@ -142,8 +141,17 @@ impl PublicKey {
142141
)
143142
}
144143

145-
/// The length of an ed25519 `PublicKey`, in bytes.
146-
pub const LENGTH: usize = ed25519_dalek::PUBLIC_KEY_LENGTH;
144+
/// Needed for internal conversions, not part of the stable API.
145+
#[doc(hidden)]
146+
pub fn as_verifying_key(&self) -> VerifyingKey {
147+
VerifyingKey::from_bytes(self.0.as_bytes()).expect("already verified")
148+
}
149+
150+
/// Needed for internal conversions, not part of the stable API.
151+
#[doc(hidden)]
152+
pub fn from_verifying_key(key: VerifyingKey) -> Self {
153+
Self(CompressedEdwardsY(key.to_bytes()))
154+
}
147155
}
148156

149157
struct PublicKeyShort([u8; 5]);
@@ -155,7 +163,7 @@ impl Display for PublicKeyShort {
155163
}
156164

157165
impl TryFrom<&[u8]> for PublicKey {
158-
type Error = SignatureError;
166+
type Error = KeyParsingError;
159167

160168
#[inline]
161169
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
@@ -165,7 +173,7 @@ impl TryFrom<&[u8]> for PublicKey {
165173
}
166174

167175
impl TryFrom<&[u8; 32]> for PublicKey {
168-
type Error = SignatureError;
176+
type Error = KeyParsingError;
169177

170178
#[inline]
171179
fn try_from(bytes: &[u8; 32]) -> Result<Self, Self::Error> {
@@ -179,13 +187,6 @@ impl AsRef<[u8]> for PublicKey {
179187
}
180188
}
181189

182-
impl From<VerifyingKey> for PublicKey {
183-
fn from(verifying_key: VerifyingKey) -> Self {
184-
let key = verifying_key.to_bytes();
185-
PublicKey(CompressedEdwardsY(key))
186-
}
187-
}
188-
189190
impl Debug for PublicKey {
190191
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
191192
write!(
@@ -234,15 +235,13 @@ impl FromStr for PublicKey {
234235
fn from_str(s: &str) -> Result<Self, Self::Err> {
235236
let bytes = decode_base32_hex(s)?;
236237

237-
Ok(Self::from_bytes(&bytes)?)
238+
Self::from_bytes(&bytes)
238239
}
239240
}
240241

241242
/// A secret key.
242-
#[derive(Clone)]
243-
pub struct SecretKey {
244-
secret: SigningKey,
245-
}
243+
#[derive(Clone, zeroize::ZeroizeOnDrop)]
244+
pub struct SecretKey(SigningKey);
246245

247246
impl Debug for SecretKey {
248247
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -264,7 +263,7 @@ impl Serialize for SecretKey {
264263
where
265264
S: serde::Serializer,
266265
{
267-
self.secret.serialize(serializer)
266+
self.0.serialize(serializer)
268267
}
269268
}
270269

@@ -274,14 +273,15 @@ impl<'de> Deserialize<'de> for SecretKey {
274273
D: serde::Deserializer<'de>,
275274
{
276275
let secret = SigningKey::deserialize(deserializer)?;
277-
Ok(secret.into())
276+
Ok(Self(secret))
278277
}
279278
}
280279

281280
impl SecretKey {
282281
/// The public key of this [`SecretKey`].
283282
pub fn public(&self) -> PublicKey {
284-
self.secret.verifying_key().into()
283+
let key = self.0.verifying_key().to_bytes();
284+
PublicKey(CompressedEdwardsY(key))
285285
}
286286

287287
/// Generate a new [`SecretKey`] with a randomness generator.
@@ -292,38 +292,33 @@ impl SecretKey {
292292
/// ```
293293
pub fn generate<R: CryptoRng + ?Sized>(csprng: &mut R) -> Self {
294294
let secret = SigningKey::generate(csprng);
295-
296-
Self { secret }
295+
Self(secret)
297296
}
298297

299298
/// Sign the given message and return a digital signature
300299
pub fn sign(&self, msg: &[u8]) -> Signature {
301300
use ed25519_dalek::Signer;
302301

303-
self.secret.sign(msg)
302+
let sig = self.0.sign(msg);
303+
Signature(sig)
304304
}
305305

306306
/// Convert this to the bytes representing the secret part.
307307
/// The public part can always be recovered.
308308
pub fn to_bytes(&self) -> [u8; 32] {
309-
self.secret.to_bytes()
309+
self.0.to_bytes()
310310
}
311311

312312
/// Create a secret key from its byte representation.
313313
pub fn from_bytes(bytes: &[u8; 32]) -> Self {
314314
let secret = SigningKey::from_bytes(bytes);
315-
secret.into()
315+
Self(secret)
316316
}
317317

318-
/// Returns the [`SigningKey`] for this `SecretKey`.
319-
pub fn secret(&self) -> &SigningKey {
320-
&self.secret
321-
}
322-
}
323-
324-
impl From<SigningKey> for SecretKey {
325-
fn from(secret: SigningKey) -> Self {
326-
SecretKey { secret }
318+
/// Needed for internal conversions, not part of the stable API.
319+
#[doc(hidden)]
320+
pub fn as_signing_key(&self) -> &SigningKey {
321+
&self.0
327322
}
328323
}
329324

@@ -334,15 +329,51 @@ impl From<[u8; 32]> for SecretKey {
334329
}
335330

336331
impl TryFrom<&[u8]> for SecretKey {
337-
type Error = SignatureError;
332+
type Error = KeyParsingError;
338333

339334
#[inline]
340335
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
341336
let secret = SigningKey::try_from(bytes)?;
342-
Ok(secret.into())
337+
Ok(Self(secret))
338+
}
339+
}
340+
341+
/// Ed25519 signature.
342+
#[derive(Copy, Clone, Eq, PartialEq)]
343+
pub struct Signature(ed25519_dalek::Signature);
344+
345+
impl Debug for Signature {
346+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347+
write!(f, "{:?}", self.0)
348+
}
349+
}
350+
351+
impl Display for Signature {
352+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353+
write!(f, "{}", self.0)
343354
}
344355
}
345356

357+
impl Signature {
358+
/// The length of an ed25519 `Signature`, in bytes.
359+
pub const LENGTH: usize = ed25519_dalek::Signature::BYTE_SIZE;
360+
361+
/// Return the inner byte array.
362+
pub fn to_bytes(&self) -> [u8; Self::LENGTH] {
363+
self.0.to_bytes()
364+
}
365+
366+
/// Parse an Ed25519 signature from a byte slice.
367+
pub fn from_bytes(bytes: &[u8; Self::LENGTH]) -> Self {
368+
Self(ed25519_dalek::Signature::from_bytes(bytes))
369+
}
370+
}
371+
372+
/// Verification of a signature failed.
373+
#[derive(Debug, Snafu)]
374+
#[snafu(display("Invalid signature"))]
375+
pub struct SignatureError;
376+
346377
fn decode_base32_hex(s: &str) -> Result<[u8; 32], KeyParsingError> {
347378
let mut bytes = [0u8; 32];
348379

iroh-relay/src/node_info.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use std::{
4040
str::{FromStr, Utf8Error},
4141
};
4242

43-
use iroh_base::{NodeAddr, NodeId, RelayUrl, SecretKey, SignatureError};
43+
use iroh_base::{KeyParsingError, NodeAddr, NodeId, RelayUrl, SecretKey};
4444
use nested_enum_utils::common_fields;
4545
use snafu::{Backtrace, ResultExt, Snafu};
4646
use url::Url;
@@ -81,7 +81,10 @@ pub enum DecodingError {
8181
#[snafu(display("length must be 32 bytes, but got {len} byte(s)"))]
8282
InvalidLength { len: usize },
8383
#[snafu(display("node id is not a valid public key"))]
84-
InvalidSignature { source: SignatureError },
84+
InvalidKey {
85+
#[snafu(source(from(KeyParsingError, Box::new)))]
86+
source: Box<KeyParsingError>,
87+
},
8588
}
8689

8790
/// Extension methods for [`NodeId`] to encode to and decode from [`z32`],
@@ -108,7 +111,7 @@ impl NodeIdExt for NodeId {
108111
let bytes: &[u8; 32] = &bytes
109112
.try_into()
110113
.map_err(|_| InvalidLengthSnafu { len: s.len() }.build())?;
111-
let node_id = NodeId::from_bytes(bytes).context(InvalidSignatureSnafu)?;
114+
let node_id = NodeId::from_bytes(bytes).context(InvalidKeySnafu)?;
112115
Ok(node_id)
113116
}
114117
}
@@ -561,7 +564,7 @@ impl<T: FromStr + Display + Hash + Ord> TxtAttrs<T> {
561564
};
562565
let pubkey = packet.public_key();
563566
let pubkey_z32 = pubkey.to_z32();
564-
let node_id = NodeId::from(*pubkey.verifying_key());
567+
let node_id = NodeId::from_bytes(&pubkey.verifying_key().to_bytes()).expect("valid key");
565568
let zone = dns::Name::new(&pubkey_z32).expect("z32 encoding is valid");
566569
let txt_data = packet
567570
.all_resource_records()

iroh-relay/src/protos/relay.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use std::num::NonZeroU16;
1111

1212
use bytes::{Buf, BufMut, Bytes, BytesMut};
13-
use iroh_base::{NodeId, SignatureError};
13+
use iroh_base::{KeyParsingError, NodeId};
1414
use n0_future::time::Duration;
1515
use nested_enum_utils::common_fields;
1616
use snafu::{Backtrace, ResultExt, Snafu};
@@ -59,7 +59,7 @@ pub enum Error {
5959
#[snafu(transparent)]
6060
FrameTypeError { source: FrameTypeError },
6161
#[snafu(display("Invalid public key"))]
62-
InvalidPublicKey { source: SignatureError },
62+
InvalidPublicKey { source: KeyParsingError },
6363
#[snafu(display("Invalid frame encoding"))]
6464
InvalidFrame {},
6565
#[snafu(display("Invalid frame type: {frame_type:?}"))]
@@ -216,7 +216,7 @@ impl Datagrams {
216216
+ self.contents.len()
217217
}
218218

219-
#[allow(clippy::len_zero)]
219+
#[allow(clippy::len_zero, clippy::result_large_err)]
220220
fn from_bytes(mut bytes: Bytes, is_batch: bool) -> Result<Self, Error> {
221221
if is_batch {
222222
// 1 bytes ECN, 2 bytes segment size

iroh/src/disco.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -521,8 +521,8 @@ mod tests {
521521
node_key: sender_key.public(),
522522
});
523523

524-
let sender_secret = secret_ed_box(sender_key.secret());
525-
let shared = SharedSecret::new(&sender_secret, &public_ed_box(&recv_key.public().public()));
524+
let sender_secret = secret_ed_box(&sender_key);
525+
let shared = SharedSecret::new(&sender_secret, &public_ed_box(&recv_key.public()));
526526
let mut seal = msg.as_bytes();
527527
shared.seal(&mut seal);
528528

@@ -535,9 +535,8 @@ mod tests {
535535
assert_eq!(raw_key, sender_key.public());
536536
assert_eq!(seal_back, seal);
537537

538-
let recv_secret = secret_ed_box(recv_key.secret());
539-
let shared_recv =
540-
SharedSecret::new(&recv_secret, &public_ed_box(&sender_key.public().public()));
538+
let recv_secret = secret_ed_box(&recv_key);
539+
let shared_recv = SharedSecret::new(&recv_secret, &public_ed_box(&sender_key.public()));
541540
let mut open_seal = seal_back.to_vec();
542541
shared_recv
543542
.open(&mut open_seal)

0 commit comments

Comments
 (0)