cswiftpointersunsafemutablepointer

Will my Swift code using UnsafeMutablePointer be safe and/or produce undefined behaviour?


I have a C library I need to use in my Swift code and a function thet expects an UnsafeMutablePointer<UInt8> that is 32 bytes long to generate a public key from an existing private key (crypto_sign_public_key). Here is a link to the docs of the C function I am calling: https://monocypher.org/manual/sign. I don't have much experience with C and pointers but I've read a few tutorials and have something that seems to be working perfectly.

Aside from that though, I wanted to see if anyone with more experience than me might be able to say if this code is "safe" and/or will potentially produce undefined behaviour?

func generatePublicKey(from privateKey: [UInt8]) -> [UInt8] {
    /// Create an empty pointer that is 32 bytes long. The resulting public key will be written to the memory the pointer is pointing to.
    let publicKeyPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: 32)
        
    /// This is using the 25519 curve and the Blake2b hash method.
    /// Sign the private key and in turn, create the public key.
    crypto_sign_public_key(publicKeyPointer, privateKey)
        
    /// Go over the 32 bytes of the pointer and save it's locations as a "buffer"
    let buffer = UnsafeMutableBufferPointer(start: publicKeyPointer, count: 32)
        
    /// Copy the data being pointed to, into an actual array.
    let publicKey = Array(buffer)
        
    /// Deallocate the memory being used by the pointer.
    publicKeyPointer.deallocate()
        
    return publicKey
}

Thank you!


Solution

  • Your code is okay, because UInt8 is a trivial type and so doesn't require that you call initialize or deinitialize on the allocated memory.

    However, you can avoid the manual allocation and deallocation entirely, like this:

    func makePublicKey(withPrivateKey privateKey: [UInt8]) -> [UInt8] {
        var publicKey = [UInt8](repeating: 0, count: 32)
        publicKey.withUnsafeMutableBufferPointer { buffer in
            crypto_sign_public_key(buffer.baseAddress!, privateKey)
        }
        return publicKey
    }