Security Analysis (#55)

* This adds two sections to dip 0008.  The first section considers the security of Chain Locks and provides the calculations needed to evaluate the security.  The second added sections provides mitigations of situtaions when
attackers do not own the collatoral of the masternodes.

* Update dip-0008.md

* Fix hyperlinks

* Update dip-0008.md

* Update dip-0008.md

correction of word.

Co-Authored-By: UdjinM6 <UdjinM6@users.noreply.github.com>

* Update dip-0008.md

Need to make sure it's always big choose small.

Co-Authored-By: UdjinM6 <UdjinM6@users.noreply.github.com>

* Fixes inconsistantcy in gifs

* Update dip-0008/quorum_attack.py

fix tpyo

Co-Authored-By: thephez <thephez@users.noreply.github.com>

* Update dip-0008/quorum_attack.py

Co-Authored-By: thephez <thephez@users.noreply.github.com>

* Update dip-0008.md

Changing titles, todo change table.

Co-Authored-By: UdjinM6 <UdjinM6@users.noreply.github.com>

* Clarify table

This handles the edge case of witholding a ChainLock correctly, it takes 161 nodes to withold a ChainLock.
Also makes table clearer to read.

* Clarify malicious chainlock

Based on suggestions from AndyFreer a second paragraph is added to explain what can go wrong.

* Update dip-0008.md

Add line break.

Co-Authored-By: UdjinM6 <UdjinM6@users.noreply.github.com>

* Apply suggestions of thephez

The calculations were updated to refelct the fact that 161 masternodes are needed to withhold a chainlock
in a previous commit.  This commit updates the text and displayed formulas to reflect this fact.

We also alert the reader that we assume that all uncompromised nodes are behaiving as expected.  We include the effect of relaxing this
assumption, however the calculations are left to the reader.  The python function provided makes it easy.

* Fix two typos

* Update dip-0008.md

one missed 160->161

Co-Authored-By: thephez <thephez@users.noreply.github.com>

* Update dip-0008.md

Co-Authored-By: thephez <thephez@users.noreply.github.com>

* Correct C size in sumation formula

* Update dip-0008/quorum_attack.py

correct spelling

Co-Authored-By: thephez <thephez@users.noreply.github.com>

* Update dip-0008/quorum_attack.py

correct spelling

Co-Authored-By: thephez <thephez@users.noreply.github.com>

* Update dip-0008/quorum_attack.py

correct spelling

Co-Authored-By: thephez <thephez@users.noreply.github.com>

* Update dip-0008/quorum_attack.py

correct spelling

Co-Authored-By: thephez <thephez@users.noreply.github.com>

* Update dip-0008/quorum_attack.py

correct spelling

Co-Authored-By: thephez <thephez@users.noreply.github.com>

* Update dip-0008/quorum_attack.py

Co-Authored-By: thephez <thephez@users.noreply.github.com>

* Update dip-0008/quorum_attack.py

Co-Authored-By: thephez <thephez@users.noreply.github.com>

* Update dip-0008/quorum_attack.py

Co-Authored-By: thephez <thephez@users.noreply.github.com>

* Update dip-0008/quorum_attack.py

Co-Authored-By: thephez <thephez@users.noreply.github.com>

* Update dip-0008/quorum_attack.py

Co-Authored-By: thephez <thephez@users.noreply.github.com>

* Update dip-0008/quorum_attack.py

Co-Authored-By: thephez <thephez@users.noreply.github.com>

* Update dip-0008/quorum_attack.py

Co-Authored-By: thephez <thephez@users.noreply.github.com>

* Update dip-0008/quorum_attack.py

Co-Authored-By: thephez <thephez@users.noreply.github.com>

Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
Co-authored-by: thephez <thephez@users.noreply.github.com>
This commit is contained in:
Darren Tapp 2020-01-02 13:43:01 -05:00 committed by thephez
parent 41fc2c9413
commit 55aa78cd1e
4 changed files with 230 additions and 0 deletions

View file

@ -24,6 +24,8 @@
1. [Implications of a signed block](#implications-of-a-signed-block)
1. [Network partitions](#network-partitions)
1. [Initial Block Download](#initial-block-download)
1. [Calculations](#calculations)
1. [Security Considerations](#security-considerations)
1. [Copyright](#copyright)
## Abstract
@ -275,6 +277,127 @@ resolve any ambiguities which might occur in the last few blocks.
If the need arises to include block signatures in initial block download, we
will update this DIP and implementations accordingly.
## Calculations
We consider the scenario where an attacker has assumed control of a number of
masternodes. We will then calculate two probabilities that the attacker will
be able to disrupt the network. Specifically, we will calculate the probability
that an attacker will be able to prevent all ChainLocks for a twelve hour period,
and we will calculate the probability that an attacker can successfully create
a malicious or erroneous ChainLock.
The consequences of an attacker withholding ChainLocks would be that the network
would fall back on proof of work. The consequence of a malicious or erroneous
ChainLock might depend on the attackers motivations. An attacker with
control of a ChainLock quorum would be able to:
1. Produce conflicting ChainLocks.
2. Withhold ChainLocks and then issue a ChainLock for a conflicting previous block
not included in the current chain of most work.
3. Secure undo advantage.
We assume that all masternodes not under malicious control are
behaving as expected. In practice this is generally observed. In theory,
it is possible for some nodes to be unreachable, or the attacker could
combine a DoS attack in conjuction with compromising nodes. If this is the case, it
would become more likely an attacker could withhold ChainLocks, and not
be any more likely the attacker could produce a malicious ChainLock.
Our calculations can easily be modified to model the network operating
under other assumptions.
In this section we will show that the random selection of a LLMQ will
not allow an attacker to control a ChainLock quorum without control of a
supermajority of masternodes.
Quorum selection is designed to provide for an effectively simple random
choice of masternodes in each quorum. Thus we may assume that each quorum is
a simple random selection. If there are a total of 'N' masternodes the
number of possible quorums is the number of ways that 400 objects can be
chosen out of `N`. In some literature this number is
written <sub>`N`</sub>`C`<sub>`400`</sub> and is enunciated as
'N choose 400'. Numbers that arise in this fashion are all
binomial coefficients and have a delightful relation to Pascal's Triangle.
For any process with an observable outcome the set of all outcomes is
called a sample space. If all outcomes are equally likely, as in the
selection of a quorum, the probability of any event is the number of
outcomes that satisfy that event over the total number outcomes.
An attacker can temporarily prevent ChainLocks if they control
`161` out of 400 masternodes in the quorum. If the attacker controls
`m` out of the `N` total masternodes we can compute the
number of outcomes that satisfy the event "exactly `161`
nodes of the quorum are controlled by the masternode."
Specifically there are
<sub>`m`</sub>`C`<sub>`161`</sub> * <sub>`N - m`</sub>`C`<sub>`239`</sub>
outcomes where the attacker controls exactly `161` masternodes.
Thus, the probability that the attacker controls exactly `161` nodes is
<p align="center"><img src="dip-0008/ThreshCase.gif" alt="Threshold Probability"></p>
The attacker could also be successful if they control <b>more</b> than `160`
of the nodes in the quorum selection. Thus the exact probability that an
attacker can successfully prevent ChainLocks for that quorum round is
computed by counting the number of outcomes where the attacker controls
160 or more nodes in the quorum divided by the total number of outcomes.
This is computed by the sum
<p align="center"><img src="dip-0008/fin_sum.gif" alt="Final sum" ></p>
The numbers involved in this sum can be quite large. We may
use a <A HREF="dip-0008/quorum_attack.py">Python Script</A> to effectively
evaluate this sum. Note
that we made the necessary modifications to this formula
to calculate the probability that an attacker controls 60% or more
of the quorum.
| N | m | Success probability of withholding a ChainLock | Success probability of creating a malicious ChainLock |
|---|---|--------------|--------------------------------|
|5000|500| 3.32e-65 | 7.11e-157|
|5000|1000| 1.69e-22 | 2.89e-76 |
|5000|1500| 3.36e-6 | 1.29e-38 |
|2000|200 | 2.12e-87 | 0 |
|2000|400 | 1.80e-26 | 9.49e-94 |
|2000|600 | 6.20e-7 | 3.94e-45 |
In all scenarios above, an attacker should not expect to withhold a
ChainLock in the next century. The attacker would have a less than
one in 100 trillion chance of producing at least
one malicious ChainLock in the next sextillion (10^21) years.
From these calculations we conclude that an attacker with control of fewer
than 30% of all masternodes will not have any influence on ChainLocks. For
completeness we note that
if an attacker controlled 50% of masternodes an attacker would
generally be able to prevent ChainLocks, but there is less than 30 out of
one billion chance that the attacker will be able to produce at least one
malicious ChainLock in the next million years.
## Security Considerations
It is of note that it is not required for an attacker to actually own the
collateral of masternodes that the attacker controls. A company offering
the service of hosting masternodes for clients could be persuaded to run
malicious software. Also if node operators do not check the digital signature
there could be a malicious download or software that spoofs being an
official download. We recommend mitigations of both these side channel attacks.
It is recommended that Dash users require some transparency
from masternode hosting services. It should be expected that a
masternode hosting service disclose all masternodes that it hosts as a
service. It is then recommended that those who utilize a masternode hosting
service check that their node is listed in the disclosure. This
information could help identify if nodes hosted by services are
behaving as expected.
It is always recommended that users check the signature on any software they
download. As long as the correct public key is acquired then it is
cryptographically not possible for the official download to be spoofed.
## Copyright
Copyright (c) 2018 Dash Core Group, Inc. [Licensed under the MIT

BIN
dip-0008/ThreshCase.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

BIN
dip-0008/fin_sum.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

107
dip-0008/quorum_attack.py Executable file
View file

@ -0,0 +1,107 @@
#!/usr/bin/python
#This script was written by Darren Tapp and optimized by thephez
from decimal import Decimal
from math import log
from math import factorial as fac
from math import log1p
from math import exp
def binom(x, y):
try:
binom = fac(x) // fac(y) // fac(x - y)
except ValueError:
binom = 0
return binom
###This function takes inputs and outputs the probability
#of success in one trial
#pcalc is short for probability calculation
def pcalc(masternodes,quorumsize,attacksuccess,Byznodes):
SampleSpace = binom(masternodes,quorumsize)
pctemp=0
for x in range(attacksuccess, quorumsize+1):
pctemp = pctemp + binom(Byznodes,x)*binom(masternodes-Byznodes,quorumsize-x)
#at this juncture the answer is pctemp/SampleSpace
#but that will produce an overflow error. We use logarithms to
#calculate this value
return 10 ** (log(pctemp,10)- log(SampleSpace,10))
#Takes the probability of success in one trial and outputs the probability of success in 730 septillion trials
#730 septillion trials requires a septillion years of masternode quorum formation.
def ZettaYear(probability):
trials = 2*365*10 ** 21
return 1-exp(trials * log1p(-probability))
def MegaYear(probability):
trials = 2*365*10 ** 6
return 1-exp(trials * log1p(-probability))
##We evaluate the function pcalc(10,5,3,4)
##print pcalc(10,5,3,4)
##as a test vector
##The answer would be [binom(3,4)*binom(2,6)+(binom(4,4)*binom(1,6)]/binom(10,5)
##[4*15+1*6]/252 = 66/252
##print float(66)/252
##quorum size for ChainLocks
qs = 400
##Number of masternodes
mn = 5000
##Number of Byzantine nodes assuming 5000 nodes
Bft = [500,1000,1500]
##Threshold out of quorum of 400
thresh = 161
for j in range(0,3):
print "For ", mn, " masternodes with ", Bft[j],"Byzantine the chance of withholding a ChainLock in one trial is ", pcalc(mn,qs,thresh,Bft[j])
##Now change the # threshold
thresh = 240
for j in range(0,3):
print "For ", mn, " masternodes with ", Bft[j],"Byzantine the chance of producing a malicious ChainLock is ", pcalc(mn,qs,thresh,Bft[j])
#In the case of a smaller number of masternodes
mn=2000
##Number of Byzantine nodes assuming 2000 nodes
Bft = [240,400,600]
##Threshold out of quorum of 400
thresh = 161
for j in range(0,3):
print "For ", mn, " masternodes with ", Bft[j],"Byzantine the chance of withholding a ChainLock in one trial is ", pcalc(mn,qs,thresh,Bft[j])
##Now change the # threshold
thresh = 240
for j in range(0,3):
print "For ", mn, " masternodes with ", Bft[j],"Byzantine the chance of producing a malicious ChainLock is ", pcalc(mn,qs,thresh,Bft[j])
print "Security interpretation:"
print "For 5000 masternodes with 1500 Byzantine nodes the chance of producing a malicious ChainLock is ", pcalc(5000,400,240,1500)
print "Which means in a Zettayear the chances of a "
print "malicious chainlock is ", ZettaYear(pcalc(5000,400,240,1500))
print "In an extreme case the chance of quorum control with 40% of nodes:"
print "5000 Masternodes ", pcalc(5000,400,240,2000)
print "2000 Masternodes ", pcalc(2000,400,240,800)
print "In an even more extreme case the chance of quorum control with 50% of nodes:"
print "5000 Masternodes ", pcalc(5000,400,240,2500)
print "2000 Masternodes ", pcalc(2000,400,240,1000)
print MegaYear(pcalc(5000,400,240,2000))
print "For 2000 total nodes with 200 attacking , the chance of withholding a ChainLock is,", pcalc(2000,400,161,200)