Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • cebash/sakia
  • santiago/sakia
  • jonas/sakia
3 results
Show changes
Showing
with 241 additions and 607 deletions
doc/uml/network.png

21.7 KiB

@startuml
Network -->o Node : Connect to node_received()
Network -> Node : Starts network discovery
activate Node
Node -> duniterpy : HTTP GET peering/peers?leaves=true
alt "root" hash changed
loop "for all leaves changed"
activate Node
Node -> duniterpy : HTTP GET peering/peers/leaf=leaf_hash
end
end
Network <-- Node : node_received()
ref over Network
New node is instanciated
if pubkey not known yet.
It starts it's own
network discovery
end ref
@enduml
\ No newline at end of file
doc/uml/processors.png

10.6 KiB

@startuml
class IdentitiesProcessor << (P,lightgreen) >> {
find_identities()
find_certifiers_of()
find_certified_by()
}
class CertificationProcessor << (P,lightgreen) >> {
}
class TransactionProcessor << (P,lightgreen) >> {
}
class CommunityProcessor << (P,lightgreen) >> {
}
class BlockchainProcessor << (P,lightgreen) >> {
}
class NodesProcessor << (P,lightgreen) >> {
}
@enduml
\ No newline at end of file
doc/uml/requests.png

26 KiB

@startuml
activate "Core Component"
"Core Component" -> BmaAccess : Request data
BmaAccess -> BmaAccess : Request cache
ref over BmaAccess
Data is obsolete
(new block mined
since last caching)
end ref
BmaAccess -> duniterpy : HTTP GET
alt Rollback
BmaAccess -> BmaAccess : Find last block number rollbacked
ref over BmaAccess
If the request is a bma/blockchain/Block, we check if the hash answered is the same
as our hash, in which case, we know that the rollback didn't reset blocks before
this one.
Blocks from this one to the current block are considered obsolete
end ref
end
BmaAccess -> BmaAccess : Update cache data
"Core Component" <- BmaAccess : Return data data
deactivate "Core Component"
@enduml
\ No newline at end of file
doc/uml/services.png

13.4 KiB

@startuml
class ProfileService << (S,cyan) >> {
add_connection()
remove_connection()
}
class AccountService << (S,cyan) >> {
send_transaction()
send_certification()
send_membership()
send_identity()
send_revokation()
}
class TransactionsService << (S,cyan) >> {
handle_new_block()
refresh_transactions()
rollback_transactions()
}
class RegistryService << (S,cyan) >> {
handle_new_block()
}
class NetworkService << (S,cyan) >> {
discover_network()
}
class BlockchainService << (S,cyan) >> {
receive_block()
}
@enduml
\ No newline at end of file
doc/uml/tx_lifecycle.png

22 KiB | W: 0px | H: 0px

doc/uml/tx_lifecycle.png

63.2 KiB | W: 0px | H: 0px

doc/uml/tx_lifecycle.png
doc/uml/tx_lifecycle.png
doc/uml/tx_lifecycle.png
doc/uml/tx_lifecycle.png
  • 2-up
  • Swipe
  • Onion skin
