6.6 KiB
6.6 KiB
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
{
"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)
{
"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)
{
"event": { /* Still-encrypted inner event */ },
"padding": "01234567890123" // Padding data to discard
}
3. Handle Payload Type
If Padding Payload:
- Discard padding - Ignore padding field completely
- Decrypt again - The "event" field contains another encrypted payload
- Process the inner payload - This will be a routing payload meant for me
If Routing Payload:
- Process routing instructions - These were created by the builder specifically for me
- 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 wrapperp
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 paymentpayment
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:
{
"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
- Throwers NEVER create routing instructions - Only padding
- Routing instructions come ONLY from the builder - Pre-encrypted for each hop
- Always use fresh ephemeral keys when forwarding
- Include audit tag in routing event p tags for camouflage
My Rules
Security Rules
- Never log sensitive data - Don't store decrypted content or routing info
- Generate new keys - Use fresh ephemeral keys for each forward
- Validate everything - Check signatures, event structure, relay URLs
Privacy Rules
- No correlation - Don't link input events to output events in logs
- Clear memory - Immediately clear decrypted data after processing
Processing Rules
- First come, first served - Process events in order received
- Fail silently - Drop invalid events without response
- Retry logic - Attempt to post 3 times before giving up
- Resource limits - Drop oldest queued events if memory/queue full
Network Rules
- Multiple relays - Connect to diverse set of relays
- Separate connections - Use different connections for input/output
- AUTH constraint - Can only write to relays that do NOT require AUTH (since I post events I didn't sign)
- Read capability - Can read from any relay (AUTH or non-AUTH) to monitor for Superballs
- NIP-65 compliance - Maintain accurate relay list marking read-only vs write-capable relays
- Authentication testing - Regularly test relays to determine AUTH requirements
- Rotate connections - Periodically reconnect to prevent fingerprinting
What I Never Do
- Never modify final signatures - Only remove padding tags, never add to signed events
- Never store routing paths - Process and forget
- Never respond to clients - Silent operation only
- Never correlate users - Each Superball is independent
- Never log destinations - Only log operational metrics
Example Processing Flow
Single Unwrapping (Routing Payload)
- Receive: Kind 22222 event with my pubkey in p tag
- Decrypt: Get payload with routing instructions
- Process: These routing instructions were created for me by builder
- Forward or Post: Based on routing.p field
Double Unwrapping (Padding Payload)
- Receive: Kind 22222 event with my pubkey in p tag
- First Decrypt: Get padding payload - discard padding
- Second Decrypt: Decrypt the inner event to get my routing instructions
- Process: These routing instructions were created for me by builder
- 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.