Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NIP-101 - Decentralized Trust System for Nostr #1718

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
f81e90e
NostrReAction - v0.1
papiche Jan 21, 2025
9138520
more descriptive variable names
papiche Jan 21, 2025
b4a7340
NIP 100 NostrReAction protocol with code examples
papiche Jan 21, 2025
398e6fb
code implementation examples
papiche Jan 21, 2025
e9770de
exploring NIP100
papiche Jan 21, 2025
272e30f
Please review and comment
papiche Jan 21, 2025
dcc9900
add language and validate / refuse
papiche Jan 21, 2025
c303e20
The key here is to see content not as static, but as a flow, an evolu…
papiche Jan 21, 2025
c1f9943
please review
papiche Jan 21, 2025
33326f2
WORK IN PROGRESS
papiche Jan 21, 2025
28efd22
demo
papiche Jan 21, 2025
0584b52
Tags
papiche Jan 21, 2025
37a5321
NIP 100 TAgs
papiche Jan 21, 2025
a0f5b3a
~NostrReAction - Unified Interactions and Content Evolution~
papiche Jan 21, 2025
d5c912b
introduce fork
papiche Jan 21, 2025
35cc648
extended version
papiche Jan 22, 2025
7fc635f
NIP-101: Decentralized Trust System for Nostr
papiche Jan 28, 2025
491a6f9
101 a proposal designed to improve content filtering and moderation o…
papiche Jan 28, 2025
be73672
This change aligns the structure with existing Nostr conventions for …
papiche Jan 28, 2025
8207920
target -> p., related_event -> e.
papiche Jan 28, 2025
f90f58c
toms_wot.py
papiche Jan 28, 2025
b7ca654
Adapt your formula
papiche Jan 29, 2025
af1b7c3
```trust(B) = Square_Root(trust(A,B) * trust(User,A))```
papiche Jan 29, 2025
36abe6e
Lets' try it out
papiche Jan 30, 2025
2c65e06
Added "lang" for categories relevant tags interpretation
papiche Feb 1, 2025
9073be7
Merge branch 'master' into NIP-101
papiche Feb 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
293 changes: 293 additions & 0 deletions 101.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
# NIP-101: Decentralized Trust System for Nostr

## Abstract

This NIP proposes a **Decentralized Trust System** for the Nostr protocol, allowing users to enhance their social feed experience by filtering content based on trust ratings. The system mirrors real-world trust relationships, helping reduce spam, trolling, and misinformation without central control or opaque algorithms.

## Motivation

While Nostr's decentralized architecture empowers users, it also lacks a scalable, decentralized moderation mechanism. The current reliance on manual blocklists and follow lists is limited. This NIP introduces a trust-based model that enhances feed quality by prioritizing content from trusted individuals and networks.

## Specification

### 1. New Event Kind: `Trust Rating` (Kind 33)

A new event kind is introduced to facilitate trust ratings:

- **Event structure:**
```json
{
"kind": 33,
"content": "", // Content remains empty
"tags": [
["p", "public key of the user being rated"],
["rating", "numerical value between -100 and 100"],
["e", "id of triggering event (optional)"],
["category", "trust category (optional)"],
["lang", "language (optional)"]
],
"pubkey": "public key of the rater",
"sig": "signature of the rater"
}
```

- **Field Descriptions:**
- `kind`: Event kind (33 for trust ratings).
- `content`: Unused; remains an empty string.
- `tags`: Contains trust-related metadata:
- `["p", "<target_pubkey>"]`: The public key of the user being rated.
- `["rating", "<-100 to 100>"]`: The numerical trust rating.
- `["e", "<event_id>"]` (optional): The ID of the event triggering the rating.
- `["category", "<category>"]` (optional): An optional trust category for context.
- `["lang", "<language>"]` (optional): An optional language for category.
- `pubkey`: The public key of the user issuing the trust rating.
- `sig`: The cryptographic signature of the event, ensuring authenticity.


### 2. Trust Calculation (Client-Side)

Trust scores are calculated dynamically based on direct and indirect relationships:

- **Direct ratings:** The score provided directly by the user.
- **Indirect ratings:** Calculated using:

