Some thoughts on chats using with shuffling feed and pss locations

Please can someone give me permission to post multiple links/images?

As you may know I am currently experimenting with a concept for chat rooms using a combination of swarm feeds and pss. And right now an idea has come up of enabling “band changes” in the chat updates that only the participants will know of.

Here’s some background on swarm feeds if necessary: https://github.com/ethersphere/go-ethereum/pull/881 and Parallel feed lookups by jpeletier · Pull Request #1332 · ethersphere/swarm · GitHub

I’ll try to keep this simple, some constraints:

  • We can exchange session public keys without outside entities associating them with identity used in initial discovery/connect.
  • We assume peer discovery and service discovery exists.
  • We assume we can promiscuously connect to pss nodes to send and receive in exchange for payment.
  • Consensus between peers on who chatroom participants are is out of scope.

Two peers A and B keep one feed each for their single-user chat. The feeds are signed by sender’s session pubkey (PKsesUSER), the feed topic contains the peer’s session ethaddress (ADDR(PKsesPEER)), thus they know how to find them if they know each others’ session keys.

Updates are posted to swarm and the feed is updated by the top swarm hash. Updates point to each others’ respective swarm hashes. Feeds have resolution of 1 second, but since updates are chained swarm content hashes and not feed updates then sub-seconds updates are possible.

PSS is used to notify about an update in chat. When notify is received, peer will start polling for new updates. If no new updates are found within a period, it will stop polling / reduce polling frequency. A new notify resets polling to default frequency.

A single chat simply compiled by adding the output of the respective two feeds. Contents are encrypted by shared secrets, which is handled by separate scheme (can relatively easily implement axolotl-style kdf schemes by passing new encryption pubkeys for every update).

Figure:
http://swarm-gateways.net/bzz:/a511e9bd8cf14ad1582c133e5090c406a761576e1f03cafde6e0312a57d71506/

Multi-user chat rooms / channels are rendered the same way; all participants have their own feed (here the feed topic is seeded by room name), and the chat room is the sum of the updates of all those feeds, signed by respective session pubkeys. Furthermore every peer keeps their own version of the room participant list on a separate feed, and links this list to every update.

Figure:
http://swarm-gateways.net/bzz:/9bf53d82fbe63cee7d328ee62b43547477da2b0ec3cf752bfd96cbe5a44d0eb5/

Let’s say that an update can be content but ALSO provide a new feed session pubkey that next update will be posted to. Peers will now consider that feed as the “current” feed and start polling this. Time between jumps can be totally arbitrary.

Figure:
http://swarm-gateways.net/bzz:/e9c3a22cb4845fe2be6f7e798d82b499f5adc535c9a32993787f6fa00b8ef18b/

Now let’s imagine we can do the same with PSS messages; arbitrarily change relay nodes for sending and receiving messages, like a distributed service provider network of sorts. In this way we can obfuscate sender and receiver identity while still keeping the kademlia routing advantages that comes with PSS. The clients would pay to send, pay to receive.

Figure:
http://swarm-gateways.net/bzz:/a164f21add7705c70732ca6344ff5e387affc0d7e24d91cf70de9f1e9d01c8e1/

Some thoughts on good stuff this provides:

  • data transmission inherits the security properties of rlpx.
  • location of swarm feed chunks inherit the random distribution of normal swarm chunks.
  • hard to guess which feed a sender switches to, because the session key could be anything from the key parameter domain.
  • hard to link actual conversation activity to notification messages, because they are not one-to-one.
  • hard to track the identity of a pss client between nodes, because pss identity keys are also changed.

Whaddyathink?

3 Likes

Hello!

I love it, I thought about this but only had the concept in mind without really knowing how to apply it. Are you going to implement this in go-ethereum and provide a high-level api for this?

In my case I don’t want to use this for chats directly but for F2F sharing of information such as latest messages in various chats, reactions to messages, reactions to dapps, list of blocked users and trusted users. I really need to update it because it is starting to get very old but here is a description of the idea if you are interested People first - CodiMD

Actually this is kind of a spin-off of an overgrown hack to make a pss and feeds messaging plugin for weechat.org . This is written in Python. and holds some generic functionality useful for implementing something like this, like classes for managing feed collections.

I spent some time a couple weeks back trying to separate that code better (also needed to go from py2 → py3, long story), but stopped momentarily as I realized that some of the concepts needed more thought (which is part of what this post is about). Current state of the code reworking is here:

Thanks for the link. So yeah, this F2F curating is actually a chat in itself, in a way. At first glance it should fit nicely into this framework, or?

This is really neat, thank you @lash. The background reading was useful too, didn’t really understand how Feeds worked internally before. Nice graphics too :slight_smile: A few questions:

  • We can exchange session public keys without outside entities associating them with identity used in initial discovery/connect.

