How It Works — Aperture

Under the hood

Real code.
Real safety.

This is exactly what happens on your device when you create a wallet, restore one, and move funds — traced, step by step, through the open-source code that runs on your iPhone.

1 / 5

128 bits of true randomness

The system CSPRNG produces raw entropy on your device — the single source of your entire wallet.

// 128 bits of entropy from the system CSPRNG
var entropy = Data(count: 16)
SecRandomCopyBytes(kSecRandomDefault, 16, &entropy)
// checksum = first bits of SHA-256(entropy)
let checksum = SHA256.hash(data: entropy).prefix(1)
let bits = entropy + checksum
// map each 11-bit group to the BIP-39 wordlist
let mnemonic = bits.chunks(of: 11)
.map { wordlist[$0] } // 12 words
// stretch to a 512-bit seed (PBKDF2-HMAC-SHA512)
let seed = PBKDF2.sha512(mnemonic.joined(" "),
salt: "mnemonic", rounds: 2048)
// seal in the Secure Enclave — it never leaves
try Keychain.store(seed, access: .thisDeviceOnly,
biometry: .faceID)
1 / 4

You type your phrase

It is entered locally and never transmitted anywhere.

// read the phrase you type — never transmitted
let words = phrase.lowercased().split(" ")
// every word must exist in the BIP-39 list
guard words.allSatisfy(wordlist.contains)
else { throw WalletError.unknownWord }
// recompute and verify the checksum
let (entropy, sum) = words.toEntropy()
guard SHA256.hash(data: entropy).verifies(sum)
else { throw WalletError.badChecksum }
// same derivation as generation — fully offline
let seed = PBKDF2.sha512(words.joined(" "),
salt: "mnemonic", rounds: 2048)
try Keychain.store(seed, access: .thisDeviceOnly)
1 / 3

Your own coins are selected

Inputs come from your unspent outputs — no third party is involved.

// pick coins from your own unspent outputs
let inputs = wallet.selectUTXOs(amount + fee)
// build the transaction entirely on device
let tx = TxBuilder(.bitcoin)
.add(inputs)
.send(amount, to: recipient)
.change(to: wallet.changeAddress).build()
// you review every detail before anything moves
present(confirm: tx.summary)
// amount · fee · recipient — nothing sent yet
1 / 4

The signing key is derived

A per-input child key is derived via the BIP-32 path.

// derive the child key for this input (BIP-32)
let key = masterKey.derive("m/84'/0'/0'/0/\(i)")
// hash the transaction preimage (double SHA-256)
let h = SHA256(SHA256(tx.preimage(i)))
// sign inside the Secure Enclave (needs Face ID)
let sig = try SecureEnclave.sign(h, key: key,
curve: .secp256k1)
// only signed bytes leave the device
tx.attach(sig, input: i)
network.broadcast(tx.serialized)

Simplified from Aperture's open-source Swift — the real algorithms, on your device.

Read the full source

Notice what is missing: no server, no account, no key ever crossing the network. The private key is created, stored, and used entirely inside your device's Secure Enclave.