Skip to content

Commit

Permalink
Public/Private key to/from bytes functions for each crypto algorithm …
Browse files Browse the repository at this point in the history
…type (#8)
  • Loading branch information
amika-sq authored Feb 6, 2024
1 parent 78d4141 commit bca9ad1
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 5 deletions.
33 changes: 31 additions & 2 deletions Sources/Web5/Crypto/DigitalSignatureAlgorithms/ECDSA+Es256k.swift
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
2 changes: 1 addition & 1 deletion Sources/Web5/Crypto/DigitalSignatureAlgorithms/ECDSA.swift
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
2 changes: 1 addition & 1 deletion Sources/Web5/Crypto/DigitalSignatureAlgorithms/EdDSA.swift
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

0 comments on commit bca9ad1

Please sign in to comment.