Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ecf248dfc2 | ||
|
|
1b28f78f44 |
126
DAEMON.md
126
DAEMON.md
@@ -5,16 +5,16 @@ I am Superball - an anonymizing node that provides location privacy for Nostr us
|
||||
|
||||
## What I Look For
|
||||
|
||||
### 1. Routing Events (Kind 30000)
|
||||
### 1. Routing Events (Kind 22222)
|
||||
- Monitor all relays I'm connected to
|
||||
- Look for events with `kind: 30000`
|
||||
- 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": 30000,
|
||||
"kind": 22222,
|
||||
"pubkey": "<some_ephemeral_key>", // Not important to me
|
||||
"content": "<nip44_encrypted_payload>", // This is what I need
|
||||
"tags": [["p", "<my_pubkey>"]],
|
||||
@@ -29,49 +29,61 @@ I am Superball - an anonymizing node that provides location privacy for Nostr us
|
||||
### 1. Validate
|
||||
- Verify the event signature is valid
|
||||
- Confirm the `p` tag contains my pubkey
|
||||
- Ensure it's kind 30000
|
||||
- Ensure it's kind 22222
|
||||
|
||||
### 2. Decrypt
|
||||
### 2. Decrypt and Identify Payload Type
|
||||
- Use my private key with NIP-44 to decrypt the content
|
||||
- Extract the payload which contains:
|
||||
```json
|
||||
{
|
||||
"event": { /* The event to forward */ },
|
||||
"routing": {
|
||||
- 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,
|
||||
"pad": "+150", // or "-50"
|
||||
"p": "next_superball_pubkey", // Optional - missing means final posting
|
||||
"audit": "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456", // Required audit tag
|
||||
"payment": "eCash_token" // Optional
|
||||
"audit": "audit_tag", // Required audit tag
|
||||
"payment": "eCash_token", // Optional
|
||||
"add_padding_bytes": 256 // Optional
|
||||
}
|
||||
}
|
||||
```
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Process Routing Instructions
|
||||
#### Type 2: Padding Payload (Created by Previous Daemon)
|
||||
```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
|
||||
|
||||
#### 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
|
||||
- **`p` field present**: Forward to next Superball 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
|
||||
@@ -82,30 +94,34 @@ I am Superball - an anonymizing node that provides location privacy for Nostr us
|
||||
- **`payment` field present**: Process eCash token for service payment
|
||||
- **`payment` field missing**: Process for free (if daemon allows)
|
||||
|
||||
### 4. Forward Event
|
||||
### 5. Forward Event
|
||||
|
||||
#### Always Rewrap (Important for Privacy)
|
||||
**ALWAYS** create a new routing event to hide whether padding was added or removed:
|
||||
#### Two-Path Processing
|
||||
|
||||
**Path 1: Forward to Next Superball (`p` field present)**
|
||||
- Create padding-only wrapper (never create routing instructions)
|
||||
- Generate fresh ephemeral keypair
|
||||
- Create padding payload:
|
||||
```json
|
||||
{
|
||||
"kind": 30000, // Always use routing event
|
||||
"pubkey": "<my_ephemeral_key>", // Generate fresh ephemeral key
|
||||
"content": "<encrypted_inner_event>", // Re-encrypt with my key
|
||||
"tags": [
|
||||
["p", "<next_hop_or_final_destination>"],
|
||||
["p", "<audit_tag_from_routing>"], // Always include audit tag as p tag
|
||||
["padding", "<random_data_1>"], // Adjusted padding
|
||||
["padding", "<random_data_2>"] // May be more or less than before
|
||||
]
|
||||
"event": { /* The still-encrypted inner event */ },
|
||||
"padding": "random_padding_data_123456789"
|
||||
}
|
||||
```
|
||||
- Encrypt to next Superball's pubkey
|
||||
- Create routing event with next hop's pubkey in p tag
|
||||
|
||||
#### 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
|
||||
**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. **Daemons 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
|
||||
|
||||
@@ -143,11 +159,21 @@ I am Superball - an anonymizing node that provides location privacy for Nostr us
|
||||
|
||||
## 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
|
||||
### 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 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.
|
||||
24
EXAMPLE.md
24
EXAMPLE.md
@@ -20,7 +20,7 @@ Alice wants to post a message under her real identity while hiding her location
|
||||
"pubkey": "alice123...",
|
||||
"content": "The government is lying about inflation statistics",
|
||||
"tags": [],
|
||||
"created_at": 1703000000,
|
||||
"created_at": 1702222200,
|
||||
"id": "alice_event_id",
|
||||
"sig": "alice_signature"
|
||||
}
|
||||
@@ -34,9 +34,10 @@ Payload for Superball B (final hop - no `p` field):
|
||||
"routing": {
|
||||
"relays": ["wss://relay3.com", "wss://relay4.com"],
|
||||
"delay": 15,
|
||||
"audit": "9f8e7d6c5b4a39281726354019283746502918374650283746501928374650"
|
||||
"payment": "eCash_ZYX321..." // Optional payment
|
||||
// No "p" field - this means final posting
|
||||
// No "pad" field - can't modify signed event
|
||||
// No "audit" field - can't audit final signed event - no need
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -44,7 +45,7 @@ Payload for Superball B (final hop - no `p` field):
|
||||
Creates routing event:
|
||||
```json
|
||||
{
|
||||
"kind": 30000,
|
||||
"kind": 22222,
|
||||
"pubkey": "ephemeral_key_2",
|
||||
"content": "<encrypted_payload_for_superball_b>",
|
||||
"tags": [["p", "sball_b012..."]],
|
||||
@@ -62,7 +63,7 @@ Payload for Superball A (continuing chain):
|
||||
"routing": {
|
||||
"relays": ["wss://relay2.com"],
|
||||
"delay": 45,
|
||||
"pad": "+200",
|
||||
"padding": "+200",
|
||||
"p": "sball_b012...", // Next Superball in chain
|
||||
"audit": "1a2b3c4d5e6f7890abcdef1234567890abcdef1234567890abcdef1234567890",
|
||||
"payment": "eCash_A1B2C3..." // Optional payment
|
||||
@@ -73,10 +74,13 @@ Payload for Superball A (continuing chain):
|
||||
Alice posts this to Relay1:
|
||||
```json
|
||||
{
|
||||
"kind": 30000,
|
||||
"kind": 22222,
|
||||
"pubkey": "ephemeral_key_1",
|
||||
"content": "<encrypted_payload_for_superball_a>",
|
||||
"tags": [["p", "sball_a789..."]],
|
||||
"tags": [
|
||||
["p", "sball_a789..."],
|
||||
["p", "fake audit tag..."],
|
||||
],
|
||||
"created_at": 1703000200,
|
||||
"id": "routing_for_a",
|
||||
"sig": "ephemeral_signature_1"
|
||||
@@ -87,12 +91,12 @@ Alice posts this to Relay1:
|
||||
|
||||
**T+0**: Alice posts routing event to Relay1
|
||||
```
|
||||
Relay1: kind 30000 event (p tag = sball_a789...)
|
||||
Relay1: kind 22222 event (p tag = sball_a789...)
|
||||
```
|
||||
|
||||
**T+5**: Superball A processes
|
||||
- Decrypts payload
|
||||
- Sees: relay2.com, delay 45s, pad +200
|
||||
- Sees: relay2.com, delay 45s, padding +200
|
||||
- Needs to ADD padding, so creates new wrapper
|
||||
- Queues for 45-second delay
|
||||
|
||||
@@ -100,7 +104,7 @@ Relay1: kind 30000 event (p tag = sball_a789...)
|
||||
```
|
||||
Relay2: NEW routing event (always looks the same)
|
||||
{
|
||||
"kind": 30000,
|
||||
"kind": 22222,
|
||||
"pubkey": "superball_a_ephemeral_key", // Fresh key
|
||||
"content": "<newly_encrypted_payload>", // Re-encrypted
|
||||
"tags": [
|
||||
@@ -130,7 +134,7 @@ Relay3 AND Relay4: Alice's original signed event appears exactly as she created
|
||||
"pubkey": "alice123...",
|
||||
"content": "The government is lying about inflation statistics",
|
||||
"tags": [], // Original tags preserved
|
||||
"created_at": 1703000000,
|
||||
"created_at": 1702222200,
|
||||
"id": "alice_event_id",
|
||||
"sig": "alice_signature" // Original signature preserved
|
||||
}
|
||||
|
||||
20
PROTOCOL.md
20
PROTOCOL.md
@@ -14,7 +14,7 @@ User creates and signs their normal Nostr event:
|
||||
"pubkey": "user_pubkey",
|
||||
"content": "Message content",
|
||||
"tags": [],
|
||||
"created_at": 1703000000,
|
||||
"created_at": 1702222200,
|
||||
"id": "event_id",
|
||||
"sig": "user_signature"
|
||||
}
|
||||
@@ -30,7 +30,7 @@ User creates routing instructions:
|
||||
"wss://target-relay3.com"
|
||||
],
|
||||
"delay": 30,
|
||||
"pad": "+150",
|
||||
"padding": "+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
|
||||
@@ -41,7 +41,7 @@ User creates routing instructions:
|
||||
User creates a routing event with NIP-44 encryption:
|
||||
```json
|
||||
{
|
||||
"kind": 30000, // Superball routing event
|
||||
"kind": 22222, // Superball routing event
|
||||
"pubkey": "ephemeral_key",
|
||||
"content": "<nip44_encrypted_payload>",
|
||||
"tags": [
|
||||
@@ -61,14 +61,14 @@ The encrypted payload contains:
|
||||
"pubkey": "user_pubkey",
|
||||
"content": "Message content",
|
||||
"tags": [],
|
||||
"created_at": 1703000000,
|
||||
"created_at": 1702222200,
|
||||
"id": "event_id",
|
||||
"sig": "user_signature"
|
||||
},
|
||||
"routing": {
|
||||
"relays": ["wss://target-relay1.com", "wss://target-relay2.com"],
|
||||
"delay": 30,
|
||||
"pad": "+150",
|
||||
"padding": "+150",
|
||||
"p": "next_superball_pubkey", // Optional - if missing, final posting
|
||||
"audit": "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456", // Required audit pubkey
|
||||
"payment": "eCash_token" // Optional payment
|
||||
@@ -78,7 +78,7 @@ The encrypted payload contains:
|
||||
|
||||
## Superball Processing
|
||||
|
||||
1. **Receive**: Monitor for kind 30000 events with p tag = own pubkey
|
||||
1. **Receive**: Monitor for kind 22222 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
|
||||
@@ -96,10 +96,10 @@ Superballs **ALWAYS** create a new routing wrapper to prevent analysis of paddin
|
||||
- **Metadata mixing**: Padding levels change unpredictably at each hop
|
||||
|
||||
### Routing Event Structure
|
||||
Every forward creates a new kind 30000 event:
|
||||
Every forward creates a new kind 22222 event:
|
||||
```json
|
||||
{
|
||||
"kind": 30000,
|
||||
"kind": 22222,
|
||||
"pubkey": "<fresh_ephemeral_key>",
|
||||
"content": "<newly_encrypted_payload>",
|
||||
"tags": [
|
||||
@@ -133,14 +133,14 @@ The audit mechanism allows users to detect malicious Superballs that drop events
|
||||
{
|
||||
"relays": ["wss://relay2.com"],
|
||||
"delay": 45,
|
||||
"pad": "+200",
|
||||
"padding": "+200",
|
||||
"p": "sball_b_real_pubkey",
|
||||
"audit": "a1b2c3...fake_pubkey_for_audit"
|
||||
}
|
||||
|
||||
// Superball A should post this after 45s with +200 bytes:
|
||||
{
|
||||
"kind": 30000,
|
||||
"kind": 22222,
|
||||
"tags": [
|
||||
["p", "sball_b_real_pubkey"], // Real next hop
|
||||
["p", "a1b2c3...fake_pubkey"], // Audit tag (looks identical)
|
||||
|
||||
@@ -14,7 +14,7 @@ Superball provides Tor-like location privacy for Nostr users. It's a daemon that
|
||||
|
||||
- **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
|
||||
- **Simple Protocol**: Uses NIP-44 encryption with new kind 22222 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
|
||||
|
||||
299
SUPs.md
Normal file
299
SUPs.md
Normal file
@@ -0,0 +1,299 @@
|
||||
# SUPs - Superball Upgrade Possibilities
|
||||
|
||||
SUPs (Superball Upgrade Possibilities) describe standards for the Superball anonymity protocol, including core protocol rules, daemon behavior specifications, routing algorithms, and security mechanisms.
|
||||
|
||||
## SUP Types
|
||||
|
||||
- **Standards Track**: SUPs that affect protocol compatibility
|
||||
- **Informational**: General guidelines and information
|
||||
- **Process**: Procedures and governance for the SUP process
|
||||
|
||||
## SUP Status
|
||||
|
||||
- **Draft**: Initial specification under development
|
||||
- **Proposed**: Ready for community review
|
||||
- **Final**: Accepted and implemented
|
||||
- **Replaced**: Superseded by newer SUP
|
||||
- **Withdrawn**: No longer pursued
|
||||
|
||||
---
|
||||
|
||||
## SUP-1: Core Protocol Specification
|
||||
|
||||
**Type**: Standards Track
|
||||
**Status**: Final
|
||||
**Author**: Alice & Contributors
|
||||
**Created**: 2024-01-17
|
||||
|
||||
### Abstract
|
||||
|
||||
This SUP defines the core Superball protocol for providing location privacy in Nostr through encrypted event routing via daemon nodes. Users can post content under their real identity while completely hiding their network location.
|
||||
|
||||
### Motivation
|
||||
|
||||
Current Nostr implementations reveal users' network locations through direct relay connections, enabling surveillance and censorship. Superball provides Tor-like anonymity while preserving message authenticity through cryptographic signatures.
|
||||
|
||||
### Specification
|
||||
|
||||
#### Event Kind
|
||||
- **Kind 22222**: Superball routing event
|
||||
|
||||
#### Routing Event Structure
|
||||
```json
|
||||
{
|
||||
"kind": 22222,
|
||||
"pubkey": "<ephemeral_key>",
|
||||
"content": "<nip44_encrypted_payload>",
|
||||
"tags": [
|
||||
["p", "<superball_pubkey>"],
|
||||
["p", "<audit_pubkey>"],
|
||||
["padding", "<random_data>"]
|
||||
],
|
||||
"created_at": "<timestamp>",
|
||||
"id": "<event_id>",
|
||||
"sig": "<ephemeral_signature>"
|
||||
}
|
||||
```
|
||||
|
||||
#### Encrypted Payload Format
|
||||
```json
|
||||
{
|
||||
"event": { /* Original signed event or next routing event */ },
|
||||
"routing": {
|
||||
"relays": ["wss://relay1.com", "wss://relay2.com"],
|
||||
"delay": 30,
|
||||
"padding": "+150",
|
||||
"p": "next_superball_pubkey", // Optional
|
||||
"audit": "audit_verification_pubkey", // Required
|
||||
"payment": "ecash_token" // Optional
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Processing Rules
|
||||
1. **Always Rewrap**: Create new routing event for every forward
|
||||
2. **Audit Verification**: Include audit tag as p tag in routing event
|
||||
3. **Delay Compliance**: Wait specified time plus random jitter
|
||||
4. **Padding Operations**: Apply size modifications as instructed
|
||||
5. **Multi-Relay Posting**: Post to all specified relays
|
||||
|
||||
### Rationale
|
||||
|
||||
The protocol uses NIP-44 encryption for simplicity over NIP-59 gift wrapping, includes mandatory audit mechanisms for security, and employs consistent rewrapping to prevent traffic analysis.
|
||||
|
||||
---
|
||||
|
||||
## SUP-2: Audit Security Mechanism
|
||||
|
||||
**Type**: Standards Track
|
||||
**Status**: Final
|
||||
**Author**: Alice & Contributors
|
||||
**Created**: 2024-01-17
|
||||
|
||||
### Abstract
|
||||
|
||||
This SUP defines the audit mechanism that allows users to detect malicious Superballs through cryptographic verification of proper event forwarding.
|
||||
|
||||
### Motivation
|
||||
|
||||
Users need the ability to verify that Superballs are honestly forwarding events according to instructions, including proper delays, padding operations, and relay posting.
|
||||
|
||||
### Specification
|
||||
|
||||
#### Audit Tag Format
|
||||
- **Length**: 64 hexadecimal characters
|
||||
- **Format**: Appears as valid Nostr pubkey
|
||||
- **Generation**: Cryptographically secure random per-hop
|
||||
- **Posting**: Always included as `["p", "<audit_tag>"]` in routing events
|
||||
|
||||
#### User Monitoring
|
||||
1. Generate unique audit tag for each routing hop
|
||||
2. Monitor specified relays for audit tag appearance
|
||||
3. Verify timing matches delay instructions
|
||||
4. Verify event size matches padding operations
|
||||
5. Build reputation scores for Superballs based on compliance
|
||||
|
||||
#### Privacy Properties
|
||||
- Audit tags indistinguishable from real next-hop pubkeys
|
||||
- Only originating user knows which tags are audit verification
|
||||
- No correlation possible between different users' audit tags
|
||||
|
||||
### Implementation
|
||||
|
||||
```javascript
|
||||
// Generate audit tag
|
||||
const auditTag = bytesToHex(randomBytes(32));
|
||||
|
||||
// Monitor relay for audit appearance
|
||||
const monitorAudit = async (relay, auditTag, expectedDelay, expectedSize) => {
|
||||
const startTime = Date.now();
|
||||
|
||||
relay.subscribe([{
|
||||
kinds: [22222],
|
||||
"#p": [auditTag]
|
||||
}], {
|
||||
onevent: (event) => {
|
||||
const actualDelay = (event.created_at * 1000) - startTime;
|
||||
const actualSize = JSON.stringify(event).length;
|
||||
|
||||
// Verify compliance
|
||||
const delayCompliant = Math.abs(actualDelay - expectedDelay) < TOLERANCE;
|
||||
const sizeCompliant = Math.abs(actualSize - expectedSize) < PADDING_TOLERANCE;
|
||||
|
||||
recordSuperballReputation(event.pubkey, delayCompliant && sizeCompliant);
|
||||
}
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SUP-3: Daemon Operational Rules
|
||||
|
||||
**Type**: Informational
|
||||
**Status**: Final
|
||||
**Author**: Superball Operators
|
||||
**Created**: 2024-01-17
|
||||
|
||||
### Abstract
|
||||
|
||||
This SUP provides operational guidelines for Superball daemon operators, including security practices, resource management, and privacy protection protocols.
|
||||
|
||||
### Security Rules
|
||||
1. **Never log sensitive data** - Don't store decrypted content or routing information
|
||||
2. **Generate fresh keys** - Use new ephemeral keys for each forward operation
|
||||
3. **Validate everything** - Check signatures, event structure, and relay URLs
|
||||
4. **Rate limiting** - Prevent abuse through request throttling
|
||||
5. **Memory clearing** - Immediately clear decrypted data after processing
|
||||
|
||||
### Privacy Rules
|
||||
1. **No correlation** - Don't link input events to output events in logs
|
||||
2. **Random timing** - Add jitter to specified delays
|
||||
3. **Traffic mixing** - Send decoy traffic when idle (optional enhancement)
|
||||
4. **Connection rotation** - Periodically reconnect to prevent fingerprinting
|
||||
|
||||
### Processing Rules
|
||||
1. **First come, first served** - Process events in arrival order
|
||||
2. **Fail silently** - Drop invalid events without response
|
||||
3. **Retry logic** - Attempt relay posting 3 times before giving up
|
||||
4. **Resource limits** - Drop oldest queued events if memory/queue full
|
||||
|
||||
---
|
||||
|
||||
## SUP-4: Multi-Path Routing Enhancement
|
||||
|
||||
**Type**: Standards Track
|
||||
**Status**: Draft
|
||||
**Author**: Security Researchers
|
||||
**Created**: 2024-01-17
|
||||
|
||||
### Abstract
|
||||
|
||||
This SUP proposes an enhancement allowing users to send the same event through multiple independent Superball chains simultaneously for increased security against coordinated attacks.
|
||||
|
||||
### Motivation
|
||||
|
||||
Single routing chains are vulnerable to adversaries who control multiple nodes in the path. Multi-path routing increases security by requiring adversaries to control nodes across multiple independent chains.
|
||||
|
||||
### Specification
|
||||
|
||||
#### Multi-Path Event Structure
|
||||
```json
|
||||
{
|
||||
"paths": [
|
||||
{
|
||||
"chain_id": "random_identifier_1",
|
||||
"routing": { /* Standard routing instructions */ }
|
||||
},
|
||||
{
|
||||
"chain_id": "random_identifier_2",
|
||||
"routing": { /* Different Superballs and relays */ }
|
||||
}
|
||||
],
|
||||
"threshold": 1 // Minimum successful deliveries required
|
||||
}
|
||||
```
|
||||
|
||||
#### Implementation Requirements
|
||||
- Generate independent routing chains with no overlapping Superballs
|
||||
- Use different target relays for each path
|
||||
- Include chain_id in audit mechanism for path-specific monitoring
|
||||
- Consider delivery successful when threshold number of paths complete
|
||||
|
||||
### Security Analysis
|
||||
|
||||
- **Resistance**: Requires adversary control of nodes across multiple chains
|
||||
- **Redundancy**: Event delivery succeeds even if some paths are compromised
|
||||
- **Cost**: Increases bandwidth and processing requirements
|
||||
- **Detection**: Path-specific audit tags enable per-chain monitoring
|
||||
|
||||
---
|
||||
|
||||
## SUP-5: Payment Integration Specification
|
||||
|
||||
**Type**: Standards Track
|
||||
**Status**: Proposed
|
||||
**Author**: Economic Protocol Designers
|
||||
**Created**: 2024-01-17
|
||||
|
||||
### Abstract
|
||||
|
||||
This SUP defines the integration of eCash payment tokens for monetized Superball services, enabling sustainable economic models for privacy infrastructure.
|
||||
|
||||
### Specification
|
||||
|
||||
#### Payment Field Format
|
||||
```json
|
||||
{
|
||||
"payment": {
|
||||
"type": "ecash",
|
||||
"token": "base64_encoded_ecash_token",
|
||||
"amount": 100, // satoshis
|
||||
"mint": "https://mint.example.com"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Processing Rules
|
||||
1. **Validate token** - Verify eCash token authenticity with mint
|
||||
2. **Check amount** - Ensure payment meets minimum service fee
|
||||
3. **Redeem atomically** - Claim payment only after successful forwarding
|
||||
4. **Rate limits** - Higher processing priority for paid requests
|
||||
|
||||
#### Economic Considerations
|
||||
- Free tier with limited throughput for accessibility
|
||||
- Premium tiers with guaranteed processing times
|
||||
- Dynamic pricing based on network congestion
|
||||
- Reputation bonuses for consistent payment
|
||||
|
||||
---
|
||||
|
||||
## Future SUP Topics
|
||||
|
||||
### Proposed Enhancements
|
||||
- **SUP-6**: Zero-Knowledge Proof Integration for Verifiable Delays
|
||||
- **SUP-7**: Decentralized Superball Discovery Protocol
|
||||
- **SUP-8**: Quantum-Resistant Encryption Migration
|
||||
- **SUP-9**: Mobile Client Optimizations
|
||||
- **SUP-10**: Governance and Protocol Upgrade Mechanisms
|
||||
|
||||
### Research Areas
|
||||
- Traffic analysis resistance measurements
|
||||
- Economic attack vectors and mitigations
|
||||
- Integration with other privacy protocols
|
||||
- Scalability optimizations
|
||||
- Censorship resistance enhancements
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
SUPs follow the collaborative development process:
|
||||
|
||||
1. **Draft**: Create initial specification
|
||||
2. **Discussion**: Community review and feedback
|
||||
3. **Implementation**: Reference implementations
|
||||
4. **Testing**: Security and compatibility testing
|
||||
5. **Final**: Adoption by Superball ecosystem
|
||||
|
||||
Submit SUP proposals through the project repository with detailed technical specifications, security analysis, and implementation considerations.
|
||||
420
debug.md
Normal file
420
debug.md
Normal file
@@ -0,0 +1,420 @@
|
||||
# Ball Structure
|
||||
|
||||
Final Event (What gets posted at the end)
|
||||
Message Content:
|
||||
2 bounce
|
||||
Create Event That Will Be Published Publicly
|
||||
{
|
||||
"kind": 1,
|
||||
"content": "2 bounce",
|
||||
"tags": [],
|
||||
"created_at": 1758196136,
|
||||
"pubkey": "8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e",
|
||||
"id": "2451f908dba9b2281751ecb91df143b83866795d29bbadde60093dd17cd039dd",
|
||||
"sig": "31400031068313ba8338faf852ca718ef3495e393a6ef66a925db6e26ef21dd825fe5beca36ad9a2af7ea87ecd1dbc50550112505b7ee30c19125ae89b610b4c"
|
||||
}
|
||||
🏀 Bounce 2 (Kind 22222 Routing Event)
|
||||
Superball Pubkey:
|
||||
03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25
|
||||
🎲 Random
|
||||
Target Relays (comma separated):
|
||||
wss://relay.laantungir.net
|
||||
Delay (seconds):
|
||||
10
|
||||
Padding (+N or -N bytes):
|
||||
+150 or -50
|
||||
Payment (optional):
|
||||
eCash token or payment info
|
||||
Audit Tag (auto-generated):
|
||||
3413dc76625f59dc88b4ff4c290643110f21208c9f4f99a678a75730fd35cef3
|
||||
Create Bounce 2
|
||||
{
|
||||
"kind": 22222,
|
||||
"content": "Aob4...2at6",
|
||||
"tags": [
|
||||
[
|
||||
"p",
|
||||
"03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25"
|
||||
],
|
||||
[
|
||||
"p",
|
||||
"3413dc76625f59dc88b4ff4c290643110f21208c9f4f99a678a75730fd35cef3"
|
||||
]
|
||||
],
|
||||
"created_at": 1758196144,
|
||||
"pubkey": "acb7a5fe35eb69a0f30e58dc790558a86143d5c489749fe9c4db52bdb3f7b310",
|
||||
"id": "00d7536a425b2d955084f920c45c1d5ddf86b5503374daa02922af60f536b953",
|
||||
"sig": "a2f9ad4f85bda8fc6ddbce28b2773e8938a747964dc278b2e89553666f777e9d27cbf37d6c69a30223dd8e2e2ace3155d31711ebb9b0b7cd0c5d1c92f8ecefec"
|
||||
}
|
||||
🔓 Decrypt Content
|
||||
|
||||
|
||||
🔓 Decrypted Payload:
|
||||
|
||||
|
||||
{
|
||||
"event": {
|
||||
"kind": 1,
|
||||
"content": "2 bounce",
|
||||
"tags": [],
|
||||
"created_at": 1758196136,
|
||||
"pubkey": "8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e",
|
||||
"id": "2451f908dba9b2281751ecb91df143b83866795d29bbadde60093dd17cd039dd",
|
||||
"sig": "31400031068313ba8338faf852ca718ef3495e393a6ef66a925db6e26ef21dd825fe5beca36ad9a2af7ea87ecd1dbc50550112505b7ee30c19125ae89b610b4c"
|
||||
},
|
||||
"routing": {
|
||||
"relays": [
|
||||
"wss://relay.laantungir.net"
|
||||
],
|
||||
"delay": 10,
|
||||
"audit": "3413dc76625f59dc88b4ff4c290643110f21208c9f4f99a678a75730fd35cef3"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
🏀 Bounce 1 (Kind 22222 Routing Event)
|
||||
Superball Pubkey:
|
||||
e295a831c9a3ae50da2ca3115f8b13b035805a5ebbbd68d95a1e0caf13bff440
|
||||
🎲 Random
|
||||
Target Relays (comma separated):
|
||||
wss://relay.laantungir.net
|
||||
Delay (seconds):
|
||||
10
|
||||
Padding (+N or -N bytes):
|
||||
+150 or -50
|
||||
Payment (optional):
|
||||
eCash token or payment info
|
||||
Audit Tag (auto-generated):
|
||||
ab35d9f342afd9541dac9679dae7a68d79eb52d01e35743d108ce0b4c56facd7
|
||||
Create Bounce 1
|
||||
{
|
||||
"kind": 22222,
|
||||
"content": "AnMH3c...B3LPiw==",
|
||||
"tags": [
|
||||
[
|
||||
"p",
|
||||
"e295a831c9a3ae50da2ca3115f8b13b035805a5ebbbd68d95a1e0caf13bff440"
|
||||
],
|
||||
[
|
||||
"p",
|
||||
"ab35d9f342afd9541dac9679dae7a68d79eb52d01e35743d108ce0b4c56facd7"
|
||||
]
|
||||
],
|
||||
"created_at": 1758196166,
|
||||
"pubkey": "ef4663112f67ab47450605fc33e03f9cf19ddcd4d8ecf83c13bf3ecc9215461d",
|
||||
"id": "1fa0869733fa11781b9130f8392b672e452e5025d7604182f83551542de21517",
|
||||
"sig": "9a0a9deee3971e62deb9ff6974251c8599c4e6fd822bca12f28fe3df1646845fa0537ae5c3764e4227ee76874c233813896ee08a1b11e8b9f6e03192577891e6"
|
||||
}
|
||||
🔓 Decrypt Content
|
||||
|
||||
|
||||
🔓 Decrypted Payload:
|
||||
|
||||
|
||||
{
|
||||
"event": {
|
||||
"kind": 22222,
|
||||
"content": "Aob44...w2at6",
|
||||
"tags": [
|
||||
[
|
||||
"p",
|
||||
"03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25"
|
||||
],
|
||||
[
|
||||
"p",
|
||||
"3413dc76625f59dc88b4ff4c290643110f21208c9f4f99a678a75730fd35cef3"
|
||||
]
|
||||
],
|
||||
"created_at": 1758196144,
|
||||
"pubkey": "acb7a5fe35eb69a0f30e58dc790558a86143d5c489749fe9c4db52bdb3f7b310",
|
||||
"id": "00d7536a425b2d955084f920c45c1d5ddf86b5503374daa02922af60f536b953",
|
||||
"sig": "a2f9ad4f85bda8fc6ddbce28b2773e8938a747964dc278b2e89553666f777e9d27cbf37d6c69a30223dd8e2e2ace3155d31711ebb9b0b7cd0c5d1c92f8ecefec"
|
||||
},
|
||||
"routing": {
|
||||
"relays": [
|
||||
"wss://relay.laantungir.net"
|
||||
],
|
||||
"delay": 10,
|
||||
"audit": "ab35d9f342afd9541dac9679dae7a68d79eb52d01e35743d108ce0b4c56facd7",
|
||||
"p": "03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Process at first bounce pubkey:e295a831c9a3ae50da2ca3115f8b13b035805a5ebbbd68d95a1e0caf13bff440
|
||||
|
||||
7:49:44 AM Successfully processed event 1fa0869733fa1178...
|
||||
7:49:44 AM Forwarded event with audit tag ab35d9f342afd954...
|
||||
7:49:44 AM
|
||||
Full published event:
|
||||
{
|
||||
"kind": 22222,
|
||||
"content": "AtcPM...GGA==",
|
||||
"tags": [
|
||||
[
|
||||
"p",
|
||||
"03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25"
|
||||
],
|
||||
[
|
||||
"p",
|
||||
"ab35d9f342afd9541dac9679dae7a68d79eb52d01e35743d108ce0b4c56facd7"
|
||||
]
|
||||
],
|
||||
"created_at": 1758196183,
|
||||
"pubkey": "c2ff758233b1099682d99687e096859e4f930ea20e73905756166ffdcab9279c",
|
||||
"id": "843d662891c497365d514b995c4135fb0cf080531cda4cef842d396cf0d1c1db",
|
||||
"sig": "765c822b75fe7772e6c10c96e159bc1e64534571d3cd9e6daf25e5276e2a5efdd6dbb3523db75aa1483ca3b1062d8444145b69d0cd0823579980fe5074f8354b"
|
||||
}
|
||||
7:49:44 AM Published to relays: wss://relay.laantungir.net
|
||||
7:49:43 AM
|
||||
Rewrapped event to publish:
|
||||
{
|
||||
"kind": 22222,
|
||||
"content": "AtcPM...GGA==",
|
||||
"tags": [
|
||||
[
|
||||
"p",
|
||||
"03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25"
|
||||
],
|
||||
[
|
||||
"p",
|
||||
"ab35d9f342afd9541dac9679dae7a68d79eb52d01e35743d108ce0b4c56facd7"
|
||||
]
|
||||
],
|
||||
"created_at": 1758196183,
|
||||
"pubkey": "c2ff758233b1099682d99687e096859e4f930ea20e73905756166ffdcab9279c",
|
||||
"id": "843d662891c497365d514b995c4135fb0cf080531cda4cef842d396cf0d1c1db",
|
||||
"sig": "765c822b75fe7772e6c10c96e159bc1e64534571d3cd9e6daf25e5276e2a5efdd6dbb3523db75aa1483ca3b1062d8444145b69d0cd0823579980fe5074f8354b"
|
||||
}
|
||||
7:49:43 AM
|
||||
New payload to encrypt:
|
||||
{
|
||||
"event": {
|
||||
"kind": 22222,
|
||||
"content": "Aob44...w2at6",
|
||||
"tags": [
|
||||
[
|
||||
"p",
|
||||
"03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25"
|
||||
],
|
||||
[
|
||||
"p",
|
||||
"3413dc76625f59dc88b4ff4c290643110f21208c9f4f99a678a75730fd35cef3"
|
||||
]
|
||||
],
|
||||
"created_at": 1758196144,
|
||||
"pubkey": "acb7a5fe35eb69a0f30e58dc790558a86143d5c489749fe9c4db52bdb3f7b310",
|
||||
"id": "00d7536a425b2d955084f920c45c1d5ddf86b5503374daa02922af60f536b953",
|
||||
"sig": "a2f9ad4f85bda8fc6ddbce28b2773e8938a747964dc278b2e89553666f777e9d27cbf37d6c69a30223dd8e2e2ace3155d31711ebb9b0b7cd0c5d1c92f8ecefec"
|
||||
},
|
||||
"routing": {
|
||||
"relays": [
|
||||
"wss://relay.laantungir.net"
|
||||
],
|
||||
"delay": 10,
|
||||
"audit": "ab35d9f342afd9541dac9679dae7a68d79eb52d01e35743d108ce0b4c56facd7",
|
||||
"p": "03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25"
|
||||
}
|
||||
}
|
||||
7:49:43 AM DEBUG Rewrapping: newRouting.p = "03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25" (string)
|
||||
7:49:43 AM Forwarding to next Superball: 03f857567fc96b47...
|
||||
7:49:43 AM DEBUG Will FORWARD event
|
||||
7:49:43 AM DEBUG Decision point - routing.p = "03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25" (string)
|
||||
7:49:43 AM Processing event 1fa0869733fa1178...
|
||||
7:49:33 AM Event queued for processing in 10s: 1fa0869733fa1178...
|
||||
7:49:33 AM DEBUG !routing.p: false
|
||||
7:49:33 AM DEBUG routing.p === null: false
|
||||
7:49:33 AM DEBUG routing.p === undefined: false
|
||||
7:49:33 AM DEBUG routing.p = "03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25" (type: string)
|
||||
7:49:33 AM
|
||||
Decrypted payload:
|
||||
{
|
||||
"event": {
|
||||
"kind": 22222,
|
||||
"content": "Aob44...w2at6",
|
||||
"tags": [
|
||||
[
|
||||
"p",
|
||||
"03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25"
|
||||
],
|
||||
[
|
||||
"p",
|
||||
"3413dc76625f59dc88b4ff4c290643110f21208c9f4f99a678a75730fd35cef3"
|
||||
]
|
||||
],
|
||||
"created_at": 1758196144,
|
||||
"pubkey": "acb7a5fe35eb69a0f30e58dc790558a86143d5c489749fe9c4db52bdb3f7b310",
|
||||
"id": "00d7536a425b2d955084f920c45c1d5ddf86b5503374daa02922af60f536b953",
|
||||
"sig": "a2f9ad4f85bda8fc6ddbce28b2773e8938a747964dc278b2e89553666f777e9d27cbf37d6c69a30223dd8e2e2ace3155d31711ebb9b0b7cd0c5d1c92f8ecefec"
|
||||
},
|
||||
"routing": {
|
||||
"relays": [
|
||||
"wss://relay.laantungir.net"
|
||||
],
|
||||
"delay": 10,
|
||||
"audit": "ab35d9f342afd9541dac9679dae7a68d79eb52d01e35743d108ce0b4c56facd7",
|
||||
"p": "03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25"
|
||||
}
|
||||
}
|
||||
7:49:33 AM Successfully decrypted routing event 1fa0869733fa1178...
|
||||
7:49:33 AM Received routing event: 1fa0869733fa1178...
|
||||
7:49:33 AM
|
||||
Full received event:
|
||||
{
|
||||
"content": "AnMH3...Piw==",
|
||||
"created_at": 1758196166,
|
||||
"id": "1fa0869733fa11781b9130f8392b672e452e5025d7604182f83551542de21517",
|
||||
"kind": 22222,
|
||||
"pubkey": "ef4663112f67ab47450605fc33e03f9cf19ddcd4d8ecf83c13bf3ecc9215461d",
|
||||
"sig": "9a0a9deee3971e62deb9ff6974251c8599c4e6fd822bca12f28fe3df1646845fa0537ae5c3764e4227ee76874c233813896ee08a1b11e8b9f6e03192577891e6",
|
||||
"tags": [
|
||||
[
|
||||
"p",
|
||||
"e295a831c9a3ae50da2ca3115f8b13b035805a5ebbbd68d95a1e0caf13bff440"
|
||||
],
|
||||
[
|
||||
"p",
|
||||
"ab35d9f342afd9541dac9679dae7a68d79eb52d01e35743d108ce0b4c56facd7"
|
||||
]
|
||||
]
|
||||
}
|
||||
7:49:33 AM Received EVENT from wss://relay.laantungir.net: 1fa0869733fa1178...
|
||||
|
||||
|
||||
# Process at second bounce pubkey: 03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25
|
||||
|
||||
7:49:54 AM Forwarded event with audit tag ab35d9f342afd954...
|
||||
7:49:54 AM
|
||||
Full published event:
|
||||
{
|
||||
"kind": 22222,
|
||||
"content": "ArEYH...cAw==",
|
||||
"tags": [
|
||||
[
|
||||
"p",
|
||||
"03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25"
|
||||
],
|
||||
[
|
||||
"p",
|
||||
"ab35d9f342afd9541dac9679dae7a68d79eb52d01e35743d108ce0b4c56facd7"
|
||||
]
|
||||
],
|
||||
"created_at": 1758196194,
|
||||
"pubkey": "76c213037af4de471d6af7fa996f0b02882ccf2606e871f49ebb6dccef7f7642",
|
||||
"id": "ddeebcc4091610ec5c7246a06ebfe31f3539492e273c920e9da5e10816b0d0d1",
|
||||
"sig": "a3845cca91cfa79eb184499350b8f1b2486ee65313371a7b9ca61506cd1abcb684673eefecf9b7b0c17e50a70f4976d750310ef393a77cd69cbe923fa351aa37"
|
||||
}
|
||||
7:49:54 AM Published to relays: wss://relay.laantungir.net
|
||||
7:49:54 AM
|
||||
Rewrapped event to publish:
|
||||
{
|
||||
"kind": 22222,
|
||||
"content": "ArEYH...cAw==",
|
||||
"tags": [
|
||||
[
|
||||
"p",
|
||||
"03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25"
|
||||
],
|
||||
[
|
||||
"p",
|
||||
"ab35d9f342afd9541dac9679dae7a68d79eb52d01e35743d108ce0b4c56facd7"
|
||||
]
|
||||
],
|
||||
"created_at": 1758196194,
|
||||
"pubkey": "76c213037af4de471d6af7fa996f0b02882ccf2606e871f49ebb6dccef7f7642",
|
||||
"id": "ddeebcc4091610ec5c7246a06ebfe31f3539492e273c920e9da5e10816b0d0d1",
|
||||
"sig": "a3845cca91cfa79eb184499350b8f1b2486ee65313371a7b9ca61506cd1abcb684673eefecf9b7b0c17e50a70f4976d750310ef393a77cd69cbe923fa351aa37"
|
||||
}
|
||||
7:49:54 AM
|
||||
New payload to encrypt:
|
||||
{
|
||||
"event": {
|
||||
"kind": 22222,
|
||||
"content": "Aob44...w2at6",
|
||||
"tags": [
|
||||
[
|
||||
"p",
|
||||
"03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25"
|
||||
],
|
||||
[
|
||||
"p",
|
||||
"3413dc76625f59dc88b4ff4c290643110f21208c9f4f99a678a75730fd35cef3"
|
||||
]
|
||||
],
|
||||
"created_at": 1758196144,
|
||||
"pubkey": "acb7a5fe35eb69a0f30e58dc790558a86143d5c489749fe9c4db52bdb3f7b310",
|
||||
"id": "00d7536a425b2d955084f920c45c1d5ddf86b5503374daa02922af60f536b953",
|
||||
"sig": "a2f9ad4f85bda8fc6ddbce28b2773e8938a747964dc278b2e89553666f777e9d27cbf37d6c69a30223dd8e2e2ace3155d31711ebb9b0b7cd0c5d1c92f8ecefec"
|
||||
},
|
||||
"routing": {
|
||||
"relays": [
|
||||
"wss://relay.laantungir.net"
|
||||
],
|
||||
"delay": 10,
|
||||
"audit": "ab35d9f342afd9541dac9679dae7a68d79eb52d01e35743d108ce0b4c56facd7",
|
||||
"p": "03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25"
|
||||
}
|
||||
}
|
||||
7:49:54 AM DEBUG Rewrapping: newRouting.p = "03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25" (string)
|
||||
7:49:54 AM Forwarding to next Superball: 03f857567fc96b47...
|
||||
7:49:54 AM DEBUG Will FORWARD event
|
||||
7:49:54 AM DEBUG Decision point - routing.p = "03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25" (string)
|
||||
7:49:54 AM Processing event 843d662891c49736...
|
||||
7:49:44 AM Event queued for processing in 10s: 843d662891c49736...
|
||||
7:49:44 AM DEBUG !routing.p: false
|
||||
7:49:44 AM DEBUG routing.p === null: false
|
||||
7:49:44 AM DEBUG routing.p === undefined: false
|
||||
7:49:44 AM DEBUG routing.p = "03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25" (type: string)
|
||||
7:49:44 AM
|
||||
Decrypted payload:
|
||||
{
|
||||
"event": {
|
||||
"kind": 22222,
|
||||
"content": "Aob44...w2at6",
|
||||
"tags": [
|
||||
[
|
||||
"p",
|
||||
"03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25"
|
||||
],
|
||||
[
|
||||
"p",
|
||||
"3413dc76625f59dc88b4ff4c290643110f21208c9f4f99a678a75730fd35cef3"
|
||||
]
|
||||
],
|
||||
"created_at": 1758196144,
|
||||
"pubkey": "acb7a5fe35eb69a0f30e58dc790558a86143d5c489749fe9c4db52bdb3f7b310",
|
||||
"id": "00d7536a425b2d955084f920c45c1d5ddf86b5503374daa02922af60f536b953",
|
||||
"sig": "a2f9ad4f85bda8fc6ddbce28b2773e8938a747964dc278b2e89553666f777e9d27cbf37d6c69a30223dd8e2e2ace3155d31711ebb9b0b7cd0c5d1c92f8ecefec"
|
||||
},
|
||||
"routing": {
|
||||
"relays": [
|
||||
"wss://relay.laantungir.net"
|
||||
],
|
||||
"delay": 10,
|
||||
"audit": "ab35d9f342afd9541dac9679dae7a68d79eb52d01e35743d108ce0b4c56facd7",
|
||||
"p": "03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25"
|
||||
}
|
||||
}
|
||||
7:49:44 AM Successfully decrypted routing event 843d662891c49736...
|
||||
7:49:44 AM Received routing event: 843d662891c49736...
|
||||
7:49:44 AM
|
||||
Full received event:
|
||||
{
|
||||
"content": "AtcPM...GGA==",
|
||||
"created_at": 1758196183,
|
||||
"id": "843d662891c497365d514b995c4135fb0cf080531cda4cef842d396cf0d1c1db",
|
||||
"kind": 22222,
|
||||
"pubkey": "c2ff758233b1099682d99687e096859e4f930ea20e73905756166ffdcab9279c",
|
||||
"sig": "765c822b75fe7772e6c10c96e159bc1e64534571d3cd9e6daf25e5276e2a5efdd6dbb3523db75aa1483ca3b1062d8444145b69d0cd0823579980fe5074f8354b",
|
||||
"tags": [
|
||||
[
|
||||
"p",
|
||||
"03f857567fc96b47b68632457a818563c53e09aaf0028ac1081450afe3352e25"
|
||||
],
|
||||
[
|
||||
"p",
|
||||
"ab35d9f342afd9541dac9679dae7a68d79eb52d01e35743d108ce0b4c56facd7"
|
||||
]
|
||||
]
|
||||
}
|
||||
7:49:44 AM Received EVENT from wss://relay.laantungir.net: 843d662891c49736...
|
||||
190
web/login-and-profile.html
Normal file
190
web/login-and-profile.html
Normal file
@@ -0,0 +1,190 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>🔐 NOSTR_LOGIN_LITE - All Login Methods Test</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background: #ffffff;
|
||||
min-height: 100vh;
|
||||
color: #000000;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="login-section">
|
||||
<!-- Login UI if needed -->
|
||||
</div>
|
||||
<div id="profile-section">
|
||||
<img id="profile-picture">
|
||||
<div id="profile-pubkey"></div>
|
||||
<div id="profile-name"></div>
|
||||
<div id="profile-about"></div>
|
||||
</div>
|
||||
|
||||
<!-- Load the official nostr-tools bundle first -->
|
||||
<script src="../lite/nostr.bundle.js"></script>
|
||||
|
||||
<!-- Load NOSTR_LOGIN_LITE main library (now includes NIP-46 extension) -->
|
||||
<script src="../lite/nostr-lite.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
// Global variables
|
||||
let nlLite = null;
|
||||
let userPubkey = null;
|
||||
let relayUrl = 'wss://relay.laantungir.net';
|
||||
|
||||
// Initialize NOSTR_LOGIN_LITE
|
||||
async function initializeApp() {
|
||||
// console.log('INFO', 'Initializing NOSTR_LOGIN_LITE...');
|
||||
|
||||
try {
|
||||
await window.NOSTR_LOGIN_LITE.init({
|
||||
theme: 'default',
|
||||
darkMode: false,
|
||||
methods: {
|
||||
extension: true,
|
||||
local: true,
|
||||
seedphrase: true,
|
||||
connect: true, // Enables "Nostr Connect" (NIP-46)
|
||||
remote: true, // Also needed for "Nostr Connect" compatibility
|
||||
otp: true // Enables "DM/OTP"
|
||||
},
|
||||
floatingTab: {
|
||||
enabled: true,
|
||||
hPosition: .98, // 95% from left
|
||||
vPosition: 0, // 50% from top (center)
|
||||
getUserInfo: true, // Fetch user profiles
|
||||
getUserRelay: ['wss://relay.laantungir.net'], // Custom relays for profiles
|
||||
appearance: {
|
||||
style: 'minimal',
|
||||
theme: 'auto',
|
||||
icon: '',
|
||||
text: 'Login',
|
||||
iconOnly: false
|
||||
},
|
||||
behavior: {
|
||||
hideWhenAuthenticated: false,
|
||||
showUserInfo: true,
|
||||
autoSlide: false,
|
||||
persistent: false
|
||||
},
|
||||
animation: {
|
||||
slideDirection: 'right' // Slide to the right when hiding
|
||||
}
|
||||
},
|
||||
debug: true
|
||||
});
|
||||
|
||||
nlLite = window.NOSTR_LOGIN_LITE;
|
||||
console.log('SUCCESS', 'NOSTR_LOGIN_LITE initialized successfully');
|
||||
|
||||
window.addEventListener('nlMethodSelected', handleAuthEvent);
|
||||
|
||||
} catch (error) {
|
||||
console.log('ERROR', `Initialization failed: ${error.message}`);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function handleAuthEvent(event) {
|
||||
const { pubkey, method, error } = event.detail;
|
||||
console.log('INFO', `Auth event received: method=${method}`);
|
||||
|
||||
if (method && pubkey) {
|
||||
userPubkey = pubkey;
|
||||
console.log('SUCCESS', `Login successful! Method: ${method}, Pubkey: ${pubkey}`);
|
||||
|
||||
loadUserProfile();
|
||||
|
||||
} else if (error) {
|
||||
console.log('ERROR', `Authentication error: ${error}`);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Load user profile using nostr-tools pool
|
||||
async function loadUserProfile() {
|
||||
if (!userPubkey) return;
|
||||
|
||||
console.log('INFO', `Loading profile for: ${userPubkey}`);
|
||||
document.getElementById('profile-name').textContent = 'Loading profile...';
|
||||
document.getElementById('profile-pubkey').textContent = userPubkey;
|
||||
|
||||
try {
|
||||
// Create a SimplePool instance
|
||||
const pool = new window.NostrTools.SimplePool();
|
||||
const relays = [relayUrl, 'wss://relay.laantungir.net'];
|
||||
|
||||
// Get profile event (kind 0) for the user using querySync
|
||||
const events = await pool.querySync(relays, {
|
||||
kinds: [0],
|
||||
authors: [userPubkey],
|
||||
limit: 1
|
||||
});
|
||||
|
||||
pool.close(relays); // Clean up connections
|
||||
|
||||
if (events.length > 0) {
|
||||
console.log('SUCCESS', 'Profile event received');
|
||||
const profile = JSON.parse(events[0].content);
|
||||
displayProfile(profile);
|
||||
} else {
|
||||
console.log('INFO', 'No profile found');
|
||||
document.getElementById('profile-name').textContent = 'No profile found';
|
||||
document.getElementById('profile-about').textContent = 'User has not set up a profile yet.';
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.log('ERROR', `Profile loading failed: ${error.message}`);
|
||||
document.getElementById('profile-name').textContent = 'Error loading profile';
|
||||
document.getElementById('profile-about').textContent = error.message;
|
||||
}
|
||||
}
|
||||
|
||||
// Display profile data
|
||||
function displayProfile(profile) {
|
||||
const name = profile.name || profile.display_name || profile.displayName || 'Anonymous User';
|
||||
const about = profile.about || '';
|
||||
const picture = profile.picture || '';
|
||||
|
||||
document.getElementById('profile-name').textContent = name;
|
||||
document.getElementById('profile-about').textContent = about;
|
||||
|
||||
if (picture) {
|
||||
document.getElementById('profile-picture').src = picture;
|
||||
}
|
||||
|
||||
console.log('SUCCESS', `Profile displayed: ${name}`);
|
||||
}
|
||||
|
||||
// Logout function
|
||||
async function logout() {
|
||||
console.log('INFO', 'Logging out...');
|
||||
try {
|
||||
await nlLite.logout();
|
||||
console.log('SUCCESS', 'Logged out successfully');
|
||||
} catch (error) {
|
||||
console.log('ERROR', `Logout failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Initialize the app
|
||||
setTimeout(initializeApp, 100);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
3190
web/nostr-lite.js
Normal file
3190
web/nostr-lite.js
Normal file
File diff suppressed because it is too large
Load Diff
11534
web/nostr.bundle.js
Normal file
11534
web/nostr.bundle.js
Normal file
File diff suppressed because it is too large
Load Diff
184
web/sign.html
Normal file
184
web/sign.html
Normal file
@@ -0,0 +1,184 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>NIP-07 Signing Test</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<div id="status"></div>
|
||||
|
||||
<div id="test-section" style="display:none;">
|
||||
<button id="sign-button">Sign Event</button>
|
||||
<button id="encrypt-button">Test NIP-04 Encrypt</button>
|
||||
<button id="decrypt-button">Test NIP-04 Decrypt</button>
|
||||
<div id="results"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="../lite/nostr.bundle.js"></script>
|
||||
<script src="../lite/nostr-lite.js"></script>
|
||||
|
||||
<script>
|
||||
let testPubkey = 'npub1damus9dqe7g7jqn45kjcjgsv0vxjqnk8cxjkf8gqjwm8t8qjm7cqm3z7l';
|
||||
let ciphertext = '';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
await window.NOSTR_LOGIN_LITE.init({
|
||||
theme: 'default',
|
||||
methods: {
|
||||
extension: true,
|
||||
local: true,
|
||||
readonly: true,
|
||||
connect: true,
|
||||
remote: true,
|
||||
otp: true
|
||||
},
|
||||
floatingTab: {
|
||||
enabled: true,
|
||||
hPosition: 1, // 0.0-1.0 or '95%' from left
|
||||
vPosition: 0, // 0.0-1.0 or '50%' from top
|
||||
appearance: {
|
||||
style: 'pill', // 'pill', 'square', 'circle', 'minimal'
|
||||
icon: '', // Clean display without icon placeholders
|
||||
text: 'Login'
|
||||
},
|
||||
behavior: {
|
||||
hideWhenAuthenticated: false,
|
||||
showUserInfo: true,
|
||||
autoSlide: true
|
||||
},
|
||||
getUserInfo: true, // Enable profile fetching
|
||||
getUserRelay: [ // Specific relays for profile fetching
|
||||
'wss://relay.laantungir.net'
|
||||
]
|
||||
}});
|
||||
|
||||
|
||||
// document.getElementById('login-button').addEventListener('click', () => {
|
||||
// window.NOSTR_LOGIN_LITE.launch('login');
|
||||
// });
|
||||
|
||||
window.addEventListener('nlMethodSelected', (event) => {
|
||||
document.getElementById('status').textContent = `Authenticated with: ${event.detail.method}`;
|
||||
document.getElementById('test-section').style.display = 'block';
|
||||
});
|
||||
|
||||
document.getElementById('sign-button').addEventListener('click', testSigning);
|
||||
document.getElementById('encrypt-button').addEventListener('click', testEncryption);
|
||||
document.getElementById('decrypt-button').addEventListener('click', testDecryption);
|
||||
});
|
||||
|
||||
async function testSigning() {
|
||||
try {
|
||||
console.log('=== DEBUGGING SIGN EVENT START ===');
|
||||
console.log('testSigning: window.nostr is:', window.nostr);
|
||||
console.log('testSigning: window.nostr constructor:', window.nostr?.constructor?.name);
|
||||
console.log('testSigning: window.nostr === our facade?', window.nostr?.constructor?.name === 'WindowNostr');
|
||||
|
||||
// Get user public key for comparison
|
||||
const userPubkey = await window.nostr.getPublicKey();
|
||||
console.log('User public key:', userPubkey);
|
||||
|
||||
// Check auth state if our facade
|
||||
if (window.nostr?.constructor?.name === 'WindowNostr') {
|
||||
console.log('WindowNostr authState:', window.nostr.authState);
|
||||
console.log('WindowNostr authenticatedExtension:', window.nostr.authenticatedExtension);
|
||||
console.log('WindowNostr existingNostr:', window.nostr.existingNostr);
|
||||
}
|
||||
|
||||
const event = {
|
||||
kind: 1,
|
||||
content: 'Hello from NIP-07!',
|
||||
tags: [],
|
||||
created_at: Math.floor(Date.now() / 1000)
|
||||
};
|
||||
|
||||
console.log('=== EVENT BEING SENT TO EXTENSION ===');
|
||||
console.log('Event object:', JSON.stringify(event, null, 2));
|
||||
console.log('Event keys:', Object.keys(event));
|
||||
console.log('Event kind type:', typeof event.kind, event.kind);
|
||||
console.log('Event content type:', typeof event.content, event.content);
|
||||
console.log('Event tags type:', typeof event.tags, event.tags);
|
||||
console.log('Event created_at type:', typeof event.created_at, event.created_at);
|
||||
console.log('Event created_at value:', event.created_at);
|
||||
|
||||
// Check if created_at is within reasonable bounds
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const timeDiff = Math.abs(event.created_at - now);
|
||||
console.log('Time difference from now (seconds):', timeDiff);
|
||||
console.log('Event timestamp as Date:', new Date(event.created_at * 1000));
|
||||
|
||||
// Additional debugging for user-specific issues
|
||||
console.log('=== USER-SPECIFIC DEBUG INFO ===');
|
||||
console.log('User pubkey length:', userPubkey?.length);
|
||||
console.log('User pubkey format check (hex):', /^[a-fA-F0-9]{64}$/.test(userPubkey));
|
||||
|
||||
// Try to get user profile info if available
|
||||
try {
|
||||
const profileEvent = {
|
||||
kinds: [0],
|
||||
authors: [userPubkey],
|
||||
limit: 1
|
||||
};
|
||||
console.log('Would query profile with filter:', profileEvent);
|
||||
} catch (profileErr) {
|
||||
console.log('Profile query setup failed:', profileErr);
|
||||
}
|
||||
|
||||
console.log('=== ABOUT TO CALL EXTENSION SIGN EVENT ===');
|
||||
const signedEvent = await window.nostr.signEvent(event);
|
||||
|
||||
console.log('=== SIGN EVENT SUCCESSFUL ===');
|
||||
console.log('Signed event:', JSON.stringify(signedEvent, null, 2));
|
||||
console.log('Signed event keys:', Object.keys(signedEvent));
|
||||
console.log('Signature present:', !!signedEvent.sig);
|
||||
console.log('ID present:', !!signedEvent.id);
|
||||
console.log('Pubkey matches user:', signedEvent.pubkey === userPubkey);
|
||||
|
||||
document.getElementById('results').innerHTML = `<h3>Signed Event:</h3><pre>${JSON.stringify(signedEvent, null, 2)}</pre>`;
|
||||
|
||||
console.log('=== DEBUGGING SIGN EVENT END ===');
|
||||
} catch (error) {
|
||||
console.error('=== SIGN EVENT ERROR ===');
|
||||
console.error('Error message:', error.message);
|
||||
console.error('Error stack:', error.stack);
|
||||
console.error('Error object:', error);
|
||||
|
||||
document.getElementById('results').innerHTML = `<h3>Sign Error:</h3><pre>${error.message}</pre><pre>${error.stack}</pre>`;
|
||||
}
|
||||
}
|
||||
|
||||
async function testEncryption() {
|
||||
try {
|
||||
const plaintext = 'Secret message for testing';
|
||||
const pubkey = await window.nostr.getPublicKey();
|
||||
|
||||
ciphertext = await window.nostr.nip04.encrypt(pubkey, plaintext);
|
||||
document.getElementById('results').innerHTML = `<h3>Encrypted:</h3><pre>${ciphertext}</pre>`;
|
||||
} catch (error) {
|
||||
document.getElementById('results').innerHTML = `<h3>Encrypt Error:</h3><pre>${error.message}</pre>`;
|
||||
}
|
||||
}
|
||||
|
||||
async function testDecryption() {
|
||||
try {
|
||||
if (!ciphertext) {
|
||||
document.getElementById('results').innerHTML = `<h3>Decrypt Error:</h3><pre>No ciphertext available. Run encrypt first.</pre>`;
|
||||
return;
|
||||
}
|
||||
|
||||
const pubkey = await window.nostr.getPublicKey();
|
||||
const decrypted = await window.nostr.nip04.decrypt(pubkey, ciphertext);
|
||||
document.getElementById('results').innerHTML = `<h3>Decrypted:</h3><pre>${decrypted}</pre>`;
|
||||
} catch (error) {
|
||||
document.getElementById('results').innerHTML = `<h3>Decrypt Error:</h3><pre>${error.message}</pre>`;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
1110
web/superball-builder.html
Normal file
1110
web/superball-builder.html
Normal file
File diff suppressed because it is too large
Load Diff
1337
web/superball.html
Normal file
1337
web/superball.html
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user