In this context, what do you imagine a session to be? How does it relate to more traditional symmetric key exchange to establish secured channels, like X3DH?

The feeds are signed by sender’s session pubkey (PKsesUSER), the feed topic contains the peer’s session ethaddress (ADDR(PKsesPEER)), thus they know how to find them if they know each others’ session keys.

So as Bob, if I know Alice I can look at her feed at topic f(Alice, Bob) and see if there’s anything there. Is this correct? Would this mean that someone who knows Alice and Bob pubkey can see that this topic has been posted to?

Feeds have resolution of 1 second, but since updates are chained swarm content hashes and not feed updates then sub-seconds updates are possible.

I understand that resolution of historical messages would be subsecond, since you can get latest update via Feed then quickly traverse linked list of chunks. But I don’t follow how new updates can be subsecond, could you elaborate? If Alice sends messages, the Feed would still only update maximum every second, so how would get more data than this?

Multi-user chat rooms / channels are rendered the same way; all participants have their own feed (here the feed topic is seeded by room name), and the chat room is the sum of the updates of all those feeds, signed by respective session pubkeys. Furthermore every peer keeps their own version of the room participant list on a separate feed, and links this list to every update.

  • Does this mean you have to query each user’s feed in a group chat to get the full history?

  • In the graphic I notice how the chat history is represented linearly, should this be a DAG since each update is concurrent? If not, how would you get a canonical order / sequential consistency here?

  • How would knowing a participant list allow us to get the latest update from each particpant? Does this mean you have to go back to the beginning for each participant (seed)?

  • Perhaps this is more for the previous architecture/pdf I read, but did you consider having multiple parents for a message to encode dependencies? Or do you imagine this being a linked list for each individual user, and then trust the timestamp of each other nodes chunk write, and then use this for message ordering?

In general, I like the idea of treating feeds as random seeds and distributing these evenly/randomly. One use that would be interesting is: 100 participants, long message history, how do you get to see recent updates as soon as possible, vs having to go the origin of time for the seed in each feed (at least as I understand it).

In this context, what do you imagine a session to be? How does it relate to more traditional symmetric key exchange to establish secured channels, like X3DH?

A session here would be the period for which you can maintain a chain of (random) session public keys that can be arbitrarily changed. The keys here are only used for changing the location the feed. Since the address of the feed is something like HASHswarmfeed(HASHeth(PKsesUSER), XOR(rootTopic, HASHeth(PKsesUSER)), ...) (here params aren’t necessarily in correct order) and the PKses is exchanged securely then Eve will have to search all unknown points in DigestSize(HASHswamfeed) to find where the feed exchange continues (especially if the switch is done symmetrically between the peers).

But I don’t follow how new updates can be subsecond, could you elaborate?

Well it’s not exactly true perhaps. I only meant that you can save to swarm sub-second. The advantage would be that if the update stream has large volume, you’re done committing the data before you change the pointer with a feed update. That feed update will still have a minimum of second pulse, of course.

Does this mean you have to query each user’s feed in a group chat to get the full history?

Yes, but each user only keeps one feed per room - not one feed per participant in the room. But we could also imagine a distributed mechanism in a higher layer where participants solidarically aggregate parts of the feeds for each other (the responsibility is your “closest” address space, and the cardinality could step-wise adjust down the larger the room gets). This, of course, opens up a whole other can of worms of accountability, so I’d rather the first iteration of this doesn’t plunge down that rabbit-hole.

How would knowing a participant list allow us to get the latest update from each particpant? Does this mean you have to go back to the beginning for each participant

No, it’s FILO.


more later…

Do you mean order between the participants? This naïve implementation trusts the self-announced timestamp by the sender. Any mechanism for enforcing timestamp truthfulness I think is out of scope for this generic description stage, and probably belongs in a higher layer. That said, timestamps perhaps should be millisecond resolution not second. I can’t remember what guarantees eth/swarm nodes have for time sync between them. Probably it’s way too permissive, but in the unlikely event that it’s good enough we could use that to sync the clock for those timestamps.

Or do you imagine this being a linked list for each individual user, and then trust the timestamp of each other nodes chunk write, and then use this for message ordering?

so yes … that, for now :slight_smile:

One use that would be interesting is: 100 participants, long message history, how do you get to see recent updates as soon as possible, vs having to go the origin of time for the seed in each feed (at least as I understand it).

You only have to go from latest to latest known hash.

Not directly related, but I had a very interesting discussion with Viktor yesterday though about using the “pot” (a trie index) keyed on timestamp to allow fast random access to a time span of updates!

So just to clarify; I pull from one feed per participant in the room, and aggregate these myself client side based on timestamp given by participants.