P2P field coordination for activit and protest movements

Hey guys, let me introduce you to my hackathon submission.

Ash - Peer-to-Peer Field Coordination (PoC / WIP)

Ash is a mapping and communication Android app powered by P2P networks. It is designed for activists and protesters, or anyone who cares about privacy and decentralized software.
It helps people share information about physical threats, safe zones, meeting points or any other type of geolocated data. It also includes instant text messaging.

The app is inspired by Organic Maps/OsmAnd for offline map functionality and Waze for sharing geolocated information with others.

Demo video

Click here to see screenshots












How It Works

Ash doesn’t come with map data or harcoded backend urls. Instead of operating with a centralized backend, it uses a decentralized peer-to-peer network named Waku for sending and receiving messages. It also uses Arti, the implementation of Tor in Rust, for downloading map data served by hidden services.

What is missing

  • Remove the last two http calls made by MapLibreGL to Github. They retrieve fonts and icons for the map.
    I need to migrate them to the hidden service.
  • Display user position.
  • Fix QRCode scanning.
  • Encrypt Waku messages in the group channel so only group members can read and reply.
  • Improve the way of communication between the app and the X number of servers listening in. Currently anyone subscribed to the right channel can read the waku messages. Also anyone can reply.
    I need to add encryption and a way to ensure that the response is correct.
  • Need a way to have only the servers with the right dta to be able to reply.
    Servers might not have the data that the user want. Being able to serve data from all localities of the world means storing 600+ gigabytes. (Which is what my service is currently doing)
  • Find a way to make Waku requests happen over Tor (SOCKS5 proxy?).
  • Continue with implementing the app features.

Peer-to-Peer Backend Components

  • localitysrv - A Rust HTTP server that runs on localhost and as a Tor hidden service.
    It enables the search of countries and localities. As well as downloading PMTiles map data

  • localitysrv-waku - A Node.js service for bridging Waku messages to localitysrv over localhost.
    It is a workaround until Waku communication is implemented in localitysrv.

Technology

Built with:

  • Tauri (Rust)
  • React (TypeScript)
  • Waku for peer-to-peer messaging
  • Arti (Rust Tor) for accessing hidden services
  • Protomaps, MapLibre GL and OpenStreetMap for map features

The UI uses @nipsysdev/lsd-react, a library built on top of shadcn and Radix UI.

Current Features

  • Search countries and localities through Waku
  • Download maps through Tor for offline use
  • Switch between different downloaded areas
  • Create, join, and manage groups
  • Message with group members
  • Share map markers between group members

Use cases

Share Critical Information

Users can share information about threats, safe zones locations, and rendezvous points through map markers.

Navigate Offline

Users can navigate with pre-downloaded maps, eliminating dependency on internet connectivity during operations.

Communicate Securely

The app provides censorship resistant communication through peer-to-peer messaging without relying on centralized infrastructure.

Coordinate Actions

Users can coordinate actions without relying on centralized infrastructure, making it resilient to shutdowns.
(not internet shutdowns though, mesh network?)

How resilience, security, and usability are achieved

Decentralized Architecture

The application uses a peer-to-peer message-based backend for all coordination, making it impossible for governments to shut down by targeting central servers.

Offline map

Maps are downloaded as PMTiles files and stored locally, enabling full offline functionality. This means users can continue accessing the map even without network access, critical in situations where governments cut internet connectivity.

Tor Anonymity Layer

All map downloads occur anonymously through Tor over its anonymous onion service using the arti-client implementation.

Guided Onboarding Process

First-time users go through a structured setup that initializes both networks before allowing the download of the map data.

Automatic Network Management

Users don’t need to manually manage Tor or Waku connections. The system automatically handles bootstrapping, circuit creation, peer discovery, and reconnection. Health status is displayed through reactive UI elements that update in real-time.

Getting Started

Prerequisites

  • Node.js
  • Rust and Cargo
  • pnpm
  • Android SDK (optional, it runs on desktop too)

Installation

  1. Clone the repository:
git clone https://github.com/nipsysdev/ash.git
cd ash
  1. Install dependencies:
pnpm install
  1. Run the development server:
pnpm tauri dev
or
pnpm tauri android dev

Building APKs

cargo tauri android build --apk
cargo tauri android build --apk --debug

License

Licensed under GNU GPL v3+

5 Likes

Dude… this is fucking heavy. As in like, really good :metal:t4:

2 Likes

This use case always comes back. The ability to tag “items” on a map, and view locally tags items, keep popping up in countries under dictatorship or authoritarian governments.

Let us know what you want to see from Waku to build faster.

Keep building.

3 Likes

Hi guys, update on my side. Instead on diving into improving the app and communication between users, I’ve been thinking about how to solve the current situation where Ash is basically trusting that the response it is getting is true and accurate.

Right now Ash sends a query to find country names that start with the substring the user has entered but the response could be wrong, the replying node could be replying with wrong countries or missing some etc.

My first idea was to have Ash communicate with a smart contract that would somehow only allow properly configured nodes to reply.

