-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Ed25519 private and public key structs
- Loading branch information
Showing
64 changed files
with
14,864 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
included: | ||
- Sources | ||
excluded: | ||
- Sources/hedera/protobuf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
{ | ||
"object": { | ||
"pins": [ | ||
{ | ||
"package": "Clibsodium", | ||
"repositoryURL": "https://github.com/tiwoc/Clibsodium.git", | ||
"state": { | ||
"branch": null, | ||
"revision": "2ac72772aae26b2da0b15c253d9bb79ba452f66a", | ||
"version": "1.0.0" | ||
} | ||
}, | ||
{ | ||
"package": "SwiftProtobuf", | ||
"repositoryURL": "https://github.com/apple/swift-protobuf", | ||
"state": { | ||
"branch": null, | ||
"revision": "3a3594f84b746793c84c2ab2f1e855aaa9d3a593", | ||
"version": "1.6.0" | ||
} | ||
}, | ||
{ | ||
"package": "Sodium", | ||
"repositoryURL": "https://github.com/jedisct1/swift-sodium", | ||
"state": { | ||
"branch": null, | ||
"revision": "5900a54dea817befa18f3148889fe922a38afe7f", | ||
"version": "0.8.0" | ||
} | ||
} | ||
] | ||
}, | ||
"version": 1 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import Foundation | ||
import Sodium | ||
|
||
// TODO | ||
public struct HederaError: Error {} | ||
|
||
public protocol PublicKey { | ||
func toProtoKey() -> Proto_Key | ||
} | ||
|
||
extension PublicKey { | ||
// static func from(proto key: Proto_Key) throws -> PublicKey { | ||
// switch key.key! { | ||
// case let .ed25519(data): | ||
// return try! Ed25519PublicKey.from(bytes: Bytes(data)) | ||
// // TODO: case .contractID() | ||
// default: | ||
// // TODO: Unhandled Key Case error | ||
// throw HederaError() | ||
// } | ||
// } | ||
|
||
// TODO | ||
// static func from(string: String) -> PublicKey {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import Sodium | ||
|
||
let sodium = Sodium() | ||
|
||
struct HexDecodeError: Error {} | ||
|
||
func hexDecode<S>(_ hex: S) -> Result<Bytes, HexDecodeError> where S: StringProtocol { | ||
if hex.count % 2 != 0 { | ||
return .failure(HexDecodeError()) | ||
} | ||
|
||
let bytesLen = hex.count / 2 | ||
var bytes = Bytes(repeating: 0, count: bytesLen) | ||
|
||
for index in 0 ..< bytesLen { | ||
let start = hex.index(hex.startIndex, offsetBy: index * 2) | ||
let end = hex.index(start, offsetBy: 2) | ||
bytes[index] = UInt8(hex[start ..< end], radix: 16)! | ||
} | ||
|
||
return .success(bytes) | ||
} | ||
|
||
func hexEncode<S>(bytes: Bytes, prefixed with: S) -> String where S: StringProtocol { | ||
var result = String(with) | ||
for byte in bytes { | ||
result.append(String(format: "%02x", byte)) | ||
} | ||
|
||
return result | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,72 @@ | ||
// TODO | ||
import Sodium | ||
|
||
let ed25519PrivateKeyPrefix = "302e020100300506032b657004220420" | ||
let ed25519PrivateKeyLength = 32 | ||
let combinedEd25519KeyLength = 64 | ||
|
||
// TODO: how to handle error possibilities??? | ||
struct InvalidKeyBytes: Error {} | ||
|
||
public struct Ed25519PrivateKey { | ||
var inner: Bytes | ||
|
||
private init(bytes: Bytes) { | ||
inner = bytes | ||
} | ||
|
||
public static func from(bytes: Bytes) -> Result<Ed25519PrivateKey, Error> { | ||
if bytes.count == ed25519PrivateKeyLength { | ||
return .success(Ed25519PrivateKey(bytes: bytes)) | ||
} else if bytes.count == combinedEd25519KeyLength { | ||
return .success(Ed25519PrivateKey(bytes: Bytes(bytes.prefix(ed25519PrivateKeyLength)))) | ||
} | ||
return .failure(InvalidKeyBytes()) | ||
} | ||
|
||
var bytes: Bytes { | ||
return inner | ||
} | ||
|
||
public static func generate() -> Ed25519PrivateKey { | ||
return Ed25519PrivateKey(bytes: sodium.box.keyPair()!.secretKey) | ||
} | ||
|
||
public func getPublicKey() -> Ed25519PublicKey { | ||
return try! Ed25519PublicKey.from(bytes: sodium.box.keyPair(seed: inner)!.publicKey).get() | ||
} | ||
} | ||
|
||
extension Ed25519PrivateKey: CustomStringConvertible { | ||
public var description: String { | ||
return hexEncode(bytes: inner, prefixed: ed25519PrivateKeyPrefix) | ||
} | ||
} | ||
|
||
extension Ed25519PrivateKey: CustomDebugStringConvertible { | ||
public var debugDescription: String { | ||
return description | ||
} | ||
} | ||
|
||
extension Ed25519PrivateKey: LosslessStringConvertible { | ||
// Recover from a hex encoded string. Does not support key derivation. | ||
public init?(_ description: String) { | ||
switch description.count { | ||
case ed25519PrivateKeyLength * 2, combinedEd25519KeyLength * 2: // lone key, or combined key | ||
// This cannot fail to decode | ||
// swiftlint:disable:next force_try | ||
inner = try! Ed25519PrivateKey.from(bytes: try! hexDecode(description).get()).get().inner | ||
case ed25519PrivateKeyLength * 2 + ed25519PrivateKeyPrefix.count: // DER encoded key | ||
if description.hasPrefix(ed25519PrivateKeyPrefix) { | ||
let range = description.index(description.startIndex, offsetBy: ed25519PrivateKeyPrefix.count)... | ||
// This cannot fail to decode | ||
// swiftlint:disable:next force_try | ||
inner = try! Ed25519PrivateKey.from(bytes: try! hexDecode(description[range]).get()).get().inner | ||
} else { | ||
return nil | ||
} | ||
default: | ||
return nil | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,64 @@ | ||
// TODO | ||
import Sodium | ||
import Foundation | ||
|
||
let ed25519PublicKeyPrefix = "302a300506032b6570032100" | ||
let ed25519PublicKeyLength = 32 | ||
|
||
public struct Ed25519PublicKey { | ||
let inner: Bytes | ||
|
||
private init(bytes: Bytes) { | ||
inner = bytes | ||
} | ||
|
||
static func from(bytes: Bytes) -> Result<Ed25519PublicKey, Error> { | ||
if bytes.count == ed25519PublicKeyLength { | ||
return .success(Ed25519PublicKey(bytes: bytes)) | ||
} else { | ||
// TODO: actual error "invalid public key" | ||
return .failure(HederaError()) | ||
} | ||
} | ||
|
||
var bytes: Bytes { | ||
return inner | ||
} | ||
} | ||
|
||
extension Ed25519PublicKey: PublicKey { | ||
public func toProtoKey() -> Proto_Key { | ||
var proto = Proto_Key() | ||
proto.ed25519 = Data(inner) | ||
return proto | ||
} | ||
} | ||
|
||
extension Ed25519PublicKey: CustomStringConvertible { | ||
public var description: String { | ||
return hexEncode(bytes: inner, prefixed: ed25519PublicKeyPrefix) | ||
} | ||
} | ||
|
||
extension Ed25519PublicKey: CustomDebugStringConvertible { | ||
public var debugDescription: String { | ||
return description | ||
} | ||
} | ||
|
||
extension Ed25519PublicKey: LosslessStringConvertible { | ||
public init?(_ description: String) { | ||
switch description.count { | ||
case ed25519PublicKeyLength * 2: | ||
// This cannot fail | ||
// swiftlint:disable:next force_try | ||
inner = try! hexDecode(description).get() | ||
case ed25519PublicKeyLength * 2 + ed25519PublicKeyPrefix.count: | ||
let start = description.index(description.startIndex, offsetBy: ed25519PublicKeyPrefix.count) | ||
// This cannot fail | ||
// swiftlint:disable:next force_try | ||
inner = try! hexDecode(description[start...]).get() | ||
default: | ||
return nil | ||
} | ||
} | ||
} |
Oops, something went wrong.