Skip to content

fcecin/minx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MINX

NOTE: This is experimental software.

MINX is a simple cooperative-economy boostrapping protocol for P2P applications that provides resistance against basic attacks, such as IP spoofing, traffic snooping and hijacking (MitM attacks), verification spam and RAM-exhaustion attacks.

This protocol is part of Hyle, a Public Computing project.

Quickstart

MINX is written in C++20. Most dependencies are downloaded by the build scripts. The exception is the Boost suite which must be already installed in your system (via e.g. sudo apt install libboost-all-dev in Ubuntu).

The provided build system is written in CMake and produces a static library in both debug and release configurations via build.sh.

Rationale

Public Computing (PubCom, for short) allows nodes in Peer-to-Peer (P2P) networks (also referred to as "decentralized networks") to provide resources to each other, enabling a diverse set of applications. In a PubCom network, a node A may provide resources for a node B so that node B can run application X, and in turn, node B may provide resources for node A so that node A can run application Y. Applications need not be aware of each other, and the network is open and general-purpose, providing for any number of users and applications. Public Computing stands in contrast to Cloud Computing, where computing resources are instead provided by businesses.

MINX is a low-level protocol built to serve as a bootstrapping mechanism for computing resource sharing in a PubCom network. Its implementation is primarily intended as a foundation for higher-level, reusable PubCom middleware, although a P2P network or application could be built directly on top of it.

MINX allows peer nodes in a P2P network to send cheap Proof-of-Work (PoW) solutions to each other in a way that is already protected against several attacks. When a node A sends a PoW solution to a node B, node B records a proportional amount of computing credits to node A. That allows node A to then ask node B for computing resources in a spam-protected, rate-limited way, since the networking, computing, memory or storage expenditure at node B from node A's requests can be billed against node A's bootstrapped credit balance at node B.

Leveraging MINX, a more complex trust and anti-spam system or resource economy can be built. Such higher-level middleware would serve user-facing decentralized applications and provide richer APIs. MINX provides middleware with a basic, generic trust mechanism that securely cold-starts resource exchanges between peer nodes in an application-agnostic way, irrespective of individual peer node capabilities or application intents.

Protocol specification

All values are encoded in network byte order (big-endian), which means the most significant byte is stored first, the second-most significant byte is stored second, and so on.

The remainder of a datagram payload is denoted by uint8_t[] (without a byte size number between the array brackets).

All datagrams have the following header:

  • uint8_t CODE: Message code.

All message codes [0xFC..0xFF] have an additional uint8_t VERSION field, which is an implementation identifier. The VERSION field has the following format:

  • Lower 4 bits: ENGINE_ID.
  • Higher 4 bits: FLAGS.

The ENGINE_ID field can have the following known values:

  • 0x0: Default RandomX PoW engine, with 256-bit secure hashes (hashing algorithm is unspecified) and/or 256-bit public keys (public-key signing algorithm unspecified).

Implementors are free to define their own engine codes. There's no mechanism that would avoid ENGINE_ID collisions across different projects, but the list above should be expanded with any known IDs.

The FLAGS field is implementation-defined. The reference implementation reserves FLAGS for an extensions or capabilities bitfield.

The remainder of the datagram is the message, which depends on CODE.

There is no point-to-point connection state tracking in MINX, no data streams and thus no stream sequence numbers. Sender IP address verification is accomplished by a continous exchange of randomized IP address validation passwords (or tickets). Generated tickets (GPASSWORD) are randomly-generated by the sender and locally saved, which can then be spent by the remote node (SPASSWORD) in a return packet later.

Receiving a packet with an SPASSWORD value that is not an outstanding, previously-unspent GPASSWORD value that was locally generated and saved beforehand causes the incoming packet with the unknown, invalid SPASSWORD value to be dropped. Whether passwords are associated with IP addresses or not, and for how long exacty they are retained after generation are up to the implementation. Passwords with a value of zero are invalid (absent).

Below is the specification for all messages.

INIT (0xFA)

A general-purpose message which does not yet have a source IP address ticket to spend.

  • uint8_t VERSION: Implementation identifier.
  • uint64_t GPASSWORD: Generated ticket value, or zero.
  • uint8_t[] DATA: Optional application data.

