An overview of Swift encryption protocols
Jan 10, 2025
The last couple of years have seen a continual increase in the adoption of blockchain/web3 applications by the uninformed masses. This development is anything but fortuitous; designers, developers and other important figures across the space have worked towards the blurring of the lines that define a "web3" or "blockchain" application. Many users are blind to the reliance of their favourite applications on these technologies, thanks to a constant push from "web3"-branded interfaces to increasingly neutral user experiences meant to distance applications from a space that is seen by most as unreliable.
These "last-generation" applications, which today's web3 applications are now attempting to emulate, are equipped with an advantage is user retention that many web3 apps are currently lacking: seamless communication through notifications, such as newsletters or push notifications targeting users directly on-device.
A majority of our newest generation of apps do not have this capability for multiple reasons:
Concern for user security/privacy.
Users' unwillingness to divulge private information. (emails, phone numbers, etc…)
Technical limitations driven by a reliance on chain-hosted data.
Swift addresses all of these issues. This article will focus on the first two: developers' concern for user privacy, and the reticence of users to divulge their information. While some users might not be entirely reassured knowing their data is encrypted, it is our belief that the decisions of a sizeable majority will be influenced by the knowledge of this fact.
The flow of data through Swift
Our website features a graph depicting a typical flow of data for a user authorizing email newsletters for a generic application. Albeit significantly simplified, this graph gives some context to the way we handle user data.
The graph in question:
Temporary key signing
When a user submits data to be stored with Swift, we first generate a temporary key on the client side to encrypt the data. We encrypt the data towards the a temporary Swift public key generated by our API at the time of the request, then delete the user's temporary key.
Once the data makes it to the Swift servers, we encrypt it towards a new key provisioned for the application that is being authorized, then delete the temporary Swift key.
Now, neither Swift servers nor the application can fully access the data. Swift stores the encrypted version while the application holds their own key. For the application to access the data, they will need to query the Swift servers, which will only allow access to the encrypted data if the application remains authorized by the user.
What constitutes an "authorization"
Users authorize apps to perform certain actions vis-à-vis their data through authorizations. A typical authorization looks something like this:
When an app makes a request to notify a user, Swift verifies that they possess the relevant authorization. If they do, we move forward with the notification process. For authorizations to be modified, the user needs to submit a request signed with their wallet.
User identity
Users are identified using a buffer derived from their address. This allows us to store data to be accessed by any applications on any Cosmos chain provided they possess the relevant authorization. Whenever a request is submitted to our API, we can decrypt the buffer into a Bech32 address of any prefix.
This method enables future integration with Ethereum, Solana or any other chain as we do not deal directly with a Bech32 address, but rather with a buffer that can be decrypted into an address for any chain's address format.
Key provisioning & application signatures
Every application that interacts with their users through Swift is equipped with a public/private key pair, which is usually stored as PEM file. Using this key, applications sign their request body to the Swift API, which allows the API to verify their identity and decrypt the data.
These keys are RSA-OAEP SHA-256 key pairs, generated using the following WebCrypto function:
The private key is exported as a PKCS-8 key while the public is exported as SPKI. The same keys are used as temporary keys for the user and the Swift API. Whenever data is encrypted, it is towards the public key of the recipient, which allows us to decrypt the data anywhere throughout the chain of ownership, provided the correct authorizations are present.
At any time, users can submit a wallet signature and a request for deletion, which deletes both the cipher texts and the decryption keys, essentially wiping their entire presence in one request.