Hey,
I would prefer a competitive mathematical model, since we have two competing blockchains.
Here is my attempt:
I am working under the assumption that the probability to find the next block is proportional to the number of coindays.
Then we need to know the following facts:
How many coindays are minting on the mainchain?
Irigi gave a good estimate in his post http://www.peercointalk.org/index.php?topic=2515.msg26006#msg26006. He concludes that the number of coindays available for the mainchain is given by:
NumberOfCoinsMintingMainchain = 4294901760 x POSdiff / ( 600)
How many coindays does the attacker has?
We assume the attacker has NumberOfCoinsParticipatingInAttack coins and they matured for 90 days. Thus he has NumberOfCoinsParticipatingInAttack*60 coindays.
What is the probability for the attacker to find the next block:
p=NumberOfCoinsParticipatingInAttack60/(NumberOfCoinsParticipatingInAttack60+NumberOfCoinsMintingMainchain);
Due to the fact that peercoin determines the mainchain in the same manner as bitcoin - both choose the longest chain - we can apply the same calculation as sathoshi did in his whitepaper. Let me summarize his calculation:
-The race between the honest chain and an attacker chain can be characterized as a Binomial
Random Walk. The success event is the honest chain being extended by one block, increasing its
lead by +1, and the failure event is the attacker’s chain being extended by one block, reducing the
gap by -1.
-The probability of an attacker catching up from a given deficit is analogous to a Gambler’s
Ruin problem. Hence, we can calculate the probability the attacker ever catches up with the honest chain from a given deficit is given by:
p_z=probability the attacker will ever catch up from z blocks behind
=> p_z=1, if p<1-p
=>p_z=(p/(1-p))^z
-While the mainchain has found z blocks, attacker’s potential progress will be a Poisson distribution with expected value:
\lambda=z*p/(1-p)
-the probability the attacker can reorganize z blocks is given by
sum_over_k=0_to_infty(lambda^k e^(-lambda)/k!*g(z-k))
where g(x)=1 if x<0
and g(x)=(p/(1-p))^x ifx>=0
Using these calculations one finds that an attacker with 10000 coins, who wants to reorganize 6 blocks at the current difficulity 12.2, has a successprobability of 2.4727e-11
A sophisticated attacker might do the following:
-organize his stack into multiple stacks
-wait 6 hours for the next stakemodifier
-make a good guess about the development of the PoSDifficulity and try to precalculate whether he will have a chance to reorganize z blocks in the next years.
-if he does not have this chance, he can reorganize his stacks and start the procedure again.
The peercoin network can even protect us from this attack:
We assume the following:
- The attacker has 1% of the total coinsupply
- The attacker has to reorganize 18 blocks (since the repicient waits this long)
- The PoSdifficulty is 60 (I think this is realistic if cold minting is enabled.)
Now the chance for an successful reorganization with one timestamp is 2.41475e-21.
The chance for an successful reorganization over the next 20 years is 6.25904e-14.
Thus the attacker is likely to find that he is not able to reorg the blocks and he will reorganize his stacks. The math says that the expected number of times the attacker has to reorg his stacks is 1/ (6.25904e-14). The cost of this attack sums up to 1.5976891e+13 transactionfees and a lot of energy. And beside this, the attacker risks the value of his own coins.
My conclusion is: Most of the time, it is okay to wait for just 6 confirmations, but if you do not want to risk anything you should wait longer. Remember, the security of PoS relies on the law of larges numbers and and it takes its time until you can apply this law.
I calculated all these number with the following code: (It is just a variation of the code from the bitcoinwhitepaper.)
#include <iostream>
#include <iomanip>
#include <math.h>
#include <gmpxx.h>
static int const PRECISION=1024;
static mpf_class SMALLEST_UNIT=1;
using namespace std;
mpf_class AttackerSuccessProbability(double q, int z);
mpf_class AttackerSuccessProbabilityForPeriod(mpf_class q, long
days);
mpf_class exp(mpf_class lambda);
mpf_class pow(mpf_class p,int z);
int main() {
double NumberOfCoinsParticipatingInAttack;
double PosDifficulty;
double NumberOfCoinsMintingMainchain;
double HowManyBlocksReorganize;
cout << "How many coins does the attacker have?"<<endl;
cin >> NumberOfCoinsParticipatingInAttack;
NumberOfCoinsParticipatingInAttack*=60;
cout << "Now the attacker can " << NumberOfCoinsParticipatingInAttack << " coindays"<<endl;
cout << "How many blocks does the attacker want to reorganize?"<<endl;
cin >> HowManyBlocksReorganize;
cout << "What is the current difficulty?"<<endl;
cin >> PosDifficulty;
NumberOfCoinsMintingMainchain=4294901760 * PosDifficulty / (600.0);
mpf_set_default_prec(PRECISION+5);
for(int i=1;i<PRECISION;i++){
SMALLEST_UNIT=SMALLEST_UNIT/2;
}
double q=NumberOfCoinsParticipatingInAttack/(NumberOfCoinsParticipatingInAttack+NumberOfCoinsMintingMainchain);
mpf_class ProbabilityForAttackerSuccess=AttackerSuccessProbability(q,HowManyBlocksReorganize);
cout << "The probability to reorganize " << HowManyBlocksReorganize<< " blocks is " << ProbabilityForAttackerSuccess << endl;
long DuranceOfAttack;
cout << "How many days does the attacker try to attack?"<<endl;
cin >> DuranceOfAttack;
mpf_class ProbabilityForSuccessInPeriod=AttackerSuccessProbabilityForPeriod(ProbabilityForAttackerSuccess,DuranceOfAttack);
cout << "The probabibilty to have a chance to reorganize these blocks in " << DuranceOfAttack<< " days is " << ProbabilityForSuccessInPeriod << endl;
return 0;
}
mpf_class AttackerSuccessProbability(double qq, int z)
{
mpf_class const q=qq;
mpf_class const p = 1.0 - q;
mpf_class const lambda = z * (q / p);
mpf_class sum = 1.0;
mpf_class const expOfLambda=exp(-1*lambda);
int i, k;
for (k = 0; k <= z; k++)
{
mpf_class poisson=expOfLambda;
for (i = 1; i <= k; i++)
poisson =poisson* lambda / i;
sum =sum - poisson * (1 - pow(q / p, z - k));
}
return sum;
}
mpf_class exp(mpf_class lambda){
mpf_class sum=0;
mpf_class exponent=1;
for(int i=1;abs(exponent)>SMALLEST_UNIT;i++){
sum=sum+exponent;
exponent=exponent*lambda/i;
}
return sum;
}
mpf_class pow(mpf_class p,int z){
mpf_class product=1;
for(int i=1;i<=z;i++){
product=product*p;
}
return product;
}
mpf_class AttackerSuccessProbabilityForPeriod(mpf_class q, long days)
{
mpf_class p = 1.0 - q;
mpf_class product=1.0;
mpf_class sum = 0.0;
long long
k;
for (k = 1; k <= days*3600; k++)
{
sum+=product;
product*=p;
}
sum*=q;
return sum;
}