[#2] Add methods sign and verify
This commit is contained in:
parent
97bc53c6f4
commit
4433fc425a
9 changed files with 102 additions and 10 deletions
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
15
frostfs_api/client/signer.py
Normal file
15
frostfs_api/client/signer.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
import ecdsa
|
||||
from hashlib import sha256
|
||||
|
||||
|
||||
class Signer:
|
||||
def sign_rfc6979(self, private_key: bytes, message: bytes) -> bytes:
|
||||
if len(private_key) == 0 or private_key is None:
|
||||
raise ValueError(f"Incorrect private_key: {private_key}")
|
||||
|
||||
# SECP256k1 is the Bitcoin elliptic curve
|
||||
sk = ecdsa.SigningKey.from_string(private_key, curve=ecdsa.SECP256k1, hashfunc=sha256)
|
||||
|
||||
signature = sk.sign(message, sigencode=ecdsa.util.sigencode_string)
|
||||
|
||||
return signature
|
18
frostfs_api/client/verifier.py
Normal file
18
frostfs_api/client/verifier.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
import ecdsa
|
||||
from hashlib import sha256
|
||||
|
||||
|
||||
class Verifier:
|
||||
def verify_rfc6979(self, public_key: bytes, message: bytes, signature: bytes) -> bool:
|
||||
if len(public_key) == 0 or public_key is None:
|
||||
raise ValueError(f"Incorrect public key: {public_key}")
|
||||
|
||||
if message is None or signature is None:
|
||||
return False
|
||||
|
||||
vk = ecdsa.VerifyingKey.from_string(public_key, curve=ecdsa.SECP256k1, hashfunc=sha256)
|
||||
|
||||
try:
|
||||
return vk.verify(signature, message)
|
||||
except ecdsa.BadSignatureError:
|
||||
return False
|
|
@ -1,11 +1,21 @@
|
|||
import base58
|
||||
import ecdsa
|
||||
|
||||
|
||||
class KeyExtension:
|
||||
def get_private_key_from_wif(self, wif: str):
|
||||
def get_private_key_from_wif(self, wif: str) -> bytes:
|
||||
if len(wif) == 0 or wif is None:
|
||||
raise ValueError(f"Empty WIF private key: {wif}")
|
||||
|
||||
decoded = base58.b58decode_check(wif)
|
||||
if len(decoded) != 34 or decoded[0] != 0x80 or decoded[-1] != 0x01:
|
||||
raise ValueError("Incorrect WIF private key")
|
||||
raise ValueError("Not decode WIF by base58")
|
||||
|
||||
private_key = decoded[1:-1]
|
||||
return private_key
|
||||
|
||||
def get_public_key(self, private_key: bytes):
|
||||
if len(private_key) == 0 or private_key is None:
|
||||
raise ValueError(f"Empty private key: {private_key}")
|
||||
|
||||
return ecdsa.SigningKey.from_string(private_key, curve=ecdsa.SECP256k1).get_verifying_key().to_string()
|
||||
|
|
4
pytest.ini
Normal file
4
pytest.ini
Normal file
|
@ -0,0 +1,4 @@
|
|||
[pytest]
|
||||
|
||||
# tests markers
|
||||
crypto: cryptographic functions tests
|
|
@ -1,3 +1,4 @@
|
|||
base58==2.1.1
|
||||
ecdsa==0.19.0
|
||||
|
||||
pytest==8.3.4
|
||||
|
|
29
tests/client/test_sign_verify.py
Normal file
29
tests/client/test_sign_verify.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
import ecdsa
|
||||
import pytest
|
||||
|
||||
from frostfs_api.client.signer import Signer
|
||||
from frostfs_api.client.verifier import Verifier
|
||||
from frostfs_api.crypto.key_extension import KeyExtension
|
||||
from tests.helpers.resources import WIF
|
||||
|
||||
|
||||
@pytest.mark.crypto
|
||||
class TestSignAndVerify:
|
||||
|
||||
@pytest.mark.parametrize("message", [b"Hello Frostfs API", b""])
|
||||
def test_sign_verify_success(
|
||||
self,
|
||||
client_signer: Signer,
|
||||
client_verifier: Verifier,
|
||||
client_key_extension: KeyExtension,
|
||||
message: bytes
|
||||
):
|
||||
private_key = client_key_extension.get_private_key_from_wif(WIF)
|
||||
public_key = client_key_extension.get_public_key(private_key)
|
||||
|
||||
signature = client_signer.sign_rfc6979(private_key, message)
|
||||
assert client_verifier.verify_rfc6979(public_key, message, signature) is True
|
||||
|
||||
def test_verify_rfc6979_empty_key(self, client_verifier: Verifier):
|
||||
with pytest.raises(ValueError, match="Incorrect public key"):
|
||||
client_verifier.verify_rfc6979(b'', b"Test message", b"signature")
|
|
@ -1,16 +1,23 @@
|
|||
import pytest
|
||||
|
||||
from frostfs_api.crypto.key_extension import KeyExtension
|
||||
from tests.helpers.convert import convert_bytes_format_127_to_256
|
||||
from tests.helpers.resources import WIF, PRIVATE_KEY
|
||||
|
||||
|
||||
@pytest.mark.crypto
|
||||
class TestKeyExtension:
|
||||
WIF = "L1YS4myg3xHPvi3FHeLaEt7G8upwJaWL5YLV7huviuUtXFpzBMqZ"
|
||||
PRIVATE_KEY = [
|
||||
-128, -5, 30, -36, -118, 85, -67, -6, 81, 43, 93, -38, 106, 21, -88, 127, 15, 125, -79, -17, -40, 77, -15,
|
||||
122, -88, 72, 109, -47, 125, -80, -40, -38
|
||||
]
|
||||
|
||||
def test_get_private_key_from_wif_success(self, client_key_extension: KeyExtension):
|
||||
private_key = client_key_extension.get_private_key_from_wif(self.WIF)
|
||||
private_key = client_key_extension.get_private_key_from_wif(WIF)
|
||||
|
||||
assert len(private_key) == 32, f"Not correct len of private key, expected: 32 Actual: {len(private_key)} "
|
||||
assert private_key == bytes(convert_bytes_format_127_to_256(self.PRIVATE_KEY)), f"Not match private key, Expected: {self.PRIVATE_KEY}, Actual: {private_key}"
|
||||
assert private_key == bytes(convert_bytes_format_127_to_256(PRIVATE_KEY)), \
|
||||
f"Not match private key, Expected: {PRIVATE_KEY}, Actual: {private_key}"
|
||||
|
||||
def test_get_private_key_empty_wif(self, client_key_extension: KeyExtension):
|
||||
with pytest.raises(ValueError, match="Empty WIF private"):
|
||||
client_key_extension.get_private_key_from_wif("")
|
||||
|
||||
def test_get_private_key_incorrect_wif(self, client_key_extension: KeyExtension):
|
||||
with pytest.raises(ValueError, match="Invalid checksum"):
|
||||
client_key_extension.get_private_key_from_wif("AAAAAAABBBBBBBBBBBCCCCCCCDDDDDDDDDDDDDDDDD")
|
||||
|
|
5
tests/helpers/resources.py
Normal file
5
tests/helpers/resources.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
WIF = "L1YS4myg3xHPvi3FHeLaEt7G8upwJaWL5YLV7huviuUtXFpzBMqZ"
|
||||
PRIVATE_KEY = [
|
||||
-128, -5, 30, -36, -118, 85, -67, -6, 81, 43, 93, -38, 106, 21, -88, 127, 15, 125, -79, -17, -40, 77, -15,
|
||||
122, -88, 72, 109, -47, 125, -80, -40, -38
|
||||
]
|
Loading…
Add table
Reference in a new issue