-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #37 from janezpodhostnik/janez/user-message-signin…
…g-verification User message signing and verification
- Loading branch information
Showing
17 changed files
with
885 additions
and
293 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
from flow_py_sdk import ( | ||
SignAlgo, | ||
HashAlgo, | ||
InMemorySigner, | ||
InMemoryVerifier, | ||
flow_client, | ||
AccountKey, | ||
utils, | ||
) | ||
from examples.common.utils import random_account, random_account_with_weights | ||
from examples.common import Example, Config | ||
|
||
|
||
# ------------------------------------------------------------------------- | ||
# Sign and verify a user message | ||
# this example shows how to verify a message was signed by the owner(s) of an account | ||
# ------------------------------------------------------------------------- | ||
class SignAndVerifyUserMessageExample(Example): | ||
def __init__(self) -> None: | ||
super().__init__( | ||
tag="V.1.", name="SignAndVerifyUserMessageExample", sort_order=601 | ||
) | ||
|
||
async def run(self, ctx: Config): | ||
# generate a random account with 3 keys | ||
async with flow_client( | ||
host=ctx.access_node_host, port=ctx.access_node_port | ||
) as client: | ||
# create account with tree half weight keys | ||
# only two signatures are required to sign a message (or a transaction) | ||
account_address, _, account_signers = await random_account_with_weights( | ||
client=client, | ||
ctx=ctx, | ||
weights=[ | ||
int(AccountKey.weight_threshold / 2), | ||
int(AccountKey.weight_threshold / 2), | ||
int(AccountKey.weight_threshold / 2), | ||
], | ||
) | ||
|
||
# the message to sign. Could include some extra information, like the reference block id or the address. | ||
message = b"Hello World!" | ||
|
||
# get two signatures from the account signers | ||
# signer 1 | ||
signature = account_signers[0].sign_user_message(message) | ||
c_signature_1 = utils.CompositeSignature( | ||
account_address.hex(), 0, signature.hex() | ||
) | ||
|
||
# signer 3 | ||
signature = account_signers[2].sign_user_message(message) | ||
c_signature_2 = utils.CompositeSignature( | ||
account_address.hex(), 2, signature.hex() | ||
) | ||
|
||
# verify the signature is valid | ||
signature_is_valid = await utils.verify_user_signature( | ||
message=message, | ||
client=client, | ||
composite_signatures=[c_signature_1, c_signature_2], | ||
) | ||
|
||
assert signature_is_valid |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
from flow_py_sdk.signer.hash_algo import HashAlgo | ||
from flow_py_sdk.signer.sign_algo import SignAlgo | ||
from flow_py_sdk.signer.signer import Signer | ||
from flow_py_sdk.signer.signer import Signer, TransactionDomainTag, UserDomainTag | ||
from flow_py_sdk.signer.verifier import Verifier | ||
from flow_py_sdk.signer.in_memory_verifier import InMemoryVerifier | ||
from flow_py_sdk.signer.in_memory_signer import InMemorySigner |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
from typing import Optional | ||
|
||
import ecdsa | ||
|
||
from flow_py_sdk.signer.hash_algo import HashAlgo | ||
from flow_py_sdk.signer.sign_algo import SignAlgo | ||
from flow_py_sdk.signer.verifier import Verifier | ||
|
||
|
||
class InMemoryVerifier(Verifier): | ||
def __init__( | ||
self, *, hash_algo: HashAlgo, sign_algo: SignAlgo, public_key_hex: str | ||
) -> None: | ||
super().__init__() | ||
self.hash_algo = hash_algo | ||
self.key = ecdsa.VerifyingKey.from_string( | ||
bytes.fromhex(public_key_hex), curve=sign_algo.get_signing_curve() | ||
) | ||
|
||
def verify(self, signature: bytes, message: bytes, tag: bytes) -> bool: | ||
hash_ = self._hash_message(message, tag) | ||
try: | ||
return self.key.verify_digest(signature, hash_) | ||
except ecdsa.keys.BadSignatureError: | ||
return False | ||
|
||
def _hash_message(self, message: bytes, tag: Optional[bytes] = None) -> bytes: | ||
m = self.hash_algo.create_hasher() | ||
if tag: | ||
m.update(tag + message) | ||
else: | ||
m.update(message) | ||
return m.digest() |
Oops, something went wrong.