Almost one billion people face food insecurity every year — not because the world doesn't produce enough food, but because the coordination infrastructure between producers and consumers is broken.
Farmers don't know who needs what. Stores don't know what's available 2km away. Surplus rots while scarcity persists — sometimes in the same city block.
We spent years building a prototype to solve this. Today we're publishing the protocol that powers it.
👉 djowda.com/difp — DIFP v0.1, Provisional Specification · CC-BY 4.0 · Free to implement
What DIFP actually is
DIFP (Djowda Interconnected Food Protocol) is a lightweight, open, spatial food coordination protocol. It defines:
- Participant identity — how food ecosystem actors identify themselves globally without a central registry
- Spatial addressing — how Earth's surface is divided into ~500m × 500m cells, each acting as a coordination zone
- Presence & discovery — how participants announce and find each other within and across cells
- The trade message format — a universal structure for orders, asks, and donations between any two participants
- Protocol federation — how independent DIFP nodes interoperate without a central broker
It is transport-agnostic. The reference implementation uses Firebase Realtime Database. Conformant implementations may use REST, WebSockets, MQTT, or anything equivalent.
The problem it solves for developers
Right now if you're building a grocery delivery app, a farm management tool, a restaurant POS, or a truck routing system — you're building in isolation.
There's no shared layer. No common identity. No standard way to say "I'm a farmer at this location with these items available." Every integration is custom. Every partnership is a new API contract.
DIFP proposes a fix: one protocol, one grid, one trade message format.
Any two systems that implement DIFP can discover each other, exchange availability data, and complete trades — with zero custom integration work.
The spatial grid — the core innovation
The foundational piece of DIFP is a deterministic global grid called MinMax99.
The entire surface of Earth is divided into ~3.44 billion cells, each 500×500 meters. Every participant gets a cell ID derived from their GPS coordinates using a single pure-math function:
public static long geoToCellNumber(double latitude, double longitude) {
// Longitude → x in meters (linear)
double x = (longitude + 180.0) * (EARTH_WIDTH_METERS / 360.0);
// Latitude → y in meters (Mercator, origin at top)
double y = (EARTH_HEIGHT_METERS / 2.0)
- Math.log(Math.tan(Math.PI / 4.0 + Math.toRadians(latitude) / 2.0))
* (EARTH_HEIGHT_METERS / (2.0 * Math.PI));
// Meters → cell indices
int xCell = (int) Math.floor(x / CELL_SIZE_METERS); // CELL_SIZE_METERS = 500
int yCell = (int) Math.floor(y / CELL_SIZE_METERS);
// Clamp + encode
xCell = Math.max(0, Math.min(xCell, NUM_COLUMNS - 1)); // NUM_COLUMNS = 82,000
yCell = Math.max(0, Math.min(yCell, NUM_ROWS - 1)); // NUM_ROWS = 42,000
return (long) xCell * NUM_ROWS + yCell;
}
Grid constants (all conformant implementations MUST use these exactly):
EARTH_WIDTH_METERS = 40,075,000
EARTH_HEIGHT_METERS = 20,000,000
CELL_SIZE_METERS = 500
NUM_COLUMNS = 82,000
NUM_ROWS = 42,000
TOTAL_CELLS ≈ 3.44 billion
Reference test vectors to validate your port:
| Location | lat, lng | Cell ID |
|---|---|---|
| Algiers, Algeria | 36.7372, 3.0868 | 3440210 |
| Paris, France | 48.8566, 2.3522 | 3467891 |
| Tokyo, Japan | 35.6762, 139.6503 | 6543210 |
| New York, USA | 40.7128, -74.0060 | 1823445 |
Why a grid instead of geo-queries?
- Discovery is O(1). To find all stores near a farmer, query the farmer's cell + immediate neighbors. No radius search. No expensive geo API call.
- Cells are lobbies. All components in the same cell share context — they can discover each other without knowing each other in advance.
- Works offline. Cell IDs are computed client-side from GPS. No server round-trip needed to know your own address.
-
Cheap at scale. A Firebase
equalTo(cellId)query is fast and inexpensive. No PostGIS, no Elasticsearch geo-shape queries.
Neighbor resolution
def get_nearby_cells(center_cell_id, radius):
xC, yC = cell_number_to_xy(center_cell_id)
result = []
for dx in range(-radius, radius + 1):
for dy in range(-radius, radius + 1):
x = clamp(xC + dx, 0, NUM_COLUMNS - 1)
y = clamp(yC + dy, 0, NUM_ROWS - 1)
result.append(x * NUM_ROWS + y)
return result
| Radius | Grid | Cells | Coverage |
|---|---|---|---|
| 0 | 1×1 | 1 | ~0.25 km² |
| 1 | 3×3 | 9 | ~2.25 km² |
| 2 | 5×5 | 25 | ~6.25 km² |
| 5 | 11×11 | 121 | ~30 km² |
Participant identity — DIDs without a blockchain
DIFP uses a Decentralized Identifier (DID) scheme that requires no central authority and works offline:
difp://{cellId}/{typeCode}/{componentId}
# Examples
difp://3440210/f/ali-farm-01 # Farmer in cell 3,440,210 (Algiers)
difp://3440210/s/safeway-dz-042 # Store in same cell
difp://1820044/fa/cevital-plant-1 # Factory in cell 1,820,044
Ten canonical component types:
| Code | Actor |
|---|---|
sp |
Seed Provider |
f |
Farmer |
fa |
Factory |
w |
Wholesaler |
s |
Store |
r |
Restaurant |
u |
User / Consumer |
t |
Transport |
d |
Delivery |
a |
Admin |
The trade message — one format for everything
All exchanges in the food ecosystem — commercial orders, donation offers, resource requests — are modeled as Trades between exactly two participants.
Three trade types:
| Code | Type | Description |
|---|---|---|
o |
Order | Purchase request with items, quantities, prices |
a |
Ask | Demand signal — "I need this, who has it?" |
d |
Donation | Surplus signal — "I have this, who needs it?" |
The Ask and Donation types are first-class citizens of the protocol, not afterthoughts. They're how DIFP addresses food insecurity directly — signaling surplus and scarcity without requiring a commercial transaction.
Trade message schema
{
"sId": "difp://3440210/f/ali-farm-01",
"sT": "f",
"sC": "3440210",
"rId": "difp://3440210/s/safeway-dz-042",
"rT": "s",
"rC": "3440210",
"ty": "o",
"st": "p",
"items": {
"difp:item:dz:vegetables:tomato_kg:v1": { "q": 50, "p": 80, "u": "kg" }
},
"total": 4000,
"listSize": 1,
"createdAt": 1710000000000,
"info": { "phone": "+213...", "address": "...", "comment": "" }
}
Status lifecycle
PENDING (p)
│
├── receiver accepts ──► ACCEPTED (a)
│ │
│ └──► PROCESSING (pr) ──► COMPLETED (c) ✓
│
├── receiver denies ──► DENIED (dn) ✗
│
└── sender cancels ──► CANCELLED (x) ✗
The four-node atomic write pattern (fan-out)
Every trade touches four Firebase nodes in a single atomic updateChildren() call. No partial writes. No race conditions.
TD/{tradeId} ← canonical full record
T/{senderType}/{senderId}/o/{tradeId} ← sender outbox summary
T/{receiverType}/{receiverId}/i/{tradeId} ← receiver inbox summary
TA/{tradeId} ← analytics (no PII)
Map<String, Object> updates = new HashMap<>();
updates.put("TD/" + tradeId, tradeData);
updates.put("T/" + senderType + "/" + senderId + "/o/" + tradeId, senderSummary);
updates.put("T/" + receiverType + "/" + receiverId + "/i/" + tradeId, receiverSummary);
updates.put("TA/" + tradeId + "/createdAt", timestamp);
updates.put("TA/" + tradeId + "/senderCell", senderCell);
updates.put("TA/" + tradeId + "/receiverCell", receiverCell);
db.updateChildren(updates); // atomic
The TA (analytics) node tracks timing and cell pairs for map-route animation — and must never contain PII (no phone numbers, no addresses, no item details).
The catalog system — PAD + live sync
DIFP separates item metadata (static) from availability and pricing (live).
- PAD (Pre-loaded Application Data): ~6,000 items per country per component type, distributed as a compressed package with the app. Contains item names (multilingual), categories, units, thumbnail references. Never changes at runtime.
-
Live sync: Only
priceandavailabletravel over the wire during normal usage.
This means a farmer's app works in a village with 2G. The catalog is already on-device. Only the delta syncs.
Item identity is globally namespaced:
difp:item:{countryCode}:{category}:{itemSlug}:{version}
# Examples
difp:item:dz:vegetables:tomato_kg:v1
difp:item:in:grains:basmati_rice_kg:v2
difp:item:fr:dairy:camembert_250g:v1
Protocol federation
DIFP is designed for independent operators — NGOs, national food agencies, regional cooperatives — to run their own nodes and interoperate.
Every conformant node exposes:
GET https://{host}/.well-known/difp/info
# Returns: protocol version, nodeId, cell coverage, federated peers
GET https://{host}/.well-known/difp/cell/{cellId}
# Returns: all PresenceRecords in that cell
POST https://{host}/.well-known/difp/trade/incoming
# Accepts: signed TradeMessage from another DIFP node
A Tunisian cooperative and an Indian marketplace running separate DIFP nodes can discover each other's participants and complete cross-node trades with zero custom integration — because they speak the same protocol.
How to implement (minimum viable node)
Step 1 — Port the grid algorithm. Validate against the reference test vectors above. This is the only piece that MUST be bit-for-bit identical across all implementations.
Step 2 — Stand up a presence store. Any backend (Firebase, PostgreSQL + PostGIS, DynamoDB). Index by cell_id + component_type. Expose the /.well-known/difp/ endpoints.
Step 3 — Implement the trade engine. Four-node write pattern. Role-based status transitions. Atomic writes.
That's a working DIFP node. Steps 4 (catalog) and 5 (federation) can be added incrementally.
A working node with 10 participants is more valuable than a perfect spec with zero.
What this means for AI + food
One thing we didn't anticipate when designing this: DIFP makes food data natively queryable by AI systems.
Because every participant has a DID, a cell ID, a typed presence record, and a live catalog — any AI assistant with access to a DIFP node can answer questions like:
- "Which farmers within 3km have tomatoes available right now?"
- "What's the current wholesale price of potatoes in this region?"
- "Which stores near me are broadcasting a donation?"
No scraping. No stale listings. Live, structured, geographic data — in a format any system can query.
Current status & what's next (v0.2 targets)
| ID | Topic |
|---|---|
| A | Ed25519 message signing for trustless cross-node verification |
| B | Supply & Demand Radar — Ask/Donation signals aggregate into cell-level heat maps |
| C | Map route animation from TA cell pairs |
| D | MQTT profile for IoT farm sensors |
| E | USSD/SMS fallback for participants with no smartphone |
| I | Conformance test suite |
Read the spec. Build on it. Break it.
Full specification: djowda.com/difp
Download: DIFP-v0.1-Provisional.docx
Contact: sales@djowda.com
License: CC-BY 4.0 — free to implement, fork, extend, and commercialize. Credit required.
The food system doesn't need another closed platform. It needs a shared language.
We just published ours. 🌍
Top comments (0)