Skip to content

Commit

Permalink
Add python tests, add travis config.
Browse files Browse the repository at this point in the history
  • Loading branch information
msinkec committed Nov 13, 2023
1 parent bf58b2f commit 30e5943
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 43 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,6 @@ dist
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.pnp.*
.pnp.*

__pycache__/
40 changes: 40 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
dist: focal
language: node_js
node_js:
- 16
- 18
- 19

before_install:

os:
- linux
- osx
- windows

osx_image:
- xcode9.4
- xcode14

jobs:
exclude:
- osx_image: xcode9.4
node_js: 18
- osx_image: xcode9.4
node_js: 19
- osx_image: xcode14
node_js: 16
# Only test on linux for regular test jobs
- if: branch != master
node_js: 18
- if: branch != master
node_js: 19
- if: type = pull_request
os: osx
- if: type = pull_request
os: windows

script:
- npm i
- npm run test-all-lang

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"build": "rimraf dist && tsc",
"test": "npm run build && mocha",
"example": "npm run build && node dist/example.js",
"prepublishOnly": "npm run build"
"prepublishOnly": "npm run build",
"test-all-lang": "npm run build && mocha && pytest -s py/test_rabin.py"
},
"repository": {
"type": "git",
Expand Down
31 changes: 27 additions & 4 deletions py/README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,47 @@
# A simple python script for Rabin Signature
# A simple Python library for generating Rabin signatures

## Usage

### As a Python module

```python
import rabin


# Generate prime pair
seed = b'\x01'
p, q = rabin.gen_prime_pair(seed)
n = p * q

# Sign message
message = bytes.fromhex('00112233445566778899aabbccddeeff')
sig, pad = rabin.sign_rabin(p, q, message)

# Verify signature
res = rabin.verify_rabin(n, message, sig, pad)
```

### From the command line

1. Generate key pairs with a seed.

```bash
> python3 rabin.py G 01
> rabin G 01
generate primes ...
n_rabin = 0x4dd67a38e65c6d5d0877e892f1453fa09d27313f1431fcea6e703571fd56bf0b8bdd4788d94a7ec79c4232ead62eb34cd4f212e13fddaadf659ac6e45dc32c9
```

2. Sign a message: get number of padding bytes and signature

```bash
> python3 rabin.py S 00112233445566778899aabbccddeeff
> rabin S 00112233445566778899aabbccddeeff
padding = 3
digital signature = 0x420818748a86065611c0e1be3c0bae9c22fe5e515a4a35601be8b4d8bc1049c75775e01e07e2257a689e916ea7751bdfc8b1eeb51d418e2714ae2fc8eadde1b
```

3. Verify signature with results from step 2

```bash
> python3 rabin.py V 00112233445566778899aabbccddeeff 3 420818748a86065611c0e1be3c0bae9c22fe5e515a4a35601be8b4d8bc1049c75775e01e07e2257a689e916ea7751bdfc8b1eeb51d418e2714ae2fc8eadde1b
> rabin V 00112233445566778899aabbccddeeff 3 420818748a86065611c0e1be3c0bae9c22fe5e515a4a35601be8b4d8bc1049c75775e01e07e2257a689e916ea7751bdfc8b1eeb51d418e2714ae2fc8eadde1b
result of verification: True
```
37 changes: 37 additions & 0 deletions py/rabin
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env python3

import sys
from rabin import next_prime, sign, SECURITY_LEVEL, write_number, hash_to_int


if __name__ == '__main__':
print('\n rabin signature - sCrypt Inc 2020 adapted from Scheerer - all rights reserved')
print('\n rabin signature - copyright Scheerer Software 2018 - all rights reserved')

print('\n\nFirst parameter is V (Verify) or S (Sign) or G (Generate)')
print('\n verify signature (2 parameters):')
print(' > python rabin.py V <hex message> <padding> <digital signature>')
print('\n create signature S (2 parameter):')
print(' > python rabin.py S <hex message>')
print('\n generate key pair G (2 parameter):')
print(' > python rabin.py G <hex seed>')

print(f'\n\nnumber of parameters is {len(sys.argv) - 1}')

if len(sys.argv) == 5 and sys.argv[1] == 'V':
print(f'\n result of verification: {verify(sys.argv[2], sys.argv[3], sys.argv[4])}')

if len(sys.argv) == 3 and sys.argv[1] == 'S':
sig, pad = sign(sys.argv[2])
print(f'\n padding = {pad}')
print(f' digital signature = {hex(sig)}')

if len(sys.argv) == 3 and sys.argv[1] == 'G':
print('\n generate primes ... ')
priv_range = 2 ** (256 * SECURITY_LEVEL)
p_rabin = next_prime(hash_to_int(bytes.fromhex(sys.argv[2])) % priv_range)
q_rabin = next_prime(hash_to_int(bytes.fromhex(sys.argv[2] + '00')) % priv_range)
write_number(p_rabin, 'p')
write_number(q_rabin, 'q')
write_number(p_rabin * q_rabin, 'n')
print(f'\n n_rabin = {hex(p_rabin * q_rabin)}')
55 changes: 18 additions & 37 deletions py/rabin.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ def gcd(a: int, b: int) -> int:
return a


def gen_prime_pair(seed) -> tuple:
if isinstance(seed, str):
seed = bytes.fromhex(seed)

priv_range = 2 ** (256 * SECURITY_LEVEL)
p = next_prime(hash_to_int(seed) % priv_range)
q = next_prime(hash_to_int(seed + b'\x00') % priv_range)
return (p, q)


def next_prime(p: int) -> int:
while p % 4 != 3:
p = p + 1
Expand Down Expand Up @@ -81,45 +91,16 @@ def read_number(filename: str) -> int:
return int(f.read())


def sign(hex_message: str) -> tuple:
p = read_number('p')
q = read_number('q')
def sign(hex_message: str, p=None, q=None) -> tuple:
if not p:
p = read_number('p')
if not q:
q = read_number('q')
return sign_rabin(p, q, bytes.fromhex(hex_message))


def verify(hex_message: str, padding: str, hex_signature: str):
n = read_number('n')
def verify(hex_message: str, padding: str, hex_signature: str, n=None):
if not n:
n = read_number('n')
return verify_rabin(n, bytes.fromhex(hex_message), int(hex_signature, 16), int(padding))


if __name__ == '__main__':
print('\n rabin signature - sCrypt Inc 2020 adapted from Scheerer - all rights reserved')
print('\n rabin signature - copyright Scheerer Software 2018 - all rights reserved')

print('\n\nFirst parameter is V (Verify) or S (Sign) or G (Generate)')
print('\n verify signature (2 parameters):')
print(' > python rabin.py V <hex message> <padding> <digital signature>')
print('\n create signature S (2 parameter):')
print(' > python rabin.py S <hex message>')
print('\n generate key pair G (2 parameter):')
print(' > python rabin.py G <hex seed>')

print(f'\n\nnumber of parameters is {len(sys.argv) - 1}')

if len(sys.argv) == 5 and sys.argv[1] == 'V':
print(f'\n result of verification: {verify(sys.argv[2], sys.argv[3], sys.argv[4])}')

if len(sys.argv) == 3 and sys.argv[1] == 'S':
sig, pad = sign(sys.argv[2])
print(f'\n padding = {pad}')
print(f' digital signature = {hex(sig)}')

if len(sys.argv) == 3 and sys.argv[1] == 'G':
print('\n generate primes ... ')
priv_range = 2 ** (256 * SECURITY_LEVEL)
p_rabin = next_prime(hash_to_int(bytes.fromhex(sys.argv[2])) % priv_range)
q_rabin = next_prime(hash_to_int(bytes.fromhex(sys.argv[2] + '00')) % priv_range)
write_number(p_rabin, 'p')
write_number(q_rabin, 'q')
write_number(p_rabin * q_rabin, 'n')
print(f'\n n_rabin = {hex(p_rabin * q_rabin)}')
39 changes: 39 additions & 0 deletions py/test_rabin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import rabin

def test_gen_prime_pair():
# Test prime pair generation
seed = b'\x01'
p, q = rabin.gen_prime_pair(seed)
assert isinstance(p, int) and isinstance(q, int), "p and q should be integers"
assert p != q, "p and q should be distinct primes"

def test_sign_rabin():
# Test signing a message
seed = b'\x01'
p, q = rabin.gen_prime_pair(seed)
message = bytes.fromhex('00112233445566778899aabbccddeeff')
sig, pad = rabin.sign_rabin(p, q, message)
assert isinstance(sig, int), "Signature should be an integer"
assert isinstance(pad, int), "Padding should be int"

def test_verify_rabin():
# Test verifying a signature
seed = b'\x01'
p, q = rabin.gen_prime_pair(seed)
n = p * q
message = bytes.fromhex('00112233445566778899aabbccddeeff')
sig, pad = rabin.sign_rabin(p, q, message)
res = rabin.verify_rabin(n, message, sig, pad)
assert res is True, "Signature verification failed"

def test_verify_rabin_with_wrong_signature():
# Test verifying with a wrong signature
seed = b'\x01'
p, q = rabin.gen_prime_pair(seed)
n = p * q
message = bytes.fromhex('00112233445566778899aabbccddeeff')
wrong_sig = 12345 # Intentionally wrong signature
pad = 8 # Intentionally wrong padding
res = rabin.verify_rabin(n, message, wrong_sig, pad)
assert res is False, "Verification should fail with wrong signature"

0 comments on commit 30e5943

Please sign in to comment.