CRYSTALS-Kyber key encapsulation in Swift

What's New


About SwiftKyber release 1.3.0:

  1. Same functionality and API as release 1.2.0

  2. Much better performance: Key generation, encapsulation and decapsulation
    is 35% - 70% faster than in release 1.2.0



SwiftKyber is a Swift implementation of the proposed PQC (Post Quantum Cryptography) key encapsulation mechanism: CRYSTALS-Kyber.

SwiftKyber makes it possible to explore CRYSTALS-Kyber in a Swift context.


In your project Package.swift file add a dependency like
  dependencies: [
  .package(url: "https://github.com/leif-ibsen/SwiftKyber", from: "1.3.0"),

How it Works

Suppose Alice and Bob wish to share a secret key they can use as a symmetric encryption key:
  • Alice generates a Kyber key pair, publicKey and secretKey. She sends publicKey to Bob
  • Bob runs publicKey.Encapsulate() to generate a shared secret K and a cipher text cipher
  • Bob sends cipher to Alice
  • Alice runs secretKey.Decapsulate(ct: cipher) to generate the same shared secret K
SwiftKyber contains three static Kyber instances: *Kyber.K512*, *Kyber.K768* and *Kyber.K1024* corresponding to the three instances defined in the Kyber specification.

Here is a Kyber.K512 example:

import SwiftKyber

// Alice:
let (publicKey, secretKey) = Kyber.K512.GenerateKeyPair()

// Bob:
let (cipher, K1) = publicKey.Encapsulate()
print("Bob's K:  ", K1)

// Alice:
let K2 = try secretKey.Decapsulate(ct: cipher)
print("Alice's K:", K2)

giving (for example):

Bob's K:   [106, 169, 16, 187, 123, 157, 206, 223, 236, 143, 173, 180, 243, 130, 157, 122, 150, 68, 167, 31, 33, 246, 28, 150, 215, 182, 71, 72, 128, 37, 202, 17]
Alice's K: [106, 169, 16, 187, 123, 157, 206, 223, 236, 143, 173, 180, 243, 130, 157, 122, 150, 68, 167, 31, 33, 246, 28, 150, 215, 182, 71, 72, 128, 37, 202, 17]

Key Representation

SwiftKyber public and secret keys can be stored in three formats:
  • DER encoded - a byte array
  • PEM encoded - a string
  • As raw bytes
The three main key management operations are:
  • Generate new keys
  • Store existing keys in DER or PEM format or as raw bytes
  • Load keys from their DER or PEM encoding or from their raw bytes
Generating new keys is easy:
import SwiftKyber

let (pk, sk) = Kyber.K768.GenerateKeyPair()

generates a new public key pk and a new secret key sk for the K768 instance.
Keys can be stored in DER format, in PEM format or as raw bytes.

import SwiftKyber

let (pk, _) = Kyber.K512.GenerateKeyPair()

let pkDer = pk.der // The DER encoding - a byte array
let pkPem = pk.pem // The PEM encoding - a String
let pkBytes = pk.bytes // The raw bytes

let newPkFromDER = try PublicKey(der: pkDer)
let newPkFromPEM = try PublicKey(pem: pkPem)
let newPkFromRaw = try PublicKey(bytes: pkBytes)

assert(pk == newPkFromDER)
assert(pk == newPkFromPEM)
assert(pk == newPkFromRaw)

and for secret keys:

import SwiftKyber

let (_, sk) = Kyber.K512.GenerateKeyPair()

let skDer = sk.der // The DER encoding - a byte array
let skPem = sk.pem // The PEM encoding - a String
let skBytes = sk.bytes // The raw bytes

let newSkFromDER = try SecretKey(der: skDer)
let newSkFromPEM = try SecretKey(pem: skPem)
let newSkFromRaw = try SecretKey(bytes: skBytes)

assert(sk == newSkFromDER)
assert(sk == newSkFromPEM)
assert(sk == newSkFromRaw)

ASN1 reservations

The DER and PEM formats are based on the ASN1 structure of the keys. These structures are defined in [KEYS], but it is my understanding that the ASN1 representation is not settled yet: It may change, there may be no ASN1 structure at all or I may have misread [KEYS].


SwiftKyber's key generation, encapsulation and decapsulation performance was measured on an iMac 2021, Apple M1 chip. The table below shows the figures in milli seconds for the three Kyber instances.
Kyber.K5120.14 mSec0.16 mSec0.18 mSec
Kyber.K7680.22 mSec0.25 mSec0.28 mSec
Kyber.K10240.33 mSec0.36 mSec0.40 mSec


The SwiftKyber package depends on the ASN1 and BigInt packages
dependencies: [
    .package(url: "https://github.com/leif-ibsen/ASN1", from: "2.2.0"),
    .package(url: "https://github.com/leif-ibsen/BigInt", from: "1.14.0"),

SwiftKyber does not do Big Integer arithmetic, but BigInt is a dependency because ASN1 depends on it.


Algorithms from the following papers have been used in the implementation. There are references in the source code where appropriate.

  • [KYBER] - CRYSTALS-Kyber, Algorithm Specifications And Supporting Documentation, January 2021
  • [DRAFT] - Kyber Post-Quantum KEM, draft-cfrg-schwabe-kyber-03, September 2023
  • [KEYS] - Quantum Safe Cryptography Key Information for CRYSTALS-Kyber, October 2022


  • Swift Tools 5.9.0
View More Packages from this Author


Last updated: Wed Nov 22 2023 18:39:07 GMT-1000 (Hawaii-Aleutian Standard Time)