Skip to content

Commit dbebb1d

Browse files
authored
Merge pull request #26 from poing/0.0.7
Better coverage
2 parents 4051636 + 29bb2ba commit dbebb1d

3 files changed

Lines changed: 178 additions & 26 deletions

File tree

gems/share.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ def dithering(random_string):
2222

2323
#print(test(2345))
2424

25-
secrets.init(4)
25+
secrets.init(8)
2626
#secrets.init()
2727
#print(max(settings.logs[1:]))
2828

29-
#settings.update_defaults(dithering=lambda string: dithering(string))
29+
settings.update_defaults(dithering=lambda string: dithering(string))
3030

3131
results = secrets.share('0074007300650074002000610020007300690073006900680074', 6, 3)
3232

3333
print(results)
3434

35-
#print(random_list)
35+
print(random_list)

js2pysecrets/base.py

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -236,28 +236,17 @@ def splitNumStringToIntArray(string, pad_length=None):
236236

237237

238238
def horner(x, coeffs):
239-
if x not in settings.logs:
240-
raise ValueError(f"Value of 'x' ({x}) is not found in logs.")
241239

242240
logx = settings.logs[x]
243241
fx = 0
244242

245243
for i in range(len(coeffs) - 1, -1, -1):
246244
if fx != 0:
247245

248-
try:
249-
250-
fx = (
251-
settings.exps[
252-
(logx + settings.logs[fx]) % settings.maxShares
253-
]
254-
^ coeffs[i]
255-
)
256-
257-
except IndexError:
258-
raise IndexError(
259-
f"list index out of range: x:{x} i:{i} fx:{fx}"
260-
)
246+
fx = (
247+
settings.exps[(logx + settings.logs[fx]) % settings.maxShares]
248+
^ coeffs[i]
249+
)
261250

262251
else:
263252
fx = coeffs[i]
@@ -294,6 +283,7 @@ def getShares(secret, num_shares, threshold):
294283

295284

296285
def constructPublicShareString(bits, share_id, data):
286+
297287
share_id = int(share_id, settings.radix)
298288
bits = bits or settings.bits
299289
bits_base36 = base36encode(bits).upper()
@@ -308,14 +298,16 @@ def constructPublicShareString(bits, share_id, data):
308298
):
309299
raise ValueError(
310300
f"Share id must be an integer between 1 and {id_max}, inclusive."
311-
)
301+
) # pragma: no cover
312302

313303
new_share_string = bits_base36 + id_hex + data
314304

315305
return new_share_string
316306

317307