@startuml
[*] --> To_send
To_send --> Awaiting : Broadcasted at B
Awaiting --> Validated : Registered in [B; B+15]
Awaiting --> Refused : Not registered in [B; B+15]
Refused --> To_send : Send back order
Refused --> Dropped : Drop order
@enduml
\ No newline at end of file
@startuml note "With B a Block\nWith W the Median fork window\nWith Cur the current block of the main branch\nWith T a time" as N1 state Local_Tx { [*] --> To_send : Signed locally To_send : B = none To_send --> Awaiting : Node answered\n200 OK to POST Awaiting : Time = Cur.MedianTime Awaiting --> Refused : Not registered in [T; T+W*MedianTime] Refused --> To_send : Send back Refused --> [*] : Drop } state Registered { [*] --> Validating : Posted\nsin the blockchain Validating : B = Block containing the Tx Awaiting --> Validating : Found in the blockchain Validating --> Validated : Cur-B > W Validated --> Validating : Blockchain\nrollback\ntx in fork window Validated --> Awaiting : Blockchain\nrollback\ntx local removed Validated --> [*] : Blockchain\nrollback\ntx removed Validating --> [*] : Blockchain\nrollback\ntx removed } @enduml
\ No newline at end of file
......
......@@ -2,24 +2,30 @@
# -*- coding: utf-8 -*-
import sys, os, multiprocessing, subprocess
root_path = os.path.abspath(os.path.join(os.path.dirname(__file__)))
resources = os.path.abspath(os.path.join(os.path.dirname(__file__), 'res'))
gen_ui = os.path.abspath(os.path.join(os.path.dirname(__file__), 'src', 'cutecoin', 'gen_resources'))
gen_resources = os.path.abspath(os.path.join(os.path.dirname(__file__), 'src'))
gen_resources = os.path.abspath(os.path.join(os.path.dirname(__file__), 'src/sakia'))
def convert_ui(args, **kwargs):
subprocess.call(args, **kwargs)
def build_resources():
try:
to_process = []
for root, dirs, files in os.walk(resources):
for root, dirs, files in os.walk(root_path):
for f in files:
if f.endswith('.ui'):
source = os.path.join(root, f)
dest = os.path.join(gen_ui, os.path.splitext(os.path.basename(source))[0]+'_uic.py')
dest = os.path.join(root, os.path.splitext(os.path.basename(source))[0]+'_uic.py')
exe = 'pyuic5'
elif f.endswith('.qrc'):
source = os.path.join(root, f)
dest = os.path.join(gen_resources, os.path.splitext(os.path.basename(source))[0]+'_rc.py')
filename = os.path.splitext(os.path.basename(source))[0]
# we remove "sakia." from the rc filename
# its only named like this so that imports are corrects in uic files
dest = os.path.join(gen_resources, filename.replace('sakia.', '')+'_rc.py')
exe = 'pyrcc5'
else:
continue
......
import sys, os, multiprocessing, subprocess, time, shutil
gen_resources = os.path.abspath(os.path.join(os.path.dirname(__file__), 'src/sakia'))
ts = os.path.abspath(os.path.join(os.path.dirname(__file__), 'res', 'i18n', 'ts'))
qm = os.path.abspath(os.path.join(os.path.dirname(__file__), 'res', 'i18n', 'qm'))
if not os.path.exists(qm):
os.mkdir(qm)
translations = []
qm_files = []
qm_shortnames = []
def prepare_qm():
for root, dirs, files in os.walk(ts):
for f in files:
if f.endswith('.ts'):
tsfilename = os.path.join(root, f)
qmshort = "{0}qm".format(f[:-2])
qmfilename = os.path.join(qm, qmshort)
srcdest = (tsfilename, qmfilename)
translations.append(srcdest)
qm_shortnames.append(qmshort)
else:
continue
print(os.path.join(root, f))
for (ts_file, qm_file) in translations:
# avoid conflict with qt4 lrelease by running qtchooser directly
if sys.platform.startswith('win') or shutil.which("qtchooser") == None or "--lrelease" in sys.argv:
subprocess.call(["lrelease", ts_file, "-qm", qm_file])
else:
subprocess.call(["qtchooser", "-run-tool=lrelease", "-qt=5", ts_file, "-qm", qm_file])
print(ts_file + " >> " + qm_file)
def build_resources():
files = ""
for file in qm_shortnames:
files += """
<file alias="{0}">qm/{0}.qm</file>""".format(file[:-3])
rccfile = """<RCC>
<qresource prefix="i18n">{0}
</qresource>
</RCC>
""".format(files)
print(rccfile)
qrc_filename = os.path.abspath(os.path.join(os.path.dirname(__file__),
'res',
'i18n',
'langs-{0}.qrc'.format(int(time.time()))
))
pyc_filename = os.path.abspath(os.path.join(gen_resources, 'i18n_rc.py'))
with open(qrc_filename, 'w') as outfile:
outfile.write(rccfile)
try:
subprocess.call(["pyrcc5", "-o", pyc_filename, qrc_filename])
print(qrc_filename + " >> " + pyc_filename)
finally:
os.remove(qrc_filename)
prepare_qm()
# add Qt standardButtons qm file
# This file must be copied from Qt libs in the res/i18n/qm folder of the project
qtbase_filename = "qtbase_fr.qm"
if os.path.exists(os.path.join(qm, qtbase_filename)):
qm_shortnames.append(qtbase_filename)
build_resources()
#-----------------------------------------------------------------------------
# Copyright (c) 2013-2016, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License with exception
# for distributing bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
hiddenimports = ['sip', 'PyQt5.QtCore']
from PyInstaller.utils.hooks import qt_plugins_binaries
from PyInstaller.compat import is_linux
binaries = []
binaries.extend(qt_plugins_binaries('accessible', namespace='PyQt5'))
binaries.extend(qt_plugins_binaries('iconengines', namespace='PyQt5'))
binaries.extend(qt_plugins_binaries('imageformats', namespace='PyQt5'))
binaries.extend(qt_plugins_binaries('inputmethods', namespace='PyQt5'))
binaries.extend(qt_plugins_binaries('graphicssystems', namespace='PyQt5'))
binaries.extend(qt_plugins_binaries('platforms', namespace='PyQt5'))
if is_linux:
binaries.extend(qt_plugins_binaries('platformthemes', namespace='PyQt5'))
#-----------------------------------------------------------------------------
# Copyright (c) 2005-2016, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License with exception
# for distributing bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
# This is needed to bundle draft3.json and draft4.json files that come
# with jsonschema module
from PyInstaller.utils.hooks import collect_data_files
datas = collect_data_files('lib2to3')
#-----------------------------------------------------------------------------
# Copyright (c) 2005-2016, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License with exception
# for distributing bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
from PyInstaller.utils.hooks import collect_submodules
hiddenimports = collect_submodules('pkg_resources._vendor')
\ No newline at end of file
# Copyright (c) 2014, Jan Varho
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""Scrypt for Python"""
__version__ = '1.4.0-git'
# First, try loading libscrypt
_done = False
try:
from .pylibscrypt import *
except ImportError:
pass
else:
_done = True
# If that didn't work, try the scrypt module
if not _done:
try:
from .pyscrypt import *
except ImportError:
pass
else:
_done = True
# Next: libsodium
if not _done:
try:
from .pylibsodium import *
except ImportError:
pass
else:
_done = True
# Unless we are on pypy, we want to try libsodium_salsa as well
if not _done:
import platform
if platform.python_implementation() != 'PyPy':
try:
from .pylibsodium_salsa import *
except ImportError:
pass
else:
_done = True
# If that didn't work either, the inlined Python version
if not _done:
from .pypyscrypt_inline import *
__all__ = ['scrypt', 'scrypt_mcf', 'scrypt_mcf_check']
#!/usr/bin/env python
# Copyright (c) 2014, Jan Varho
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""Simple benchmark of python vs c scrypt"""
import time
from .common import *
from .pylibscrypt import scrypt
from .pypyscrypt_inline import scrypt as pyscrypt
from .pylibsodium_salsa import scrypt as pcscrypt
# Benchmark time in seconds
tmin = 5
Nmax = 20
t1 = time.time()
for i in xrange(1, Nmax+1):
pyscrypt(b'password', b'NaCl', N=2**i)
if time.time() - t1 > tmin:
Nmax = i
break
t1 = time.time() - t1
print('Using N = 2,4,..., 2**%d' % Nmax)
print('Python scrypt took %.2fs' % t1)
t2 = time.time()
for i in xrange(1, Nmax+1):
pcscrypt(b'password', b'NaCl', N=2**i)
t2 = time.time() - t2
print('Py + C scrypt took %.2fs' % t2)
t3 = time.time()
for i in xrange(1, Nmax+1):
scrypt(b'password', b'NaCl', N=2**i)
t3 = time.time() - t3
print('C scrypt took %.2fs' % t3)
print('Python scrypt took %.2f times as long as C' % (t1 / t3))
print('Py + C scrypt took %.2f times as long as C' % (t2 / t3))
# Copyright (c) 2014, Jan Varho
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""Common variables and functions used by scrypt implementations"""
import numbers
SCRYPT_MCF_PREFIX_7 = b'$7$'
SCRYPT_MCF_PREFIX_s1 = b'$s1$'
SCRYPT_MCF_PREFIX_DEFAULT = b'$s1$'
SCRYPT_MCF_PREFIX_ANY = None
SCRYPT_N = 1<<14
SCRYPT_r = 8
SCRYPT_p = 1
# The last one differs from libscrypt defaults, but matches the 'interactive'
# work factor from the original paper. For long term storage where runtime of
# key derivation is not a problem, you could use 16 as in libscrypt or better
# yet increase N if memory is plentiful.
xrange = xrange if 'xrange' in globals() else range
def check_args(password, salt, N, r, p, olen=64):
if not isinstance(password, bytes):
raise TypeError('password must be a byte string')
if not isinstance(salt, bytes):
raise TypeError('salt must be a byte string')
if not isinstance(N, numbers.Integral):
raise TypeError('N must be an integer')
if not isinstance(r, numbers.Integral):
raise TypeError('r must be an integer')
if not isinstance(p, numbers.Integral):
raise TypeError('p must be an integer')
if not isinstance(olen, numbers.Integral):
raise TypeError('length must be an integer')
if N > 2**63:
raise ValueError('N cannot be larger than 2**63')
if (N & (N - 1)) or N < 2:
raise ValueError('N must be a power of two larger than 1')
if r <= 0:
raise ValueError('r must be positive')
if p <= 0:
raise ValueError('p must be positive')
if r * p >= 2**30:
raise ValueError('r * p must be less than 2 ** 30')
if olen <= 0:
raise ValueError('length must be positive')
#!/usr/bin/env python
# Copyright (c) 2014, Jan Varho
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""Fuzzes scrypt function input, comparing two implementations"""
import itertools
import random
from random import randrange as rr
import unittest
class Skip(Exception):
pass
class Fuzzer(object):
"""Fuzzes function input"""
def __init__(self, f, args, g=None, pass_good=None, pass_bad=None):
self.f = f
self.g = g
self.args = args
self.pass_good = pass_good
self.pass_bad = pass_bad
@staticmethod
def get_random_int():
return int((1<<rr(66)) * 1.3)
@staticmethod
def get_random_bytes(lrange=None, skip=None):
if lrange is None:
v = bytearray(rr(2**rr(10)))
else:
v = bytearray(rr(*lrange))
for i in range(len(v)):
v[i] = rr(256)
while v[i] == skip:
v[i] = rr(256)
return bytes(v)
def get_good_args(self):
kwargs = {}
for a in self.args:
assert isinstance(a, dict)
if 'opt' in a and a['opt'] and random.randrange(2):
continue
if 'val' in a:
kwargs[a['name']] = a['val']
elif 'vals' in a:
kwargs[a['name']] = random.choice(a['vals'])
elif 'valf' in a:
kwargs[a['name']] = a['valf']()
elif 'type' in a and a['type'] == 'int':
kwargs[a['name']] = self.get_random_int()
elif 'type' in a and a['type'] == 'bytes':
kwargs[a['name']] = self.get_random_bytes()
else:
raise ValueError
if 'none' in a and not random.randrange(10):
kwargs[a['name']] = None
if 'skip' in a and a['skip'](kwargs[a['name']]):
if 'opt' in a and a['opt']:
del kwargs[a['name']]
else:
raise Skip
return kwargs
def get_bad_args(self, kwargs=None):
kwargs = kwargs or self.get_good_args()
a = random.choice(self.args)
if not 'opt' in a:
if not random.randrange(10):
del kwargs[a['name']]
return kwargs
if not 'type' in a:
return self.get_bad_args(kwargs)
if not random.randrange(10):
wrongtype = [
self.get_random_int(), self.get_random_bytes(), None,
1.1*self.get_random_int(), 1.0*self.get_random_int()
]
if a['type'] == 'int':
del wrongtype[0]
elif a['type'] == 'bytes':
del wrongtype[1]
v = random.choice(wrongtype)
try:
if 'valf' in a:
if a['valf'](v):
return self.get_bad_args(kwargs)
if 'skip' in a and a['skip'](v):
return self.get_bad_args(kwargs)
except TypeError:
pass # Surely bad enough
kwargs[a['name']] = v
return kwargs
if a['type'] == 'int':
v = self.get_random_int()
if 'valf' in a:
if a['valf'](v):
return self.get_bad_args(kwargs)
if 'skip' in a and a['skip'](v):
return self.get_bad_args(kwargs)
kwargs[a['name']] = v
return kwargs
if a['type'] == 'bytes' and 'valf' in a:
v = self.get_random_bytes()
if not a['valf'](v):
kwargs[a['name']] = v
return kwargs
return self.get_bad_args(kwargs)
def fuzz_good_run(self, tc):
try:
kwargs = self.get_good_args()
r1 = self.f(**kwargs)
r2 = self.g(**kwargs) if self.g is not None else None
if self.g is not None:
r2 = self.g(**kwargs)
except Skip:
tc.skipTest('slow')
except Exception as e:
assert False, ('unexpected exception', kwargs, e)
try:
if self.pass_good:
tc.assertTrue(self.pass_good(r1, r2, kwargs),
msg=('unexpected output', r1, r2, kwargs))
else:
if self.g is not None:
assert r1 == r2, ('f and g mismatch', kwargs, r1, r2)
tc.assertTrue(r1)
except Exception as e:
print ('unexpected exception', kwargs, r1, r2, e)
raise
def fuzz_bad(self, f=None, kwargs=None):
f = f or self.f
kwargs = kwargs or self.get_bad_args()
return f(**kwargs)
def fuzz_bad_run(self, tc):
try:
kwargs = self.get_bad_args()
except Skip:
tc.skipTest('slow')
for f in ((self.f,) if not self.g else (self.f, self.g)):
try:
r = self.fuzz_bad(f, kwargs)
assert False, ('no exception', kwargs, r)
except Skip:
tc.skipTest('slow')
except AssertionError:
raise
except Exception:
pass
def testcase_good(self, tests=1, name='FuzzTestGood'):
testfs = {}
for i in range(tests):
testfs['test_fuzz_good_%d' % i] = lambda s: self.fuzz_good_run(s)
t = type(name, (unittest.TestCase,), testfs)
return t
def testcase_bad(self, tests=1, name='FuzzTestBad'):
testfs = {}
for i in range(tests):
testfs['test_fuzz_bad_%d' % i] = lambda s: self.fuzz_bad_run(s)
t = type(name, (unittest.TestCase,), testfs)
return t
def generate_tests(self, suite, count, name):
loader = unittest.defaultTestLoader
suite.addTest(
loader.loadTestsFromTestCase(
self.testcase_good(count, name + 'Good')
)
)
suite.addTest(
loader.loadTestsFromTestCase(
self.testcase_bad(count, name + 'Bad')
)
)
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description='Fuzz testing')
parser.add_argument('-c', '--count', type=int, default=100)
parser.add_argument('-f', '--failfast', action='store_true')
clargs = parser.parse_args()
modules = []
try:
from . import pylibscrypt
modules.append((pylibscrypt, 'pylibscrypt'))
except ImportError:
pass
try:
from . import pyscrypt
modules.append((pyscrypt, 'pyscrypt'))
except ImportError:
pass
try:
from . import pylibsodium_salsa
modules.append((pylibsodium_salsa, 'pylibsodium_salsa'))
except ImportError:
pass
try:
from . import pylibsodium
modules.append((pylibsodium, 'pylibsodium'))
except ImportError:
pass
try:
from . import pypyscrypt_inline as pypyscrypt
modules.append((pypyscrypt, 'pypyscrypt'))
except ImportError:
pass
scrypt_args = (
{'name':'password', 'type':'bytes'},
{'name':'salt', 'type':'bytes'},
{
'name':'N', 'type':'int', 'opt':False,
'valf':(lambda N=None: 2**rr(1,6) if N is None else
1 < N < 2**64 and not (N & (N - 1))),
'skip':(lambda N: (N & (N - 1)) == 0 and N > 32 and N < 2**64)
},
{
'name':'r', 'type':'int', 'opt':True,
'valf':(lambda r=None: rr(1, 16) if r is None else 0<r<2**30),
'skip':(lambda r: r > 16 and r < 2**30)
},
{
'name':'p', 'type':'int', 'opt':True,
'valf':(lambda p=None: rr(1, 16) if p is None else 0<p<2**30),
'skip':(lambda p: p > 16 and p < 2**30)
},
{
'name':'olen', 'type':'int', 'opt':True,
'valf':(lambda l=None: rr(1, 1000) if l is None else l >= 0),
'skip':(lambda l: l < 0 or l > 1024)
},
)
scrypt_mcf_args = (
{
'name':'password', 'type':'bytes',
'valf':(lambda p=None: Fuzzer.get_random_bytes(skip=0) if p is None
else not b'\0' in p)
},
{
'name':'salt', 'type':'bytes', 'opt':False, 'none':True,
'valf':(lambda s=None: Fuzzer.get_random_bytes((1,17)) if s is None
else 1 <= len(s) <= 16)
},
{
'name':'N', 'type':'int', 'opt':False,
'valf':(lambda N=None: 2**rr(1,6) if N is None else
1 < N < 2**64 and not (N & (N - 1))),
'skip':(lambda N: (N & (N - 1)) == 0 and N > 32 and N < 2**64)
},
{
'name':'r', 'type':'int', 'opt':True,
'valf':(lambda r=None: rr(1, 16) if r is None else 0<r<2**30),
'skip':(lambda r: r > 16 and r < 2**30)
},
{
'name':'p', 'type':'int', 'opt':True,
'valf':(lambda p=None: rr(1, 16) if p is None else 0<p<2**30),
'skip':(lambda p: p > 16 and p < 2**30)
},
{
'name':'prefix', 'type':'bytes', 'opt':True,
'vals':(b'$s1$', b'$7$'),
'skip':(lambda p: p is None)
}
)
random.shuffle(modules)
suite = unittest.TestSuite()
loader = unittest.defaultTestLoader
for m1, m2 in itertools.permutations(modules, 2):
Fuzzer(
m1[0].scrypt, scrypt_args, m2[0].scrypt,
pass_good=lambda r1, r2, a: (
isinstance(r1, bytes) and
(r2 is None or r1 == r2) and
(len(r1) == 64 if 'olen' not in a else len(r1) == a['olen'])
)
).generate_tests(suite, clargs.count, m1[1])
Fuzzer(
m1[0].scrypt_mcf, scrypt_mcf_args, m2[0].scrypt_mcf,
pass_good=lambda r1, r2, a: (
m2[0].scrypt_mcf_check(r1, a['password']) and
(r2 is None or m1[0].scrypt_mcf_check(r2, a['password'])) and
(r2 is None or 'salt' not in a or a['salt'] is None or r1 == r2)
)
).generate_tests(suite, clargs.count, m1[1])
unittest.TextTestRunner(failfast=clargs.failfast).run(suite)
#!/usr/bin/env python
# Copyright (c) 2014, Jan Varho
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""Inlines the salsa20 core lines into salsa20_8"""
of = open('pylibscrypt/pypyscrypt_inline.py', 'w')
assert of
def indent(line):
i = 0
while i < len(line) and line[i] == ' ':
i += 1
return i
with open('pylibscrypt/pypyscrypt.py', 'r') as f:
in_loop = False
loop_indent = 0
lc = 0
rl = []
skipping = False
for line in f:
lc += 1
i = indent(line)
if line[i:].startswith('def R('):
skipping = True
elif line[i:].startswith('def array_overwrite('):
skipping = True
elif skipping:
if line[i:].startswith('def'):
of.write(line)
skipping = False
elif line[i:].startswith('R('):
parts = line.split(';')
rl += parts
if len(rl) == 32:
# Interleave to reduce dependencies for pypy
rl1 = rl[:16]
rl2 = rl[16:]
rl1 = rl1[0::4] + rl1[1::4] + rl1[2::4] + rl1[3::4]
rl2 = rl2[0::4] + rl2[1::4] + rl2[2::4] + rl2[3::4]
rl = rl1 + rl2
for p, q in zip(rl[::2], rl[1::2]):
pvals = p.split(',')[1:]
pvals = [int(v.strip(' )\n')) for v in pvals]
qvals = q.split(',')[1:]
qvals = [int(v.strip(' )\n')) for v in qvals]
of.write(' '*i)
of.write('a = (x[%d]+x[%d]) & 0xffffffff\n' %
(pvals[1], pvals[2]))
of.write(' '*i)
of.write('b = (x[%d]+x[%d]) & 0xffffffff\n' %
(qvals[1], qvals[2]))
of.write(' '*i)
of.write('x[%d] ^= (a << %d) | (a >> %d)\n' %
(pvals[0], pvals[3], 32 - pvals[3]))
of.write(' '*i)
of.write('x[%d] ^= (b << %d) | (b >> %d)\n' %
(qvals[0], qvals[3], 32 - qvals[3]))
elif line[i:].startswith('array_overwrite('):
vals = line.split(',')
vals[0] = vals[0].split('(')[1]
vals[-1] = vals[-1].split(')')[0]
vals = [v.strip() for v in vals]
assert len(vals) == 5
of.write(' '*i)
of.write(vals[2] + '[' + vals[3] + ':(' + vals[3] + ')+(' +
vals[4] + ')] = ' + vals[0] + '[' + vals[1] + ':(' +
vals[1] + ')+(' + vals[4] + ')]\n')
else:
of.write(line)
if lc == 1:
of.write('\n# Automatically generated file, see inline.py\n')