From 66e9400cb60fedbe46163e12774a407d8a2c13ec Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Fri, 14 Apr 2023 08:26:06 +0200 Subject: [PATCH 1/3] Make Curve25519 PublicKeys Equatable --- Sources/Crypto/Keys/EC/Ed25519.swift | 6 +++- Sources/Crypto/Keys/EC/X25519Keys.swift | 6 +++- .../Signatures/EdDSA/EdDSATests.swift | 34 +++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/Sources/Crypto/Keys/EC/Ed25519.swift b/Sources/Crypto/Keys/EC/Ed25519.swift index 14d11ca23..f8ed8d5db 100644 --- a/Sources/Crypto/Keys/EC/Ed25519.swift +++ b/Sources/Crypto/Keys/EC/Ed25519.swift @@ -57,7 +57,7 @@ extension Curve25519 { } } - public struct PublicKey { + public struct PublicKey: Equatable { private var baseKey: Curve25519.Signing.Curve25519PublicKeyImpl public init(rawRepresentation: D) throws { @@ -75,6 +75,10 @@ extension Curve25519 { var keyBytes: [UInt8] { return self.baseKey.keyBytes } + + public static func ==(lhs: Self, rhs: Self) -> Bool { + lhs.rawRepresentation == rhs.rawRepresentation + } } } } diff --git a/Sources/Crypto/Keys/EC/X25519Keys.swift b/Sources/Crypto/Keys/EC/X25519Keys.swift index 250eec355..acdc3a40d 100644 --- a/Sources/Crypto/Keys/EC/X25519Keys.swift +++ b/Sources/Crypto/Keys/EC/X25519Keys.swift @@ -26,7 +26,7 @@ extension Curve25519 { typealias Curve25519PublicKeyImpl = Curve25519.KeyAgreement.OpenSSLCurve25519PublicKeyImpl #endif - public struct PublicKey: ECPublicKey { + public struct PublicKey: ECPublicKey, Equatable { fileprivate var baseKey: Curve25519PublicKeyImpl /// Initializes a Curve25519 Key for Key Agreement. @@ -54,6 +54,10 @@ extension Curve25519 { private func withUnsafeBytes(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R { return try self.baseKey.keyBytes.withUnsafeBytes(body) } + + public static func ==(lhs: Self, rhs: Self) -> Bool { + lhs.rawRepresentation == rhs.rawRepresentation + } } public struct PrivateKey: ECPrivateKey, DiffieHellmanKeyAgreement { diff --git a/Tests/CryptoTests/Signatures/EdDSA/EdDSATests.swift b/Tests/CryptoTests/Signatures/EdDSA/EdDSATests.swift index 233e30146..73d64f902 100644 --- a/Tests/CryptoTests/Signatures/EdDSA/EdDSATests.swift +++ b/Tests/CryptoTests/Signatures/EdDSA/EdDSATests.swift @@ -75,4 +75,38 @@ class EdDSATests: XCTestCase { // This signature should be invalid XCTAssertFalse(privateKey.publicKey.isValidSignature(DispatchData.empty, for: DispatchData.empty)) } + + func testCurve25519SigningPublicKeyEquatable() throws { + // Inequality + + // The probability of this inequality check loop + // accidentally failing is... 1/(2^246), i.e. low. + for _ in 0..<1024 { + XCTAssertNotEqual( + Curve25519.Signing.PrivateKey().publicKey, + Curve25519.Signing.PrivateKey().publicKey + ) + } + + // Equality + let publicKey = Curve25519.Signing.PrivateKey().publicKey + XCTAssertEqual(publicKey, publicKey) + } + + func testCurve25519KeyAgreementPublicKeyEquatable() throws { + // Inequality + + // The probability of this inequality check loop + // accidentally failing is... 1/(2^246), i.e. low. + for _ in 0..<1024 { + XCTAssertNotEqual( + Curve25519.KeyAgreement.PrivateKey().publicKey, + Curve25519.KeyAgreement.PrivateKey().publicKey + ) + } + + // Equality + let publicKey = Curve25519.KeyAgreement.PrivateKey().publicKey + XCTAssertEqual(publicKey, publicKey) + } } From cd98129de63e95696f77d1d6365722fb4600ad7a Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Mon, 17 Apr 2023 12:34:03 +0200 Subject: [PATCH 2/3] Update tests --- .../Signatures/EdDSA/EdDSATests.swift | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Tests/CryptoTests/Signatures/EdDSA/EdDSATests.swift b/Tests/CryptoTests/Signatures/EdDSA/EdDSATests.swift index 73d64f902..75ed69e76 100644 --- a/Tests/CryptoTests/Signatures/EdDSA/EdDSATests.swift +++ b/Tests/CryptoTests/Signatures/EdDSA/EdDSATests.swift @@ -77,36 +77,37 @@ class EdDSATests: XCTestCase { } func testCurve25519SigningPublicKeyEquatable() throws { + // Equality + let publicKey = Curve25519.Signing.PrivateKey().publicKey + XCTAssertEqual(publicKey, publicKey) + // Inequality // The probability of this inequality check loop - // accidentally failing is... 1/(2^246), i.e. low. + // accidentally failing is... 1/2^246, i.e. low. for _ in 0..<1024 { XCTAssertNotEqual( - Curve25519.Signing.PrivateKey().publicKey, + publicKey, Curve25519.Signing.PrivateKey().publicKey ) } - - // Equality - let publicKey = Curve25519.Signing.PrivateKey().publicKey - XCTAssertEqual(publicKey, publicKey) + } func testCurve25519KeyAgreementPublicKeyEquatable() throws { + // Equality + let publicKey = Curve25519.KeyAgreement.PrivateKey().publicKey + XCTAssertEqual(publicKey, publicKey) + // Inequality // The probability of this inequality check loop - // accidentally failing is... 1/(2^246), i.e. low. + // accidentally failing is... 1/2^246, i.e. low. for _ in 0..<1024 { XCTAssertNotEqual( - Curve25519.KeyAgreement.PrivateKey().publicKey, + publicKey, Curve25519.KeyAgreement.PrivateKey().publicKey ) } - - // Equality - let publicKey = Curve25519.KeyAgreement.PrivateKey().publicKey - XCTAssertEqual(publicKey, publicKey) } } From f5810645c53ddeec357afcfb48a3975a865c0649 Mon Sep 17 00:00:00 2001 From: Alexander Cyon Date: Tue, 18 Apr 2023 08:59:27 +0200 Subject: [PATCH 3/3] Make Curve25519 PublicKey's conform to Hashable --- Sources/Crypto/Keys/EC/Ed25519.swift | 12 ++++++++++-- Sources/Crypto/Keys/EC/X25519Keys.swift | 8 ++++++-- .../Signatures/EdDSA/EdDSATests.swift | 17 ++++++++++++++++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/Sources/Crypto/Keys/EC/Ed25519.swift b/Sources/Crypto/Keys/EC/Ed25519.swift index f8ed8d5db..4b0e4c3de 100644 --- a/Sources/Crypto/Keys/EC/Ed25519.swift +++ b/Sources/Crypto/Keys/EC/Ed25519.swift @@ -57,7 +57,7 @@ extension Curve25519 { } } - public struct PublicKey: Equatable { + public struct PublicKey: Hashable { private var baseKey: Curve25519.Signing.Curve25519PublicKeyImpl public init(rawRepresentation: D) throws { @@ -76,8 +76,16 @@ extension Curve25519 { return self.baseKey.keyBytes } + private func withUnsafeBytes(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R { + return try self.baseKey.keyBytes.withUnsafeBytes(body) + } + public static func ==(lhs: Self, rhs: Self) -> Bool { - lhs.rawRepresentation == rhs.rawRepresentation + return lhs.rawRepresentation == rhs.rawRepresentation + } + + public func hash(into hasher: inout Hasher) { + return self.withUnsafeBytes { hasher.combine(bytes: $0) } } } } diff --git a/Sources/Crypto/Keys/EC/X25519Keys.swift b/Sources/Crypto/Keys/EC/X25519Keys.swift index acdc3a40d..4dc90a3e2 100644 --- a/Sources/Crypto/Keys/EC/X25519Keys.swift +++ b/Sources/Crypto/Keys/EC/X25519Keys.swift @@ -26,7 +26,7 @@ extension Curve25519 { typealias Curve25519PublicKeyImpl = Curve25519.KeyAgreement.OpenSSLCurve25519PublicKeyImpl #endif - public struct PublicKey: ECPublicKey, Equatable { + public struct PublicKey: ECPublicKey, Hashable { fileprivate var baseKey: Curve25519PublicKeyImpl /// Initializes a Curve25519 Key for Key Agreement. @@ -56,7 +56,11 @@ extension Curve25519 { } public static func ==(lhs: Self, rhs: Self) -> Bool { - lhs.rawRepresentation == rhs.rawRepresentation + return lhs.rawRepresentation == rhs.rawRepresentation + } + + public func hash(into hasher: inout Hasher) { + self.withUnsafeBytes { hasher.combine(bytes: $0) } } } diff --git a/Tests/CryptoTests/Signatures/EdDSA/EdDSATests.swift b/Tests/CryptoTests/Signatures/EdDSA/EdDSATests.swift index 75ed69e76..3ae789b79 100644 --- a/Tests/CryptoTests/Signatures/EdDSA/EdDSATests.swift +++ b/Tests/CryptoTests/Signatures/EdDSA/EdDSATests.swift @@ -91,7 +91,6 @@ class EdDSATests: XCTestCase { Curve25519.Signing.PrivateKey().publicKey ) } - } func testCurve25519KeyAgreementPublicKeyEquatable() throws { @@ -110,4 +109,20 @@ class EdDSATests: XCTestCase { ) } } + + func testCurve25519SigningPublicKeyHashable() throws { + let expectedCount = 1000 + let set = Set((0..