SRS is a service to securely store and recover user secrets like passwords or seed phrases for crypto accounts, etc. Web3 and DeFi require users to take responsibility for securing private keys and keeping account secrets safe is a central challenge. The current system of writing down long recovery phrases places a high burden on the user and can compromise the essential properties of security, availability, and usability. To address these challenges, SRS proposes a chain- and wallet-agnostic service that stores user secrets securely with remarkably short recovery phrases.
A more comprehensive description of SRS can be found in our whitepaper.
Development of SRS is funded by Protocol Labs through the RFP-014 Research Grant.
SRS is under active development and we are working towards our first production release. If you have any questions, are interested in using SRS, or you want to contribute, shoot us an email at info@blockshake.io.
SRS relies on several state-of-the-art cryptographic protocols (Argon2, OPRF, and OPAQUE etc.) to provide best-in-class security.
Argon2 is a key-stretching function (KSF) that is designed to be slow and resource-intensive to make it time-consuming and expensive for attackers to compute a large number of hash values. To control Argon2’s resource-usage, it is parameterized by the number of iterations that it performs (controlling CPU cost), the amount of memory it uses (controlling space usage), and the level of parallelism it is allowed to use. Argon2 is the winner of the Password Hashing Competition and recommended by OWASP.
We use Argon2 client-side during authentication to harden a derived cryptographic key and make brute-force attacks expensive.
OPRF is a protocol to securely compute a pseudorandom function
- The client learns the output of the function but nothing else (in particular not
the secret key
$s$ ). - The server learns the public input
$i$ but nothing else (neither the private input$p$ nor the output of$H$ ). - An outside observer can only observe the public input, but learns nothing else.
In a nutshell, we use the OPRF protocol to harden the user's passphrase with the
server-side secret key
OPAQUE is a protocol for secure password-based authentication without reavling the passphrase to a server or anyone else. Password authentication is the most commonly used authentication mechanism that exists today, but the way it is traditionally implemented sends the user's passphrase in cleartext to the server (but hopefully encrypted in transit by TLS). This makes the passphrase vulnerable to mishandling on the server’s side, e.g., by inadvertently logging all passphrases or storing them in plaintext.
We use OPAQUE as a secure authentication mechanism for SRS's indexer service to make sure that a user's passphrase is protected. OPAQUE comes with the OPRF protocol built in and this allows us to derive a strong cryptographic key that only the user is able to compute and that can be used to securely encrypt the user's secrets.
SRS consists of two services, oracles and indexers.
The oracle service provides the server-side component necessary to run the OPRF
protocol and it holds the secret key
The SRS indexer service is the main service that users interact with to back-up and recover their secrets. The indexer uses OPAQUE to authenticate a user and in that process it communicates with the oracle servers to assemble the results of the oracle servers.
SRS is written in Rust and requires an up-to-date Rust compiler that
compiles Rust version 1.68.2 or newer. Use cargo
to download all necessary
dependencies and compile the code (drop the --release
flag if you want to
compile a debug build):
cargo build --release
The compiled artifacts can be found in the folder ./target/release
(or
./target/debug
for a debug build). Two binaries are generated:
indexer_server
oracle_server
In addition, the repository contains two examples in the ./examples
folder
that demonstrate how to intereact with the indexer & oracle servers. They can be
compiled as follows:
cargo build --examples
SRS servers require access to the following services:
- PostgreSQL: used by the indexer server to store user-related data
- Redis: used by the indexer and oracle servers for rate limiting and session management
In the following we assume that those external services have been set up and you have the necessary credentials to access them.
The following environment variables need to be set for an oracle server:
SRV_ADDRESS
: This is the address that the server binds to (e.g.,127.0.0.1
orlocalhost
)SRV_PORT
: This is the port that the server binds to (e.g.,8081
)SRV_SECRET_KEYS
: This represents the OPRF key material(s) that the server uses, explained in detail below.SRV_DEFAULT_KEY_VERSION
: This is an integer that denotes which OPRF key to useREDIS_CONNECTION_STRING
: This is the connection string that allows the server to access a redis instance
Environment variable SRV_SECRET_KEYS
is a string that encodes one ore more
OPRF key shares. We use Shamir's Secret Sharing (SSS)
to split up the OPRF key across a number of oracle servers. Each key share has
an index
that represents the share
that
represents its share
is an element of the BLS12-381 scalar field and it is serialized as
the base64-encoded big-endian value of the 32-byte scalar. In addition, secret
OPRF keys are versioned and an oracle server supports multiple such keys in
order to support, e.g., key rotations. SRV_SECRET_KEYS
is a
string-representation of a JSON array that looks like this:
[
{
"version": 1,
"index": 1,
"share": "ICnhAK5Gokxz2NYIynPDFj9hpmC0zJ4Kr5rPD6ce58w"
}
]
Key SRV_DEFAULT_KEY_VERSION
points to one of the keys in SRV_SECRET_KEYS
that is considered the default key if a user doesn't specify a key version in
requests. This is typically the most recent key.
How to configure the environment variables depends on your system, for example
many cloud providers have a dedicated GUI to set them up. During development, it
is convenient to store these values in an .env
file and load them into the
shell. An example .env
file is shown in .oracle.env
and it can be loaded
(depending on your shell) by calling source .oracle.env
.
Once compiled in release mode and configured, an oracle can be executed by calling:
./target/release/oracle_server
During development it is more convenient to use the following to compile & execute an oracle server:
cargo run --bin oracle_server
The following environment variables need to be set for an indexer server:
SRV_ADDRESS
: This is the address that the server binds to (e.g.,127.0.0.1
orlocalhost
)SRV_PORT
: This is the port that the server binds to (e.g.,8081
)SRV_KE_PUBLIC_KEY
: This is the server's public key in the key-exchange protocolSRV_KE_PRIVATE_KEY
: This is the server's private key in the key-exchange protocolSRV_IDENTITY
: The name of the server (e.g.,srs.blockshake.io
)SRV_OPRF_HOSTS
: This is a whitespace separated list of hosts that run oracle servers (e.g.,"http://localhost:8081 http://localhost:8082 http://localhost:8083"
)SRV_OPRF_THRESHOLD
: This denotes the threshold of Oracle servers that need to be available to perform Shamir's secret sharingSRV_USERNAME_OPRF_KEY
: This is a base64-encoded scalar in BLS12-381 that is used to blind usernames before they are sent to oracle serversSRV_DEFAULT_KEY_VERSION
: This is the OPRF key version to use by defaultSRV_FAKE_KSF_PARAMS
: This is a string (e.g.,"[{\"m_cost\": 8192, \"t_cost\": 1, \"p_cost\": 1}]"
) that denotes a list of KSF (e.g., Argon2) parameters that are used for fake records when someone tries to login with a username that does not existDB_USER
: This is the username used to connect to postgresDB_PASSWORD
: This is the password used to connect to postgresDB_HOST
: This is the host of the postgres serverDB_NAME
: This is the name of the databaseREDIS_CONNECTION_STRING
: This is the connection string that allows the server to access a redis instance
Like with the oracle server, an example .env
file that contains these environment
variables can be found in the file .indexer.env
.
Once compiled in release mode and configured, an indexer can be executed by calling:
./target/release/indexer_server
During development it is more convenient to use the following to compile & execute an indexer server:
cargo run --bin indexer_server
We provide a toy client for the indexer service to demonstrate how to interact with it. It expects the following environment variables:
SRV_ADDRESS
: This is the indexer's address (e.g.,http://localhost:8080
)SRV_KE_PUBLIC_KEY
: This is the server's public key in the key-exchange protocol
To run the client:
cargo run --example indexer_client
This example provides a command-line interface for the indexer and you can register users, login, encrypt & upload secrets, and download & decrypt them again.
The oracle and indexer servers can be accessed via HTTP and their API is specified in OpenAPI format:
You can render the OpenAPI files with an appropriate editor.
We use Shamir's Secret Sharing (SSS) scheme to split up a secret key across a
number
The
There are multiple ways to generate a SSS polynomial. In production, it is recommended to use a ceremony to generate the OPRF key shares such that they never leave an oracle. During development, holding such a ceremony is cumbersome, hence we provide a simple tool to generate the OPRF key shares on a single machine:
cargo run --bin shamir_config $treshold $number_shares
where, $threshold
is the number of oracle servers that are needed to evaluate
OPRF and $number_shares
is the total number of oracle servers.
This project is licensed under the AGPLv3 license.
Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Tokio by you, shall be licensed as AGPLv3, without any additional terms or conditions.