In this post we explain what are Hierarchical Deterministic (HD) wallets and Pseudo Random Functions (PRFs), and how they can be used in a Multi Party Computation (MPC) setting in a very efficient manner.
Hierarchical Deterministic (HD) wallets were invented by Pieter Wuille [1], They provide a mechanism to generate a lot of private keys deterministically from a single master key. That way you only need to backup the master key and you can restore all future keys even if you generate multiple private keys.
There are a few reasons why you would want to keep switching keys:
There are 2 kinds of HD wallets:
Non-Hardened HD means that there's a master public key
You can generate new public keys using the master public key, and their corresponding private keys using the master private key.
This allows you to use the master public key on a "hot" wallet and generate new public keys for every transaction without risking the private key.
The downside of this is that if an attacker gets hold of your master public key you lose both the privacy and the security properties of the HD wallet.
Generally speaking key generation here looks as follows:
Hardened HD on the other hand, doesn't use the master public key to generate keys, instead it always uses the master private key, so it looks as follows:
On one hand you can no longer store the master public key on a web server to generate public keys,
but on the other hand it means that leaking public keys will never expose
Pseudo Random Functions (PRF) are a very common primitive in cryptography,
we use them for HD wallets, but also to construct block ciphers, MACs (Message Authenticated Codes) and more.
Simply speaking a PRF is defined as a function that receives a key
Multi-Party Computation (MPC) is concerned with computing functions over data that is shared between multiple parties while keeping the shares secret even from the other parties.
One common way to do that is using Secret Sharing, which is a mechanism where we share a secret between multiple parties and do operations on that shared secret.
Secret sharing works as follows, each party has a
Throughout the blog we'll use
Now we can do arithmetics on secret shares:
We also use
MPC and secret sharing is used in practice in a lot of cryptocurrency wallets, currently these wallets either don't use a HD wallet, or use the non-hardened variant.
In this post we describe a protocol that will allow us to implement the hardened variant of a HD wallet even when our key is secret shared.
For that we need a PRF that can work with a shared key
So what's the problem with known PRFs such as HMAC-SHA256 and Chacha20?
If we want to use HMAC-SHA256 like BIP32 does over our shared key, we will either need a garbled circuit which requires a tremendous amount of computational and communication complexity, or to transform these algorithms into arithmetic circuits, which can then be computed using secret sharing arithmetic but these contain thousands of gates, and between dozens to hundreds rounds of communication.
So if we want something much faster and with low number of rounds, there are a few known solutions like the Naor-Reingold PRF[2] which work on secret shared keys and are quite simple and efficient. These rely on the discrete logarithm and related problems, but their output must be public and we want the output
The Legendre symbol is a way to symbolize if a scalar
The Legendre symbol just gives the number 1 to quadratic residues, -1 to quadratic non residues and 0 to 0.
Formally (source):
(note that
Calculating the Legendre symbol can be done in an efficient manner, the simplest way is using Euler's criterion[3]
This PRF was first proposed and analyzed by Ivan Damgård in 1990[4], he conjectured the hardness of a few problems, together they give us the following informal assumption:
Given a randomly sampled
Now we can build a PRF from it as follows:
This gives us
At first glance it looks hard to compute the Legendre symbol of a shared value in MPC, as all these algorithms involve a lot of multiplications, but we will quickly see that it's actually much easier by using a modified version of a trick shown by Grassi et al[5].
To do this we will blind the value of the shared secret
For that we need blinding values with known Legendre symbols, so we will need to generate:
We then compute the blinder:
If
If
So
Next we compute:
This is where the magic happens, each party can send their
So
To do that we compute:
Let's go over it:
if
if
You can see that this cancels out the effect of
This means that
We can then convert that into a bit in a secret shared way by doing
This can be executed
For a fully dishonest majority, security proofs and an implementation wait for the paper
We thank Nikolaos Makriyannis who's a co-author on the yet to be published paper, and to Claudio Orlandi and the ZenGo-X team for reviewing it.
https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki ↩︎
https://en.wikipedia.org/wiki/Naor–Reingold_pseudorandom_function ↩︎
Damgård, I.B., 1990. On the randomness of Legendre and Jacobi sequences, in: Proceedings on Advances in Cryptology, CRYPTO ’88. Springer-Verlag, Berlin, Heidelberg, pp. 163–172. ↩︎
Grassi, L., Rechberger, C., Rotaru, D., Scholl, P., Smart, N.P., 2016.
MPC-Friendly Symmetric Key Primitives. In Proceedings of the 2016 ACM SIGSAC Conference on Computer and Communications Security (CCS '16) pp. 430–443. https://doi.org/10.1145/2976749.2978332 ↩︎
You generate a random secret square and then multiply it by some publicly known Quadratic Non Residue ↩︎
You generate a random