-rw-r--r-- 4362 cryptattacktester-20230614/transition.cpp raw
#include <map>
#include <cassert>
#include "transition.h"
using namespace std;
// consider the following markov chain:
// state 0: search has not finished, and target has 0 errors within KK positions
// state 1: search has not finished, and target has 1 error within KK positions
// ...
// state W: search has not finished, and target has W errors within KK positions
// state W+1: have finished by finding target
// state W+2: have finished with systematic-form failure
// initial state is 0...W
// chance of state e: binomial(KK,e)*binomial(N-KK,W-e)/binomial(N,W)
vector<vector<bigfloat>> transition_zero(bigint W)
{
vector<vector<bigfloat>> result;
vector<bigfloat> zerorow;
for (bigint v = 0;v <= W+2;++v) zerorow.push_back(0);
for (bigint u = 0;u <= W+2;++u) result.push_back(zerorow);
return result;
}
vector<vector<bigfloat>> transition_identity(bigint W)
{
vector<vector<bigfloat>> result = transition_zero(W);
for (bigint u = 0;u <= W+2;++u) result.at(u).at(u) = 1;
return result;
}
static map<tuple<bigint,bigint,bigint,bigint,bigint>,vector<vector<bigfloat>>> transition_weightstep_cache;
// output[u][v] is chance that a type-3 exchange of X columns moves state u to state v
vector<vector<bigfloat>> transition_weightstep(bigint N,bigint KK,bigint W,bigint X)
{
tuple<bigint,bigint,bigint,bigint,bigint> key = make_tuple(N,KK,W,X,bigfloat::get_default_precision());
if (transition_weightstep_cache.count(key))
return transition_weightstep_cache[key];
vector<vector<bigfloat>> result = transition_identity(W);
bigfloat denom = bigfloat(binomial(N-KK,X)*binomial(KK,X));
for (bigint u = 0;u <= W;++u) {
for (bigint v = 0;v <= W;++v) {
bigint resultuv = 0;
bigint d = u-v;
if (d > X && d < -X) continue;
for (bigint i = 0;i <= W-u;++i) {
if (X-i < 0) continue;
if (d+i < 0) continue;
if (X-d-i < 0) continue;
if (X-i > N-KK-W+u) continue;
if (d+i > u) continue;
if (X-d-i > KK-u) continue;
resultuv += binomial(W-u,i)*binomial(N-KK-W+u,X-i)*binomial(u,d+i)*binomial(KK-u,X-d-i);
}
result.at(u).at(v) = bigfloat(resultuv)/denom;
}
}
transition_weightstep_cache[key] = result;
return result;
}
vector<vector<bigfloat>> transition_checksystematic(bigint W,bigint X,bigint Y)
{
vector<vector<bigfloat>> result = transition_identity(W);
bigfloat success;
assert(X <= Y);
// what's the chance that an XxY matrix has rank X?
// 1/2^Y chance of first row failing
// if it's ok: 1/2^(Y-1) chance of second row failing
// ...
// so overall chance (1-1/2^Y)(1-1/2^(Y-1))...(1-1/2^(Y-X+1))
bigfloat log05 = -log1p(bigfloat(1));
success = 1;
for (bigint pos = Y;pos > Y-X;--pos)
success *= -expm1(pos*log05);
for (bigint u = 0;u <= W;++u) {
result.at(u).at(u) = success;
result.at(u).at(W+2) = 1-success;
}
return result;
}
// pr: conditional probability of finding target given P errors
vector<vector<bigfloat>> transition_found(bigint W,bigint P,bigfloat pr)
{
vector<vector<bigfloat>> result = transition_identity(W);
assert(P <= W);
result.at(P).at(P) = 1-pr;
result.at(P).at(W+1) = pr;
return result;
}
vector<vector<bigfloat>> transition_multiply(bigint W,const vector<vector<bigfloat>> &T0,const vector<vector<bigfloat>> &T1)
{
vector<vector<bigfloat>> result = transition_zero(W);
for (bigint t = 0;t <= W+2;++t)
for (bigint u = 0;u <= W+2;++u) {
bigfloat T0tu = T0.at(t).at(u);
if (T0tu.definitely_zero()) continue;
for (bigint v = 0;v <= W+2;++v)
result.at(t).at(v) += T0tu*T1.at(u).at(v);
}
#ifdef TRANSITION_RENORMALIZE
// renormalize for better floating-point stability
for (bigint t = 0;t <= W+2;++t) {
bigfloat x = 0;
for (bigint u = 0;u <= W+2;++u)
x += result.at(t).at(u);
if (x <= 0) continue;
x = 1/x;
for (bigint u = 0;u <= W+2;++u)
result.at(t).at(u) *= x;
}
#endif
return result;
}
vector<vector<bigfloat>> transition_power(bigint W,const vector<vector<bigfloat>> &T,bigint e)
{
assert(e >= 0);
if (e == 0) return transition_identity(W);
if (e == 1) return T;
vector<vector<bigfloat>> result = transition_power(W,T,e/2);
result = transition_multiply(W,result,result);
if ((e&1) != 0) result = transition_multiply(W,result,T);
return result;
}