mirror of
https://github.com/monero-project/research-lab.git
synced 2024-12-23 03:59:40 +00:00
110 lines
3.1 KiB
Python
110 lines
3.1 KiB
Python
import Crypto.Random.random as rand
|
|
import itertools
|
|
import math #for log
|
|
import sys
|
|
def decomposition(i):
|
|
#from stack exchange, don't think it's uniform
|
|
while i > 0:
|
|
n = rand.randint(1, i)
|
|
yield n
|
|
i -= n
|
|
|
|
def Decomposition(i):
|
|
while True:
|
|
l = list(decomposition(i))
|
|
if len(set(l)) == len(l):
|
|
return l
|
|
|
|
def decomposition2(n, s, d, k):
|
|
#home-brewed, returns no duplicates, includes the number d
|
|
s = s - 1
|
|
n = n
|
|
while True:
|
|
a = [d]
|
|
nn = n
|
|
#a.append(d)
|
|
for i in range(0, s):
|
|
a.append(rand.randint(0, n))
|
|
a.sort()
|
|
#print("a", a)
|
|
b = []
|
|
c = []
|
|
while len(a) > 0:
|
|
t = a.pop()
|
|
#print(t, a)
|
|
if t >= d:
|
|
b.append(nn - t)
|
|
else:
|
|
c.append(nn - t)
|
|
nn = t
|
|
c.append(nn)
|
|
tot = b[:] + c[:]
|
|
#print("b", b)
|
|
if sum(set(tot)) == n and len(c) > int(k):
|
|
return sorted(c), sorted(b)
|
|
|
|
def decomposition3(n, s, d, k):
|
|
#a combination of both methods, designed to get some smaller values
|
|
send, change = decomposition2(n, s, d, k)
|
|
for i in send:
|
|
if i > n / s:
|
|
send.remove(i)
|
|
send = send + list(Decomposition(i))
|
|
for i in change:
|
|
if i > n / (s - 1):
|
|
change.remove(i)
|
|
change = change + list(Decomposition(i))
|
|
return send, change
|
|
|
|
def divv(l, m):
|
|
return [a /float( m) for a in l]
|
|
|
|
def frexp10(x):
|
|
exp = int(math.log10(x))
|
|
return x / 10**exp, exp
|
|
|
|
|
|
def decideAmounts(totalInputs, toSend, Partitions, k, fuzz):
|
|
#fuzz is an optional amount to fuzz the transaction by
|
|
#so if you start with a big obvious number like 2000, it might be fuzzed by up to "fuzz" amount
|
|
fz = rand.randint(0, int(fuzz * 1000) ) / 1000.0
|
|
toSend += fz
|
|
|
|
|
|
g, ii =frexp10(totalInputs)
|
|
ii = 10 ** (-1 * min(ii - 2, 0))
|
|
print("ii", ii)
|
|
M = 10 ** (int(math.log(2 ** Partitions) / math.log(10))) * ii
|
|
#M = 10 ** M
|
|
print("multiplier:", M)
|
|
totalInputs = int(totalInputs * M)
|
|
toSend = int(toSend * M)
|
|
change = totalInputs - toSend
|
|
send_amounts, change_amounts = decomposition3(totalInputs, Partitions, toSend, k)
|
|
all_amounts = send_amounts[:] + change_amounts[:]
|
|
rand.shuffle(all_amounts)
|
|
print("")
|
|
print("change amounts:", divv(change_amounts, M))
|
|
print("send amounts:", divv(send_amounts, M))
|
|
print("now from the following, how much is sent?")
|
|
print("all amounts:", sorted(divv(all_amounts, M)))
|
|
print("possible sent amounts:")
|
|
amounts = []
|
|
for L in range(0, len(all_amounts)+1):
|
|
for subset in itertools.combinations(all_amounts, L):
|
|
amounts.append(sum(subset))
|
|
|
|
print("number of possible sent amounts:")
|
|
print(len(amounts))
|
|
print("2^N:", 2 ** len(all_amounts))
|
|
print("number of possible sent amounts duplicates removed:")
|
|
print(len(list(set(amounts))))
|
|
|
|
|
|
|
|
if len(sys.argv) > 2:
|
|
kk = 2
|
|
parts = 7
|
|
kk = rand.randint(1, int(parts / 4)) #how many sends to demand
|
|
fuzz = 1
|
|
decideAmounts(float(sys.argv[1]), float(sys.argv[2]), parts, kk, fuzz)
|