But then it hit me, isn’t this the perfect use case for zero knowledge proofs?
I could host the full list of countries on Codex, have the nodes download it. And Ash would use the hash of the list (hardcoded into the codebase) to verify that the response from the node has been properly computed from this list of countries.

So yeah, I’ll be experimenting with Noir, see if I can solve the issue for the country search and try to apply the same logic for the locality search. For the map data it might be a bit more complex we’ll see.

3 Likes

I obviously want you to play around with ZK, but I have a few comments:-)

I believe the only way to make sure that something belong to a list in ZK right now is to build Merkle Tree out of the list and then provide proof of inclusion.

I don’t know if you can easily compute proof of inclusion of multiple leaves as an optimization.

In any case, it only solves half of the issue because you can then say “this item does not belong to the list”, but I don’t think you can say “this item is missing from this subset”, so there would still be space for “censorship” - e.g. the node could decide that you are looking for items from a country where a coup is going on and just not give it to you and you have no way to know…unless…

Unless you put the list of countries and locations in the countries on the device itself :person_shrugging:

Brave AI says this:

  • SimpleMaps World Cities Database (Comprehensive) : Contains ~4.3 million entries. While the exact file size isn’t specified, the Basic edition (48k entries) is 5.1 MB, suggesting the full version could be several hundred MBs when uncompressed.
  • GeoNames AllCountries Database : Includes over 11 million placenames. The compressed file is ~330 MB , expanding to ~1.4 GB when uncompressed.
  • GeoDataSource World Cities Database (Titanium Edition) : Covers ~3 million cities. The compressed ZIP is 64.35 MB , requiring 257.38 MB of disk space when extracted.

So now the question is if we could have a list of countries e.g. on-chain, pointing to a CID of the list of locations inside the country - then we should get to reasonable sizes per-country (assuming rarely anyone would want/need to download the whole world), but if you are in given region, maybe you’d download ~100MB to be sure you have your current country + neighbours covered?

This would essentially take the filtering away from the node providing map data.

Obviously eventually we’d also want to push the map data to a decentralized storage to avoid a single node issue altogether…

Maybe someone has a better idea using ZK, so that you can play around with it and learn (I root for you!), but I am sceptical that it will work and I kinda like the idea of having the list of locations locally - less queries to the network to correlate when you try to find and download a new map…

2 Likes

Thank you that is what I needed to hear :100: I highly appreciate.

Alright, so what about including the list of countries inside the app. There are around 200 countries so it should be okay to have it bundled and loaded in memory.
Ash could come with an object like Map<CountryName, localitiesFileCID>.
The file containing the localities of a country would be hosted on Codex.
I need to evaluate if its okay, size wise, for the localities of a country to be stored as json. I’m not a big fan of that idea though, I would prefer an sqlite db as it allows to build more complex and quicker queries.
Will give you an update on that tomorrow.

I haven’t compared the WOF admin DB with other alternatives. It might be a good opportunity to do it I’ll see if I have the time. But at least I’ll work on this country localities file.

I agree that the end goal would be to remove the node dependency and have Ash retrieve the data it needs from Codex.
The node software could be refurbished into a tool generating the datasets and map data and hosting those onto Codex. (At some point we will also need to generate routing data to enable map navigation)

1 Like

(ZK meganoob so can’t comment on that)

What I will say, though, is from a practicality standpoint, minimizing (especially large) downloads On Site (ie at a protest or Spicy Event) would be ideal. Even in situations where you’re not dealing with state censorship, cell service is going to be spotty. I’ve been to football games with crowds < the size of a lot of the big protests I’ve seen and cell service has been minimal.

This is another reason why I think a great project (not saying for you, just thinking out loud) is a protest mesh net with exit nodes that can spread the traffic out and software like Ash that can attempt to work local-first before going out to the web.

Regardless, minimizing on-site downloads is probably a good idea if you want this to be for activists in protest zones.

(p.s. following very closely because I’m going to be working with Waku p soon and Ash is awesome)

2 Likes

100% - downloading in crowded spaces is gonna be impossible, but that is gonna be an issue regardless of the way how data is structured - you need to do most of bandwidth intensive network related activities before you to the “event”:slight_smile:

I agree on the mesh - Bitchat has shown some of that in Nepal, I believe and it would be cool to be able to form hyperlocal BLE or Wifi Direct meshes and then use Waku to relay content out to the public domain

Thanks for your feedbacks guys. I totally agree with the points you raised.

Update on what I’m doing: Currently working on having working rust bindings for Codex. And then I’ll work on generating the smallest datasets for the localities so it can be hosted and downloadable from Codex (alongside the country names).

Update: I think I have now a good enough crate that provides the Codex library bindings in Rust: View on Github & View on Crates.io.

I’m now working on refurbishing the localitysrv project, keeping the locality data extraction but instead of running a http server it will run a Codex node, uploading and ensuring the availability of those data.

I’ll also have it generate the reference Json files that will map localities to CIDs.
I’m thinking about having one main Json file that maps country names to CIDs of Json files, those files mapping each locality to the CID of the map data.

The main json CID would be hardcoded in Ash.

cc @vpavlin

2 Likes