Manifold Labs

Epistula Release

Posted 9/5/2024

Intro

Manifold Labs is proud to announce the release of the Epistula protocol. This is the first truly open source networking protocol in Bittensor history. This protocol will be used to ensure security, reduce bloat, and improve QOL for any users.

What is Epistula?
Epistula /eˈpis.tu.la/ is the Latin word for letter, or a piece of mail.

High Level

The Epistula Protocol is a standard for sending signed public messages between entities using ed25519 keys. Although primarily developed for the Bittensor network, the Epistula standard can be used on any network with ed25519 keys. The Epistula protocol is a ground up protocol created by the Manifold Labs team that provides easy to understand, industry standard ways of communicating between any product. We at Manifold use this already in not only Subnet 4, but Sybil, Targon Hub, and Targon Stats.

DDOS attacks are a challenge that miners often face. Epistula provides an extra set of signatures that are temporally cacheable and easy to validate that miners can optionally use to protect against such attacks. These can be implemented all the way up to the load balancer level, so that protecting against such attacks takes virtually no compute.

Axon Interface on Bittensor vs Epistula

We chose to create Epistula because of some glaring issues we encountered in the Axon Interface, these include:

  • Strict and opinionated
  • Forced usage of Bittensor library
  • Essentially forced usage of Python
  • Slow to process incoming requests
  • Potentially broke on new versions of Bittensor
  • Implementation was not industry standard
  • Only usable between validators and miners

Epistula was built with these issues in mind to improve quality of life for any user. Some of Epistula's core features include:

  • Easy to implement in any language
  • No library -> no breaking changes
  • Simply a protocol
  • Allows secure communication between any entities on Bittensor
  • uses industry standards; header naming conventions, hashing algorithms (sha256)
  • no limits on speed
  • no limits on request body (can be json, images, streams, etc)

Epistula replaces the axon interface for subnet 4. With this new build, all Epistula requests allow miners to primarily focus on speed for their responses rather than being unfairly scored lower due to blackbox code that they are not privy to. Epistula lets miners and validators use any software they choose to interface with requests. Miners could find faster or better http servers, and are no longer locked to fastapi, let alone python.

Why we are releasing as v2 instead of v1?

v1 of Epistula was a silent roll out, and we spent additional time identifying potential bugs before a full public release.

v1 at its core is simply a header that is the signature of the request body. The header body-signature is the signature created vie the sender's ed25519 key. In Bittensor this is generally the users hotkey.

Header

{
  "Body-Signature": str
}

Body

{
  "data": any,
  "nonce": int64,
  "signed_by": str,
  "signed_for": option[str],
  "version": int32
}

With this implementation we noticed that miners were prone to DDOS attacks as they had to decode the entire body to determine if the signature was verified, which was expensive to compute. This was our initial motivation for a v2.

In v2 we looked for a methodology in which a miner could determine from the header if it is a verified request. The header now holds multiple signatures and a time stamp to determine a recent request and the validity of said request.

Header

{
  "Epistula-Version": "(str,)",
  "Epistula-Timestamp": "(str,)",
  "Epistula-Uuid": "(str,)",
  "Epistula-Signed-By": "(str,)",
  "Epistula-Request-Signature": "(str,)",
  "Epistula-Signed-For": "(str, optional)",
  "Epistula-Secret-Signature-0": "(str, optional)",
  "Epistula-Secret-Signature-1": "(str, optional)",
  "Epistula-Secret-Signature-2": "(str, optional)"
}

After the release of v1 we noticed some important changes that were needed. These include, by moving the Epistula fields to the body we no longer require forced use of json. The previous iteration was not industry standard, siting most protocol level details should be in the headers. Finally, v1 required full parse of body to verify the only signature (slow and costly). These ideas helped us migrate to our v2.

Header Fields:

Epistula-Version (str): The version of the Epistula protocol being used. For this specification, it's "2".

Epistula-Timestamp (str): and Epistula-Uuid (str): To protect against MITM replay attacks, Epistula uses UNIX millisecond timestamps and request UUIDs with a 5 second delta. It is up to the receiver to properly handle the storage of UUIDs and detect if a message has been replayed within the allowed delta.

Epistula-Signed-By (str): The ss58_address of the signer, used to verify the request signature.

Epistula-Request-Signature (str): A hex-encoded signature created using the signer's ed25519 key (typically the user's hotkey in Bittensor) via the schnorrkel algorithm. The signature is generated from period joined concatenated string containing:

  • SHA256 hash of the body as bytes
  • UUID of the request
  • Timestamp
  • Signed-for address (if present, otherwise an empty string)

Epistula-Signed-For (str, optional): The ss58_address of the intended receiver. This helps prevent relay attacks.

Epistula-Secret-Signature-0 (str, optional): and Epistula-Secret-Signature-1 (str, optional): and Epistula-Secret-Signature-2 (str, optional): These three signatures are used as a sliding window of signatures that can checked purely from headers and cached across requests. The signatures are crafted by taking the current time in milliseconds, rounding to the nearest 10,000th combined with the receiver's hotkey.

epochNonce = round(time.time() * 1000)
epochInterval = ceil(epochNonce / 1e4) * 1e4
secretSig0 = hotkey.sign(str(epochInterval-1) + '.' + signed_for)
secretSig1 = hotkey.sign(str(epochInterval)   + '.' + signed_for)
secretSig2 = hotkey.sign(str(epochInterval+1) + '.' + signed_for)

Miners can optionally use these to protect against DDOS attacks by implementing the following process:

When no signatures are cached, or all signatures are stale (older than current epoch interval - 2) only check Epistula-Secret-Signature-1. When a valid request is found, cache all 3 signatures, each with a stale time of 1.6 min * x, where x is the signature index + 1. If you get a request where any signature is cached and not stale, re-cache with the new requests 3 signatures. If all signatures are stale, act as if there are no signatures.

As long as the endpoint is getting valid requests from the same sender once every interval [1.6 min] * 3, the cache should always be populated.

Conclusion

With this new protocol Manifold Labs is forging the path to truly open source and easy to use standards in Bittensor that will pave the way for the community to build products like Sybil.

Epistula Documentation


Contact us