
The goal of Axiom is to provide a completely anonymous, decentralized, and censorship-resistant social media platform. To make this possible, the architecture is strictly divided for the protocol and the clients. This repository defines the protocol and the smart contract and a standardized data structure on an Ethereum Layer 2 network.
42161https://arb1.arbitrum.io/rpc (or any custom Alchemy/Infura endpoint)0xc11CFf8111e8b1F055eba095Efb679a38Abe6b63(Note: Axiom uses a UUPS Upgradeable Proxy architecture. All client interactions must always be directed towards this Proxy address, never the underlying implementation contract).
Clients should never attempt to read protocol posts directly from the smart contract state variables (as preserving gas is a priority, content is not stored in state). Instead, clients must index the blockchain events.
To publish data to the Protocol, clients must submit an on-chain transaction calling the publishAxiom function on the Proxy contract.
The goal of Axiom is to provide a completely anonymous, decentralized, and censorship-resistant social media platform.
To make this possible, the architecture is strictly divided: the foundation (the protocol) and the clients (the software). This repository defines that foundation—a smart contract and a standardized data structure on an Ethereum Layer 2 network.
The protocol establishes the foundation of the platform:
Axiom is designed to enable true freedom of speech for users in countries where communication is restricted. The protocol distinguishes between three security levels. It assumes that users know which security level is appropriate for their specific situation.
For all levels, Onion Routing (e.g., Tor) is strictly mandatory. Communicating with commercial RPC providers (like Infura or Alchemy) leaks the sender's IP address in plaintext. To close potentially life-threatening OPSEC vulnerabilities for dissidents, clients are required to route transactions to the RPC nodes exclusively through the Tor network.
For messages on Level 3, all clients must strictly adhere to the following cryptographic standards to ensure interoperability and avoid compromising security.
Axiom utilizes a hybrid payload delivery (ABI Split). To prevent the smart contract from having to unpack expensive data formats, the data is separated prior to transmission:
uint8 _level) and the initialization vector (bytes _iv) are passed as direct parameters to the smart contract, as it requires them to enforce its security rules.Axiom uses single letters as keys to save bytes. The author (msg.sender) and timestamp (block.timestamp) are omitted, as the smart contract extracts these values in a tamper-proof manner anyway.
t (Type): Integer. The type of action.c (Content): String/Bytes. The text, name, or ciphertext.h (Hashtags/Tags): Array. Optional. Used for categorization (subchannels).m (Message Hint): Bytes (length of 2). Level 3 only. A 2-byte HMAC hash used for fuzzy bucketing.r (Reply-To): Bytes. Optional. The transaction hash of a referenced post.t Field)0 = Profile Update (Links the wallet address to a readable name in field c)1 = Post (Standard message)2 = Reply (r requires the hash of the original post)3 = Like (r requires the hash of the post)4 = Unlike (Reverts Type 3)5 = Retweet / Repost (r requires the hash of the post)6 = Un-Retweet (Reverts Type 5)h Field)c). For external observers, the tags are therefore completely invisible (Dark Routing).m Field)Because tags are encrypted on Level 3, clients theoretically have to attempt to decrypt every single message (Trial Decryption). To prevent CPU overloads, Axiom uses Message Hints:
HMAC-SHA256(AES_Key, IV) and places the first 2 bytes as field m into the CBOR payload.Axiom handles identity with total transparency: The L2 wallet address (msg.sender) is the sole social and financial identity. The protocol transfers the responsibility for financial OPSEC entirely to the user (e.g., the use of mixers and bridges to anonymously procure gas tokens).
The profile update action (t: 0) behaves differently depending on the chosen security level:
@Dissident99).Axiom relies on on-chain validation with O(1) complexity. To keep gas costs at an absolute minimum, the smart contract only performs basic cryptographic checks. All resource-intensive content validations are offloaded to the clients (Layer 2).
The contract acts as an incorruptible bouncer. If a payload does not adhere to the strict rules, the transaction is reverted.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
contract Axiom is Initializable, UUPSUpgradeable, OwnableUpgradeable {
uint256 public entryFee;
mapping(address => uint8) public walletPath; // 0=New, 1=PathA(Level1), 2=PathB(Level2/3)
event AxiomPost(address indexed sender, uint8 level, bytes iv, bytes cbor, uint256 timestamp);
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize() initializer public {
__Ownable_init(msg.sender);
entryFee = 0.0001 ether;
}
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
function publishAxiom(
uint8 _level,
bytes calldata _iv,
bytes calldata _cbor
) external payable {
require(_level >= 1 && _level <= 3, "Invalid level");
uint8 requiredPath = (_level == 1) ? 1 : 2;
uint8 currentPath = walletPath[msg.sender];
if (currentPath == 0) {
require(msg.value >= entryFee, "Anti-Sybil: Insufficient entry fee");
walletPath[msg.sender] = requiredPath;
} else {
require(msg.value == 0, "Fee already paid");
require(currentPath == requiredPath, "OPSEC Violation: Wallet is tainted");
}
if (_level == 3) {
require(_iv.length == 12, "Level 3 strictly requires a 12-byte IV");
} else {
require(_iv.length == 0, "Level 1 and 2 require strictly empty IV");
}
emit AxiomPost(msg.sender, _level, _iv, _cbor, block.timestamp);
}
function withdraw() external onlyOwner {
payable(owner()).transfer(address(this).balance);
}
}
If a post violates protocol rules, the client must discard it silently (Local Drop).
c) of Level 2 messages. If URLs, IP addresses, or typical media tags are detected, the post is completely blocked.Axiom is deployed on an Ethereum Layer 2 (L2) network (e.g., Arbitrum Nova).
To avoid overloading mobile devices (battery life, storage limitations, WebAssembly limits for Argon2id), Axiom enforces a highly performant client architecture:
Clients do not download the entire blockchain state. They filter for the smart contract's AxiomPost event, which contains all necessary data in plaintext (Sender, Level, IV, CBOR, Timestamp).
Because Ethereum nodes will eventually discard historical data (events older than 365 days) according to EIP-4444, the protocol recommends that local Axiom Cores serve as decentralized archives, storing the databases permanently.
To illustrate how the architecture works in practice, here is a complete lifecycle run-through.
Scenario: Alice wants to post the message "Meeting at 8 PM" into the subchannel "AxiomDev". The group previously agreed offline on the password "Secret123".
Alice's Axiom Core handles the computational heavy lifting:
0x12ab34cd56ef789012ab34cd).m: "0xa1b2").Since the level and the IV are passed directly to the contract, they are excluded from the CBOR object.
Internal JSON Representation:
{
"t": 1,
"c": "0x8a4f...",
"h": ["0x9b5e..."],
"m": "0xa1b2"
}
This JSON is compressed into a raw CBOR byte array (0xa3617401...) to save gas.
Alice triggers the contract function. Important: The call is strictly routed through Tor!
(Examples for L3 and L1:)
// Example 1: Client calling the Smart Contract for an encrypted Level 3 post
await axiomContract.publishAxiom(
3, // _level: 3
"0x12ab34cd56ef789012ab34cd", // _iv: 12 bytes hex string required
"0xa3617401616358208a4f..." // _cbor: packed CBOR hex string
);
// Example 2: Client calling the Smart Contract for a public Level 1 post
await axiomContract.publishAxiom(
1, // _level: 1
"0x", // _iv: strictly empty byte array
"0xa361740161634c48656c6c6f204178..." // _cbor: packed CBOR hex string
);
The smart contract then emits the event:
Event: AxiomPost(Sender: 0xAlice..., Level: 3, IV: 0x12ab..., CBOR: 0xa361..., Timestamp: 1710425890)
Bob's Axiom Core is listening to the blockchain and receives the event.
Level 3 and unpacks the CBOR to access the content, tags, and the hint m.m against Bob's stored passwords.