nanocurrency / nano-node

Nano is digital currency. Its ticker is: XNO and its currency symbol is: Ӿ
https://nano.org
BSD 3-Clause "New" or "Revised" License
3.47k stars 783 forks source link

Ability to recover from a future compromise of Nano's signature scheme #2027

Open PlasmaPower opened 5 years ago

PlasmaPower commented 5 years ago

Like other coins, Nano's signature scheme could be compromised in a number of ways

Most of these are in the far future, but in the event that one happens, or one becomes imminent, recovering ownership in a decentralized manner would be near impossible without having a safety net in place. This proposal is for a safety net, what I'm calling recovery keys.

Recovery key requirements

Assumptions

My proposal

My proposal uses Lamport one-time hash-based signatures, double hashing for private key -> public key conversion, key derivation by hashing with an index, and a hashed public key.

For hash functions my proposal uses H0(x) as SHA3-512, H1(x) as Whirlpool, and H2(x) as blake2b with 64 byte output for key derivation.

Denoting x || y as x concatenated with y, and pk being the private key, my proposed 64 byte recovery key would be calculated as follows:

H0(H1( H0(H1(H2("recovery key" || 0 || 0 || pk))) || H0(H1(H2("recovery key" || 0 || 1 || pk))) || H0(H1(H2("recovery key" || 1 || 0 || pk))) || H0(H1(H2("recovery key" || 1 || 1 || pk))) || H0(H1(H2("recovery key" || 2 || 0 || pk))) || H0(H1(H2("recovery key" || 2 || 1 || pk))) || ... ))

I'll be denoting these hashes by their depth from the outside, so the recovery key is at depth 0, and the private key is part of each depth 4. The repeated hashes at depth 1 would be continued until the first index is 255, inclusive. The first index is the bit position (0 through 255), and the second is the bit value (0 or 1). This gives the recovery key the one-time ability to sign a 256 bit message, presumably a public key for a new signature scheme.

A signature with the recovery key would consist of firstly revealing the expanded public key (the concatenated hashes at depth 1), and secondly the hashes at depth 3 for the chosen bit values at each bit position. If Nano's signature scheme is compromised, or compromise is imminent (e.g. a quantum computer has been shown to be capable of an attack), once the dust settles, this would be used to prove ownership and transition to a new signature scheme.

My proposed recovery key for an all 0 32-bit private key is 0b2d29b511f8e97792074d91fbebb5760da9a2d07f09678a35eb57ee0e098d44ad3681a7f3ecd567ca5dba3bdb9cf09015a9c007880518bf16973f53409bf68f. This took my desktop 0.002 seconds to compute (using only one thread) using the following Rust implementation compiled on release mode, so this scheme is definitely fast enough.

use blake2::Blake2b;
use digest::Digest;
use hex;
use sha3::Sha3_512;
use whirlpool::Whirlpool;

fn main() {
    let key = [0u8; 32];
    let mut depth0 = Sha3_512::default();
    let mut depth1 = Whirlpool::default();
    for i in 0..=255 {
        for v in 0..=1 {
            let mut depth2 = Sha3_512::default();
            let mut depth3 = Whirlpool::default();
            let mut depth4 = Blake2b::default();
            depth4.input(b"recovery key");
            depth4.input(&[i]);
            depth4.input(&[v]);
            depth4.input(&key);
            depth3.input(depth4.result());
            depth2.input(depth3.result());
            depth1.input(depth2.result());
        }
    }
    depth0.input(depth1.result());
    println!("{}", hex::encode(depth0.result().as_slice()));
}

Additional assumptions for this scheme

How to distribute these keys

In any scenario, these would be signed by the account. The point is that they're signed for and recorded well before an attack is known, so that when the attack happens the community will have already recorded the recovery keys and doesn't need to trust new signatures from the account, just one made and recorded well before the attack. After the attack, establishing community consensus on the recovery keys for each account would probably be a manual process.

clemahieu commented 5 years ago

consensus should not be able to overwrite recovery keys, because consensus is reliant on the signature scheme working

The point is that they're signed for and recorded well before an attack is known

Can these points be guaranteed?

An attacker constructing a fork which sends the entire balance of a victim account to two different accounts with two different recovery keys would favor consensus over recovery key and thus break the first assumption.

Sending the entire balance of a victim account to a new account, and thus a new recovery key would seem to erase the "well before" nature of the recovery key.

PlasmaPower commented 5 years ago

Here's how I think it would go down:

Basically, no Nano couldn't establish perfect consensus on which transactions were part of the attack, what the exact state of the ledger without the attack would be, or completely nullify the damage of an attack to services accepting deposits like exchanges. But at least Nano would have a clear definition of who owns the vast majority of funds, instead of attackers having as much of a claim to the funds as the real owner (since the attacker can sign as the owner).

PlasmaPower commented 5 years ago

So to answer your question:

Can these points be guaranteed?

Not for the movement of funds post-attack, but that's an intrinsic problem and this solution does a lot better than what Nano could do without such a safety net.

funkspock commented 5 years ago

@clemahieu While I find the concept of recovery keys interesting, at minimum I believe that Nano should have the capability to switch its Public-key cryptography. As you might know NIST is working on the standardization of Post-Quantum Crypto: https://www.nist.gov/news-events/news/2019/01/nist-reveals-26-algorithms-advancing-post-quantum-crypto-semifinals So far, 26 algorithms have made it to the semi finals, and the expectation is that 3 algorithms (based on three different families of crypto) will prevail. At some point eventually a switch needs to take place, and this capability for (almost) seamless transition needs to be thought about and worked out: e.g. code-readiness, testing, playbook, communication plan, etc. Also, as @PlasmaPower mentioned, the current or any future crypto might become compromised which again shows that this capability is highly needed. This leads to the question, how well is Nano currently prepared and what would its desired state be.

PlasmaPower commented 5 years ago

What do you mean by "the capability to switch its Public-key cryptography" other than recovery keys?

funkspock commented 5 years ago

@PlasmaPower We might need to switch to a Lattice-, or Code-based, or Multivariate crypto system. This means that the Nano code needs to be (1) made ready to easily switch the crypto system. This is not trivial, as you probably need to make sure that this part of the code can easily be replaced -which of course requires testing. There is no reason to wait on testing as now there is no time pressure to realize a solution. (2) Consequently, this also means that the code needs to enable transitioning: e.g. via hardfork/snapshots, dual-stack, or some form of translation/tunneling (similar to IPv4 to IPv6 transition). Recovery keys is one of the options that can be considered. With capability I was referring to item (1) which I see as a pre-requisite for (2).

PlasmaPower commented 5 years ago

I don't think investing near that much effort right now is warranted. We'll have plenty of heads up for quantum computers. As long as we have recovery keys, we can implement the rest later without causing any additional problems.

PlasmaPower commented 5 years ago

Even if I was given the option of switching all accounts to quantum secure signatures right now, seamlessly, I would decline, because there are tradeoffs with quantum secure crypto such as performance, size, and that it hasn't been studied as much.