docs/03a-quickstart-gpg
Monday 2 March 2026

Quick Start: GPG Fundamentals

This tutorial shows how Mau works at the lowest level using only GPG commands. Understanding these primitives will help you appreciate what Mau does behind the scenes.

Time: ~15 minutes
Prerequisites: GPG installed (gpg --version)

Why Start with GPG?

Mau is built on PGP/GPG. Before using Mau’s tools, it’s valuable to understand:

  • How identity works (key pairs)
  • How signing proves authenticity
  • How encryption ensures privacy
  • How the filesystem stores everything

Step 1: Create Your Identity

Generate a PGP key pair:

1gpg --full-generate-key

Follow the prompts:

  • Kind: (9) ECC (sign and encrypt) *default: Curve 25519* (recommended, Ed25519)
    • Alternative: (1) RSA and RSA with 4096 bits for compatibility
  • Expiration: 0 (no expiration) or your preference
  • Name: Your real name or pseudonym
  • Email: Your email address
  • Passphrase: Strong password (you’ll need this often)

Note: Mau defaults to Ed25519 keys (faster, smaller, modern crypto). RSA 4096 still works for compatibility.

Get your fingerprint:

1gpg --fingerprint your-email@example.com

Output example (Ed25519):

pub   ed25519 2026-03-02 [SC]
      5D00 0B2F 2C04 0A16 75B4  9D7F 0C7C B7DC 3699 9D56
uid           [ultimate] Alice <alice@example.com>

Export fingerprint without spaces:

1export MY_FPR="5D000B2F2C040A1675B49D7F0C7CB7DC36999D56"
2echo "My fingerprint: $MY_FPR"

What just happened?

  • You created a private key (secret, stays on your machine)
  • You created a public key (shareable, proves your identity)
  • Your fingerprint is a unique 160-bit identifier (SHA-1 of public key)

Step 2: Create a Mau Directory Structure

Mau uses a simple directory layout:

1mkdir -p ~/.mau/$MY_FPR        # Your posts go here
2mkdir -p ~/.mau/.mau           # Keys and metadata

Export your private key (encrypted with a passphrase):

1gpg --export-secret-keys --armor $MY_FPR | \
2  gpg --symmetric --armor --output ~/.mau/.mau/account.pgp

Enter a passphrase to protect this file. This is your account backup.

Step 3: Create Your First Post

Create a social media post (JSON-LD with Schema.org vocabulary):

 1cat > /tmp/hello.json <<'EOF'
 2{
 3  "@context": "https://schema.org",
 4  "@type": "SocialMediaPosting",
 5  "headline": "Hello from the decentralized web!",
 6  "articleBody": "This post is encrypted, signed, and stored as a file on my disk.",
 7  "author": {
 8    "@type": "Person",
 9    "name": "Alice",
10    "identifier": "5D000B2F2C040A1675B49D7F0C7CB7DC36999D56"
11  },
12  "datePublished": "2026-02-28T07:00:00Z"
13}
14EOF

Sign and encrypt the post (for yourself, making it public):

1gpg --sign --encrypt --recipient $MY_FPR \
2  --output ~/.mau/$MY_FPR/hello.json.pgp \
3  /tmp/hello.json

What just happened?

  1. Sign: GPG creates a signature using your private key
  2. Encrypt: GPG encrypts for recipient(s) - in this case, yourself
  3. Output: Binary .pgp file (OpenPGP message format)

Verify it exists:

1ls -lh ~/.mau/$MY_FPR/hello.json.pgp

Step 4: Read Your Post

Decrypt and verify:

1gpg --decrypt ~/.mau/$MY_FPR/hello.json.pgp

Output:

1{
2  "@context": "https://schema.org",
3  "@type": "SocialMediaPosting",
4  ...
5}
6gpg: Signature made Sat 28 Feb 2026 07:00:00 AM CET
7gpg:                using RSA key 5D000B2F...
8gpg: Good signature from "Alice <alice@example.com>" [ultimate]

What does “Good signature” mean?

  • The file hasn’t been tampered with
  • It was definitely created by your private key
  • The timestamp is authentic

Step 5: Simulate a Friend (Bob)

Let’s create a second identity to understand peer interaction:

1# Generate Bob's key (use different email)
2gpg --batch --passphrase '' --quick-generate-key "Bob <bob@example.com>" rsa4096
3
4# Get Bob's fingerprint
5export BOB_FPR=$(gpg --list-keys --with-colons bob@example.com | awk -F: '/^fpr:/ {print $10; exit}')
6echo "Bob's fingerprint: $BOB_FPR"
7
8# Create Bob's directory
9mkdir -p ~/.mau/$BOB_FPR

Step 6: Send a Private Message to Bob

Create a private message (encrypted only for Bob):

 1cat > /tmp/private-msg.json <<EOF
 2{
 3  "@context": "https://schema.org",
 4  "@type": "Message",
 5  "text": "Hey Bob, this is a private message only you can read!",
 6  "sender": {
 7    "@type": "Person",
 8    "identifier": "$MY_FPR"
 9  },
10  "recipient": {
11    "@type": "Person",
12    "identifier": "$BOB_FPR"
13  },
14  "dateSent": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
15}
16EOF

Encrypt for Bob (and sign with your key):

1gpg --sign --encrypt --recipient $BOB_FPR \
2  --output ~/.mau/$MY_FPR/msg-to-bob.json.pgp \
3  /tmp/private-msg.json

Try to read it as yourself:

