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.
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.
We chose to create Epistula because of some glaring issues we encountered in the Axon Interface, these include:
Epistula was built with these issues in mind to improve quality of life for any user. Some of Epistula's core features include:
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.
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.
{
"Body-Signature": str
}
{
"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.
{
"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:
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.
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.