Skip to content

Commit 9c07785

Browse files
committed
add function and tests to convert public key to public key hash
1 parent f8e81c7 commit 9c07785

File tree

3 files changed

+41
-0
lines changed

3 files changed

+41
-0
lines changed

Sources/KukaiCryptoSwift/KeyPair.swift

+8
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ public enum EllipticalCurve: String, Codable {
2222
else if prefix == "tz2" { return .secp256k1 }
2323
else { return nil }
2424
}
25+
26+
public static func fromBase58Key(_ key: String) -> EllipticalCurve? {
27+
let prefix = key.lowercased().prefix(4)
28+
29+
if prefix == "edpk" { return .ed25519 }
30+
else if prefix == "sppk" { return .secp256k1 }
31+
else { return nil }
32+
}
2533
}
2634

2735
/// A struct representing a both a `PrivateKey` and `PublicKey` with helper methods to create various kinds

Sources/KukaiCryptoSwift/PublicKey.swift

+19
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,25 @@ public struct PublicKey: Codable {
9292
return secp256k1_ecdsa_verify(context, &cSignature, message, &publicKey) == 1
9393
}
9494
}
95+
96+
/**
97+
Take a base58Encoded public key (with a prefix) and convert it to a tzX public key hash
98+
*/
99+
public static func publicKeyHash(fromBase58EncodedKey key: String) -> String? {
100+
guard let algo = EllipticalCurve.fromBase58Key(key),
101+
let decoded = Base58Check.decode(string: key, prefix: algo == .ed25519 ? Prefix.Keys.Ed25519.public : Prefix.Keys.Secp256k1.public),
102+
let hash = Sodium.shared.genericHash.hash(message: decoded, outputLength: 20) else {
103+
return nil
104+
}
105+
106+
switch algo {
107+
case .ed25519:
108+
return Base58Check.encode(message: hash, prefix: Prefix.Address.tz1)
109+
110+
case .secp256k1:
111+
return Base58Check.encode(message: hash, prefix: Prefix.Address.tz2)
112+
}
113+
}
95114
}
96115

97116
extension PublicKey: CustomStringConvertible {

Tests/KukaiCryptoSwiftTests/KeyPairTests.swift

+14
Original file line numberDiff line numberDiff line change
@@ -175,4 +175,18 @@ final class KeyPairTests: XCTestCase {
175175
let pubKeySafety = KeyPair.secp256k1PublicKey(fromPrivateKeyBytes: signatureBytes)
176176
XCTAssert(pubKeySafety == nil, (pubKeySafety?.bytes.count ?? 0).description)
177177
}
178+
179+
func testKeyToHash() throws {
180+
let hash1 = PublicKey.publicKeyHash(fromBase58EncodedKey: "edpkuLshcvrn2x7c2QtCCMv8XFNEM2gHkPDGb3paKt2hBvnBRfepR4")
181+
XCTAssert(hash1 == "tz1Xx4vxaUCkgxfaUhr1EV1kvTE2Rt3BkEdm", hash1 ?? "-")
182+
183+
let hash2 = PublicKey.publicKeyHash(fromBase58EncodedKey: "edpkuaUnRZQzwP1QYHFFXzbhN919wg17KHm7vHH86pxxgSSkqT7U4a")
184+
XCTAssert(hash2 == "tz1ZYoRJ2iouRi5r6CT83Ptp9Bof7RMRkxXe", hash2 ?? "-")
185+
186+
let hash3 = PublicKey.publicKeyHash(fromBase58EncodedKey: "edpkufQ3nNdMJBkgfzCgCLmk1tbfLsqK7W8AR37KiCe7tDVvmsroHh")
187+
XCTAssert(hash3 == "tz1WCBJKr1rRivyCnN9hREpRAMqrLdmqDcym", hash3 ?? "-")
188+
189+
let hash4 = PublicKey.publicKeyHash(fromBase58EncodedKey: "sppk7Zzqz2AjP4yXqr5ys99gZkaPLFKfGKnUxn3u1T1xfNSArZ5CKX6")
190+
XCTAssert(hash4 == "tz2HpbGQcmU3UyusJ78Sbqeg9fYteamSMDGo", hash4 ?? "-")
191+
}
178192
}

0 commit comments

Comments
 (0)