Applications can drop some or all INIT messages. The sender IP address cannot be penalized, since it is not spending an address verification ticket.

MESSAGE (0xFB)

A general-purpose message which asks the receiver to match and spend a ticket (SPASSWORD) and generates a new ticket (GPASSWORD) that the receiver can use as a spending ticket later when replying.

  • uint8_t VERSION: Implementation identifier.
  • uint64_t GPASSWORD: Generated ticket value, or zero.
  • uint64_t SPASSWORD: Ticket value to spend, or zero.
  • uint8_t[] DATA: Optional application data.

If the application finds the message to be spam, the sender address can be penalized.

GET_INFO (0xFC)

Asks the receiver to start verification of the sender's IP address, and also asks for information on the receiver node such as the parameters for its PoW engine.

  • uint8_t VERSION: Implementation identifier.
  • uint64_t GPASSWORD: Generated ticket value, or zero.
  • uint8_t[] DATA: Optional application data.

Applications can drop some or all GET_INFO messages. The sender IP address cannot be penalized, since it is not spending an address verification ticket.

INFO (0xFD)

Optional answer to a GET_INFO message. Receiver assumes that its VERSION informed by the previous GET_INFO message is supported by the sender.

  • uint8_t VERSION: Implementation identifier.
  • uint64_t GPASSWORD: Generated ticket value, or zero.
  • uint64_t SPASSWORD: Ticket value to spend, or zero.
  • uint8_t[] ENGINE_INFO: Parameter values for the sender's PoW engine (given by its ENGINE_ID).
  • uint8_t[] DATA: Optional application data.

The ENGINE_INFO data packet's format depends on the value of ENGINE_ID.

If ENGINE_ID is 0x0 (the default engine), ENGINE_INFO has the following format:

  • uint8_t[32] SKEY: A 256-bit secure hash over some cryptographic public key controlled by the sender (or the public key itself, if it happens to be 256 bits long).
  • uint8_t DIFFICULTY: Minimum solution difficulty accepted by the sender, where the average number of hash lookups is in the order of 2^DIFFICULTY.

If the application finds the message to be spam, the sender address can be penalized.

PROVE_WORK (0xFE)

A message that presents a PoW solution for a PoW puzzle.

  • uint8_t VERSION: Implementation identifier.
  • uint64_t GPASSWORD: Generated ticket value, or zero.
  • uint64_t SPASSWORD: Ticket value to spend, or zero.
  • uint8_t[] POW_DATA: The PoW data packet for the PoW engine to process.
  • uint8_t[] DATA: Optional application data.

The POW_DATA data packet's format depends on the value of ENGINE_ID.

If ENGINE_ID is 0x0 (the default engine), POW_DATA has the following format:

  • uint8_t[32] CKEY: A 256-bit secure hash over some cryptographic public key controlled by the sender (or the public key itself, if it happens to be 256 bits long); part of the PoW puzzle.
  • uint8_t[32] HDATA: Application-defined 256-bit value that is part of the PoW puzzle; can be used to store a 256-bit secure hash computed over DATA.
  • uint64_t TIME: Timestamp of the PoW puzzle.
  • uint64_t NONCE: PoW puzzle nonce.
  • uint8_t[32] SOLUTION: RandomX hash over the concatenation of CKEY, HDATA, TIME, NONCE.

The protocol does not specify an acknowledgement or return message for PROVE_WORK. Such a facility can be provided by the application or a protocol extension. For example, the application can choose to check for some kind of credit balance at the remote node and just keep resubmitting proofs until it increases. Or the application can just blindly resubmit PROVE_WORK datagrams a certain number of times, or resort to recent proof resubmission if other operations are denied due to a lack of credit. In any case, the receiver should generally not penalise the sender for a double-spend attempt, since looking up SOLUTION against a record of previously spent solutions should be a fast operation.

The receiver is responsible for detecting solutions that are correct but that need to be rejected because the puzzle difficulty is not high enough to justify tracking its solution.

