Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Public/Private key to/from bytes functions for each crypto algorithm type #8

Merged
merged 1 commit into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ extension ECDSA {

/// Crypto operations using the Elliptic Curve Digital Signature Algorithm (ECDSA)
/// with the secp256k1 elliptic curve and SHA-256
enum Es256k: AsymmetricKeyGenerator, Signer {
public enum Es256k: AsymmetricKeyGenerator, Signer {

public static func generatePrivateKey() throws -> Jwk {
return try secp256k1.Signing.PrivateKey().jwk()
Expand All @@ -16,6 +16,29 @@ extension ECDSA {
return try privateKey.publicKey.jwk()
}

public static func privateKeyToBytes(_ privateKey: Jwk) throws -> Data {
let privateKey = try secp256k1.Signing.PrivateKey(privateJwk: privateKey)
return privateKey.dataRepresentation
}

public static func privateKeyFromBytes(_ bytes: Data) throws -> Jwk {
return try secp256k1.Signing.PrivateKey(dataRepresentation: bytes).jwk()
}

public static func publicKeyToBytes(_ publicKey: Jwk) throws -> Data {
let publicKey = try secp256k1.Signing.PublicKey(publicJwk: publicKey)
return publicKey.uncompressedBytes()
}

public static func publicKeyFromBytes(_ bytes: Data) throws -> Jwk {
return try secp256k1.Signing.PublicKey(
dataRepresentation: bytes,
format: bytes.count == secp256k1.Signing.PublicKey.Constants.compressedKeySize
? .compressed
: .uncompressed
).jwk()
}

public static func sign<D>(payload: D, privateKey: Jwk) throws -> Data where D: DataProtocol {
let privateKey = try secp256k1.Signing.PrivateKey(privateJwk: privateKey)
return try privateKey.signature(for: payload).compactRepresentation
Expand Down Expand Up @@ -74,7 +97,7 @@ extension secp256k1.Signing.PrivateKey {

extension secp256k1.Signing.PublicKey {

private enum Constants {
fileprivate enum Constants {
/// Uncompressed key leading byte that indicates both the X and Y coordinates are available directly within the key.
static let uncompressedKeyID: UInt8 = 0x04

Expand All @@ -83,6 +106,12 @@ extension secp256k1.Signing.PublicKey {
/// An uncompressed key is represented with a leading 0x04 bytes,
/// followed by 32 bytes for the x-coordinate and 32 bytes for the y-coordinate.
static let uncompressedKeySize: Int = 65

/// Size of a compressed public key, in bytes.
///
/// A compressed key is represented with a leading 0x02 or 0x03 byte,
/// followed by 32 bytes for the x-coordinate.
static let compressedKeySize: Int = 33
}

init(publicJwk: Jwk) throws {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Foundation

/// Elliptic Curve Digital Signature Algorithm (ECDSA)
enum ECDSA {}
public enum ECDSA {}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ extension EdDSA {

/// Cryptographic operations using the Edwards-curve Digital Signature Algorithm (EdDSA)
/// with the Ed25519 elliptic curve
enum Ed25519: AsymmetricKeyGenerator, Signer {
public enum Ed25519: AsymmetricKeyGenerator, Signer {

enum Error: Swift.Error {
case invalidPrivateJwk
Expand All @@ -21,6 +21,24 @@ extension EdDSA {
return try privateKey.publicKey.jwk()
}

public static func privateKeyToBytes(_ privateKey: Jwk) throws -> Data {
let privateKey = try Curve25519.Signing.PrivateKey(privateJwk: privateKey)
return privateKey.rawRepresentation
}

public static func privateKeyFromBytes(_ bytes: Data) throws -> Jwk {
return try Curve25519.Signing.PrivateKey(rawRepresentation: bytes).jwk()
}

public static func publicKeyToBytes(_ publicKey: Jwk) throws -> Data {
let publicKey = try Curve25519.Signing.PublicKey(publicJwk: publicKey)
return publicKey.rawRepresentation
}

public static func publicKeyFromBytes(_ bytes: Data) throws -> Jwk {
return try Curve25519.Signing.PublicKey(rawRepresentation: bytes).jwk()
}

public static func sign<D>(payload: D, privateKey: Jwk) throws -> Data where D: DataProtocol {
let privateKey = try Curve25519.Signing.PrivateKey(privateJwk: privateKey)
return try privateKey.signature(for: payload)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Foundation

/// Edwards-curve Digital Signature Algorithm (EdDSA)
enum EdDSA {}
public enum EdDSA {}
20 changes: 20 additions & 0 deletions Sources/Web5/Crypto/Primitives/AsymmetricKeyGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,26 @@ public protocol AsymmetricKeyGenerator {
/// - Returns: Public key in JWK format which corresponds to the provided `privateKey`
static func computePublicKey(privateKey: Jwk) throws -> Jwk

/// Convert a JWK private key into its data representation
/// - Parameter privateKey: Public JWK to be converted
/// - Returns: Data representation of the provided `privateKey`
static func privateKeyToBytes(_ privateKey: Jwk) throws -> Data

/// Convert a data representation of a private key into a JWK
/// - Parameter bytes: Data representation of a private key
/// - Returns: JWK representation of the provided `bytes`
static func privateKeyFromBytes(_ bytes: Data) throws -> Jwk

/// Convert a JWK public key into its data representation
/// - Parameter publicKey: Private JWK to be converted
/// - Returns: Data representation of the provided `publicKey`
static func publicKeyToBytes(_ publicKey: Jwk) throws -> Data

/// Convert a data representation of a public key into a JWK
/// - Parameter bytes: Data representation of a public key
/// - Returns: JWK representation of the provided `bytes`
static func publicKeyFromBytes(_ bytes: Data) throws -> Jwk

/// Determine if a given private key is a valid key that was generated by this generator
/// - Parameter privateKey: Private key in JWK format
/// - Returns: Boolean indicating if the provided `privateKey` is a valid key generated by this generator
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import CustomDump
import XCTest

@testable import Web5
Expand Down Expand Up @@ -35,6 +36,23 @@ final class ECDSA_Es256kTests: XCTestCase {
XCTAssertEqual(publicKey.y, privateKey.y)
}

func test_privateKey_toAndFromBytes() throws {
let privateKey = try ECDSA.Es256k.generatePrivateKey()
let privateKeyBytes = try ECDSA.Es256k.privateKeyToBytes(privateKey)
let restoredPrivateKey = try ECDSA.Es256k.privateKeyFromBytes(privateKeyBytes)

XCTAssertNoDifference(privateKey, restoredPrivateKey)
}

func test_publicKey_toAndFromBytes() throws {
let privateKey = try ECDSA.Es256k.generatePrivateKey()
let publicKey = try ECDSA.Es256k.computePublicKey(privateKey: privateKey)
let publicKeyBytes = try ECDSA.Es256k.publicKeyToBytes(publicKey)
let restoredPublicKey = try ECDSA.Es256k.publicKeyFromBytes(publicKeyBytes)

XCTAssertNoDifference(publicKey, restoredPublicKey)
}

func test_sign() throws {
let privateKey = try ECDSA.Es256k.generatePrivateKey()
let signature = try ECDSA.Es256k.sign(payload: payload, privateKey: privateKey)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import CustomDump
import XCTest

@testable import Web5
Expand Down Expand Up @@ -39,6 +40,23 @@ final class EdDSA_Ed25519Tests: XCTestCase {
XCTAssertEqual(publicKey.y, privateKey.y)
}

func test_privateKey_toAndFromBytes() throws {
let privateKey = try EdDSA.Ed25519.generatePrivateKey()
let privateKeyBytes = try EdDSA.Ed25519.privateKeyToBytes(privateKey)
let restoredPrivateKey = try EdDSA.Ed25519.privateKeyFromBytes(privateKeyBytes)

XCTAssertNoDifference(privateKey, restoredPrivateKey)
}

func test_publicKey_toAndFromBytes() throws {
let privateKey = try EdDSA.Ed25519.generatePrivateKey()
let publicKey = try EdDSA.Ed25519.computePublicKey(privateKey: privateKey)
let publicKeyBytes = try EdDSA.Ed25519.publicKeyToBytes(publicKey)
let restoredPublicKey = try EdDSA.Ed25519.publicKeyFromBytes(publicKeyBytes)

XCTAssertNoDifference(publicKey, restoredPublicKey)
}

func test_sign() throws {
let privateKey = try EdDSA.Ed25519.generatePrivateKey()
let signature = try EdDSA.Ed25519.sign(payload: payload, privateKey: privateKey)
Expand Down
Loading