How it works

Encrypted where you work. Stored where it can’t be read.

SealedGit splits a code host into three parts and gives the keys to only one of them: your team’s devices. This page follows a change from your editor to your teammate’s, and shows what each part holds on the way.

Your devices
Hold every key. Encrypt and decrypt.
The host
Stores and serves ciphertext. Holds no key.
The accounts service
Email identity and invitations. No repository keys.
Security level
NIST Category 5, post-quantum

01

Three parts, one key holder

SealedGit is three pieces of software, run in three places. Only one of them ever holds a key that opens a repository.

Your computer

The tools and the app

shub, sgit, git-remote-sgit and the SealedGit app. They keep the repository keys on this computer and do all of the encrypting and decrypting.

The host

sealedgit-server

Stores encrypted git bundles, opaque MLS framing and hash-chained RefHeads, and serves them to members. It never has a key.

Identity

sealedgit-accounts

Signup and email confirmation, password resets, invitations, and the sign-in the host trusts (OIDC). It holds no repository keys.

Who holds what

  • Repository keysMembers’ devices, and nowhere else.
  • Code, commit messages, issues, pull requests, reviews, release notesMembers’ devices in plaintext. The host, as ciphertext.
  • Handles, repository names, membership, push sizes and timesThe host. What the host can see
  • Email addresses and password hashesThe accounts service. The host holds neither.

02

Enrolling a device

Signing in, in the app or with shub auth email-login, enrols the computer as a device. It generates the device’s MLS key package there: an ML-KEM-1024 key that group secrets are encrypted to, and an ML-DSA-87 key the device signs with. The private halves never leave the computer.

The public key package goes to the host, so that members can add this device to repositories. Its fingerprint is the device’s safety number, which the login prints and which the person admitting you compares.

shell
shub auth email-login --email you@example.com --password '…'
Signed in as you <you@example.com>.
Enrolled device 'default' (safety number 48 29 11 70 3a 56 09 c2).

03

Creating a repository

shub repo create makes the repository’s MLS group on your computer, with your device as its only member, at epoch 0. The host records the repository’s name and that you are a member. A description, if you give one, is encrypted.

From then on, the group’s current epoch is what every key for the repository comes from. The host relays the group’s MLS messages between devices without being able to read them or take part.

04

A push, step by step

Everything before the last step happens on your computer.

  1. Git bundles your commits

    sgit push hands the push to your own git, which runs git-remote-sgit for the sgit:// remote. The helper bundles the commits the host doesn’t have yet.

  2. The bundle is sealed

    The helper derives a key for this push from the group’s current epoch and seals the bundle with a key-committing AEAD built on SHA-512. Commit messages are inside the bundle, so they are sealed with the code.

    Key-committing means a sealed push opens under exactly one key, into exactly one result.

  3. A new RefHead is signed

    Where your branches and tags now point is recorded in a RefHead, encrypted, signed with your device’s ML-DSA-87 key, and chained by SHA-512 hash to the RefHead before it. Members can tell if the host drops or reorders pushes.

  4. The host stores ciphertext

    The host appends the RefHead if it follows the one it already has, and stores the bundle. It learns how large the push was and when it arrived.

05

A pull

sgit pull or sgit fetch asks the host for everything after the last RefHead your device has. Your device checks each RefHead’s signature and its link to the one before, decrypts the bundles with the epoch keys it holds, and hands git ordinary objects.

From there it is git: merges, rebases and --ff-only happen on your machine, exactly as they would with any other remote.

06

Adding someone

The host can pass along an invitation. Only a member’s device can let someone in.

  1. Invite a member

    The accounts service records an invitation for an email address and sends a link. No keys change hands.

  2. Accept the invitee

    They sign up or sign in, and accept. Signing in enrols their device and publishes its key package.

  3. Compare both of you

    You compare their safety number over a channel you already trust, so a key substituted by the host would show.

  4. Admit a member’s device

    Your device makes an MLS Commit that adds their key package, pinned to the digest you compared. The group moves to a new epoch, and a Welcome that only their device can open carries them its secrets.

What they can read of the past depends on the grant. A full-history grant opens the whole history. A forward-only grant starts them at a snapshot of the tree as it is when they join, using dual key regression to open that window and nothing before it.

07

Removing someone

Removal is also an MLS Commit from a member’s device. The group moves to a new epoch whose secrets reach every device except the removed one, so nothing pushed afterwards opens for it.

Removal looks forward. What their device already fetched and decrypted, it keeps. If they could read secrets in the repository, rotate those secrets.

08

The cryptography

Every algorithm is a published standard. The post-quantum ones use the parameter sets NIST places in security category 5, the highest of its five: breaking them should take at least as much work as a key search on AES-256.

MLS_256_MLKEM1024_AES256GCM_SHA512_MLDSA87

Key encapsulation
ML-KEM-1024
Signatures
ML-DSA-87
AEAD
AES-256-GCM
Hash
SHA-512
The algorithms SealedGit uses
AlgorithmStandardStrengthWhat it does here
ML-KEM-1024FIPS 203NIST Category 5Carries each epoch’s secrets to members’ devices in the repository’s MLS group.
ML-DSA-87FIPS 204NIST Category 5Signs MLS messages, device key packages and RefHeads, so the host can’t forge any of them.
AES-256-GCMFIPS 197, SP 800-38D256-bit keyEncrypts the group’s MLS messages: issues, pull requests, reviews and release notes.
SHA-512, HKDF, HMACFIPS 180-4, FIPS 198-1, RFC 5869512-bit hashChains RefHeads, derives per-push keys, and seals pushes in the key-committing AEAD.

AES-256 is the yardstick category 5 is defined by, so the symmetric encryption is held to the same level as the post-quantum key exchange and signatures.

Check the binary you run

shub crypto report prints the ciphersuite and AEAD actually linked into the program on your computer.

shell
shub crypto report
MLS ciphersuite   MLS_256_MLKEM1024_AES256GCM_SHA512_MLDSA87
MLS backend       vendored OpenMLS (draft-ietf-mls-pq-ciphersuites)
transport AEAD    hkdf-sha512-pad+HMAC-SHA-512-256

NIST standardised these algorithms. The implementations SealedGit links are open-source Rust libraries, not a FIPS 140-validated module.

See it for yourself

Push something the host can’t read.

Install the CLI, create an account, and watch the host receive only ciphertext.