318-
def base36encode(number, alphabet="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
308+
def base36encode(
309+
number, alphabet="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
310+
): # pragma: no cover
319311
"""Converts an integer to a base36 string."""
320312
if not isinstance(number, int):
321313
raise TypeError("number must be an integer")
@@ -337,7 +329,7 @@ def base36encode(number, alphabet="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
337329
return sign + base36
338330

339331

340-
def base36decode(number):
332+
def base36decode(number): # pragma: no cover
341333
return int(number, 36)
342334

343335

@@ -452,15 +444,15 @@ def share(secret, num_shares, threshold, pad_length=None):
452444
pad_length = pad_length or 128
453445

454446
if not isinstance(secret, str):
455-
raise ValueError("Secret must be a string.")
447+
raise ValueError("Secret must be a hex string.")
456448

457449
if not isinstance(num_shares, int) or num_shares < 2:
458450
raise ValueError("Number of shares must be an integer >= 2.")
459451

460452
if num_shares > settings.maxShares:
461453
needed_bits = math.ceil(math.log(num_shares + 1) / math.log(2))
462454
raise ValueError(
463-
f"Number of shares must be <= {settings.settings.maxShares}."
455+
f"Number of shares must be <= {settings.maxShares}."
464456
f" Use at least {needed_bits} bits."
465457
)
466458

@@ -471,7 +463,7 @@ def share(secret, num_shares, threshold, pad_length=None):
471463
needed_bits = math.ceil(math.log(threshold + 1) / math.log(2))
472464
raise ValueError(
473465
f"Threshold number of shares must be <= "
474-
f"{settings.settings.maxShares}. Use at least {needed_bits} bits."
466+
f"{settings.maxShares}. Use at least {needed_bits} bits."
475467
)
476468

477469
if threshold > num_shares:
@@ -491,7 +483,6 @@ def share(secret, num_shares, threshold, pad_length=None):
491483

492484
num_shares = int(num_shares)
493485
threshold = int(threshold)
494-
# bits = 128 # Assuming bits as 128, you can adjust it accordingly
495486

496487
x = [None] * num_shares
497488
y = [None] * num_shares

tests/test_basePrivate.py

Lines changed: 162 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,37 @@ def test_getShares(set_init_bits):
646646
assert True
647647

648648

649+
def test_random_dithering():
650+
random_list = []
651+
652+
def dithering(random_string):
653+
random_list.append(hex(int(random_string)))
654+
655+
# Check dithering disabled
656+
secrets.init()
657+
secrets.getShares(1234, 6, 3)
658+
assert len(set(random_list)) == 0
659+
660+
# Enable dithering
661+
settings.update_defaults(dithering=lambda string: dithering(string))
662+
secrets.getShares(1234, 6, 3)
663+
# print(random_list)
664+
assert len(set(random_list)) > 1
665+
666+
# Check testRandom values are the same
667+
random_list = []
668+
secrets.init(8, "testRandom")
669+
settings.update_defaults(dithering=lambda string: dithering(string))
670+
secrets.getShares(1234, 6, 3)
671+
assert len(set(random_list)) == 1
672+
673+
# Check dithering disabled
674+
random_list = []
675+
secrets.init()
676+
secrets.getShares(1234, 6, 3)
677+
assert len(set(random_list)) == 0
678+
679+
649680
@pytest.fixture(
650681
params=[
651682
None,
@@ -673,15 +704,145 @@ def full_range_of_bits(request):
673704
return request.param
674705

675706

707+
# Select a number of random shares
676708
def pieces(shares, number=3):
677709
random.shuffle(shares) # Randomize
678710
return shares[-number:]
679711

680712

681713
def test_py_share(full_range_of_bits):
714+
# Generate shares with python
682715
secrets.init(full_range_of_bits)
683-
secret = secrets.random(64)
716+
secret = secrets.random(128)
717+
718+
# A few cold runs to cover non-zero in rng
719+
secrets.share(secret, 7, 6)
720+
secrets.share(secret, 7, 6)
721+
secrets.share(secret, 7, 6)
722+
684723
shares = secrets.share(secret, 6, 3)
685724

725+
# Combine shares using the JavaScript
686726
result = node.combine(pieces(shares, 3))
687727
assert result == secret
728+
729+
730+
def test_py_share_error_string():
731+
match = "Secret must be a hex string."
732+
with pytest.raises(ValueError, match=match):
733+
secrets.init()
734+
secrets.share(12345, 6, 3)
735+
# Check if any warnings were raised
736+
assert len(caught_warnings) == 1
737+
assert issubclass(caught_warnings[0].category, Warning)
738+
assert match in str(caught_warnings[0].message)
739+
740+
741+
def test_py_share_error_shares():
742+
match = "Number of shares must be an integer"
743+
with pytest.raises(ValueError, match=match):
744+
secrets.init()
745+
secret = secrets.random(32)
746+
secrets.share(secret, 1, 1)
747+
# Check if any warnings were raised
748+
assert len(caught_warnings) == 1
749+
assert issubclass(caught_warnings[0].category, Warning)
750+
assert match in str(caught_warnings[0].message)
751+
with pytest.raises(ValueError, match=match):
752+
secrets.init()
753+
secret = secrets.random(32)
754+
secrets.share(secret, "hello", 3)
755+
# Check if any warnings were raised
756+
assert len(caught_warnings) == 1
757+
assert issubclass(caught_warnings[0].category, Warning)
758+
assert match in str(caught_warnings[0].message)
759+
760+
761+
def test_py_share_error_high_shares():
762+
match = "Number of shares must be"
763+
with pytest.raises(ValueError, match=match):
764+
secrets.init()
765+
secret = secrets.random(32)
766+
secrets.share(secret, 800, 3)
767+
# Check if any warnings were raised
768+
assert len(caught_warnings) == 1
769+
assert issubclass(caught_warnings[0].category, Warning)
770+
assert match in str(caught_warnings[0].message)
771+
772+
773+
def test_py_share_error_threshold():
774+
match = "Threshold number of shares must be an integer >= 2."
775+
with pytest.raises(ValueError, match=match):
776+
secrets.init()
777+
secret = secrets.random(32)
778+
secrets.share(secret, 6, 1)
779+
# Check if any warnings were raised
780+
assert len(caught_warnings) == 1
781+
assert issubclass(caught_warnings[0].category, Warning)
782+
assert match in str(caught_warnings[0].message)
783+
with pytest.raises(ValueError, match=match):
784+
secrets.init()
785+
secret = secrets.random(32)
786+
secrets.share(secret, 6, "two")
787+
# Check if any warnings were raised
788+
assert len(caught_warnings) == 1
789+
assert issubclass(caught_warnings[0].category, Warning)
790+
assert match in str(caught_warnings[0].message)
791+
792+
793+
def test_py_share_error_high_threshold():
794+
match = "Threshold number of shares must be"
795+
with pytest.raises(ValueError, match=match):
796+
secrets.init()
797+
secret = secrets.random(32)
798+
secrets.share(secret, 6, 800)
799+
# Check if any warnings were raised
800+
assert len(caught_warnings) == 1
801+
assert issubclass(caught_warnings[0].category, Warning)
802+
assert match in str(caught_warnings[0].message)
803+
with pytest.raises(ValueError, match=match):
804+
secrets.init()
805+
secret = secrets.random(32)
806+
secrets.share(secret, 6, 7)
807+
# Check if any warnings were raised
808+
assert len(caught_warnings) == 1
809+
assert issubclass(caught_warnings[0].category, Warning)
810+
assert match in str(caught_warnings[0].message)
811+
812+
813+
def test_py_share_error_padding():
814+
match = "Zero-pad length must be an integer between 0 and 1024 inclusive."
815+
with pytest.raises(ValueError, match=match):
816+
secrets.init()
817+
secret = secrets.random(32)
818+
secrets.share(secret, 6, 3, "hello")
819+
# Check if any warnings were raised
820+
assert len(caught_warnings) == 1
821+
assert issubclass(caught_warnings[0].category, Warning)
822+
assert match in str(caught_warnings[0].message)
823+
with pytest.raises(ValueError, match=match):
824+
secrets.init()
825+
secret = secrets.random(32)
826+
secrets.share(secret, 6, 3, -1)
827+
# Check if any warnings were raised
828+
assert len(caught_warnings) == 1
829+
assert issubclass(caught_warnings[0].category, Warning)
830+
assert match in str(caught_warnings[0].message)
831+
with pytest.raises(ValueError, match=match):
832+
secrets.init()
833+
secret = secrets.random(32)
834+
secrets.share(secret, 6, 3, 1025)
835+
# Check if any warnings were raised
836+
assert len(caught_warnings) == 1
837+
assert issubclass(caught_warnings[0].category, Warning)
838+
assert match in str(caught_warnings[0].message)
839+
840+
841+
def test_py_random_error():
842+
match = "Number of bits must be an Integer between 1 and 65536."
843+
with pytest.raises(ValueError, match=match):
844+
secret = secrets.random(65538)
845+
# Check if any warnings were raised
846+
assert len(caught_warnings) == 1
847+
assert issubclass(caught_warnings[0].category, Warning)
848+
assert match in str(caught_warnings[0].message)

0 commit comments

Comments
 (0)