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

Use OpenSSL for keccak256 encryption #430

Merged
merged 2 commits into from
Jan 21, 2025
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
18 changes: 9 additions & 9 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,6 @@
"version" : "4.14.3"
}
},
{
"identity" : "cryptoswift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/krzyzanowskim/CryptoSwift.git",
"state" : {
"revision" : "db51c407d3be4a051484a141bf0bff36c43d3b1e",
"version" : "1.8.0"
}
},
{
"identity" : "grpc-swift",
"kind" : "remoteSourceControl",
Expand All @@ -72,6 +63,15 @@
"version" : "4.5.4"
}
},
{
"identity" : "openssl-package",
"kind" : "remoteSourceControl",
"location" : "https://github.com/krzyzanowskim/OpenSSL-Package.git",
"state" : {
"revision" : "b9eb055fdf73e595cb4b9f665d13dc85975bf80a",
"version" : "3.3.2000"
}
},
{
"identity" : "routing-kit",
"kind" : "remoteSourceControl",
Expand Down
6 changes: 3 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,12 @@ let package = Package(
// swift-asn1 wants swift 5.7+ past 0.4
.package(url: "https://github.com/apple/swift-asn1.git", .upToNextMinor(from: "0.3.0")),
.package(url: "https://github.com/GigaBitcoin/secp256k1.swift.git", .upToNextMinor(from: "0.12.0")),
// we use this entirely for sha3-keccak256, yes, I'm serious.
.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"),
.package(url: "https://github.com/pointfreeco/swift-snapshot-testing.git", from: "1.0.0"),
.package(url: "https://github.com/vapor/vapor.git", from: "4.101.3"),
.package(url: "https://github.com/attaswift/BigInt.git", from: "5.2.0"),
// Currently, only used for keccak256
.package(url: "https://github.com/krzyzanowskim/OpenSSL-Package.git", from: "3.3.2000"),
],
targets: [
.target(
Expand Down Expand Up @@ -133,7 +133,7 @@ let package = Package(
.product(name: "Atomics", package: "swift-atomics"),
.product(name: "secp256k1", package: "secp256k1.swift"),
.product(name: "BigInt", package: "BigInt"),
"CryptoSwift",
.product(name: "OpenSSL", package: "OpenSSL-Package"),
]
// todo: find some way to enable these locally.
// swiftSettings: [
Expand Down
35 changes: 33 additions & 2 deletions Sources/Hedera/Crypto/CryptoSha3.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
* ‍
*/

import CryptoSwift
import Foundation
import OpenSSL

extension Crypto {
internal enum Sha3 {
Expand All @@ -32,7 +32,7 @@ extension Crypto {
internal func digest(_ data: Data) -> Data {
switch self {
case .keccak256:
return Data(CryptoSwift.SHA3(variant: .keccak256).calculate(for: Array(data)))
return keccak256Digest(data)
}
}

Expand All @@ -44,5 +44,36 @@ extension Crypto {
internal static func keccak256(_ data: Data) -> Data {
digest(.keccak256, data)
}

private func keccak256Digest(_ data: Data) -> Data {
// Initialize OpenSSL's new context
let ctx = EVP_MD_CTX_new()
defer { EVP_MD_CTX_free(ctx) }

// Fetch Keccak-256 Algorithm
guard let keccak256 = EVP_MD_fetch(nil, "KECCAK-256", nil) else {
fatalError("Failed to get Keccak-256 digest method")
}

guard EVP_DigestInit_ex(ctx, keccak256, nil) == 1 else {
fatalError("Failed to initialize Keccak-256 context")
}

// Feed data into the hashing context
data.withUnsafeBytes { buffer in
_ = EVP_DigestUpdate(ctx, buffer.baseAddress, buffer.count)
}

// 32 bytes for standard output size
let hashSize = 32
var hash = [UInt8](repeating: 0, count: hashSize)

var length = UInt32(hash.count)
guard EVP_DigestFinal_ex(ctx, &hash, &length) == 1 else {
fatalError("Failed to finalize Keccak-256 hash computation")
}

return Data(hash)
}
}
}
12 changes: 12 additions & 0 deletions Sources/Hedera/Rlp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,18 @@ extension AnyRlp {
}
}

// Extend Optional where Wrapped is Data to conform to RlpEncodable
extension Optional: RlpEncodable where Wrapped == Data {
internal func encode(to encoder: inout Rlp.Encoder) {
switch self {
case .some(let data):
data.encode(to: &encoder) // Encode the wrapped Data
case .none:
encoder.appendRawValue(Data()) // Handle nil case by encoding an empty Data
}
}
}

extension Rlp.Encoder {
internal init(buffer: Data = Data()) {
self.raw = buffer
Expand Down
4 changes: 2 additions & 2 deletions Sources/HederaTCK/SDKClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ internal class SDKClient {
do {
return Key.single(try PublicKey.fromStringDer(key))
} catch {
return try Key(protobuf: try Proto_Key(serializedBytes: Data(hex: key)))
return try Key(protobuf: try Proto_Key(serializedBytes: key.data(using: .utf8)!))
}
}
}
Expand Down Expand Up @@ -129,7 +129,7 @@ internal class SDKClient {
keyList.threshold = Int(threshold!)
}

return Key.keyList(keyList).toProtobufBytes().toHexString()
return Key.keyList(keyList).toProtobufBytes().hexStringEncoded()

case .evmAddressKeyType:
guard let fromKey = fromKey else {
Expand Down
16 changes: 8 additions & 8 deletions Tests/HederaE2ETests/EthereumTransaction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ internal class Ethereum: XCTestCase {

let contractId = try XCTUnwrap(contractReceipt.contractId)

let chainId = Data(hex: "012a")
let nonce = Data(hex: "00")
let maxPriorityGas = Data(hex: "00")
let maxGas = Data(hex: "d1385c7bf0")
let gasLimit = Data(hex: "0249f0")
let to = Data(hex: try contractId.toSolidityAddress())
let value = Data(hex: "00")
let chainId = Data(hexEncoded: "012a")
let nonce = Data(hexEncoded: "00")
let maxPriorityGas = Data(hexEncoded: "00")
let maxGas = Data(hexEncoded: "d1385c7bf0")
let gasLimit = Data(hexEncoded: "0249f0")
let to = Data(hexEncoded: try contractId.toSolidityAddress())
let value = Data(hexEncoded: "00")
let callData = ContractFunctionParameters().addString("new message").toBytes("setMessage")
let recoveryId = Data(hex: "01")
let recoveryId = Data(hexEncoded: "01")
let accessList: Data = Data()
var newData = Data([2])

Expand Down
7 changes: 4 additions & 3 deletions Tests/HederaE2ETests/Topic/TopicMessageSubmit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
* ‍
*/

import Hedera
import HederaExampleUtilities
import XCTest

@testable import Hedera

internal class TopicMessageSubmit: XCTestCase {
internal func testBasic() async throws {
let testEnv = try TestEnvironment.nonFree
Expand Down Expand Up @@ -117,7 +118,7 @@ internal class TopicMessageSubmit: XCTestCase {

internal func testDecodeHexRegressionTest() throws {
let transactionBytes = Data(
hex:
hexEncoded:
"""
2ac2010a580a130a0b08d38f8f880610a09be91512041899e11c120218041880\
c2d72f22020878da01330a0418a5a12012103030303030303136323736333737\
Expand All @@ -127,7 +128,7 @@ internal class TopicMessageSubmit: XCTestCase {
2177f129ca0abae7831e595b5beaa1c947e2cb71201642bab33fece5184b0454\
7afc40850a
"""
)
)!

let transaction = try Transaction.fromBytes(transactionBytes)

Expand Down
3 changes: 2 additions & 1 deletion Tests/HederaTests/ContractInfoTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ internal final class ContractInfoTests: XCTestCase {

internal func testToBytes() throws {
assertSnapshot(
matching: try ContractInfo.fromBytes(Self.info.serializedData()).toBytes().toHexString(), as: .description)
matching: try ContractInfo.fromBytes(Self.info.serializedData()).toBytes().hexStringEncoded(),
as: .description)
}
}
2 changes: 1 addition & 1 deletion Tests/HederaTests/ContractLogInfoTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ internal final class ContractLogInfoTests: XCTestCase {

internal func testToBytes() throws {
assertSnapshot(
matching: try ContractLogInfo.fromBytes(Self.info.serializedData()).toBytes().toHexString(),
matching: try ContractLogInfo.fromBytes(Self.info.serializedData()).toBytes().hexStringEncoded(),
as: .description)
}
}
2 changes: 1 addition & 1 deletion Tests/HederaTests/DelegateContractIdTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ internal final class DelegateContractIdTests: XCTestCase {

internal func testToBytes() throws {
assertSnapshot(
matching: try DelegateContractId.fromString("0.0.5005").toBytes().toHexString(), as: .description)
matching: try DelegateContractId.fromString("0.0.5005").toBytes().hexStringEncoded(), as: .description)
}

internal func testFromBytes() throws {
Expand Down
2 changes: 1 addition & 1 deletion Tests/HederaTests/FileInfoTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,6 @@ internal final class FileInfoTests: XCTestCase {

internal func testToBytes() throws {
assertSnapshot(
matching: try FileInfo.fromBytes(Self.info.serializedData()).toBytes().toHexString(), as: .description)
matching: try FileInfo.fromBytes(Self.info.serializedData()).toBytes().hexStringEncoded(), as: .description)
}
}
12 changes: 6 additions & 6 deletions Tests/HederaTests/KeyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import XCTest

internal final class KeyTests: XCTestCase {
internal func testFromProtoKeyEd25519() throws {
let keyBytes = Data(hex: "0011223344556677889900112233445566778899001122334455667788990011")
let keyBytes = Data(hexEncoded: "0011223344556677889900112233445566778899001122334455667788990011")!

let keyProto = Proto_Key.with { proto in
proto.key = .ed25519(keyBytes)
Expand All @@ -38,7 +38,7 @@ internal final class KeyTests: XCTestCase {
}

internal func testFromProtoKeyEcdsa() throws {
let keyBytes = Data(hex: "3a21034e0441201f2bf9c7d9873c2a9dc3fd451f64b7c05e17e4d781d916e3a11dfd99")
let keyBytes = Data(hexEncoded: "3a21034e0441201f2bf9c7d9873c2a9dc3fd451f64b7c05e17e4d781d916e3a11dfd99")!

let keyProto = try Proto_Key.init(serializedBytes: keyBytes)

Expand All @@ -49,8 +49,8 @@ internal final class KeyTests: XCTestCase {
}

internal func testFromProtoKeyKeyList() throws {
let keyBytes1 = Data(hex: "0011223344556677889900112233445566778899001122334455667788990011")
let keyBytes2 = Data(hex: "aa11223344556677889900112233445566778899001122334455667788990011")
let keyBytes1 = Data(hexEncoded: "0011223344556677889900112233445566778899001122334455667788990011")!
let keyBytes2 = Data(hexEncoded: "aa11223344556677889900112233445566778899001122334455667788990011")!

let keyProto1 = Proto_Key.with { proto in
proto.key = .ed25519(keyBytes1)
Expand Down Expand Up @@ -88,8 +88,8 @@ internal final class KeyTests: XCTestCase {
}

internal func testFromProtoKeyThresholdKey() throws {
let keyBytes1 = Data(hex: "0011223344556677889900112233445566778899001122334455667788990011")
let keyBytes2 = Data(hex: "aa11223344556677889900112233445566778899001122334455667788990011")
let keyBytes1 = Data(hexEncoded: "0011223344556677889900112233445566778899001122334455667788990011")!
let keyBytes2 = Data(hexEncoded: "aa11223344556677889900112233445566778899001122334455667788990011")!

let keyProto1 = Proto_Key.with { proto in
proto.key = .ed25519(keyBytes1)
Expand Down
20 changes: 10 additions & 10 deletions Tests/HederaTests/MnemonicTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -232,32 +232,32 @@ internal final class MnemonicTests: XCTestCase {

// Chain m/44'/3030'/0'/0/0
let key = try mnemonic.toStandardECDSAsecp256k1PrivateKey("", 0)
XCTAssertEqual(key.chainCode!.data.toHexString(), chainCode)
XCTAssertEqual(key.chainCode!.data.hexStringEncoded(), chainCode)
XCTAssertEqual(key.toStringRaw(), privateKey)
XCTAssert(publicKey.contains(key.publicKey.toStringRaw()))

// Chain m/44'/3030'/0'/0/0; Passphrase "some pass"
let key2 = try mnemonic.toStandardECDSAsecp256k1PrivateKey("some pass", 0)
XCTAssertEqual(key2.chainCode!.data.toHexString(), chainCode2)
XCTAssertEqual(key2.chainCode!.data.hexStringEncoded(), chainCode2)
XCTAssertEqual(key2.toStringRaw(), privateKey2)
XCTAssert(publicKey2.contains(key2.publicKey.toStringRaw()))

// Chain m/44'/3030'/0'/0/2147483647; Passphrase "some pass"
let key3 = try mnemonic.toStandardECDSAsecp256k1PrivateKey("some pass", 2_147_483_647)
XCTAssertEqual(key3.chainCode!.data.toHexString(), chainCode3)
XCTAssertEqual(key3.chainCode!.data.hexStringEncoded(), chainCode3)
XCTAssertEqual(key3.toStringRaw(), privateKey3)
XCTAssert(publicKey3.contains(key3.publicKey.toStringRaw()))

// Chain m/44'/3030'/0'/0/0'
let key4 = try mnemonic.toStandardECDSAsecp256k1PrivateKey("", Bip32Utils.toHardenedIndex(0))
XCTAssertEqual(key4.chainCode!.data.toHexString(), chainCode4)
XCTAssertEqual(key4.chainCode!.data.hexStringEncoded(), chainCode4)
XCTAssertEqual(key4.toStringRaw(), privateKey4)
XCTAssert(publicKey4.contains(key4.publicKey.toStringRaw()))

// Chain m/44'/3030'/0'/0/2147483647'; Passphrase "some pass"
let key5 = try mnemonic.toStandardECDSAsecp256k1PrivateKey(
"some pass", Bip32Utils.toHardenedIndex(2_147_483_647))
XCTAssertEqual(key5.chainCode!.data.toHexString(), chainCode5)
XCTAssertEqual(key5.chainCode!.data.hexStringEncoded(), chainCode5)
XCTAssertEqual(key5.toStringRaw(), privateKey5)
XCTAssert(publicKey5.contains(key5.publicKey.toStringRaw()))
}
Expand Down Expand Up @@ -291,32 +291,32 @@ internal final class MnemonicTests: XCTestCase {

// Chain m/44'/3030'/0'/0 /0
let key = try mnemonic.toStandardECDSAsecp256k1PrivateKey("", 0)
XCTAssertEqual(key.chainCode!.data.toHexString(), chainCode)
XCTAssertEqual(key.chainCode!.data.hexStringEncoded(), chainCode)
XCTAssertEqual(key.toStringRaw(), privateKey)
XCTAssert(publicKey.contains(key.publicKey.toStringRaw()))

// Chain m/44'/3030'/0'/0 /0; Passphrase "some pass"
let key2 = try mnemonic.toStandardECDSAsecp256k1PrivateKey("some pass", 0)
XCTAssertEqual(key2.chainCode!.data.toHexString(), chainCode2)
XCTAssertEqual(key2.chainCode!.data.hexStringEncoded(), chainCode2)
XCTAssertEqual(key2.toStringRaw(), privateKey2)
XCTAssert(publicKey2.contains(key2.publicKey.toStringRaw()))

// Chain m/44'/3030'/0'/0/2147483647; Passphrase "some pass"
let key3 = try mnemonic.toStandardECDSAsecp256k1PrivateKey("some pass", 2_147_483_647)
XCTAssertEqual(key3.chainCode!.data.toHexString(), chainCode3)
XCTAssertEqual(key3.chainCode!.data.hexStringEncoded(), chainCode3)
XCTAssertEqual(key3.toStringRaw(), privateKey3)
XCTAssert(publicKey3.contains(key3.publicKey.toStringRaw()))

// Chain m/44'/3030'/0'/0/0'
let key4 = try mnemonic.toStandardECDSAsecp256k1PrivateKey("", Bip32Utils.toHardenedIndex(0))
XCTAssertEqual(key4.chainCode!.data.toHexString(), chainCode4)
XCTAssertEqual(key4.chainCode!.data.hexStringEncoded(), chainCode4)
XCTAssertEqual(key4.toStringRaw(), privateKey4)
XCTAssert(publicKey4.contains(key4.publicKey.toStringRaw()))

// Chain m/44'/3030'/0'/0/2147483647'; Passphrase "some pass"
let key5 = try mnemonic.toStandardECDSAsecp256k1PrivateKey(
"some pass", Bip32Utils.toHardenedIndex(2_147_483_647))
XCTAssertEqual(key5.chainCode!.data.toHexString(), chainCode5)
XCTAssertEqual(key5.chainCode!.data.hexStringEncoded(), chainCode5)
XCTAssertEqual(key5.toStringRaw(), privateKey5)
XCTAssert(publicKey5.contains(key5.publicKey.toStringRaw()))
}
Expand Down
2 changes: 1 addition & 1 deletion Tests/HederaTests/NftIdTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,6 @@ internal final class NftIdTests: XCTestCase {
internal func testToBytes() throws {
let nftId = TokenId(5005).nft(4920)

assertSnapshot(matching: nftId.toBytes().toHexString(), as: .description)
assertSnapshot(matching: nftId.toBytes().hexStringEncoded(), as: .description)
}
}
2 changes: 1 addition & 1 deletion Tests/HederaTests/PrivateKeyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ internal final class PrivateKeyTests: XCTestCase {
let seed = Data(hexEncoded: "000102030405060708090a0b0c0d0e0f")!

let key1 = PrivateKey.fromSeedECDSAsecp256k1(seed)
XCTAssertEqual(key1.chainCode?.data.toHexString(), chainCode1)
XCTAssertEqual(key1.chainCode?.data.hexStringEncoded(), chainCode1)
XCTAssertEqual(key1.toStringRaw(), privateKey1)
XCTAssert(publicKey1.contains(key1.publicKey.toStringRaw()))

Expand Down
4 changes: 2 additions & 2 deletions Tests/HederaTests/StakingInfoTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ internal final class StakingInfoTests: XCTestCase {

internal func testToBytesAccount() throws {
assertSnapshot(
matching: try StakingInfo.fromBytes(Self.stakingInfoAccount.serializedData()).toBytes().toHexString(),
matching: try StakingInfo.fromBytes(Self.stakingInfoAccount.serializedData()).toBytes().hexStringEncoded(),
as: .description)
}

Expand All @@ -73,7 +73,7 @@ internal final class StakingInfoTests: XCTestCase {

internal func testToBytesNode() throws {
assertSnapshot(
matching: try StakingInfo.fromBytes(Self.stakingInfoNode.serializedData()).toBytes().toHexString(),
matching: try StakingInfo.fromBytes(Self.stakingInfoNode.serializedData()).toBytes().hexStringEncoded(),
as: .description)
}
}
2 changes: 1 addition & 1 deletion Tests/HederaTests/TransactionFeeScheduleTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ internal final class TransactionFeeScheduleTests: XCTestCase {
}

internal func testToBytes() throws {
let schedule = try Self.makeSchedule().toBytes().toHexString()
let schedule = try Self.makeSchedule().toBytes().hexStringEncoded()

assertSnapshot(matching: schedule, as: .description)
}
Expand Down