# 解读Damus和去中心化社交协议Nostr

By [zhongxuqi](https://paragraph.com/@zhongxuqi) · 2023-02-21

---

近期damus社交软件大火，作为web3赛道率先上线app store的应用，很快引起了圈内圈外人士的关注。那么不少会有一个疑问，同样作为社交软件，web3赛道的damus相比于web2赛道的twitter和微博有什么优势，用户为什么要迁移到web3社交产品呢？ 首先，看下damus官方给出的web2社交的一些关键问题：

1.  web2社交有广告，比如twitter上经常会看到一些广告，非常影响用户体验。
    
2.  web2社交会使用一些推荐技术让用户上瘾，比如twitter、tiktok都有自己的推荐算法，推荐算法会根据用户喜好不断推荐一些类似的内容，吸引用户留存。
    
3.  web2产品能封禁用户，比如特朗普的twitter账户就曾被twitter封禁。
    
4.  web2产品能对用户限流，导致用户的推文无法被其它用户看到。
    
5.  web2产品有很多垃圾信息。
    

上述问题导致web2产品无法实现真正的言论自由，根本原因在于web2产品是有专门中心化的公司和机构运营和维护，而且永远无法被替换。这些公司和机构为了盈利的目的，会破坏社交软件的言论自由。 为了实现真正的言论自由，web3就是一个很好的技术发展方向。web3的任何产品都不会由中心化的机构和公司来维护和运营，全靠社区和用户自主来维护，而且产品的代码也是开源的，任何人都可以下载阅读并参与开发。 那么Damus是如何做到的呢？那就不得不说一下它背后的去中心化社交协议Nostr了。打个比方，如果说Damus是一个大楼，那么nostr就是这个大楼的地基。

技术原理
----

#### Nostr是什么

Nostr是一个p2p的社交网络协议，基于密码学的公钥私钥和签名技术，并且不需要依赖任何的中心化服务器。

### Nostr是如何工作的

Nostr网络由client和relay两个角色组成，用户运行client（比如手机上运行damus客户端），任何个人或者机构都可以运行relay。

![](https://storage.googleapis.com/papyrus_images/1957b056c139da78780ac1447306ea3d2e68f686a63151a1337578c95b6e92a4.png)

发送推文流程

1.  第一步，用户使用客服端需要先生成[公钥私钥](https://zh.wikipedia.org/zh-hans/%E5%85%AC%E5%BC%80%E5%AF%86%E9%92%A5%E5%8A%A0%E5%AF%86)，私钥相当于用户身份，不能对外公开。
    
2.  第二步，用户在客户端提交推文内容，client会用私钥对推文内容进行签名，
    
3.  第三步，client会把推文、公钥和签名发送到配置好的relay，relay会用公钥校验签名正确性。 推文内容格式为
    

    {
      "id": "<消息ID>",
      "pubkey": "<用户公钥>",
      "created_at": "<创建时间>",
      "kind": "<消息类型>",
      "tags": [ // <用于订阅规则过滤>
        ["e", "<其它推文ID>", "<推荐relay地址>"],
        ["p", "<公钥>", "<推荐relay地址>"]
        ... // other kinds of tags may be included later
      ],
      "content": "<推文内容>",
      "sig": "<私钥签名>"
    }
    

其中，`id=sha256(JSON.stringify[0,pubkey,created_at,kind,tags,content])`，`sig=seckey.sign(id)`

接收推文流程

1.  第一步，用户通过client发送推文订阅消息到relay。订阅消息格式为
    

    ["REQ", "<subscription_id>", {
      "ids": "<消息ID json array>",
      "authors": "<被订阅用户的pubkey json array>",
      "kinds": "<消息类型 json array>",
      "#e": "<'e' tag json array>",
      "#p": "<'p' tag json array>",
      "since": "<订阅开始时间>",
      "until": "<订阅结束时间>",
      "limit": "<初次订阅返回的最大历史推文数量>"
    }, ...]
    

其中，subscription\_id为客户端随机生成的uuid字符串 2. 第二步，relay发送推文消息到client。消息格式为

    ["EVENT", "<subscription_id>", {
      "id": "<消息ID>",
      "pubkey": "<用户公钥>",
      "created_at": "<创建时间>",
      "kind": "<消息类型>",
      "tags": [ // <用于订阅规则过滤>
        ["e", "<其它推文ID>", "<推荐relay地址>"],
        ["p", "<公钥>", "<推荐relay地址>"]
        ... // other kinds of tags may be included later
      ],
      "content": "<推文内容>",
      "sig": "<私钥签名>"
    }]
    

取消推文流程

用户通过客户端发送关闭订阅消息

    ["CLOSE", "<subscription_id>"]
    

### Damus如何实现推文评论

damus基于tags字段来实现推文评论功能，具体格式如下：

    {
      ...
      "tags": [
        ["e", "<推文ID>", "<推荐relay地址>", "root"], // 评论链的根推文ID，必有
        ["e", "<推文ID>", "<推荐relay地址>", "mention"], // 相关推文ID，可选
        ["e", "<推文ID>", "<推荐relay地址>", "reply"], // 被评论推文ID，可选。如果没有就是root推文ID
        ...
      ],
      ...
    }
    

### Damus是如何管理用户信息

client会把用户信息发送到relay，格式如下

    {
      "kind": 0,
      "name": "用户名",
      "about": "",
      "picture": "",
      ... // other fields
    }
    

用户可以通过发送订阅消息来获取自己的用户信息，格式如下

    ["REQ", "<subscription_id>", {  "authors": "<用户的公钥>",  "kinds": [0]
    }]
    

### Damus的follower和following原理

following用户本地会维护一份contact列表，格式如下

    {
      "kind": 3,
      "tags": [
        ["p", "91cf9..4e5ca", "wss://alicerelay.com/", "alice"], // 订阅用户1
        ["p", "14aeb..8dad4", "wss://bobrelay.com/nostr", "bob"], // 订阅用户2
        ["p", "612ae..e610f", "ws://carolrelay.com/ws", "carol"] // 订阅用户3
      ],
      "content": "",
      ...other fields
    }
    

这些都是订阅的用户pubkey。但用户定阅新的用户或者取消已由的用户订阅的时候，会往relay发送新的contact列表，例如删除carol，订阅新的用户xxx

    {
      "kind": 3,
      "tags": [
        ["p", "91cf9..4e5ca", "wss://alicerelay.com/", "alice"], // 订阅用户1
        ["p", "14aeb..8dad4", "wss://bobrelay.com/nostr", "bob"], // 订阅用户1
        ["p", "xxx", "ws://carolrelay.com/ws", "xxx"] // 订阅用户4
      ],
      "content": "",
      ...other fields
    }
    

那么如何计算following就很简单，如果是在旧设备登录，只需要获取本地的订阅用户列表即可；如果是在新设备登录，就需要从relay中获取contact列表，那么就需要发送订阅消息，例如

    ["REQ", "<subscription_id>", {  "authors": "<用户的公钥>",  "kinds": [3]
    }]
    

如何计算follower数量，也需要往relay发送订阅消息，例如

    ["REQ", "<subscription_id>", {  "kinds": "3",  "pubkeys": "<被订阅用户的pubkey json array>"}]
    

根据relay返回的消息条数就可以计算

### Nostr目前存在的一些缺陷和问题

1.  无法发送图片等多媒体资源。因为nostr只负责发送文本消息，因此结合外部系统才能支持多媒体数据的上传。
    
2.  relay提供商缺少激励机制。目前relay服务提供商属于完成免费提供服务，长期看并不稳定可靠。
    
3.  无法发送私信。由于推文内容目前都是对外公开的，还无法支持用户和用户之间点对点的私信。
    
4.  seckey作为用户的唯一身份验证，如果不小心泄露，那么用户账号就会永久丢失，无法重新恢复。
    

### 总结

总体上看，Damus是一款优缺点很明显的社交软件。它的去中心化特点可以最大化实现言论自由，同时也正是去中心导致用户体验上做了很多妥协。以Damus目前的产品，显然无法吸引绝大多数web2社交上的用户。这种新赛道的产品还是非常值得我们去持续关注的，等它解决好自身的问题后，可能会在未来的某个时间突然爆发。

---

*Originally published on [zhongxuqi](https://paragraph.com/@zhongxuqi/damus-nostr)*
