Sometimes we need to add c code in a Swift Package so we can use it in swift. One of situation can be when we want to use some security code that has been used and tested for years. This can be a case that we don’t want to take the risk to write the code from scratch in Swift.
Let’s try it in an example, so let’s assume we want to use the Nacl code to calculate the public key from the private by using elliptic curves. First we need to have access to the files (AND ALWAYS CHECK THE LICENCE) so we follow the steps to download them from here: http://nacl.cr.yp.to/internals.html.
Let’s now create a package. The package can be the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import PackageDescription let package = Package( name: "NaCl", platforms: [ .macOS(.v10_12), .iOS(.v9) ], products: [ .library( name: "NaCl", targets: ["NaCl"]), ], targets: [ .target( name: "NaCl", dependencies: ["NaClC"]), .target( name: "NaClC", resources: [ .copy("ge25519_base.data")]), .testTarget( name: "NaClTests", dependencies: ["NaCl"]) ] ) |
As we see we have two main targets and one test target. The NaCLC target is where we have the c code and the Nacl where we provide an easier swift interface by handling the memory management complexity (we talk about this in another post). Also note that we have to declare as resource the .data file.
Let’s now see the NaCLC target:
As we see we place all the headers in an include folder and rest of the c files outside.
In the NaCL target we provide a simplified interface and we handle the memory management so the swift caller to call it as easier as possible.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import Foundation import NaClC public struct NaCl { public init() {} public func toPublic(_ input: [UInt8]) -> [UInt8] { let capacity = 32 let pk = UnsafeMutablePointer<UInt8>.allocate(capacity: capacity) let sk = UnsafeMutablePointer<UInt8>.allocate(capacity: capacity) var pkCopy: [UInt8] = Array(repeating: 0, count: capacity) for i in 0..<capacity { (pk + i).initialize(to: 0) (sk + i).initialize(to: input[i]) } modified_crypto_sign_publickey(pk, sk) for i in 0..<capacity { pkCopy[i] = (pk + i).pointee } pk.deallocate() sk.deallocate() return pkCopy } } |
You can find the code in the following link: