commit f86e0ce7dd4c5651def866bfc2259f9b8e62e84d Author: Your Name Date: Wed Sep 17 10:03:26 2025 -0400 v0.0.1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e59d632 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +Nostr_NIPs/ \ No newline at end of file diff --git a/DAEMON.md b/DAEMON.md new file mode 100644 index 0000000..afb872a --- /dev/null +++ b/DAEMON.md @@ -0,0 +1,153 @@ +# Superball Daemon Rules + +## What I Am +I am Superball - an anonymizing node that provides location privacy for Nostr users by forwarding their encrypted events with timing delays and size obfuscation. + +## What I Look For + +### 1. Routing Events (Kind 30000) +- Monitor all relays I'm connected to +- Look for events with `kind: 30000` +- Check if `tags` contains `["p", ""]` +- These are events meant for me to process + +### 2. Event Structure I Expect +```json +{ + "kind": 30000, + "pubkey": "", // Not important to me + "content": "", // This is what I need + "tags": [["p", ""]], + "created_at": , + "id": "", + "sig": "" +} +``` + +## What I Do When I Receive An Event + +### 1. Validate +- Verify the event signature is valid +- Confirm the `p` tag contains my pubkey +- Ensure it's kind 30000 + +### 2. Decrypt +- Use my private key with NIP-44 to decrypt the content +- Extract the payload which contains: + ```json + { + "event": { /* The event to forward */ }, + "routing": { + "relays": ["wss://relay1.com", "wss://relay2.com"], + "delay": 30, + "pad": "+150", // or "-50" + "p": "next_superball_pubkey", // Optional - missing means final posting + "audit": "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456", // Required audit tag + "payment": "eCash_token" // Optional + } + } + ``` + +### 3. Process Routing Instructions + +#### Delay +- Wait the specified number of seconds before forwarding +- Add random jitter (±10%) to prevent timing analysis +- Queue the event for delayed processing + +#### Padding +- **Remove padding (`"pad": "-N"`)**: Delete N bytes worth of padding tags from the event +- **Add padding (`"pad": "+N"`)**: Create new routing wrapper with N bytes of padding tags + +#### Relays +- Post to ALL relays in the `relays` array +- Validate all relay URLs are properly formatted +- Provides redundancy and availability + +#### Next Hop Logic +- **`p` field present**: Create routing event for specified next Superball (can apply padding) +- **`p` field missing**: Extract inner event and post directly to relays (end chain, no padding changes) + +#### Padding Logic +- **`p` field present + `pad` field**: Apply padding changes when creating routing wrapper +- **`p` field missing**: Ignore any `pad` field - cannot modify signed event +- **Final hop rule**: Never modify signed events, post exactly as received + +#### Audit Tag Processing +- **`audit` field**: Always present - include as `["p", ""]` in routing event +- **Camouflage**: Audit tag looks identical to real next-hop pubkeys +- **Security**: Enables user detection of dropped/delayed/modified events + +#### Payment Processing +- **`payment` field present**: Process eCash token for service payment +- **`payment` field missing**: Process for free (if daemon allows) + +### 4. Forward Event + +#### Always Rewrap (Important for Privacy) +**ALWAYS** create a new routing event to hide whether padding was added or removed: + +```json +{ + "kind": 30000, // Always use routing event + "pubkey": "", // Generate fresh ephemeral key + "content": "", // Re-encrypt with my key + "tags": [ + ["p", ""], + ["p", ""], // Always include audit tag as p tag + ["padding", ""], // Adjusted padding + ["padding", ""] // May be more or less than before + ] +} +``` + +#### Next Hop Handling +- **If `p` field in routing**: Create routing event with that pubkey in p tag +- **If no `p` field in routing**: Extract inner event and post directly to all relays +- **Multi-relay posting**: Post to every relay in the `relays` array +- **End of chain**: When no `p` field, I am the final hop + +## My Rules + +### Security Rules +1. **Never log sensitive data** - Don't store decrypted content or routing info +2. **Generate new keys** - Use fresh ephemeral keys for each forward +3. **Validate everything** - Check signatures, event structure, relay URLs +4. **Rate limiting** - Don't process more than X events per minute from same source + +### Privacy Rules +1. **No correlation** - Don't link input events to output events in logs +2. **Clear memory** - Immediately clear decrypted data after processing +3. **Random timing** - Add jitter to specified delays +4. **Mix traffic** - Send decoy traffic when idle (optional) + +### Processing Rules +1. **First come, first served** - Process events in order received +2. **Fail silently** - Drop invalid events without response +3. **Retry logic** - Attempt to post 3 times before giving up +4. **Resource limits** - Drop oldest queued events if memory/queue full + +### Network Rules +1. **Multiple relays** - Connect to diverse set of relays +2. **Separate connections** - Use different connections for input/output +3. **AUTH support** - Prefer relays that support AUTH for privacy +4. **Rotate connections** - Periodically reconnect to prevent fingerprinting + +## What I Never Do + +1. **Never modify final signatures** - Only remove padding tags, never add to signed events +2. **Never store routing paths** - Process and forget +3. **Never respond to clients** - Silent operation only +4. **Never correlate users** - Each event is independent +5. **Never log destinations** - Only log operational metrics + +## Example Processing Flow + +1. **Receive**: Kind 30000 event with my pubkey in p tag +2. **Decrypt**: Extract inner event + routing instructions +3. **Queue**: Schedule for delayed processing (e.g., 30 seconds + jitter) +4. **Process**: Apply padding changes and prepare for forwarding +5. **Forward**: Post to target relay(s) +6. **Clean**: Clear all decrypted data from memory + +I am a privacy-preserving relay that helps users post content while hiding their location. I ask no questions, store no logs, and remember nothing about the events that pass through me. \ No newline at end of file diff --git a/EXAMPLE.md b/EXAMPLE.md new file mode 100644 index 0000000..b0228ed --- /dev/null +++ b/EXAMPLE.md @@ -0,0 +1,157 @@ +# Superball Example: Anonymous Posting + +## Scenario +Alice wants to post a message under her real identity while hiding her location from surveillance. + +### Participants +- **Alice**: Original sender (pubkey: `alice123...`) +- **Superball A**: First hop (pubkey: `sball_a789...`) +- **Superball B**: Second hop (pubkey: `sball_b012...`) +- **Relay1**: `wss://relay1.com` (where Alice posts) +- **Relay2**: `wss://relay2.com` (intermediate relay) +- **Relay3**: `wss://relay3.com` (where final message appears) + +## Step-by-Step Flow + +### 1. Alice Creates Her Final Message That Will Be Posted +```json +{ + "kind": 1, + "pubkey": "alice123...", + "content": "The government is lying about inflation statistics", + "tags": [], + "created_at": 1703000000, + "id": "alice_event_id", + "sig": "alice_signature" +} +``` + +### 2. Alice Encrypts Instructions for Superball B (Final Hop) +Payload for Superball B (final hop - no `p` field): +```json +{ + "event": { /* Alice's signed event above */ }, + "routing": { + "relays": ["wss://relay3.com", "wss://relay4.com"], + "delay": 15, + "audit": "9f8e7d6c5b4a39281726354019283746502918374650283746501928374650" + // No "p" field - this means final posting + // No "pad" field - can't modify signed event + } +} +``` + +Creates routing event: +```json +{ + "kind": 30000, + "pubkey": "ephemeral_key_2", + "content": "", + "tags": [["p", "sball_b012..."]], + "created_at": 1703000100, + "id": "routing_for_b", + "sig": "ephemeral_signature_2" +} +``` + +### 3. Alice Encrypts Instructions for Superball A (First Hop) +Payload for Superball A (continuing chain): +```json +{ + "event": { /* routing event for Superball B above */ }, + "routing": { + "relays": ["wss://relay2.com"], + "delay": 45, + "pad": "+200", + "p": "sball_b012...", // Next Superball in chain + "audit": "1a2b3c4d5e6f7890abcdef1234567890abcdef1234567890abcdef1234567890", + "payment": "eCash_A1B2C3..." // Optional payment + } +} +``` + +Alice posts this to Relay1: +```json +{ + "kind": 30000, + "pubkey": "ephemeral_key_1", + "content": "", + "tags": [["p", "sball_a789..."]], + "created_at": 1703000200, + "id": "routing_for_a", + "sig": "ephemeral_signature_1" +} +``` + +## Execution Timeline + +**T+0**: Alice posts routing event to Relay1 +``` +Relay1: kind 30000 event (p tag = sball_a789...) +``` + +**T+5**: Superball A processes +- Decrypts payload +- Sees: relay2.com, delay 45s, pad +200 +- Needs to ADD padding, so creates new wrapper +- Queues for 45-second delay + +**T+50**: Superball A always rewraps (consistent behavior) +``` +Relay2: NEW routing event (always looks the same) +{ + "kind": 30000, + "pubkey": "superball_a_ephemeral_key", // Fresh key + "content": "", // Re-encrypted + "tags": [ + ["p", "sball_b012..."], // Real next hop + ["p", "1a2b3c4d5e6f7890abcdef1234567890abcdef1234567890abcdef1234567890"], // Audit tag + ["padding", "random_data_1..."], // Adjusted padding + ["padding", "random_data_2..."], // (+200 bytes added) + ["padding", "random_data_3..."] + ] +} +``` + +Alice monitors relay2.com and sees her audit tag `1a2b3c4d5e6f...` appear at T+50 with correct +200 byte padding, confirming Superball A is honest. + +**T+55**: Superball B processes +- Decrypts payload +- Sees: Alice's event + instructions (relays=[relay3.com, relay4.com], delay 15s) +- NO `p` field - this means final posting, extract and post Alice's event exactly as-is +- Cannot modify padding on signed event +- Queues for 15-second delay + +**T+70**: Superball B posts Alice's final event (end of chain) +``` +Relay3 AND Relay4: Alice's original signed event appears exactly as she created it +{ + "kind": 1, + "pubkey": "alice123...", + "content": "The government is lying about inflation statistics", + "tags": [], // Original tags preserved + "created_at": 1703000000, + "id": "alice_event_id", + "sig": "alice_signature" // Original signature preserved +} +``` + +Alice's message now appears on both relay3.com and relay4.com for redundancy. + +## Privacy and Security Achieved + +- **Alice's location**: Completely hidden from surveillance +- **Message origin**: Appears to come from Superball B's location +- **Traffic analysis**: 65-second delay + size changes prevent correlation +- **Identity preserved**: Alice's real pubkey and signature maintained +- **Plausible deniability**: No proof Alice initiated the posting +- **Malicious node detection**: Audit tags allow Alice to verify proper forwarding +- **Accountability**: Bad Superballs can be identified and avoided + +### Audit Trail for Alice +- **T+50**: Audit tag `1a2b3c4d5e6f...` appears on relay2.com (✓ Superball A honest) +- **T+70**: Final message appears on relay3.com and relay4.com (✓ Superball B honest) +- **Size verification**: Event sizes match expected padding operations +- **Timing verification**: Delays match requested timeouts + +Alice successfully posts controversial content under her identity while protecting her physical location AND maintaining the ability to detect and avoid malicious routing nodes. \ No newline at end of file diff --git a/Norman_Stingley.txt b/Norman_Stingley.txt new file mode 100644 index 0000000..73ac0ce --- /dev/null +++ b/Norman_Stingley.txt @@ -0,0 +1 @@ +Norman Stingley - inventor of the super-ball \ No newline at end of file diff --git a/PROTOCOL.md b/PROTOCOL.md new file mode 100644 index 0000000..fc10b49 --- /dev/null +++ b/PROTOCOL.md @@ -0,0 +1,198 @@ +# Superball Protocol + +## Overview + +Superball provides location privacy for Nostr by using encrypted routing through daemon nodes. Users can post content under their real identity while completely hiding their network location. + +## Protocol Structure + +### Step 1: Create Signed Event +User creates and signs their normal Nostr event: +```json +{ + "kind": 1, + "pubkey": "user_pubkey", + "content": "Message content", + "tags": [], + "created_at": 1703000000, + "id": "event_id", + "sig": "user_signature" +} +``` + +### Step 2: Create Routing Instructions +User creates routing instructions: +```json +{ + "relays": [ + "wss://target-relay1.com", + "wss://target-relay2.com", + "wss://target-relay3.com" + ], + "delay": 30, + "pad": "+150", + "p": "superball_b_pubkey", // Next superball (optional - if missing, final posting) + "audit": "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456", // Audit pubkey (always required) + "payment": "eCash_token_here" // Optional payment for processing +} +``` + +### Step 3: Encrypt and Send +User creates a routing event with NIP-44 encryption: +```json +{ + "kind": 30000, // Superball routing event + "pubkey": "ephemeral_key", + "content": "", + "tags": [ + ["p", "superball_pubkey"] + ], + "created_at": 1703000100, + "id": "routing_event_id", + "sig": "ephemeral_signature" +} +``` + +The encrypted payload contains: +```json +{ + "event": { + "kind": 1, + "pubkey": "user_pubkey", + "content": "Message content", + "tags": [], + "created_at": 1703000000, + "id": "event_id", + "sig": "user_signature" + }, + "routing": { + "relays": ["wss://target-relay1.com", "wss://target-relay2.com"], + "delay": 30, + "pad": "+150", + "p": "next_superball_pubkey", // Optional - if missing, final posting + "audit": "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456", // Required audit pubkey + "payment": "eCash_token" // Optional payment + } +} +``` + +## Superball Processing + +1. **Receive**: Monitor for kind 30000 events with p tag = own pubkey +2. **Decrypt**: Use NIP-44 to decrypt the content +3. **Parse**: Extract the event and routing instructions +4. **Apply Padding**: Modify padding according to instructions +5. **Delay**: Wait specified time +6. **Always Rewrap**: Create new routing event to hide padding operations +7. **Forward**: Post the new routing event to specified relay + +## Always Rewrap Rule + +### Privacy Protection +Superballs **ALWAYS** create a new routing wrapper to prevent analysis of padding operations: +- **Consistent behavior**: Every forward looks the same (new routing event) +- **Hide operations**: No way to tell if padding was added, removed, or unchanged +- **Fresh encryption**: New ephemeral key and encryption for each hop +- **Metadata mixing**: Padding levels change unpredictably at each hop + +### Routing Event Structure +Every forward creates a new kind 30000 event: +```json +{ + "kind": 30000, + "pubkey": "", + "content": "", + "tags": [ + ["p", ""], + ["p", ""], + ["padding", ""] + ] +} +``` + +## Audit Mechanism for Security + +### Purpose +The audit mechanism allows users to detect malicious Superballs that drop events, ignore timing delays, or modify padding incorrectly. + +### Audit Tag Structure +- **Format**: 64-character hex string (looks like a Nostr pubkey) +- **Generation**: User creates random audit tag for each hop +- **Labeling**: Always labeled as `["p", ""]` in routing events +- **Camouflage**: Indistinguishable from real next-hop pubkeys to observers + +### How It Works +1. **User includes audit tag** in routing instructions for each hop +2. **Superball posts audit tag** as additional `p` tag when forwarding +3. **User monitors relays** for audit tag appearances +4. **Timing and size analysis** reveals compliance with instructions + +### Example Audit Detection +```json +// Alice creates routing with audit tag +{ + "relays": ["wss://relay2.com"], + "delay": 45, + "pad": "+200", + "p": "sball_b_real_pubkey", + "audit": "a1b2c3...fake_pubkey_for_audit" +} + +// Superball A should post this after 45s with +200 bytes: +{ + "kind": 30000, + "tags": [ + ["p", "sball_b_real_pubkey"], // Real next hop + ["p", "a1b2c3...fake_pubkey"], // Audit tag (looks identical) + ["padding", "..."] // +200 bytes of padding + ] +} +``` + +Alice monitors relay2.com and verifies the audit tag appears with correct timing and size. + +### Security Properties +- **Misbehavior Detection**: Dropped, delayed, or incorrectly padded events +- **Reputation Building**: Users can rate Superball reliability over time +- **Privacy Preserved**: Audit tags look like normal routing to observers +- **Always Active**: Every routing event includes audit verification + +## Routing Instructions Fields + +### Required Fields +- **`relays`**: Array of relay URLs to post to (allows multi-relay posting) +- **`delay`**: Minimum delay in seconds before forwarding + +### Required Fields +- **`audit`**: 64-character hex audit tag (format: Nostr pubkey) + - User-generated random identifier for this hop + - Always posted as `["p", ""]` in routing event + - Enables detection of malicious Superballs + +### Optional Fields +- **`pad`**: Padding instruction (`"+N"` to add, `"-N"` to remove N bytes) + - Only valid when `p` field is present (continuing chain) + - Ignored when `p` field missing (final hop - can't modify signed event) +- **`p`**: Pubkey of next Superball in chain + - If present: Create routing event for next Superball (can apply padding) + - If missing: Post final event directly to relays (end of chain, no padding changes) +- **`payment`**: eCash token for processing payment + - Allows monetized Superball services + - Optional - many daemons may operate for free + +## Processing Logic + +### Multi-Relay Posting +Superballs post to ALL specified relays in the `relays` array for redundancy and availability. + +### Chain Termination +- **`p` field present**: Continue routing chain to specified Superball +- **`p` field missing**: Extract and post final event directly, end chain + +## Benefits + +- **Location Privacy**: User's network location completely hidden +- **Identity Preservation**: Posts appear with user's real pubkey +- **Simple Implementation**: Single NIP-44 encryption layer per hop +- **Purpose-Built**: Designed specifically for anonymous posting +- **Traffic Analysis Resistance**: Timing delays and padding protect against correlation \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ed91d0e --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# Superball +![superball](super_ball.jpg) + +Superball provides Tor-like location privacy for Nostr users. It's a daemon that bounces encrypted events between relays, allowing users to post content under their real identity while completely hiding their network location. + +## How It Works + +1. **User creates content** - Normal signed Nostr event with their real pubkey +2. **Encrypt with routing** - Bundle event + routing instructions, encrypt to Superball daemon +3. **Anonymous forwarding** - Event bounces through multiple daemons with delays and padding +4. **Final posting** - Original event appears on target relay with user's identity but from daemon's location + +## Key Features + +- **Location Privacy**: Hide your network location while preserving your identity +- **Traffic Analysis Resistance**: Random delays and size padding prevent correlation +- **Simple Protocol**: Uses NIP-44 encryption with new kind 30000 for routing +- **Flexible Routing**: Support for multi-hop paths through multiple daemons +- **Signature Preservation**: Original event signatures maintained for authenticity +- **Audit Security**: Detect and avoid malicious Superballs through cryptographic verification + +## Documentation + +- [`PROTOCOL.md`](PROTOCOL.md) - Technical protocol specification +- [`EXAMPLE.md`](EXAMPLE.md) - Complete walkthrough example +- [`DAEMON.md`](DAEMON.md) - Rules and behavior for Superball daemon operators + +Perfect for journalists, activists, or anyone who needs to protect their physical location while maintaining accountability for their public statements. + diff --git a/super_ball.code-workspace b/super_ball.code-workspace new file mode 100644 index 0000000..876a149 --- /dev/null +++ b/super_ball.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file diff --git a/super_ball.jpg b/super_ball.jpg new file mode 100644 index 0000000..872a2e8 Binary files /dev/null and b/super_ball.jpg differ