Skip to content

Commit 5bc77d1

Browse files
committed
Added functions, tests, and other modifications
1 parent bf71770 commit 5bc77d1

18 files changed

Lines changed: 1534 additions & 205 deletions

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ lint: ## Run pep8, black, mypy linters.
3838
$(ENV_PREFIX)mypy --ignore-missing-imports js2pysecrets/
3939

4040
.PHONY: test
41-
test: lint ## Run tests and generate coverage report.
42-
$(ENV_PREFIX)pytest -v --cov-config .coveragerc --cov=js2pysecrets -l --tb=short --maxfail=1 tests/
41+
test: lint ## Run tests and generate coverage report. Add -s for print
42+
$(ENV_PREFIX)pytest -s -v --cov-config .coveragerc --cov=js2pysecrets -l --tb=short --maxfail=1 tests/
4343
$(ENV_PREFIX)coverage xml
4444
$(ENV_PREFIX)coverage html
4545

docs/contributing/tests/index.html

Lines changed: 539 additions & 85 deletions
Large diffs are not rendered by default.

docs/sitemap.xml.gz

0 Bytes
Binary file not shown.

docs_source/contributing/tests.md

Lines changed: 184 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,154 @@
1-
# Running the JavaScript Commands
1+
## Ready for Testing
2+
3+
All of the JavaScript functions of the `secrets.js-grempe` JavaScript package are accessable through the Node.js wrapper. _more details on this page_
4+
5+
!!! success "Running Tests"
6+
7+
Simple test of `str2hex()`. Comparing output of the Python version to the output of the JavaScript version.
8+
9+
=== " :fontawesome-brands-python: Python"
10+
11+
12+
13+
``` py
14+
import js2pysecrets.base as secrets # The Python Version
15+
import js2pysecrets.node as node # JavaScript using the Node.js wrapper
16+
import pytest
17+
18+
def test_str2hex_ASCII():
19+
# Set the test string
20+
test_string = "foobar"
21+
22+
# Perform conversion using the str2hex function in Python
23+
py_hex = secrets.str2hex(test_string)
24+
25+
# Perform conversion using the str2hex function in JavaScript
26+
js_hex = node.str2hex(test_string)
27+
28+
# Confirm the Python and JavaScript outputs match
29+
assert py_hex == js_hex
30+
```
31+
32+
# Configuration
33+
34+
All of the settings are stored using a `dataclass`. Allowing for the default values to be maintained, while allowing settings to modified too.
35+
36+
## ==Settings()==
37+
38+
=== " :fontawesome-brands-python: Accessing Settings"
39+
``` py
40+
from js2pysecrets.settings import Settings
41+
42+
# Initilize Settings
43+
settings = Settings()
44+
45+
# Accessing bits Variables
46+
print(settings.bits) # 8
47+
```
48+
### ==update_defaults()==
49+
50+
=== " :fontawesome-brands-python: Change a Setting"
51+
``` py
52+
from js2pysecrets.settings import Settings
53+
54+
# Initilize Settings
55+
settings = Settings()
56+
57+
# Accessing bits Variables
58+
print(settings.bits) # 8
59+
60+
# Update bits Variables
61+
settings.update_defaults(bits=16)
62+
print(settings.bits) # 16
63+
64+
# Empty Update - Reverts all settings to default
65+
settings.update_defaults()
66+
print(settings.bits) # 8
67+
```
68+
69+
### ==reset_defaults()==
70+
71+
=== " :fontawesome-brands-python: Revert to Defaults"
72+
``` py
73+
from js2pysecrets.settings import Settings
74+
75+
# Initilize Settings
76+
settings = Settings()
77+
78+
# Accessing bits Variables
79+
print(settings.bits) # 8
80+
81+
# Update bits Variables
82+
settings.update_defaults(bits=16)
83+
print(settings.bits) # 16
84+
85+
# Empty Update - Reverts all settings to default
86+
settings.reset_defaults()
87+
print(settings.bits) # 8
88+
```
89+
90+
### ==get_defaults()==
91+
92+
=== " :fontawesome-brands-python: Get the Default Values"
93+
``` py
94+
from js2pysecrets.settings import Settings
95+
96+
# Initilize Settings
97+
settings = Settings()
98+
99+
# Accessing bits Variables
100+
print(settings.bits) # 8
101+
102+
# Update bits Variables
103+
settings.update_defaults(bits=16)
104+
print(settings.bits) # 16
105+
106+
# Get the default values
107+
settings.get_defaults()
108+
defaults = settings.get_defaults()
109+
110+
# Updated variables ARE NOT changed
111+
print(settings.bits) # 16
112+
113+
# New variable contains all the defaults
114+
print(defaults.bits) # 8
115+
```
116+
117+
### ==get_config()==
118+
119+
Returns a subset of the settings. _Used by `getConfig()`_
120+
121+
=== " :fontawesome-brands-python: get_config()"
122+
``` py
123+
from js2pysecrets.settings import Settings
124+
125+
# Initilize Settings
126+
settings = Settings()
127+
config = settings.get_config()
128+
print(config)
129+
"""
130+
Config(
131+
bits=8,
132+
radix=16,
133+
maxShares=255,
134+
hasCSPRNG=False,
135+
typeCSPRNG=None
136+
)
137+
"""
138+
```
139+
140+
141+
142+
## Running the JavaScript Commands
2143