![](https://ipfs.copylaradio.com/ipfs/QmPtQxDk8pc8aGBwWNs38nTVP2Zg8Cb8Ag9s4xb35NtL93)

```trust(B) = Square_Root(trust(A,B) * trust(User,A))```

- **trust(A,B)**: Trust rating given by user ( A ) to ( B ).
- **trust(User,A)**: Trust rating given by the current User to ( A ).
- Negative ratings are ignored for indirect calculations.
- Trust is averaged if multiple paths exist between users.

Users can configure the depth of the trust network (friends, friends of friends, etc.) and thresholds for ratings.

### 3. Feed Filtering (Client-Side)

- Users define a trust threshold (e.g., -100 to 100) for displaying events.
- Content from users below the threshold is hidden by default, with an option to explore hidden content.

### 4. User Interface

Clients implementing this system should provide:
- **Trust/Distrust Buttons**: For rating users or content.
- **Trust Scores**: Displayed for users, configurable by category.
- **Import/Export Tools**: To manage trust lists.
- **Trust Network Visualization**: Interactive diagrams to understand trust relationships.

## Rationale

- **Decentralization:** Users manage their trust network without relying on centralized entities.
- **Transparency:** All ratings are public and verifiable.
- **Customization:** Each user can tailor their experience to their preferences.
- **Real-world analogy:** Mirrors trust in real-life relationships, fostering organic moderation.

## Compatibility

This system integrates seamlessly with existing Nostr clients by introducing a new event kind. Clients not implementing it will simply ignore Kind 33 events.

## Potential Applications

- **Spam Reduction:** Filter out spam and low-quality content.
- **Personalized Feeds:** Prioritize relevant and meaningful content.
- **Community Building:** Create shared trust networks for specific groups.
- **News Verification:** Utilize trusted entities for fact-checking and labeling.

## Security and Privacy

- **Integrity:** Trust ratings are signed by their authors, ensuring authenticity.
- **Public Nature:** Ratings are public by design. Users retain control over how they interpret and use these ratings.

## Advantages

- **Decentralized Moderation:** No central authority required.
- **Scalability:** The trust system grows organically with the network.
- **Resilience:** Hard for bad actors to manipulate due to multiple trust layers.

## Disadvantages

- **Echo Chambers:** Users might over-filter their feeds, reducing diversity.
- **Complexity:** Requires education to prevent misuse or bias-driven ratings.

## Alternatives

- **Blocklists:** Effective for basic use but lack flexibility for nuanced moderation.
- **Follow Lists:** Useful but limited for filtering unknown users.

This system enhances these approaches by creating an organic, decentralized trust network.

## Implementation Reference
- **Code Repo (current implementation)**: [NIP-101 Implementation on Github](https://github.com/papiche/NIP-101)
- **Demo Implementation:** [Decentralized Trust Demo](https://github.com/adecentworld/decentralized-trust-demo)
- **Source Article** : [A Trust and Moderation System for the Decentralized Web](https://web.archive.org/web/20230324134924/https://adecentralizedworld.com/2020/06/a-trust-and-moderation-system-for-the-decentralized-web/)

### Python Demo Code

```python
import math

def calculate_trust(target_user, friend_ratings, all_ratings):
"""
Calculate the trust score for a target user based on direct and indirect trust ratings.

Args:
target_user (str): The public key of the user whose trust score is being calculated.
friend_ratings (dict): Direct trust ratings given by the current user to their friends.
all_ratings (dict): A nested dictionary containing trust ratings between all users (e.g., friend-of-friend ratings).

Returns:
float: The calculated trust score for the target user.
"""
trust_score = 0.0
weight_sum = 0.0

for friend, direct_rating in friend_ratings.items():
if friend in all_ratings and target_user in all_ratings[friend]:
mutual_rating = all_ratings[friend][target_user]
if mutual_rating > 0: # Ignore negative ratings for this calculation
weighted_trust = direct_rating * mutual_rating
trust_score += weighted_trust
weight_sum += abs(direct_rating) # Weight contributions by the strength of direct trust

if weight_sum == 0:
return 0.0 # No valid trust path to target user
return math.sqrt(trust_score / weight_sum)


# Example Data
all_ratings = {
"tom": { # Tom's direct ratings
"alice": 80,
"mike": 50
},
"alice": { # Alice's ratings of others
"jeremy": 30,
"sophie": -10,
"dave": 15
},
"mike": { # Mike's ratings of others
"jeremy": 20,
"sophie": 25
}
}

# Direct ratings from Tom
friend_ratings = all_ratings["tom"]

# Calculate trust scores for specific users
for user in ["jeremy", "sophie", "dave"]:
trust = calculate_trust(user, friend_ratings, all_ratings)
print(f"Tom's calculated trust score for {user}: {trust:.2f}")

```

### Extended Formula and Use Cases

**The formula `trust(B)=math.sqrt(trust(A,B)×trust(User,A))` is intended as a simple example for calculating trust.**
Clients are not bound to use this algorithm but are encouraged to use the kind 33 to build their own custom models.
The following extended section is intended to showcase the potential of using the kind 33 event,
and illustrate how clients could customize the formula or take into account other factors.

**Use Case 1: Personalized Feed Filtering**

In a typical social media scenario, users may wish to prioritize content from specific trusted users.
Clients can implement the above formula, but also adjust the way trust is calculated or displayed:

- **Category:** Use `category="friend"` to compute the trust only using close friends.
- **Depth:** Limit calculation to one degree of separation (direct friends) for increased relevance and decreased network weight.
- **Boost:** Boost users who frequently interact with the current user by adding +10 for each reply, +20 for each like, +50 for every zap. The score must be capped at 100.
- **UX:** Clients could use a simplified "Trust Signal" system, as displayed below.

| Mood Level | Meaning | Trust Value (Internal) |
|----------------|----------------------------|-----------------------|
| ❤️ Love | Fully trust & endorse | `+100` |
| 😊 Positive | Positive opinion | `+50` |
| 👍 Like | Good opinion | `+25` |
| 😐 Distrust | Cautious, minor distrust | `-25` |
| 😠 Dislike | Strong distrust | `-50` |
| 🤬 Hate | Fully untrusted, block | `-100` |


**Use Case 2: Contextual Filtering**

To filter content within a specific category, or filter specific types of content :

* **Categories:** Filter by `category="news"`, `category="music"`, or `category="video"` to prioritize content.
* **Language:** Filter by `lang="fr"` to show language relevant categories.
* **Context-Aware Filtering:** Combine scores with keywords, tags, or user settings to match the current context.
* **Algorithme :** The formula `trust(B)=math.sqrt(trust(A,B)×trust(User,A))` can be changed to only take into account direct friends, or if they are tagged using a specific keyword.
* **UX:** Show the user the category of content being filtered, and give them easy controls on how to tweak it.

The following JavaScript code snippet demonstrates how a client can calculate a relative trust score and display it to the user, it fetches the last rating given to a user, it calculates an average score, filtered by a category, and shows it on the UI.

```javascript
async function calculateRelativeTrustScore(targetPubKey, selectedCategory) {
return new Promise(async (resolve, reject) => {
let filter = {
kinds: [33],
"#p": [targetPubKey]
};
if (selectedCategory !== 'all' && selectedCategory !== 'general') {
filter["#category"] = [selectedCategory];
}

relay.send(JSON.stringify(["REQ", trustReqId, filter]));

let ratings = new Map();

relay.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data[0] === "EVENT") {
const event = data[2];
let rating = null;
event.tags.forEach(tag => {
if(tag[0] === 'rating'){
rating = parseFloat(tag[1])
}
});
if (rating !== null) {
ratings.set(event.pubkey, rating) // store ratings by authors, overwriting old values with new ones.
}
}
if (data[0] === "EOSE") {
let averageRating = null;
if (ratings.size > 0) {
const sum = Array.from(ratings.values()).reduce((acc, rating) => acc + rating, 0);
averageRating = sum / ratings.size;
}
resolve(averageRating)
}
}
relay.onerror = (error) => {
reject(error)
};
});
}

// Example of use
const myPubKey = "c81e8b31dbac658a3f53cf57521d75c1035129c7ae80b364dcc5204b96f4657d"
const targetPubKey = "72a89258afb5a6ea94b6e680597bd049a2739f2448d4fb01439793444f6700d2"
const category = "news"
calculateRelativeTrustScore(targetPubKey, category).then(score => {
if (score !== null) {
console.log(`The relative trust score of ${targetPubKey} from ${myPubKey} in the category ${category} is ${score.toFixed(2)}`);
// You could show that on the UI like this: document.getElementById('trustScore').textContent = `Score: ${score.toFixed(2)}`
} else {
console.log("No score found")
// document.getElementById('trustScore').textContent = 'N/A'
}
})

```

## Conclusion

This proposal introduces a decentralized, flexible, and user-driven trust system that empowers everyone
on Nostr to take control of their social experience.
By adopting this system, users can filter out spam, reduce misinformation, and engage in more meaningful
conversations—without compromising the open and decentralized principles of the network.

We encourage developers, relay operators, and Nostr users to explore and implement this proposal.
By participating, you can help shape a safer, more collaborative, and vibrant Nostr ecosystem.
The more people adopt this trust system, the more powerful and refined the network becomes.
Lets' try it out and see how it transforms our experience on Nostr!
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
- [NIP-08: Handling Mentions](08.md) --- **unrecommended**: deprecated in favor of [NIP-27](27.md)
- [NIP-09: Event Deletion Request](09.md)
- [NIP-10: Text Notes and Threads](10.md)
- [NIP-101: Decentralized Trust System for Nostr](101.md)
- [NIP-11: Relay Information Document](11.md)
- [NIP-13: Proof of Work](13.md)
- [NIP-14: Subject tag in text events](14.md)
Expand Down Expand Up @@ -124,6 +125,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
| `20` | Picture | [68](68.md) |
| `21` | Video Event | [71](71.md) |
| `22` | Short-form Portrait Video Event | [71](71.md) |
| `33` | Trust Rating | [101](101.md) |
| `40` | Channel Creation | [28](28.md) |
| `41` | Channel Metadata | [28](28.md) |
| `42` | Channel Message | [28](28.md) |
Expand Down Expand Up @@ -336,6 +338,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
| `tracker` | torrent tracker URL | -- | [35](35.md) |
| `web` | webpage URL | -- | [34](34.md) |
| `zap` | pubkey (hex), relay URL | weight | [57](57.md) |
|

Please update these lists when proposing new NIPs.

Expand Down