diff --git a/Blockchain/Package.resolved b/Blockchain/Package.resolved index 0c724b53..f5b4d6bb 100644 --- a/Blockchain/Package.resolved +++ b/Blockchain/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "70e836bce6a34055534368d9795a06e92002ca028f0fcd154b1d037502f7060c", + "originHash" : "0ac92ee4aeacbb08a4c124d75df94d0eef8e04bbc2ecc74287b02650ec69779a", "pins" : [ { "identity" : "async-channels", @@ -37,6 +37,15 @@ "version" : "1.1.0" } }, + { + "identity" : "swift-crypto", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-crypto.git", + "state" : { + "revision" : "bc1c29221f6dfeb0ebbfbc98eb95cd3d4967868e", + "version" : "3.4.0" + } + }, { "identity" : "tuples.swift", "kind" : "remoteSourceControl", diff --git a/Boka/Package.resolved b/Boka/Package.resolved index e5aca38c..addc9220 100644 --- a/Boka/Package.resolved +++ b/Boka/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "bd44440d7f85d30386716bbd2cc933f21b5ebbc0e75fbfc91dc6a138b6c8ce43", + "originHash" : "a4042fe50ef710cddb88ce0dedba5a852492f62faeacb51990391e81ddcf7e06", "pins" : [ { "identity" : "async-channels", @@ -46,6 +46,15 @@ "version" : "1.1.1" } }, + { + "identity" : "swift-crypto", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-crypto.git", + "state" : { + "revision" : "bc1c29221f6dfeb0ebbfbc98eb95cd3d4967868e", + "version" : "3.4.0" + } + }, { "identity" : "tuples.swift", "kind" : "remoteSourceControl", diff --git a/Node/Package.resolved b/Node/Package.resolved index 3062c167..39c28070 100644 --- a/Node/Package.resolved +++ b/Node/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "82a6d0499b5b0467ed0f8512e428444b3e8626df0667aaa6217ac2055f9ae08c", + "originHash" : "9410affb9296c71e9328e458fd6424e870da866b122c00a7925ca2247508a8e9", "pins" : [ { "identity" : "async-channels", @@ -37,6 +37,15 @@ "version" : "1.1.0" } }, + { + "identity" : "swift-crypto", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-crypto.git", + "state" : { + "revision" : "bc1c29221f6dfeb0ebbfbc98eb95cd3d4967868e", + "version" : "3.4.0" + } + }, { "identity" : "tuples.swift", "kind" : "remoteSourceControl", diff --git a/Utils/Package.resolved b/Utils/Package.resolved index 52ec90a0..99da95e3 100644 --- a/Utils/Package.resolved +++ b/Utils/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "7e6e33157836e05375f90c70184331ac5884a4dc78788ca4ae9e201bcdf8dfed", + "originHash" : "20e3a243ff55bca06efe38725567e64612fcf69c4836f7018fbfb322bcf6d466", "pins" : [ { "identity" : "scalecodec.swift", @@ -10,6 +10,15 @@ "version" : "0.3.1" } }, + { + "identity" : "swift-crypto", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-crypto.git", + "state" : { + "revision" : "bc1c29221f6dfeb0ebbfbc98eb95cd3d4967868e", + "version" : "3.4.0" + } + }, { "identity" : "tuples.swift", "kind" : "remoteSourceControl", diff --git a/Utils/Package.swift b/Utils/Package.swift index 8daa1c93..a3c5d357 100644 --- a/Utils/Package.swift +++ b/Utils/Package.swift @@ -17,6 +17,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/tesseract-one/ScaleCodec.swift.git", from: "0.3.0"), + .package(url: "https://github.com/apple/swift-crypto.git", "1.0.0" ..< "4.0.0"), ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. @@ -25,6 +26,7 @@ let package = Package( name: "Utils", dependencies: [ .product(name: "ScaleCodec", package: "ScaleCodec.swift"), + .product(name: "Crypto", package: "swift-crypto"), ] ), .testTarget( diff --git a/Utils/Sources/Utils/Ed25519.swift b/Utils/Sources/Utils/Ed25519.swift new file mode 100644 index 00000000..6f788578 --- /dev/null +++ b/Utils/Sources/Utils/Ed25519.swift @@ -0,0 +1,37 @@ +import Crypto +import Foundation + +public struct Ed25519 { + public let secretKey: Curve25519.Signing.PrivateKey + + public var publicKey: Data32 { + Data32(secretKey.publicKey.rawRepresentation)! + } + + public var privateKey: Data32 { + Data32(secretKey.rawRepresentation)! + } + + public init() { + secretKey = Curve25519.Signing.PrivateKey() + } + + public init?(privateKey: Data32) { + guard let key = try? Curve25519.Signing.PrivateKey(rawRepresentation: privateKey.data) else { + return nil + } + secretKey = key + } + + public func sign(message: Data) throws -> Data64 { + let signature = try secretKey.signature(for: message) + return Data64(signature)! + } + + public func verify(signature: Data64, message: Data, publicKey: Data32) -> Bool { + guard let publicKey = try? Curve25519.Signing.PublicKey(rawRepresentation: publicKey.data) else { + return false + } + return publicKey.isValidSignature(signature.data, for: message) + } +} diff --git a/Utils/Tests/UtilsTests/Ed25519Tests.swift b/Utils/Tests/UtilsTests/Ed25519Tests.swift new file mode 100644 index 00000000..37057745 --- /dev/null +++ b/Utils/Tests/UtilsTests/Ed25519Tests.swift @@ -0,0 +1,21 @@ +import XCTest + +@testable import Utils + +final class Ed25519Tests: XCTestCase { + func testEd25519Signature() throws { + let ed25519 = Ed25519() + let publicKey = ed25519.publicKey + + let message = Data("test".utf8) + let signature = try ed25519.sign(message: message) + XCTAssertTrue(ed25519.verify(signature: signature, message: message, publicKey: publicKey)) + + let invalidMessage = Data("tests".utf8) + XCTAssertFalse(ed25519.verify(signature: signature, message: invalidMessage, publicKey: publicKey)) + + var invalidSignature = signature.data + invalidSignature.replaceSubrange(0 ... 1, with: [10, 12]) + XCTAssertFalse(ed25519.verify(signature: Data64(invalidSignature)!, message: message, publicKey: publicKey)) + } +}