3144
Since the primary goal of this project is to create a Python implementation of Shamir's Secret Sharing that can interoperates with a JavaScript implementation. This package needs to run the JavaScript commands.
4145

5146
While there are a variety of Python libraries to execute JavaScript, they had limitations. Some translate JavaScript into Python. For others, using `require()` was a challange. In the end, this package uses a wrapper to make function calls directly to Node.js.
6147

148+
## Node.js Wrapper
149+
150+
The Node.js wrapper allows tests to be run against the JavaScript version from Python.
151+
7152
??? danger "Warning - The JavaScript wrapper uses the `eval()` function. "
8153
JavaScript's eval() function is a powerful tool that can execute code stored as a string. However, it also poses a security risk when used improperly. Here are a few reasons why eval() is considered insecure:
9154

@@ -16,6 +161,8 @@ While there are a variety of Python libraries to execute JavaScript, they had li
16161
- Debugging difficulties: When bugs or errors occur within code executed by eval(), they can be difficult to diagnose and fix due to the dynamic nature of the function. This can make it challenging for developers to find and fix problems in their code.
17162

18163

164+
165+
19166
``` { .yaml .no-copy }
20167
|-- javascript
21168
| `-- wrapper.js
@@ -36,12 +183,20 @@ While there are a variety of Python libraries to execute JavaScript, they had li
36183
secrets.share("aabb", 6, 3)
37184
```
38185

39-
There is a drawback to this approach, each call to Node.js invokes a new process. It easily handles single functions, but another approach is needed to handle subsequent calls.
186+
## Complications with the wrapper
187+
188+
There is a drawback to using the wrapper, each call to Node.js invokes a new process. It easily handles single functions, but another approach is needed to handle subsequent calls.
40189

41190

42191
!!! warning "The Python Wrapper"
43192

44193
The Python wrapper __does not__ operate like Javascript, calls are not sequential.
194+
195+
As you can see in Python example, using `setRNG('testRandom')` is not persistant.
196+
197+
Calling `random()` after `setRNG()` __will not__ use the defined RNG.
198+
199+
_While in Node.js, `setRNG()` is persistant and all subsequent calls to `random()` uses the RNG defined._
45200

46201
=== " :fontawesome-brands-python: Python"
47202

@@ -73,12 +228,27 @@ There is a drawback to this approach, each call to Node.js invokes a new process
73228
secrets.random(8) // '15'
74229
```
75230

231+
### Subsequent Commands
232+
233+
The wrapper and calling the JavaScript was built to _either_ execute the command in Node.js __or__ output the command as a string to build a list of commands.
234+
235+
This is accomplished by setting the `list` keyword in the command to `True`
236+
237+
=== " :fontawesome-brands-python: Python"
238+
239+
``` py
240+
some_func('aaa', 1, 2, 3) # Executes the command in Node.js
241+
some_func('aaa', 1, 2, 3, list=True) # String: "some_func('aaa', 1, 2, 3)"
242+
```
243+
76244

77245

78246
!!! success "Chaining a Series"
79247

80-
The Python wrapper __does not__ operate like Javascript, calls are not sequential.
248+
After building a series of commands, run them _in order_ on Node.js by passing the list to `chain()`
81249

250+
Output for each command can be accessed using the corresponding element returned by `chain()`.
251+
82252
=== " :fontawesome-brands-python: Python"
83253

84254
``` py
@@ -114,18 +284,28 @@ There is a drawback to this approach, each call to Node.js invokes a new process
114284
secrets.random(8) // '15'
115285
secrets.random(8) // '15'
116286
```
287+
_Now we can see the Python and Node.js function in similar ways._
288+
289+
### testRandom
290+
291+
Generating repeatable non-random test bits can be __important__ for cryptographic testing.
292+
293+
The wrapper includes the ability to call `setRNG('testRandom')` before indvidual commands _without_ the need of building a list. _Without the need to use `chain()`._
294+
295+
This is accomplished by setting the `test` keyword in the command to `True`
117296