MINX does not specify a cryptographic signature for PROVE_WORK messages, as there isn't a fundamental need to authenticate any of its fields. The solution cannot be stolen, since the solution is bound to CKEY. As for impersonating a CKEY for griefing, that is prevented if the application does not penalize a CKEY for an invalid request (as an attacker might as well just generate disposable keypairs) and instead relies on MINX's sender address filters.

The HDATA field is part of the PoW puzzle and is free to use by the application. For example, the application can bind DATA to SOLUTION by computing a 256-bit secure hash over DATA and relaying it via HDATA. In that case, the application can defend itself from spam attacks in the DATA field by first ensuring that the provided PoW solution is valid. The hash function to be used, hash computation and verification are left to the application. The PoW double-spend check also filters regular duplicate packets, so a secure hash over DATA in HDATA also prevents DATA replay attacks.

If the application finds the message to be spam, the sender address can be penalized.

EXTENSION (0xFF)

Message code for protocol extensions. Extensions are implementation-defined.

  • uint8_t VERSION: Implementation identifier.
  • uint8_t[] DATA: Extension data.

APPLICATION ([0x00, 0xF9])

All remaining message codes denote application-defined messages. Application messages are just forwarded to the application.

Implementation

MINX was designed to work on top of unreliable datagram networks. The reference implementation uses UDP/IP sockets. It comes with a simple networking engine written with Boost ASIO.

MINX assumes that applications will use a public-key signature scheme, but it does not specify it. MINX only handles secure hashes over public key data, freeing the application to use public-key cryptography schemes that generate public keys of any length (which is especially useful for quantum-resistant schemes).

The protocol can be extended to support any Proof-of-Work algorithm. The reference implementation uses RandomX and assumes a 256-bit secure hash function for the specified default engine (ENGINE_ID = 0x0).

RandomX is a good equalizer for CPU, GPU, FPGA and ASIC miners, and it currently allows MINX to just assume that PoW solutions translate roughly to the same resource expenditure. The main trade-offs in RandomX are memory use (between 256 MB and 2 GB) and verification speed.

RandomX memory use at the verifier is optimized by using a single verifier for all incoming puzzles. PoW solution spam is mitigated by banning IP address ranges for verification failures.

Application protocols that need up to 251 datagram codes ([0x00..0xFB]) can just directly extend the message set, reusing the single CODE byte in the header. This allows the application to avoid creating its own message frame and to just use the provided networking engine and API.

Implementors can also insert another protocol between the datagram network and MINX, or they can simply replace the header's CODE byte with their own header, effectively creating a derived protocol.

Default engine

The reference implementation of the default engine also serves as its specification, that is, it provides the definitive semantics for the default engine's PROVE_WORK message syntax.

One of the core design decisions in MINX is to have both the PoW puzzle (the base challenge or problem) and the PoW solution (the hash) be generated by the client, and having both be informed in a single PROVE_WORK message.

The RandomX hasher at both the client and the server is initialized with SKEY, which is a secure hash computed over the server's public key (or is the server's public key itself, if it fits in 256 bits). That prevents same PoW solution generated by a client from being spent across multiple servers. The RandomX hasher is expensive to create, but since it depends only on SKEY, a server has to create only one verifier to handle any number of clients, while clients have to create one RandomX hasher for every server they want to send PROVE_WORK messages to.

The PoW puzzle, that is, the data to be hashed by RandomX, is a concatenation of:

  • CKEY: A secure hash computer over a public key controlled by the client (or the client's public key itself, if it fits in 256 bits).
  • HDATA: A secure hash computer over some arbitrary application-defined data block inside the PROVE_WORK message.
  • TIME: The current global UTC time at the client.
  • NONCE: An integer field incremented by the client during the RandomX hashing loop, where the client tries to meet the difficulty target.

The inclusion of CKEY in the PoW puzzle ensures the server can securely credit the correct client for any valid PoW solution (RandomX hash) it receives.

Double-spending in the same server is solved by the server keeping track of all previously accepted solutions. Solutions can be forgotten by the server after a given time, since puzzles with a TIME that is too old are not accepted by the server.

About

MINimal eXtensible protocol

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published