1gpg --decrypt ~/.mau/$MY_FPR/msg-to-bob.json.pgp

You’ll get:

gpg: decryption failed: No secret key

Why? Because you encrypted it for Bob’s public key. Only Bob’s private key can decrypt it.

Now read as Bob:

1gpg --decrypt --local-user bob@example.com ~/.mau/$MY_FPR/msg-to-bob.json.pgp

Success! Bob can read the message, and GPG confirms it was signed by you.

Step 7: Bob Creates a Comment

Bob can comment on your post:

 1cat > /tmp/comment.json <<EOF
 2{
 3  "@context": "https://schema.org",
 4  "@type": "Comment",
 5  "text": "Great post, Alice!",
 6  "author": {
 7    "@type": "Person",
 8    "name": "Bob",
 9    "identifier": "$BOB_FPR"
10  },
11  "about": "/p2p/$MY_FPR/hello.json",
12  "dateCreated": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
13}
14EOF
15
16# Bob signs and encrypts for himself (public comment)
17gpg --sign --encrypt --recipient $BOB_FPR \
18  --local-user bob@example.com \
19  --output ~/.mau/$BOB_FPR/comment-alice.json.pgp \
20  /tmp/comment.json

Bob’s comment references your post using the Mau address: /p2p/<fingerprint>/<filename>

Step 8: Share with Multiple Recipients (Group)

Create a post visible to both you and Bob:

 1cat > /tmp/group-post.json <<'EOF'
 2{
 3  "@context": "https://schema.org",
 4  "@type": "SocialMediaPosting",
 5  "headline": "Weekend plans?",
 6  "articleBody": "Anyone up for hiking on Saturday?",
 7  "datePublished": "2026-02-28T08:00:00Z"
 8}
 9EOF
10
11# Encrypt for multiple recipients
12gpg --sign --encrypt \
13  --recipient $MY_FPR \
14  --recipient $BOB_FPR \
15  --output ~/.mau/$MY_FPR/group-post.json.pgp \
16  /tmp/group-post.json

Now both you and Bob can decrypt this file. This is how Mau implements group chats!

Step 9: Versioning (Edit a Post)

When you edit a post, Mau keeps old versions:

 1# Create a versions directory
 2mkdir -p ~/.mau/$MY_FPR/hello.json.pgp.versions
 3
 4# Hash the current version
 5CURRENT_HASH=$(sha256sum ~/.mau/$MY_FPR/hello.json.pgp | cut -d' ' -f1)
 6echo "Current version hash: $CURRENT_HASH"
 7
 8# Move current version to versions directory
 9cp ~/.mau/$MY_FPR/hello.json.pgp \
10   ~/.mau/$MY_FPR/hello.json.pgp.versions/$CURRENT_HASH.pgp
11
12# Create new version (edited)
13cat > /tmp/hello-v2.json <<'EOF'
14{
15  "@context": "https://schema.org",
16  "@type": "SocialMediaPosting",
17  "headline": "Hello from the decentralized web! [EDITED]",
18  "articleBody": "This post is encrypted, signed, and stored as a file. I can edit it!",
19  "datePublished": "2026-02-28T07:00:00Z",
20  "dateModified": "2026-02-28T08:00:00Z"
21}
22EOF
23
24gpg --sign --encrypt --recipient $MY_FPR \
25  --output ~/.mau/$MY_FPR/hello.json.pgp \
26  /tmp/hello-v2.json

Your directory now has:

~/.mau/5D000B2F.../
  hello.json.pgp                    # Latest version
  hello.json.pgp.versions/
    abc123...def.pgp                # Old version (SHA-256 hash)

Step 10: Export and Share Your Public Key

For others to follow you, they need your public key:

1# Export in binary format (Mau standard)
2gpg --export $MY_FPR > /tmp/alice-pubkey.pgp
3
4# Or ASCII-armored (human-readable)
5gpg --export --armor $MY_FPR > /tmp/alice-pubkey.asc

Send this file to friends via email, USB drive, QR code, etc.

Bob imports your key:

1# Bob receives alice-pubkey.pgp and imports it
2gpg --import /tmp/alice-pubkey.pgp
3
4# Encrypt it with his own key and save to .mau directory
5gpg --export $MY_FPR | \
6  gpg --encrypt --recipient $BOB_FPR \
7  --output ~/.mau/.mau/$MY_FPR.pgp

Why encrypt the friend’s public key? To prevent malicious programs from adding fake friends.

What You’ve Learned

✅ PGP identity = public/private key pair
✅ Fingerprint = unique 160-bit identifier
✅ Signing = proves authenticity
✅ Encryption = ensures privacy
✅ Multiple recipients = group communication
✅ File structure = simple directory layout
✅ Versioning = hash-based old versions
✅ Mau addressing = /p2p/<fingerprint>/<filename>

Key Takeaways

  1. Everything is a file - Posts, messages, comments are just .pgp files
  2. Identity is cryptographic - No usernames, no passwords, just key pairs
  3. Privacy by math - Encryption makes content unreadable without the key
  4. Signatures prevent tampering - You can’t fake someone else’s signature
  5. No central server needed - Just files and GPG

Limitations of Manual GPG

What you’ve done manually is tedious:

  • Creating directories
  • Encrypting/decrypting files
  • Managing fingerprints
  • Handling versioning
  • No automatic syncing

This is where Mau CLI and Mau packages come in!

Next Steps


Note: The commands above work on Linux/macOS. Windows users should use WSL or adapt paths accordingly.