118297

119298
!!! tip "Using `testRandom` _without_ `chain()`"
120299

121-
Since a large percentage of tests only require `testRandom` to be run before the command under test,
300+
Indvidual commands can use `setRNG('testRandom')` without passing a list to `chain()`.
122301

123302
=== " :fontawesome-brands-python: Python"
124303

125304
``` py
126305
import js2pysecrets.node as secrets
127306
128307
# Use test keyword to enable fixed pattern for simulated random number generation (RNG)
308+
129309
# Outputs should all be the same
130310
secrets.random(8, test=True) # '15'
131311
secrets.random(8, test=True) # '15'
@@ -149,5 +329,4 @@ There is a drawback to this approach, each call to Node.js invokes a new process
149329
```
150330

151331

152-
153332

docs_source/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
It doesn't work just yet, but it's progressing.
88

9+
910
Python implementation of Shamir's Secret Sharing.
1011

1112
$q(x) = a_0 + a_1x + \dotsi + a_{k-1}x^{k-1}$

gems/check_funcs.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#! /usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
# vim: set et sw=4 fenc=utf-8:
4+
#
5+
# defaults.py
6+
7+
import js2pysecrets.base
8+
9+
def test_functions_exist():
10+
# List of functions you expect to exist in your_module
11+
expected_functions = [
12+
'init',
13+
'combine',
14+
'getConfig',
15+
'extractShareComponents',
16+
'setRNG',
17+
'str2hex',
18+
'hex2str',
19+
'random',
20+
'share',
21+
'newShare',
22+
'_reset',
23+
'_padLeft',
24+
'_hex2bin',
25+
'_bin2hex',
26+
'_hasCryptoGetRandomValues',
27+
'_hasCryptoRandomBytes',
28+
'_getRNG',
29+
'_isSetRNG',
30+
'_splitNumStringToIntArray',
31+
'_horner',
32+
'_lagrange',
33+
'_getShares',
34+
'_constructPublicShareString'
35+
]
36+
37+
# List to collect missing functions
38+
missing_functions = []
39+
40+
# Loop through each function name and check if it exists in your_module
41+
for func_name in expected_functions:
42+
if not hasattr(your_module, func_name):
43+
missing_functions.append(func_name)
44+
45+
# Print the list of missing functions
46+
if missing_functions:
47+
print("Functions to create:")
48+
for missing_func in missing_functions:
49+
print(missing_func)
50+
else:
51+
print("All expected functions exist.")

gems/defaults3.py

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,26 @@
1313

1414
# This does not work
1515
settings = Settings()
16-
config = settings.get_config()
17-
print(secrets.isSetRNG())
16+
#config = settings.get_config()
17+
#print(secrets.isSetRNG())
1818

1919
secrets.setRNG('hello')
2020
config = settings.get_config()
21-
print(secrets.isSetRNG())
21+
#print(secrets.isSetRNG())
2222

2323
#settings.update_defaults(rng=99)
24-
secrets.setRNG(999)
25-
config = settings.get_config()
24+
#secrets.setRNG(999)
25+
#config = settings.get_config()
2626

27-
print(config.rng)
28-
print(secrets.isSetRNG())
27+
#print(config.rng)
28+
#print(secrets.isSetRNG())
2929

3030

3131

3232
secrets.setRNG(lambda bits: bin(random.getrandbits(bits))[2:].zfill(bits))
3333
config = settings.get_config()
3434

35-
print(config.rng(8))
35+
print(settings.rng(8))
3636
#config.rng(8)
3737

3838
# pre_gen_padding = "0" * 1024 # Pre-generate a string of 1024 '0's
@@ -49,3 +49,22 @@
4949

5050
print(secrets.hex2str(bar))
5151
print(node.hex2str(foo))
52+
53+
from js2pysecrets.settings import Settings
54+
import js2pysecrets as secrets
55+
56+
# Initilize Settings
57+
settings = Settings()
58+
defaults = settings.get_defaults()
59+
60+
# Accessing bits Variables
61+
print(defaults.size) # 8
62+
63+
# Update bits Variables
64+
settings.update_defaults(size=16)
65+
print(defaults.size) # 16
66+
67+
settings = Settings()
68+
print(settings.size)
69+
70+

gems/generate_non_zero_bits.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import secrets
2+
3+
def generate_non_zero_bits(bits):
4+
while True:
5+
result = bin(secrets.randbits(bits))[2:].zfill(bits)
6+
if '1' in result:
7+
return result
8+
9+
# Example usage:
10+
bits = 8 # Number of bits required
11+
random_bits = generate_non_zero_bits(bits)
12+
print("Random bits:", random_bits)

0 commit comments

Comments
 (0)