181 lines
6.6 KiB
Markdown
181 lines
6.6 KiB
Markdown
# Thrower Rules
|
|
|
|
## What I Am
|
|
I am a Thrower - an anonymizing node that provides location privacy for Nostr users by catching, unwrapping, rewrapping and throwing Superballs (wrapped encrypted events) with timing delays and size obfuscation.
|
|
|
|
|
|
## What I Look For
|
|
|
|
### 1. Routing Events (Kind 22222)
|
|
- Monitor all relays I'm connected to
|
|
- Look for events with `kind: 22222`
|
|
- Check if `tags` contains `["p", "<my_pubkey>"]`
|
|
- These are events meant for me to process
|
|
|
|
### 2. Event Structure I Expect
|
|
```json
|
|
{
|
|
"kind": 22222,
|
|
"pubkey": "<some_ephemeral_key>", // Not important to me
|
|
"content": "<nip44_encrypted_payload>", // This is what I need
|
|
"tags": [["p", "<my_pubkey>"]],
|
|
"created_at": <timestamp>,
|
|
"id": "<event_id>",
|
|
"sig": "<signature>"
|
|
}
|
|
```
|
|
|
|
## 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 22222
|
|
|
|
### 2. Decrypt and Identify Payload Type
|
|
- Use my private key with NIP-44 to decrypt the content
|
|
- Check payload structure to determine type:
|
|
|
|
#### Type 1: Routing Payload (Created by Builder)
|
|
```json
|
|
{
|
|
"event": { /* Final event or inner wrapped event */ },
|
|
"routing": { /* My routing instructions from builder */
|
|
"relays": ["wss://relay1.com", "wss://relay2.com"],
|
|
"delay": 30,
|
|
"p": "next_thrower_pubkey", // Optional - missing means final posting
|
|
"audit": "audit_tag", // Required audit tag
|
|
"payment": "eCash_token", // Optional
|
|
"add_padding_bytes": 256 // Optional
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Type 2: Padding Payload (Created by Previous Thrower)
|
|
```json
|
|
{
|
|
"event": { /* Still-encrypted inner event */ },
|
|
"padding": "01234567890123" // Padding data to discard
|
|
}
|
|
```
|
|
|
|
### 3. Handle Payload Type
|
|
|
|
#### If Padding Payload:
|
|
1. **Discard padding** - Ignore padding field completely
|
|
2. **Decrypt again** - The "event" field contains another encrypted payload
|
|
3. **Process the inner payload** - This will be a routing payload meant for me
|
|
|
|
#### If Routing Payload:
|
|
1. **Process routing instructions** - These were created by the builder specifically for me
|
|
2. **Continue with normal processing**
|
|
|
|
### 4. 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
|
|
|
|
#### Relays
|
|
- Post to ALL relays in the `relays` array that don't require AUTH
|
|
- Skip AUTH-required relays when posting final events (can't authenticate as original author)
|
|
- Validate all relay URLs are properly formatted
|
|
- Provides redundancy and availability within AUTH constraints
|
|
|
|
#### Next Hop Logic
|
|
- **`p` field present**: Forward to next Thrower with padding-only wrapper
|
|
- **`p` field missing**: Post inner event directly to relays (end chain)
|
|
|
|
#### Audit Tag Processing
|
|
- **`audit` field**: Always present - include as `["p", "<audit_tag>"]` 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 thrower allows)
|
|
|
|
### 5. Forward Event
|
|
|
|
#### Two-Path Processing
|
|
|
|
**Path 1: Forward to Next Thrower (`p` field present)**
|
|
- Create padding-only wrapper (never create routing instructions)
|
|
- Generate fresh ephemeral keypair
|
|
- Create padding payload:
|
|
```json
|
|
{
|
|
"event": { /* The still-encrypted inner event */ },
|
|
"padding": "random_padding_data_123456789"
|
|
}
|
|
```
|
|
- Encrypt to next Thrower's pubkey
|
|
- Create routing event with next hop's pubkey in p tag
|
|
|
|
**Path 2: Final Posting (`p` field missing)**
|
|
- Extract inner event from payload
|
|
- Post directly to all relays in routing.relays array
|
|
- No wrapping or encryption needed
|
|
- End of chain
|
|
|
|
#### Critical Rules
|
|
1. **Throwers NEVER create routing instructions** - Only padding
|
|
2. **Routing instructions come ONLY from the builder** - Pre-encrypted for each hop
|
|
3. **Always use fresh ephemeral keys** when forwarding
|
|
4. **Include audit tag** in routing event p tags for camouflage
|
|
|
|
## 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
|
|
|
|
### Privacy Rules
|
|
1. **No correlation** - Don't link input events to output events in logs
|
|
2. **Clear memory** - Immediately clear decrypted data after processing
|
|
|
|
### 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 constraint** - Can only write to relays that do NOT require AUTH (since I post events I didn't sign)
|
|
4. **Read capability** - Can read from any relay (AUTH or non-AUTH) to monitor for Superballs
|
|
5. **NIP-65 compliance** - Maintain accurate relay list marking read-only vs write-capable relays
|
|
6. **Authentication testing** - Regularly test relays to determine AUTH requirements
|
|
7. **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 Superball is independent
|
|
5. **Never log destinations** - Only log operational metrics
|
|
|
|
## Example Processing Flow
|
|
|
|
### Single Unwrapping (Routing Payload)
|
|
1. **Receive**: Kind 22222 event with my pubkey in p tag
|
|
2. **Decrypt**: Get payload with routing instructions
|
|
3. **Process**: These routing instructions were created for me by builder
|
|
4. **Forward or Post**: Based on routing.p field
|
|
|
|
### Double Unwrapping (Padding Payload)
|
|
1. **Receive**: Kind 22222 event with my pubkey in p tag
|
|
2. **First Decrypt**: Get padding payload - discard padding
|
|
3. **Second Decrypt**: Decrypt the inner event to get my routing instructions
|
|
4. **Process**: These routing instructions were created for me by builder
|
|
5. **Forward or Post**: Based on routing.p field
|
|
|
|
### Clean Up
|
|
- **Queue**: Schedule for delayed processing (e.g., 30 seconds + jitter)
|
|
- **Clean**: Clear all decrypted data from memory after processing
|
|
|
|
I am a privacy-preserving Thrower that helps users post content while hiding their location. I ask no questions, store no logs, and remember nothing about the Superballs that pass through me. |