mirror of https://github.com/nucypher/pyUmbral.git
commit
2ad8223b68
|
@ -121,9 +121,12 @@ commands:
|
|||
- run:
|
||||
name: Install Python dependencies with Pipenv
|
||||
command: pipenv install --python << parameters.python_version >> --dev --skip-lock --pre
|
||||
# Workaround for pipenv check erroneously requiring pip>=21.1,
|
||||
# even if it is in fact installed and that version is fixed in Pipfile.
|
||||
# See https://github.com/pypa/pipenv/issues/4147
|
||||
- run:
|
||||
name: Check PEP 508 Requirements
|
||||
command: pipenv check
|
||||
command: pipenv check --ignore 40291
|
||||
- persist_to_workspace:
|
||||
root: ~/.local/share/virtualenvs/
|
||||
paths:
|
||||
|
|
|
@ -62,13 +62,14 @@ Additionally, users that delegate access to their data (like Alice, in this exam
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
from umbral import SecretKey, PublicKey
|
||||
from umbral import SecretKey, PublicKey, Signer
|
||||
|
||||
# Generate Umbral keys for Alice.
|
||||
alices_secret_key = SecretKey.random()
|
||||
alices_public_key = PublicKey.from_secret_key(alices_secret_key)
|
||||
|
||||
alices_signing_key = SecretKey.random()
|
||||
alices_signer = Signer(alices_signing_key)
|
||||
alices_verifying_key = PublicKey.from_secret_key(alices_signing_key)
|
||||
|
||||
# Generate Umbral keys for Bob.
|
||||
|
@ -112,7 +113,7 @@ which are next sent to N proxies or *Ursulas*.
|
|||
# In this example, 10 out of 20.
|
||||
kfrags = generate_kfrags(delegating_sk=alices_secret_key,
|
||||
receiving_pk=bobs_public_key,
|
||||
signing_sk=alices_signing_key,
|
||||
signer=alices_signer,
|
||||
threshold=10,
|
||||
num_kfrags=20)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import random
|
||||
from umbral import (
|
||||
SecretKey, PublicKey, GenericError,
|
||||
SecretKey, PublicKey, Signer, GenericError, CapsuleFrag,
|
||||
encrypt, generate_kfrags, reencrypt, decrypt_original, decrypt_reencrypted)
|
||||
|
||||
# Generate an Umbral key pair
|
||||
|
@ -13,6 +13,7 @@ alices_public_key = PublicKey.from_secret_key(alices_secret_key)
|
|||
|
||||
alices_signing_key = SecretKey.random()
|
||||
alices_verifying_key = PublicKey.from_secret_key(alices_signing_key)
|
||||
alices_signer = Signer(alices_signing_key)
|
||||
|
||||
# Encrypt some data for Alice
|
||||
# ---------------------------
|
||||
|
@ -58,7 +59,7 @@ except GenericError:
|
|||
|
||||
kfrags = generate_kfrags(delegating_sk=alices_secret_key,
|
||||
receiving_pk=bobs_public_key,
|
||||
signing_sk=alices_signing_key,
|
||||
signer=alices_signer,
|
||||
threshold=10,
|
||||
num_kfrags=20)
|
||||
|
||||
|
@ -85,14 +86,18 @@ assert len(cfrags) == 10
|
|||
|
||||
# Bob checks the capsule fragments
|
||||
# --------------------------------
|
||||
# Bob can verify that the capsule fragments are valid and really originate from Alice,
|
||||
# If Bob received the capsule fragments in serialized form,
|
||||
# he can verify that they are valid and really originate from Alice,
|
||||
# using Alice's public keys.
|
||||
|
||||
assert all(cfrag.verify(capsule,
|
||||
delegating_pk=alices_public_key,
|
||||
receiving_pk=bobs_public_key,
|
||||
signing_pk=alices_verifying_key)
|
||||
for cfrag in cfrags)
|
||||
suspicious_cfrags = [CapsuleFrag.from_bytes(bytes(cfrag)) for cfrag in cfrags]
|
||||
|
||||
cfrags = [cfrag.verify(capsule,
|
||||
verifying_pk=alices_verifying_key,
|
||||
delegating_pk=alices_public_key,
|
||||
receiving_pk=bobs_public_key,
|
||||
)
|
||||
for cfrag in suspicious_cfrags]
|
||||
|
||||
# Bob opens the capsule
|
||||
# ------------------------------------
|
||||
|
@ -101,7 +106,7 @@ assert all(cfrag.verify(capsule,
|
|||
bob_cleartext = decrypt_reencrypted(decrypting_sk=bobs_secret_key,
|
||||
delegating_pk=alices_public_key,
|
||||
capsule=bob_capsule,
|
||||
cfrags=cfrags,
|
||||
verified_cfrags=cfrags,
|
||||
ciphertext=ciphertext)
|
||||
print(bob_cleartext)
|
||||
assert bob_cleartext == plaintext
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from umbral import SecretKey, PublicKey\n",
|
||||
"from umbral import SecretKey, PublicKey, Signer\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Alice's Keys\n",
|
||||
|
@ -30,7 +30,8 @@
|
|||
"alices_public_key = PublicKey.from_secret_key(alices_private_key)\n",
|
||||
"\n",
|
||||
"alices_signing_key = SecretKey.random()\n",
|
||||
"alices_verifying_key = PublicKey.from_secret_key(alices_signing_key)"
|
||||
"alices_verifying_key = PublicKey.from_secret_key(alices_signing_key)\n",
|
||||
"alices_signer = Signer(alices_signing_key)"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -55,7 +56,7 @@
|
|||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"b'\\x1c\\xa0\\xa83\\x0cv\\x97\\x02d\\xe9\\xe9\\xc5_\\x9d5NRGRx\\xd4\\xc9\\x17%\\x9b\\xb4\\x05\\xd1\\xc2\\x1e\\x9d\\x0b\\xbf\\xb4g\\xf0n\\xfe\\x9eM\\x93\\xe0\\xbf#l\\xf9\\x033\\xb00\\xf5\\r\\xff\\xc9\\x133C\\xf0\\xa3\\xc0\\xd1e\\xdb~.E$%'\n"
|
||||
"b'\\xfb\\xc3T\\xb2\\x89=\\x08X\\xb1<\\xd0G/\\xab\\x8c\\xac\\x7f\\xd4)\\xcbB\\xcb^\\x99;P\\x9c\\xbf\\xaaf\\x03\\xdd\\n\\x1f$\\x1b\\xfb\\x88\\xfa\\xcd\\xe2\\x11\\x8d\\xcf\\xe5\\x88\\xaf\\x00\\xfe\\xcb\\x9d\\xf83\\x17\\x9b\\xdd\\xba\\xab\\x8b\\x08\\xbe\\xb1M\\x80\\xf1<S#'\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
@ -169,7 +170,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
@ -179,7 +180,7 @@
|
|||
"M, N = 10, 20 # the threshold and the total number of fragments\n",
|
||||
"kfrags = generate_kfrags(delegating_sk=alices_private_key,\n",
|
||||
" receiving_pk=bobs_public_key,\n",
|
||||
" signing_sk=alices_signing_key,\n",
|
||||
" signer=alices_signer,\n",
|
||||
" threshold=M,\n",
|
||||
" num_kfrags=N)"
|
||||
]
|
||||
|
@ -195,7 +196,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
@ -218,22 +219,27 @@
|
|||
"metadata": {},
|
||||
"source": [
|
||||
"## Bob checks the capsule fragments\n",
|
||||
"Bob can verify that the capsule fragments are valid and really originate from Alice, using Alice's public keys."
|
||||
"If Bob received the capsule fragments in serialized form, he can verify that they are valid and really originate from Alice, using Alice's public keys."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"execution_count": 10,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"assert all(cfrag.verify(capsule,\n",
|
||||
" delegating_pk=alices_public_key,\n",
|
||||
" receiving_pk=bobs_public_key,\n",
|
||||
" signing_pk=alices_verifying_key)\n",
|
||||
" for cfrag in cfrags)"
|
||||
"from umbral import CapsuleFrag\n",
|
||||
"\n",
|
||||
"suspicious_cfrags = [CapsuleFrag.from_bytes(bytes(cfrag)) for cfrag in cfrags]\n",
|
||||
"\n",
|
||||
"cfrags = [cfrag.verify(capsule,\n",
|
||||
" verifying_pk=alices_verifying_key,\n",
|
||||
" delegating_pk=alices_public_key,\n",
|
||||
" receiving_pk=bobs_public_key,\n",
|
||||
" )\n",
|
||||
" for cfrag in suspicious_cfrags]"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -263,7 +269,7 @@
|
|||
"bob_cleartext = decrypt_reencrypted(decrypting_sk=bobs_private_key,\n",
|
||||
" delegating_pk=alices_public_key,\n",
|
||||
" capsule=capsule,\n",
|
||||
" cfrags=cfrags,\n",
|
||||
" verified_cfrags=cfrags,\n",
|
||||
" ciphertext=ciphertext)\n",
|
||||
"\n",
|
||||
"print(bob_cleartext)\n",
|
||||
|
|
|
@ -19,6 +19,14 @@ Keys
|
|||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: Signer
|
||||
:members:
|
||||
|
||||
.. autoclass:: Signature()
|
||||
:members:
|
||||
:special-members: __eq__, __hash__
|
||||
:show-inheritance:
|
||||
|
||||
Intermediate objects
|
||||
--------------------
|
||||
|
||||
|
@ -31,11 +39,17 @@ Intermediate objects
|
|||
:special-members: __eq__, __hash__
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: VerifiedKeyFrag()
|
||||
:special-members: __eq__, __hash__
|
||||
|
||||
.. autoclass:: CapsuleFrag()
|
||||
:members: verify
|
||||
:members:
|
||||
:special-members: __eq__, __hash__
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: VerifiedCapsuleFrag()
|
||||
:special-members: __eq__, __hash__
|
||||
|
||||
Encryption, re-encryption and decryption
|
||||
----------------------------------------
|
||||
|
||||
|
@ -55,6 +69,9 @@ Utilities
|
|||
.. autoclass:: umbral.GenericError
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: umbral.VerificationError
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: umbral.serializable.Serializable
|
||||
:members: from_bytes
|
||||
:special-members: __bytes__
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'pyUmbral'
|
||||
copyright = u'2019, Michael Egorov, Justin Myles Holmes, David Nuñez, John Pacific, Kieran Prasch'
|
||||
author = u'Michael Egorov, Justin Myles Holmes, David Nuñez, John Pacific, Kieran Prasch'
|
||||
copyright = u'2019, Michael Egorov, Justin Myles Holmes, David Nuñez, John Pacific, Kieran Prasch, Bogdan Opanchuk'
|
||||
author = u'Michael Egorov, Justin Myles Holmes, David Nuñez, John Pacific, Kieran Prasch, Bogdan Opanchuk'
|
||||
|
||||
# The short X.Y version
|
||||
version = '0.1'
|
||||
|
@ -133,7 +133,7 @@ latex_elements = {
|
|||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'pyUmbral.tex', 'pyUmbral Documentation',
|
||||
u'Michael Egorov, Justin Myles Holmes, David Nuñez, John Pacific, Kieran Prasch', 'manual'),
|
||||
u'Michael Egorov, Justin Myles Holmes, David Nuñez, John Pacific, Kieran Prasch, Bogdan Opanchuk', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -43,13 +43,14 @@ A delegating key pair and a signing key pair.
|
|||
|
||||
.. doctest:: capsule_story
|
||||
|
||||
>>> from umbral import SecretKey, PublicKey
|
||||
>>> from umbral import SecretKey, PublicKey, Signer
|
||||
|
||||
>>> alices_secret_key = SecretKey.random()
|
||||
>>> alices_public_key = PublicKey.from_secret_key(alices_secret_key)
|
||||
|
||||
>>> alices_signing_key = SecretKey.random()
|
||||
>>> alices_verifying_key = PublicKey.from_secret_key(alices_signing_key)
|
||||
>>> alices_signer = Signer(alices_signing_key)
|
||||
|
||||
|
||||
Encrypt with a public key
|
||||
|
@ -105,7 +106,7 @@ but Bob needs to get only 10 re-encryptions to activate the capsule.
|
|||
>>> from umbral import generate_kfrags
|
||||
>>> kfrags = generate_kfrags(delegating_sk=alices_secret_key,
|
||||
... receiving_pk=bobs_public_key,
|
||||
... signing_sk=alices_signing_key,
|
||||
... signer=alices_signer,
|
||||
... threshold=10,
|
||||
... num_kfrags=20)
|
||||
|
||||
|
@ -172,17 +173,20 @@ Decryption
|
|||
|
||||
Bob checks the capsule fragments
|
||||
--------------------------------
|
||||
Bob can verify that the capsule fragments are valid and really originate from Alice,
|
||||
If Bob received the capsule fragments in serialized form,
|
||||
he can verify that they are valid and really originate from Alice,
|
||||
using Alice's public keys.
|
||||
|
||||
.. doctest:: capsule_story
|
||||
|
||||
>>> all(cfrag.verify(capsule,
|
||||
... delegating_pk=alices_public_key,
|
||||
... receiving_pk=bobs_public_key,
|
||||
... signing_pk=alices_verifying_key)
|
||||
... for cfrag in cfrags)
|
||||
True
|
||||
>>> from umbral import CapsuleFrag
|
||||
>>> suspicious_cfrags = [CapsuleFrag.from_bytes(bytes(cfrag)) for cfrag in cfrags]
|
||||
>>> cfrags = [cfrag.verify(capsule,
|
||||
... verifying_pk=alices_verifying_key,
|
||||
... delegating_pk=alices_public_key,
|
||||
... receiving_pk=bobs_public_key,
|
||||
... )
|
||||
... for cfrag in suspicious_cfrags]
|
||||
|
||||
|
||||
Bob opens the capsule
|
||||
|
@ -195,7 +199,7 @@ Finally, Bob decrypts the re-encrypted ciphertext using his key.
|
|||
>>> cleartext = decrypt_reencrypted(decrypting_sk=bobs_secret_key,
|
||||
... delegating_pk=alices_public_key,
|
||||
... capsule=capsule,
|
||||
... cfrags=cfrags,
|
||||
... verified_cfrags=cfrags,
|
||||
... ciphertext=ciphertext)
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
[MASTER]
|
||||
|
||||
# Specify a configuration file.
|
||||
#rcfile=
|
||||
|
||||
# Python code to execute, usually for sys.path manipulation such as
|
||||
# pygtk.require().
|
||||
#init-hook=
|
||||
|
||||
# Profiled execution.
|
||||
profile=no
|
||||
|
||||
# Add files or directories to the blacklist. They should be base names, not
|
||||
# paths.
|
||||
ignore=CVS
|
||||
|
||||
# Pickle collected data for later comparisons.
|
||||
persistent=yes
|
||||
|
||||
# List of plugins (as comma separated values of python modules names) to load,
|
||||
# usually to register additional checkers.
|
||||
load-plugins=
|
||||
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
|
||||
# Enable the message, report, category or checker with the given id(s). You can
|
||||
# either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time.
|
||||
#enable=
|
||||
|
||||
# Disable the message, report, category or checker with the given id(s). You
|
||||
# can either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time (only on the command line, not in the configuration file where
|
||||
# it should appear only once).
|
||||
|
||||
# disable warnings:
|
||||
# - C0103 (we have a lot of short names)
|
||||
# - C0114 (flat package, no need for module docstrings)
|
||||
# - C0116 (we have many short self-documenting functions)
|
||||
disable=C0103,C0114,C0116
|
||||
|
||||
|
||||
[REPORTS]
|
||||
|
||||
# Set the output format. Available formats are text, parseable, colorized, msvs
|
||||
# (visual studio) and html
|
||||
output-format=text
|
||||
|
||||
# Include message's id in output
|
||||
include-ids=no
|
||||
|
||||
# Put messages in a separate file for each module / package specified on the
|
||||
# command line instead of printing them on stdout. Reports (if any) will be
|
||||
# written in a file name "pylint_global.[txt|html]".
|
||||
files-output=no
|
||||
|
||||
# Tells whether to display a full report or only the messages
|
||||
reports=yes
|
||||
|
||||
# Python expression which should return a note less than 10 (10 is the highest
|
||||
# note). You have access to the variables errors warning, statement which
|
||||
# respectively contain the number of errors / warnings messages and the total
|
||||
# number of statements analyzed. This is used by the global evaluation report
|
||||
# (RP0004).
|
||||
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
|
||||
|
||||
# Add a comment according to your evaluation note. This is used by the global
|
||||
# evaluation report (RP0004).
|
||||
comment=no
|
||||
|
||||
|
||||
[BASIC]
|
||||
|
||||
# Required attributes for module, separated by a comma
|
||||
required-attributes=
|
||||
|
||||
# List of builtins function names that should not be used, separated by a comma
|
||||
bad-functions=map,filter,apply,input
|
||||
|
||||
# Regular expression which should only match correct module names
|
||||
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
|
||||
|
||||
# Regular expression which should only match correct module level names
|
||||
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
|
||||
|
||||
# Regular expression which should only match correct class names
|
||||
class-rgx=[A-Z_][a-zA-Z0-9]+$
|
||||
|
||||
# Regular expression which should only match correct function names
|
||||
function-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct method names
|
||||
method-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct instance attribute names
|
||||
attr-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct argument names
|
||||
argument-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct variable names
|
||||
variable-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match correct list comprehension /
|
||||
# generator expression variable names
|
||||
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma
|
||||
good-names=i,j,k,ex,Run,_
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma
|
||||
bad-names=foo,bar,baz,toto,tutu,tata
|
||||
|
||||
# Regular expression which should only match functions or classes name which do
|
||||
# not require a docstring
|
||||
no-docstring-rgx=__.*__
|
||||
|
||||
|
||||
[FORMAT]
|
||||
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=100
|
||||
|
||||
# Maximum number of lines in a module
|
||||
max-module-lines=1000
|
||||
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||
# tab).
|
||||
indent-string=' '
|
||||
|
||||
|
||||
[MISCELLANEOUS]
|
||||
|
||||
# List of note tags to take in consideration, separated by a comma.
|
||||
notes=FIXME,XXX,TODO
|
||||
|
||||
|
||||
[SIMILARITIES]
|
||||
|
||||
# Minimum lines number of a similarity.
|
||||
min-similarity-lines=4
|
||||
|
||||
# Ignore comments when computing similarities.
|
||||
ignore-comments=yes
|
||||
|
||||
# Ignore docstrings when computing similarities.
|
||||
ignore-docstrings=yes
|
||||
|
||||
|
||||
[TYPECHECK]
|
||||
|
||||
# Tells whether missing members accessed in mixin class should be ignored. A
|
||||
# mixin class is detected if its name ends with "mixin" (case insensitive).
|
||||
ignore-mixin-members=yes
|
||||
|
||||
# List of classes names for which member attributes should not be checked
|
||||
# (useful for classes with attributes dynamically set).
|
||||
ignored-classes=SQLObject
|
||||
|
||||
# When zope mode is activated, add a predefined set of Zope acquired attributes
|
||||
# to generated-members.
|
||||
zope=no
|
||||
|
||||
# List of members which are set dynamically and missed by pylint inference
|
||||
# system, and so shouldn't trigger E0201 when accessed. Python regular
|
||||
# expressions are accepted.
|
||||
generated-members=REQUEST,acl_users,aq_parent
|
||||
|
||||
|
||||
[VARIABLES]
|
||||
|
||||
# Tells whether we should check for unused import in __init__ files.
|
||||
init-import=no
|
||||
|
||||
# A regular expression matching the beginning of the name of dummy variables
|
||||
# (i.e. not used).
|
||||
dummy-variables-rgx=_|dummy
|
||||
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid to define new builtins when possible.
|
||||
additional-builtins=
|
||||
|
||||
|
||||
[CLASSES]
|
||||
|
||||
# List of interface methods to ignore, separated by a comma. This is used for
|
||||
# instance to not check methods defines in Zope's Interface base class.
|
||||
ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
|
||||
|
||||
# List of method names used to declare (i.e. assign) instance attributes.
|
||||
defining-attr-methods=__init__,__new__,setUp
|
||||
|
||||
# List of valid names for the first argument in a class method.
|
||||
valid-classmethod-first-arg=cls
|
||||
|
||||
|
||||
[DESIGN]
|
||||
|
||||
# Maximum number of arguments for function / method
|
||||
max-args=5
|
||||
|
||||
# Argument names that match this expression will be ignored. Default to name
|
||||
# with leading underscore
|
||||
ignored-argument-names=_.*
|
||||
|
||||
# Maximum number of locals for function / method body
|
||||
max-locals=20
|
||||
|
||||
# Maximum number of return / yield for function / method body
|
||||
max-returns=6
|
||||
|
||||
# Maximum number of branch for function / method body
|
||||
max-branchs=12
|
||||
|
||||
# Maximum number of statements in function / method body
|
||||
max-statements=50
|
||||
|
||||
# Maximum number of parents for a class (see R0901).
|
||||
max-parents=7
|
||||
|
||||
# Maximum number of attributes for a class (see R0902).
|
||||
max-attributes=7
|
||||
|
||||
# Minimum number of public methods for a class (see R0903).
|
||||
min-public-methods=2
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=20
|
||||
|
||||
|
||||
[IMPORTS]
|
||||
|
||||
# Deprecated modules which should not be used, separated by a comma
|
||||
deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
|
||||
|
||||
# Create a graph of every (i.e. internal and external) dependencies in the
|
||||
# given file (report RP0402 must not be disabled)
|
||||
import-graph=
|
||||
|
||||
# Create a graph of external dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
ext-import-graph=
|
||||
|
||||
# Create a graph of internal dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
int-import-graph=
|
||||
|
||||
|
||||
[EXCEPTIONS]
|
||||
|
||||
# Exceptions that will emit a warning when being caught. Defaults to
|
||||
# "Exception"
|
||||
overgeneral-exceptions=Exception
|
|
@ -1,6 +1,6 @@
|
|||
import pytest
|
||||
|
||||
from umbral import SecretKey, PublicKey, generate_kfrags, encrypt
|
||||
from umbral import SecretKey, PublicKey, Signer, generate_kfrags, encrypt
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -17,12 +17,23 @@ def bobs_keys():
|
|||
return sk, pk
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def verification_keys(alices_keys, bobs_keys):
|
||||
delegating_sk, signing_sk = alices_keys
|
||||
_receiving_sk, receiving_pk = bobs_keys
|
||||
|
||||
verifying_pk = PublicKey.from_secret_key(signing_sk)
|
||||
delegating_pk = PublicKey.from_secret_key(delegating_sk)
|
||||
|
||||
return verifying_pk, delegating_pk, receiving_pk
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def kfrags(alices_keys, bobs_keys):
|
||||
delegating_sk, signing_sk = alices_keys
|
||||
receiving_sk, receiving_pk = bobs_keys
|
||||
yield generate_kfrags(delegating_sk=delegating_sk,
|
||||
signing_sk=signing_sk,
|
||||
signer=Signer(signing_sk),
|
||||
receiving_pk=receiving_pk,
|
||||
threshold=6, num_kfrags=10)
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ def __standard_encryption_api(umbral) -> tuple:
|
|||
delegating_pk = umbral.PublicKey.from_secret_key(delegating_sk)
|
||||
|
||||
signing_sk = umbral.SecretKey.random()
|
||||
signer = umbral.Signer(signing_sk)
|
||||
|
||||
receiving_sk = umbral.SecretKey.random()
|
||||
receiving_pk = umbral.PublicKey.from_secret_key(receiving_sk)
|
||||
|
@ -48,7 +49,7 @@ def __standard_encryption_api(umbral) -> tuple:
|
|||
plain_data = os.urandom(32)
|
||||
capsule, ciphertext = umbral.encrypt(delegating_pk, plain_data)
|
||||
|
||||
return delegating_sk, receiving_pk, signing_sk, ciphertext, capsule
|
||||
return delegating_sk, receiving_pk, signer, ciphertext, capsule
|
||||
|
||||
|
||||
#
|
||||
|
@ -64,8 +65,8 @@ def __standard_encryption_api(umbral) -> tuple:
|
|||
def test_generate_kfrags_performance(benchmark, m: int, n: int, umbral) -> None:
|
||||
|
||||
def __setup():
|
||||
delegating_sk, receiving_pk, signing_sk, ciphertext, capsule = __standard_encryption_api(umbral)
|
||||
return (delegating_sk, receiving_pk, signing_sk, m, n, True, True), {}
|
||||
delegating_sk, receiving_pk, signer, ciphertext, capsule = __standard_encryption_api(umbral)
|
||||
return (delegating_sk, receiving_pk, signer, m, n, True, True), {}
|
||||
|
||||
benchmark.pedantic(umbral.generate_kfrags, setup=__setup, rounds=1000)
|
||||
assert True # ensure function finishes and succeeds.
|
||||
|
@ -84,8 +85,8 @@ def test_generate_kfrags_performance(benchmark, m: int, n: int, umbral) -> None:
|
|||
def test_random_frag_reencryption_performance(benchmark, m: int, n: int, umbral) -> None:
|
||||
|
||||
def __setup():
|
||||
delegating_sk, receiving_pk, signing_sk, ciphertext, capsule = __standard_encryption_api(umbral)
|
||||
kfrags = umbral.generate_kfrags(delegating_sk, receiving_pk, signing_sk, m, n, True, True)
|
||||
delegating_sk, receiving_pk, signer, ciphertext, capsule = __standard_encryption_api(umbral)
|
||||
kfrags = umbral.generate_kfrags(delegating_sk, receiving_pk, signer, m, n, True, True)
|
||||
one_kfrag, *remaining_kfrags = kfrags
|
||||
return (capsule, one_kfrag), {}
|
||||
|
||||
|
@ -104,8 +105,8 @@ def test_random_frag_reencryption_performance(benchmark, m: int, n: int, umbral)
|
|||
@pytest.mark.parametrize("m, n", ((6, 10), ))
|
||||
def test_single_frag_reencryption_performance(benchmark, m: int, n: int, umbral) -> None:
|
||||
|
||||
delegating_sk, receiving_pk, signing_sk, ciphertext, capsule = __standard_encryption_api(umbral)
|
||||
kfrags = umbral.generate_kfrags(delegating_sk, receiving_pk, signing_sk, m, n, True, True)
|
||||
delegating_sk, receiving_pk, signer, ciphertext, capsule = __standard_encryption_api(umbral)
|
||||
kfrags = umbral.generate_kfrags(delegating_sk, receiving_pk, signer, m, n, True, True)
|
||||
one_kfrag, *remaining_kfrags = kfrags
|
||||
args, kwargs = (capsule, one_kfrag), {}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ def __produce_kfrags_and_capsule(m: int, n: int) -> Tuple[List[umbral.KeyFrag],
|
|||
delegating_pk = umbral.PublicKey.from_secret_key(delegating_sk)
|
||||
|
||||
signing_sk = umbral.SecretKey.random()
|
||||
signer = umbral.Signer(signing_sk)
|
||||
|
||||
receiving_sk = umbral.SecretKey.random()
|
||||
receiving_pk = umbral.PublicKey.from_secret_key(receiving_sk)
|
||||
|
@ -24,7 +25,7 @@ def __produce_kfrags_and_capsule(m: int, n: int) -> Tuple[List[umbral.KeyFrag],
|
|||
plain_data = os.urandom(32)
|
||||
capsule, ciphertext = umbral.encrypt(delegating_pk, plain_data)
|
||||
|
||||
kfrags = umbral.generate_kfrags(delegating_sk, receiving_pk, signing_sk, m, n)
|
||||
kfrags = umbral.generate_kfrags(delegating_sk, receiving_pk, signer, m, n)
|
||||
|
||||
return kfrags, capsule
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ from umbral import (
|
|||
Capsule,
|
||||
SecretKey,
|
||||
PublicKey,
|
||||
Signer,
|
||||
GenericError,
|
||||
encrypt,
|
||||
decrypt_original,
|
||||
|
@ -66,17 +67,17 @@ def test_open_reencrypted(alices_keys, bobs_keys):
|
|||
delegating_sk, signing_sk = alices_keys
|
||||
receiving_sk, receiving_pk = bobs_keys
|
||||
|
||||
signing_pk = PublicKey.from_secret_key(signing_sk)
|
||||
signer = Signer(signing_sk)
|
||||
delegating_pk = PublicKey.from_secret_key(delegating_sk)
|
||||
|
||||
capsule, key = Capsule.from_public_key(delegating_pk)
|
||||
kfrags = generate_kfrags(delegating_sk=delegating_sk,
|
||||
signing_sk=signing_sk,
|
||||
signer=signer,
|
||||
receiving_pk=receiving_pk,
|
||||
threshold=threshold,
|
||||
num_kfrags=num_kfrags)
|
||||
|
||||
cfrags = [reencrypt(capsule, kfrag) for kfrag in kfrags]
|
||||
cfrags = [reencrypt(capsule, kfrag).cfrag for kfrag in kfrags]
|
||||
key_back = capsule.open_reencrypted(receiving_sk, delegating_pk, cfrags[:threshold])
|
||||
assert key_back == key
|
||||
|
||||
|
@ -94,11 +95,11 @@ def test_open_reencrypted(alices_keys, bobs_keys):
|
|||
|
||||
# Mismatched cfrags
|
||||
kfrags2 = generate_kfrags(delegating_sk=delegating_sk,
|
||||
signing_sk=signing_sk,
|
||||
signer=signer,
|
||||
receiving_pk=receiving_pk,
|
||||
threshold=threshold,
|
||||
num_kfrags=num_kfrags)
|
||||
cfrags2 = [reencrypt(capsule, kfrag) for kfrag in kfrags2]
|
||||
cfrags2 = [reencrypt(capsule, kfrag).cfrag for kfrag in kfrags2]
|
||||
with pytest.raises(ValueError, match="CapsuleFrags are not pairwise consistent"):
|
||||
capsule.open_reencrypted(receiving_sk, delegating_pk, [cfrags2[0]] + cfrags[:threshold-1])
|
||||
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
from umbral import reencrypt, CapsuleFrag, PublicKey, Capsule
|
||||
import pytest
|
||||
|
||||
from umbral import reencrypt, CapsuleFrag, PublicKey, Capsule, VerificationError
|
||||
from umbral.curve_point import CurvePoint
|
||||
|
||||
|
||||
def test_cfrag_serialization(alices_keys, bobs_keys, capsule, kfrags):
|
||||
def test_cfrag_serialization(verification_keys, capsule, kfrags):
|
||||
|
||||
delegating_sk, signing_sk = alices_keys
|
||||
_receiving_sk, receiving_pk = bobs_keys
|
||||
|
||||
signing_pk = PublicKey.from_secret_key(signing_sk)
|
||||
delegating_pk = PublicKey.from_secret_key(delegating_sk)
|
||||
verifying_pk, delegating_pk, receiving_pk = verification_keys
|
||||
|
||||
metadata = b'This is an example of metadata for re-encryption request'
|
||||
for kfrag in kfrags:
|
||||
|
@ -16,56 +14,63 @@ def test_cfrag_serialization(alices_keys, bobs_keys, capsule, kfrags):
|
|||
cfrag_bytes = bytes(cfrag)
|
||||
|
||||
new_cfrag = CapsuleFrag.from_bytes(cfrag_bytes)
|
||||
assert new_cfrag == cfrag
|
||||
|
||||
assert new_cfrag.verify(capsule,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
signing_pk=signing_pk,
|
||||
metadata=metadata)
|
||||
verified_cfrag = new_cfrag.verify(capsule,
|
||||
verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
metadata=metadata,
|
||||
)
|
||||
assert verified_cfrag == cfrag
|
||||
|
||||
# No metadata
|
||||
assert not new_cfrag.verify(capsule,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
signing_pk=signing_pk)
|
||||
with pytest.raises(VerificationError):
|
||||
new_cfrag.verify(capsule,
|
||||
verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
)
|
||||
|
||||
# Wrong metadata
|
||||
assert not new_cfrag.verify(capsule,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
signing_pk=signing_pk,
|
||||
metadata=b'Not the same metadata')
|
||||
with pytest.raises(VerificationError):
|
||||
new_cfrag.verify(capsule,
|
||||
verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
metadata=b'Not the same metadata',
|
||||
)
|
||||
|
||||
# Wrong delegating key
|
||||
assert not new_cfrag.verify(capsule,
|
||||
delegating_pk=receiving_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
signing_pk=signing_pk,
|
||||
metadata=metadata)
|
||||
with pytest.raises(VerificationError):
|
||||
new_cfrag.verify(capsule,
|
||||
verifying_pk=verifying_pk,
|
||||
delegating_pk=receiving_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
metadata=metadata,
|
||||
)
|
||||
|
||||
# Wrong receiving key
|
||||
assert not new_cfrag.verify(capsule,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=delegating_pk,
|
||||
signing_pk=signing_pk,
|
||||
metadata=metadata)
|
||||
with pytest.raises(VerificationError):
|
||||
new_cfrag.verify(capsule,
|
||||
verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=delegating_pk,
|
||||
metadata=metadata,
|
||||
)
|
||||
|
||||
# Wrong signing key
|
||||
assert not new_cfrag.verify(capsule,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
signing_pk=receiving_pk,
|
||||
metadata=metadata)
|
||||
with pytest.raises(VerificationError):
|
||||
new_cfrag.verify(capsule,
|
||||
verifying_pk=receiving_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
metadata=metadata,
|
||||
)
|
||||
|
||||
|
||||
def test_cfrag_serialization_no_metadata(alices_keys, bobs_keys, capsule, kfrags):
|
||||
def test_cfrag_serialization_no_metadata(verification_keys, capsule, kfrags):
|
||||
|
||||
delegating_sk, signing_sk = alices_keys
|
||||
_receiving_sk, receiving_pk = bobs_keys
|
||||
|
||||
signing_pk = PublicKey.from_secret_key(signing_sk)
|
||||
delegating_pk = PublicKey.from_secret_key(delegating_sk)
|
||||
verifying_pk, delegating_pk, receiving_pk = verification_keys
|
||||
|
||||
for kfrag in kfrags:
|
||||
|
||||
|
@ -74,65 +79,68 @@ def test_cfrag_serialization_no_metadata(alices_keys, bobs_keys, capsule, kfrags
|
|||
cfrag_bytes = bytes(cfrag)
|
||||
new_cfrag = CapsuleFrag.from_bytes(cfrag_bytes)
|
||||
|
||||
assert new_cfrag.verify(capsule,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
signing_pk=signing_pk)
|
||||
verified_cfrag = new_cfrag.verify(capsule,
|
||||
verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
)
|
||||
assert verified_cfrag == cfrag
|
||||
|
||||
assert not new_cfrag.verify(capsule,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
signing_pk=signing_pk,
|
||||
metadata=b'some metadata')
|
||||
with pytest.raises(VerificationError):
|
||||
new_cfrag.verify(capsule,
|
||||
verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
metadata=b'some metadata',
|
||||
)
|
||||
|
||||
|
||||
def test_cfrag_with_wrong_capsule(alices_keys, bobs_keys,
|
||||
kfrags, capsule_and_ciphertext, message):
|
||||
def test_cfrag_with_wrong_capsule(verification_keys, kfrags, capsule_and_ciphertext, message):
|
||||
|
||||
capsule, ciphertext = capsule_and_ciphertext
|
||||
|
||||
delegating_sk, signing_sk = alices_keys
|
||||
delegating_pk = PublicKey.from_secret_key(delegating_sk)
|
||||
|
||||
_receiving_sk, receiving_pk = bobs_keys
|
||||
verifying_pk, delegating_pk, receiving_pk = verification_keys
|
||||
|
||||
capsule_alice1 = capsule
|
||||
capsule_alice2, _unused_key2 = Capsule.from_public_key(delegating_pk)
|
||||
|
||||
metadata = b"some metadata"
|
||||
cfrag = reencrypt(capsule_alice2, kfrags[0], metadata=metadata)
|
||||
cfrag = CapsuleFrag.from_bytes(bytes(cfrag)) # de-verify
|
||||
|
||||
assert not cfrag.verify(capsule_alice1,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
signing_pk=PublicKey.from_secret_key(signing_sk),
|
||||
metadata=metadata)
|
||||
with pytest.raises(VerificationError):
|
||||
cfrag.verify(capsule_alice1,
|
||||
verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
metadata=metadata,
|
||||
)
|
||||
|
||||
|
||||
def test_cfrag_with_wrong_data(kfrags, alices_keys, bobs_keys, capsule_and_ciphertext, message):
|
||||
def test_cfrag_with_wrong_data(verification_keys, kfrags, capsule_and_ciphertext, message):
|
||||
|
||||
capsule, ciphertext = capsule_and_ciphertext
|
||||
|
||||
delegating_sk, signing_sk = alices_keys
|
||||
delegating_pk = PublicKey.from_secret_key(delegating_sk)
|
||||
|
||||
_receiving_sk, receiving_pk = bobs_keys
|
||||
verifying_pk, delegating_pk, receiving_pk = verification_keys
|
||||
|
||||
metadata = b"some metadata"
|
||||
cfrag = reencrypt(capsule, kfrags[0], metadata=metadata)
|
||||
|
||||
# Let's put random garbage in one of the cfrags
|
||||
cfrag = CapsuleFrag.from_bytes(bytes(cfrag)) # de-verify
|
||||
cfrag.point_e1 = CurvePoint.random()
|
||||
cfrag.point_v1 = CurvePoint.random()
|
||||
|
||||
assert not cfrag.verify(capsule,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
signing_pk=PublicKey.from_secret_key(signing_sk),
|
||||
metadata=metadata)
|
||||
with pytest.raises(VerificationError):
|
||||
cfrag.verify(capsule,
|
||||
verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
metadata=metadata,
|
||||
)
|
||||
|
||||
|
||||
def test_cfrag_is_hashable(capsule, kfrags):
|
||||
def test_cfrag_is_hashable(verification_keys, capsule, kfrags):
|
||||
|
||||
verifying_pk, delegating_pk, receiving_pk = verification_keys
|
||||
|
||||
cfrag0 = reencrypt(capsule, kfrags[0], metadata=b'abcdef')
|
||||
cfrag1 = reencrypt(capsule, kfrags[1], metadata=b'abcdef')
|
||||
|
@ -140,10 +148,22 @@ def test_cfrag_is_hashable(capsule, kfrags):
|
|||
assert hash(cfrag0) != hash(cfrag1)
|
||||
|
||||
new_cfrag = CapsuleFrag.from_bytes(bytes(cfrag0))
|
||||
assert hash(new_cfrag) == hash(cfrag0)
|
||||
assert hash(new_cfrag) != hash(cfrag0)
|
||||
|
||||
verified_cfrag = new_cfrag.verify(capsule,
|
||||
verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
metadata=b'abcdef')
|
||||
|
||||
assert hash(verified_cfrag) == hash(cfrag0)
|
||||
|
||||
|
||||
def test_cfrag_str(capsule, kfrags):
|
||||
cfrag0 = reencrypt(capsule, kfrags[0], metadata=b'abcdef')
|
||||
s = str(cfrag0)
|
||||
assert 'CapsuleFrag' in s
|
||||
assert 'VerifiedCapsuleFrag' in s
|
||||
|
||||
s = str(CapsuleFrag.from_bytes(bytes(cfrag0)))
|
||||
assert "VerifiedCapsuleFrag" not in s
|
||||
assert "CapsuleFrag" in s
|
||||
|
|
|
@ -93,30 +93,32 @@ def test_encrypt_decrypt(implementations):
|
|||
|
||||
|
||||
def _generate_kfrags(umbral, delegating_sk_bytes, receiving_pk_bytes,
|
||||
signing_sk_bytes, threshold, num_frags):
|
||||
signing_sk_bytes, threshold, num_kfrags):
|
||||
|
||||
delegating_sk = umbral.SecretKey.from_bytes(delegating_sk_bytes)
|
||||
receiving_pk = umbral.PublicKey.from_bytes(receiving_pk_bytes)
|
||||
signing_sk = umbral.SecretKey.from_bytes(signing_sk_bytes)
|
||||
|
||||
kfrags = umbral.generate_kfrags(delegating_sk,
|
||||
receiving_pk,
|
||||
signing_sk,
|
||||
threshold,
|
||||
num_frags,
|
||||
True,
|
||||
True,
|
||||
kfrags = umbral.generate_kfrags(delegating_sk=delegating_sk,
|
||||
receiving_pk=receiving_pk,
|
||||
signer=umbral.Signer(signing_sk),
|
||||
threshold=threshold,
|
||||
num_kfrags=num_kfrags,
|
||||
sign_delegating_key=True,
|
||||
sign_receiving_key=True,
|
||||
)
|
||||
|
||||
return [bytes(kfrag) for kfrag in kfrags]
|
||||
|
||||
|
||||
def _verify_kfrags(umbral, kfrags_bytes, signing_pk_bytes, delegating_pk_bytes, receiving_pk_bytes):
|
||||
def _verify_kfrags(umbral, kfrags_bytes, verifying_pk_bytes, delegating_pk_bytes, receiving_pk_bytes):
|
||||
kfrags = [umbral.KeyFrag.from_bytes(kfrag_bytes) for kfrag_bytes in kfrags_bytes]
|
||||
signing_pk = umbral.PublicKey.from_bytes(signing_pk_bytes)
|
||||
verifying_pk = umbral.PublicKey.from_bytes(verifying_pk_bytes)
|
||||
delegating_pk = umbral.PublicKey.from_bytes(delegating_pk_bytes)
|
||||
receiving_pk = umbral.PublicKey.from_bytes(receiving_pk_bytes)
|
||||
assert all(kfrag.verify(signing_pk, delegating_pk, receiving_pk) for kfrag in kfrags)
|
||||
return [kfrag.verify(verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk) for kfrag in kfrags]
|
||||
|
||||
|
||||
def test_kfrags(implementations):
|
||||
|
@ -124,49 +126,55 @@ def test_kfrags(implementations):
|
|||
umbral1, umbral2 = implementations
|
||||
|
||||
threshold = 2
|
||||
num_frags = 3
|
||||
num_kfrags = 3
|
||||
plaintext = b'peace at dawn'
|
||||
|
||||
# On client 1
|
||||
|
||||
receiving_sk_bytes, receiving_pk_bytes = _create_keypair(umbral1)
|
||||
delegating_sk_bytes, delegating_pk_bytes = _create_keypair(umbral1)
|
||||
signing_sk_bytes, signing_pk_bytes = _create_keypair(umbral1)
|
||||
signing_sk_bytes, verifying_pk_bytes = _create_keypair(umbral1)
|
||||
kfrags_bytes = _generate_kfrags(umbral1, delegating_sk_bytes, receiving_pk_bytes,
|
||||
signing_sk_bytes, threshold, num_frags)
|
||||
signing_sk_bytes, threshold, num_kfrags)
|
||||
|
||||
# On client 2
|
||||
|
||||
_verify_kfrags(umbral2, kfrags_bytes, signing_pk_bytes, delegating_pk_bytes, receiving_pk_bytes)
|
||||
_verify_kfrags(umbral2, kfrags_bytes, verifying_pk_bytes, delegating_pk_bytes, receiving_pk_bytes)
|
||||
|
||||
|
||||
def _reencrypt(umbral, capsule_bytes, kfrags_bytes, threshold, metadata):
|
||||
def _reencrypt(umbral, verifying_pk_bytes, delegating_pk_bytes, receiving_pk_bytes,
|
||||
capsule_bytes, kfrags_bytes, threshold, metadata):
|
||||
capsule = umbral.Capsule.from_bytes(bytes(capsule_bytes))
|
||||
kfrags = [umbral.KeyFrag.from_bytes(kfrag_bytes) for kfrag_bytes in kfrags_bytes]
|
||||
cfrags = [umbral.reencrypt(capsule, kfrag, metadata=metadata) for kfrag in kfrags[:threshold]]
|
||||
verified_kfrags = _verify_kfrags(umbral, kfrags_bytes,
|
||||
verifying_pk_bytes, delegating_pk_bytes, receiving_pk_bytes)
|
||||
cfrags = [umbral.reencrypt(capsule, kfrag, metadata=metadata) for kfrag in verified_kfrags[:threshold]]
|
||||
return [bytes(cfrag) for cfrag in cfrags]
|
||||
|
||||
|
||||
def _decrypt_reencrypted(umbral, receiving_sk_bytes, delegating_pk_bytes, signing_pk_bytes,
|
||||
def _decrypt_reencrypted(umbral, receiving_sk_bytes, delegating_pk_bytes, verifying_pk_bytes,
|
||||
capsule_bytes, cfrags_bytes, ciphertext, metadata):
|
||||
|
||||
receiving_sk = umbral.SecretKey.from_bytes(receiving_sk_bytes)
|
||||
receiving_pk = umbral.PublicKey.from_secret_key(receiving_sk)
|
||||
delegating_pk = umbral.PublicKey.from_bytes(delegating_pk_bytes)
|
||||
signing_pk = umbral.PublicKey.from_bytes(signing_pk_bytes)
|
||||
verifying_pk = umbral.PublicKey.from_bytes(verifying_pk_bytes)
|
||||
|
||||
capsule = umbral.Capsule.from_bytes(bytes(capsule_bytes))
|
||||
cfrags = [umbral.CapsuleFrag.from_bytes(cfrag_bytes) for cfrag_bytes in cfrags_bytes]
|
||||
|
||||
assert all(cfrag.verify(capsule, delegating_pk, receiving_pk, signing_pk, metadata=metadata)
|
||||
for cfrag in cfrags)
|
||||
verified_cfrags = [cfrag.verify(capsule,
|
||||
verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
metadata=metadata)
|
||||
for cfrag in cfrags]
|
||||
|
||||
# Decryption by Bob
|
||||
plaintext = umbral.decrypt_reencrypted(receiving_sk,
|
||||
delegating_pk,
|
||||
capsule,
|
||||
cfrags,
|
||||
ciphertext,
|
||||
plaintext = umbral.decrypt_reencrypted(decrypting_sk=receiving_sk,
|
||||
delegating_pk=delegating_pk,
|
||||
capsule=capsule,
|
||||
verified_cfrags=verified_cfrags,
|
||||
ciphertext=ciphertext,
|
||||
)
|
||||
|
||||
return plaintext
|
||||
|
@ -178,28 +186,60 @@ def test_reencrypt(implementations):
|
|||
|
||||
metadata = b'metadata'
|
||||
threshold = 2
|
||||
num_frags = 3
|
||||
num_kfrags = 3
|
||||
plaintext = b'peace at dawn'
|
||||
|
||||
# On client 1
|
||||
|
||||
receiving_sk_bytes, receiving_pk_bytes = _create_keypair(umbral1)
|
||||
delegating_sk_bytes, delegating_pk_bytes = _create_keypair(umbral1)
|
||||
signing_sk_bytes, signing_pk_bytes = _create_keypair(umbral1)
|
||||
signing_sk_bytes, verifying_pk_bytes = _create_keypair(umbral1)
|
||||
|
||||
capsule_bytes, ciphertext = _encrypt(umbral1, plaintext, delegating_pk_bytes)
|
||||
|
||||
kfrags_bytes = _generate_kfrags(umbral1, delegating_sk_bytes, receiving_pk_bytes,
|
||||
signing_sk_bytes, threshold, num_frags)
|
||||
signing_sk_bytes, threshold, num_kfrags)
|
||||
|
||||
# On client 2
|
||||
|
||||
cfrags_bytes = _reencrypt(umbral2, capsule_bytes, kfrags_bytes, threshold, metadata)
|
||||
cfrags_bytes = _reencrypt(umbral2, verifying_pk_bytes, delegating_pk_bytes, receiving_pk_bytes,
|
||||
capsule_bytes, kfrags_bytes, threshold, metadata)
|
||||
|
||||
# On client 1
|
||||
|
||||
plaintext_reencrypted = _decrypt_reencrypted(umbral1,
|
||||
receiving_sk_bytes, delegating_pk_bytes, signing_pk_bytes,
|
||||
receiving_sk_bytes, delegating_pk_bytes, verifying_pk_bytes,
|
||||
capsule_bytes, cfrags_bytes, ciphertext, metadata)
|
||||
|
||||
assert plaintext_reencrypted == plaintext
|
||||
|
||||
|
||||
def _sign_message(umbral, sk_bytes, message):
|
||||
sk = umbral.SecretKey.from_bytes(sk_bytes)
|
||||
signer = umbral.Signer(sk)
|
||||
assert signer.verifying_key() == umbral.PublicKey.from_secret_key(sk)
|
||||
return bytes(signer.sign(message))
|
||||
|
||||
|
||||
def _verify_message(umbral, pk_bytes, signature_bytes, message):
|
||||
pk = umbral.PublicKey.from_bytes(pk_bytes)
|
||||
signature = umbral.Signature.from_bytes(signature_bytes)
|
||||
return signature.verify(pk, message)
|
||||
|
||||
|
||||
def test_signer(implementations):
|
||||
|
||||
umbral1, umbral2 = implementations
|
||||
|
||||
message = b'peace at dawn'
|
||||
|
||||
sk_bytes, pk_bytes = _create_keypair(umbral1)
|
||||
|
||||
signature1_bytes = _sign_message(umbral1, sk_bytes, message)
|
||||
signature2_bytes = _sign_message(umbral2, sk_bytes, message)
|
||||
|
||||
# Signatures are random, so we can't compare them.
|
||||
# Cross-verify instead
|
||||
|
||||
assert _verify_message(umbral1, pk_bytes, signature2_bytes, message)
|
||||
assert _verify_message(umbral2, pk_bytes, signature1_bytes, message)
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
import pytest
|
||||
|
||||
from umbral.openssl import Curve, bn_to_int, point_to_affine_coords
|
||||
from umbral.curve import CURVE, CURVES, SECP256R1, SECP256K1, SECP384R1
|
||||
from umbral.curve import CURVE, SECP256K1
|
||||
|
||||
|
||||
def test_supported_curves():
|
||||
|
||||
# Ensure we have the correct number of supported curves hardcoded
|
||||
number_of_supported_curves = 3
|
||||
number_of_supported_curves = 1
|
||||
assert len(Curve._supported_curves) == number_of_supported_curves
|
||||
|
||||
# Manually ensure the `_supported curves` dict contains only valid supported curves
|
||||
assert Curve._supported_curves[415] == 'secp256r1'
|
||||
assert Curve._supported_curves[714] == 'secp256k1'
|
||||
assert Curve._supported_curves[715] == 'secp384r1'
|
||||
|
||||
|
||||
def test_create_by_nid():
|
||||
|
@ -46,20 +44,12 @@ def test_create_by_name():
|
|||
|
||||
def test_curve_constants():
|
||||
|
||||
test_p256 = SECP256R1
|
||||
test_secp256k1 = SECP256K1
|
||||
test_p384 = SECP384R1
|
||||
|
||||
assert CURVE == SECP256K1
|
||||
|
||||
# Test the hardcoded curve NIDs are correct:
|
||||
assert test_p256.nid == 415
|
||||
assert test_secp256k1.nid == 714
|
||||
assert test_p384.nid == 715
|
||||
|
||||
# Ensure every curve constant is in the CURVES collection
|
||||
number_of_supported_curves = 3
|
||||
assert len(CURVES) == number_of_supported_curves
|
||||
|
||||
# Ensure all supported curves can be initialized
|
||||
for nid, name in Curve._supported_curves.items():
|
||||
|
@ -69,7 +59,8 @@ def test_curve_constants():
|
|||
|
||||
|
||||
def test_curve_str():
|
||||
for curve in CURVES:
|
||||
for nid in Curve._supported_curves:
|
||||
curve = Curve(nid=nid)
|
||||
s = str(curve)
|
||||
assert str(curve.nid) in s
|
||||
assert str(curve.name) in s
|
||||
|
@ -91,23 +82,3 @@ def test_secp256k1():
|
|||
assert info['generator'] == (
|
||||
0x79BE667E_F9DCBBAC_55A06295_CE870B07_029BFCDB_2DCE28D9_59F2815B_16F81798,
|
||||
0x483ADA77_26A3C465_5DA4FBFC_0E1108A8_FD17B448_A6855419_9C47D08F_FB10D4B8)
|
||||
|
||||
|
||||
def test_p256():
|
||||
info = _curve_info(SECP256R1)
|
||||
assert info['order'] == 0xFFFFFFFF_00000000_FFFFFFFF_FFFFFFFF_BCE6FAAD_A7179E84_F3B9CAC2_FC632551
|
||||
assert info['field_element_size'] == 32
|
||||
assert info['scalar_size'] == 32
|
||||
assert info['generator'] == (
|
||||
0x6B17D1F2_E12C4247_F8BCE6E5_63A440F2_77037D81_2DEB33A0_F4A13945_D898C296,
|
||||
0x4FE342E2_FE1A7F9B_8EE7EB4A_7C0F9E16_2BCE3357_6B315ECE_CBB64068_37BF51F5)
|
||||
|
||||
|
||||
def test_p384():
|
||||
info = _curve_info(SECP384R1)
|
||||
assert info['order'] == 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_C7634D81_F4372DDF_581A0DB2_48B0A77A_ECEC196A_CCC52973
|
||||
assert info['field_element_size'] == 48
|
||||
assert info['scalar_size'] == 48
|
||||
assert info['generator'] == (
|
||||
0xAA87CA22_BE8B0537_8EB1C71E_F320AD74_6E1D3B62_8BA79B98_59F741E0_82542A38_5502F25D_BF55296C_3A545E38_72760AB7,
|
||||
0x3617DE4A_96262C6F_5D9E98BF_9292DC29_F8F41DBD_289A147C_E9DA3113_B5F0B8C0_0A60B1CE_1D7E819D_7A431D7C_90EA0E5F)
|
||||
|
|
|
@ -24,16 +24,6 @@ def test_generator_point():
|
|||
assert g1 == g2
|
||||
|
||||
|
||||
def test_to_and_from_affine():
|
||||
|
||||
x = 17004608369308732328368332205668001941491834793934321461466076545247324070015
|
||||
y = 69725941631324401609944843130171147910924748427773762412028916504484868631573
|
||||
|
||||
p = CurvePoint.from_affine(x, y)
|
||||
|
||||
assert p.to_affine() == (x, y)
|
||||
|
||||
|
||||
def test_invalid_serialized_points():
|
||||
|
||||
field_order = 2**256 - 0x1000003D1
|
||||
|
@ -72,19 +62,15 @@ def test_serialize_point_at_infinity():
|
|||
assert bytes_point_at_infinity == b'\x00'
|
||||
|
||||
|
||||
def test_coords_with_special_characteristics():
|
||||
def test_to_affine():
|
||||
p = CurvePoint.generator()
|
||||
x_ref = 0x79BE667E_F9DCBBAC_55A06295_CE870B07_029BFCDB_2DCE28D9_59F2815B_16F81798
|
||||
y_ref = 0x483ADA77_26A3C465_5DA4FBFC_0E1108A8_FD17B448_A6855419_9C47D08F_FB10D4B8
|
||||
assert p.to_affine() == (x_ref, y_ref)
|
||||
|
||||
# Testing that a point with x coordinate greater than the curve order is still valid.
|
||||
# In particular, we will test the last valid point from the default curve (secp256k1)
|
||||
# whose x coordinate is `field_order - 3` and is greater than the order of the curve
|
||||
|
||||
field_order = 2**256 - 0x1000003D1
|
||||
compressed = b'\x02' + (field_order-3).to_bytes(32, 'big')
|
||||
|
||||
last_point = CurvePoint.from_bytes(compressed)
|
||||
|
||||
# The same point, but obtained through the from_affine method
|
||||
x = 115792089237316195423570985008687907853269984665640564039457584007908834671660
|
||||
y = 109188863561374057667848968960504138135859662956057034999983532397866404169138
|
||||
|
||||
assert last_point == CurvePoint.from_affine(x, y)
|
||||
def test_identity_to_affine():
|
||||
p = CurvePoint.generator()
|
||||
identity = p - p
|
||||
with pytest.raises(ValueError):
|
||||
identity.to_affine()
|
||||
|
|
|
@ -1,54 +1,48 @@
|
|||
import pytest
|
||||
|
||||
from umbral import KeyFrag, PublicKey, generate_kfrags
|
||||
from umbral.key_frag import KeyFragID
|
||||
from umbral import KeyFrag, PublicKey, Signer, VerificationError
|
||||
from umbral.key_frag import KeyFragID, KeyFragBase
|
||||
from umbral.curve_scalar import CurveScalar
|
||||
|
||||
|
||||
def test_kfrag_serialization(alices_keys, bobs_keys, kfrags):
|
||||
def test_kfrag_serialization(verification_keys, kfrags):
|
||||
|
||||
delegating_sk, signing_sk = alices_keys
|
||||
_receiving_sk, receiving_pk = bobs_keys
|
||||
|
||||
signing_pk = PublicKey.from_secret_key(signing_sk)
|
||||
delegating_pk = PublicKey.from_secret_key(delegating_sk)
|
||||
verifying_pk, delegating_pk, receiving_pk = verification_keys
|
||||
|
||||
for kfrag in kfrags:
|
||||
kfrag_bytes = bytes(kfrag)
|
||||
new_kfrag = KeyFrag.from_bytes(kfrag_bytes)
|
||||
|
||||
assert new_kfrag.verify(signing_pk=signing_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk)
|
||||
new_kfrag = new_kfrag.verify(verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk)
|
||||
|
||||
assert new_kfrag == kfrag
|
||||
|
||||
|
||||
def test_kfrag_verification(alices_keys, bobs_keys, kfrags):
|
||||
def test_kfrag_verification(verification_keys, kfrags):
|
||||
|
||||
delegating_sk, signing_sk = alices_keys
|
||||
_receiving_sk, receiving_pk = bobs_keys
|
||||
|
||||
signing_pk = PublicKey.from_secret_key(signing_sk)
|
||||
delegating_pk = PublicKey.from_secret_key(delegating_sk)
|
||||
verifying_pk, delegating_pk, receiving_pk = verification_keys
|
||||
|
||||
# Wrong signature
|
||||
kfrag = kfrags[0]
|
||||
kfrag.id = KeyFragID.random()
|
||||
kfrag.kfrag.id = KeyFragID.random()
|
||||
kfrag_bytes = bytes(kfrag)
|
||||
new_kfrag = KeyFrag.from_bytes(kfrag_bytes)
|
||||
assert not new_kfrag.verify(signing_pk=signing_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk)
|
||||
with pytest.raises(VerificationError):
|
||||
new_kfrag.verify(verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk)
|
||||
|
||||
# Wrong key
|
||||
kfrag = kfrags[1]
|
||||
kfrag.key = CurveScalar.random_nonzero()
|
||||
kfrag.kfrag.key = CurveScalar.random_nonzero()
|
||||
kfrag_bytes = bytes(kfrag)
|
||||
new_kfrag = KeyFrag.from_bytes(kfrag_bytes)
|
||||
assert not new_kfrag.verify(signing_pk=signing_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk)
|
||||
with pytest.raises(VerificationError):
|
||||
new_kfrag.verify(verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('sign_delegating_key',
|
||||
|
@ -62,18 +56,17 @@ def test_kfrag_signing(alices_keys, bobs_keys, sign_delegating_key, sign_receivi
|
|||
delegating_sk, signing_sk = alices_keys
|
||||
_receiving_sk, receiving_pk = bobs_keys
|
||||
|
||||
signing_pk = PublicKey.from_secret_key(signing_sk)
|
||||
verifying_pk = PublicKey.from_secret_key(signing_sk)
|
||||
delegating_pk = PublicKey.from_secret_key(delegating_sk)
|
||||
|
||||
kfrags = generate_kfrags(delegating_sk=delegating_sk,
|
||||
signing_sk=signing_sk,
|
||||
receiving_pk=receiving_pk,
|
||||
threshold=6,
|
||||
num_kfrags=10,
|
||||
sign_delegating_key=sign_delegating_key,
|
||||
sign_receiving_key=sign_receiving_key)
|
||||
base = KeyFragBase(delegating_sk=delegating_sk,
|
||||
receiving_pk=receiving_pk,
|
||||
signer=Signer(signing_sk),
|
||||
threshold=6)
|
||||
|
||||
kfrag = kfrags[0]
|
||||
kfrag = KeyFrag.from_base(base=base,
|
||||
sign_delegating_key=sign_delegating_key,
|
||||
sign_receiving_key=sign_receiving_key)
|
||||
|
||||
# serialize/deserialize to make sure sign_* fields are serialized correctly
|
||||
kfrag = KeyFrag.from_bytes(bytes(kfrag))
|
||||
|
@ -84,43 +77,50 @@ def test_kfrag_signing(alices_keys, bobs_keys, sign_delegating_key, sign_receivi
|
|||
receiving_key_ok = (not sign_receiving_key) or pass_receiving_key
|
||||
should_verify = delegating_key_ok and receiving_key_ok
|
||||
|
||||
result = kfrag.verify(signing_pk=signing_pk,
|
||||
delegating_pk=delegating_pk if pass_delegating_key else None,
|
||||
receiving_pk=receiving_pk if pass_receiving_key else None)
|
||||
verification_passed = True
|
||||
try:
|
||||
kfrag.verify(verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk if pass_delegating_key else None,
|
||||
receiving_pk=receiving_pk if pass_receiving_key else None)
|
||||
except VerificationError:
|
||||
verification_passed = False
|
||||
|
||||
assert result == should_verify
|
||||
assert verification_passed == should_verify
|
||||
|
||||
|
||||
def test_kfrag_is_hashable(kfrags):
|
||||
|
||||
assert hash(kfrags[0]) != hash(kfrags[1])
|
||||
|
||||
new_kfrag = KeyFrag.from_bytes(bytes(kfrags[0]))
|
||||
assert hash(new_kfrag) == hash(kfrags[0])
|
||||
|
||||
|
||||
def test_kfrag_str(kfrags):
|
||||
s = str(kfrags[0])
|
||||
assert "KeyFrag" in s
|
||||
|
||||
|
||||
WRONG_PARAMETERS = (
|
||||
# (num_kfrags, threshold)
|
||||
(-1, -1), (-1, 0), (-1, 5),
|
||||
(0, -1), (0, 0), (0, 5),
|
||||
(1, -1), (1, 0), (1, 5),
|
||||
(5, -1), (5, 0), (5, 10)
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("num_kfrags, threshold", WRONG_PARAMETERS)
|
||||
def test_wrong_threshold_and_num_kfrags(num_kfrags, threshold, alices_keys, bobs_keys):
|
||||
|
||||
def test_wrong_threshold(alices_keys, bobs_keys):
|
||||
delegating_sk, signing_sk = alices_keys
|
||||
_receiving_sk, receiving_pk = bobs_keys
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
generate_kfrags(delegating_sk=delegating_sk,
|
||||
signing_sk=signing_sk,
|
||||
receiving_pk=receiving_pk,
|
||||
threshold=threshold,
|
||||
num_kfrags=num_kfrags)
|
||||
KeyFragBase(delegating_sk=delegating_sk,
|
||||
receiving_pk=receiving_pk,
|
||||
signer=Signer(signing_sk),
|
||||
threshold=0)
|
||||
|
||||
|
||||
def test_kfrag_is_hashable(verification_keys, kfrags):
|
||||
|
||||
verifying_pk, delegating_pk, receiving_pk = verification_keys
|
||||
|
||||
assert hash(kfrags[0]) != hash(kfrags[1])
|
||||
|
||||
new_kfrag = KeyFrag.from_bytes(bytes(kfrags[0]))
|
||||
|
||||
# Not verified yet
|
||||
assert hash(new_kfrag) != hash(kfrags[0])
|
||||
|
||||
verified_kfrag = new_kfrag.verify(verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk)
|
||||
|
||||
assert hash(verified_kfrag) == hash(kfrags[0])
|
||||
|
||||
|
||||
def test_kfrag_str(kfrags):
|
||||
s = str(kfrags[0])
|
||||
assert "VerifiedKeyFrag" in s
|
||||
|
||||
s = str(KeyFrag.from_bytes(bytes(kfrags[0])))
|
||||
assert "VerifiedKeyFrag" not in s
|
||||
assert "KeyFrag" in s
|
||||
|
|
|
@ -3,8 +3,7 @@ import string
|
|||
|
||||
import pytest
|
||||
|
||||
from umbral.keys import PublicKey, SecretKey, SecretKeyFactory, Signature
|
||||
from umbral.hashing import Hash
|
||||
from umbral.keys import PublicKey, SecretKey, SecretKeyFactory
|
||||
|
||||
|
||||
def test_gen_key():
|
||||
|
@ -18,6 +17,11 @@ def test_gen_key():
|
|||
assert pk == pk2
|
||||
|
||||
|
||||
def test_secret_scalar():
|
||||
sk = SecretKey.random()
|
||||
assert sk.secret_scalar() == sk._scalar_key
|
||||
|
||||
|
||||
def test_derive_key_from_label():
|
||||
factory = SecretKeyFactory.random()
|
||||
|
||||
|
@ -58,7 +62,7 @@ def test_secret_key_str():
|
|||
def test_secret_key_hash():
|
||||
sk = SecretKey.random()
|
||||
# Insecure Python hash, shouldn't be available.
|
||||
with pytest.raises(NotImplementedError):
|
||||
with pytest.raises(RuntimeError):
|
||||
hash(sk)
|
||||
|
||||
|
||||
|
@ -71,7 +75,7 @@ def test_secret_key_factory_str():
|
|||
def test_secret_key_factory_hash():
|
||||
skf = SecretKeyFactory.random()
|
||||
# Insecure Python hash, shouldn't be available.
|
||||
with pytest.raises(NotImplementedError):
|
||||
with pytest.raises(RuntimeError):
|
||||
hash(skf)
|
||||
|
||||
|
||||
|
@ -95,7 +99,7 @@ def test_public_key_str():
|
|||
assert 'PublicKey' in s
|
||||
|
||||
|
||||
def test_keying_material_serialization():
|
||||
def test_secret_key_factory_serialization():
|
||||
factory = SecretKeyFactory.random()
|
||||
|
||||
encoded_factory = bytes(factory)
|
||||
|
@ -117,87 +121,3 @@ def test_public_key_is_hashable():
|
|||
|
||||
pk3 = PublicKey.from_bytes(bytes(pk))
|
||||
assert hash(pk) == hash(pk3)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('execution_number', range(20)) # Run this test 20 times.
|
||||
def test_sign_and_verify(execution_number):
|
||||
sk = SecretKey.random()
|
||||
pk = PublicKey.from_secret_key(sk)
|
||||
|
||||
message = b"peace at dawn"
|
||||
dst = b"dst"
|
||||
|
||||
digest = Hash(dst)
|
||||
digest.update(message)
|
||||
signature = sk.sign_digest(digest)
|
||||
|
||||
digest = Hash(dst)
|
||||
digest.update(message)
|
||||
assert signature.verify_digest(pk, digest)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('execution_number', range(20)) # Run this test 20 times.
|
||||
def test_sign_serialize_and_verify(execution_number):
|
||||
sk = SecretKey.random()
|
||||
pk = PublicKey.from_secret_key(sk)
|
||||
|
||||
message = b"peace at dawn"
|
||||
dst = b"dst"
|
||||
|
||||
digest = Hash(dst)
|
||||
digest.update(message)
|
||||
signature = sk.sign_digest(digest)
|
||||
|
||||
signature_bytes = bytes(signature)
|
||||
signature_restored = Signature.from_bytes(signature_bytes)
|
||||
|
||||
digest = Hash(dst)
|
||||
digest.update(message)
|
||||
assert signature_restored.verify_digest(pk, digest)
|
||||
|
||||
|
||||
def test_verification_fail():
|
||||
sk = SecretKey.random()
|
||||
pk = PublicKey.from_secret_key(sk)
|
||||
|
||||
message = b"peace at dawn"
|
||||
dst = b"dst"
|
||||
|
||||
digest = Hash(dst)
|
||||
digest.update(message)
|
||||
signature = sk.sign_digest(digest)
|
||||
|
||||
# wrong DST
|
||||
digest = Hash(b"other dst")
|
||||
digest.update(message)
|
||||
assert not signature.verify_digest(pk, digest)
|
||||
|
||||
# wrong message
|
||||
digest = Hash(dst)
|
||||
digest.update(b"no peace at dawn")
|
||||
assert not signature.verify_digest(pk, digest)
|
||||
|
||||
# bad signature
|
||||
signature_bytes = bytes(signature)
|
||||
signature_bytes = b'\x00' + signature_bytes[1:]
|
||||
signature_restored = Signature.from_bytes(signature_bytes)
|
||||
|
||||
digest = Hash(dst)
|
||||
digest.update(message)
|
||||
assert not signature_restored.verify_digest(pk, digest)
|
||||
|
||||
|
||||
def test_signature_repr():
|
||||
|
||||
sk = SecretKey.random()
|
||||
pk = PublicKey.from_secret_key(sk)
|
||||
|
||||
message = b"peace at dawn"
|
||||
dst = b"dst"
|
||||
|
||||
digest = Hash(dst)
|
||||
digest.update(message)
|
||||
signature = sk.sign_digest(digest)
|
||||
|
||||
s = repr(signature)
|
||||
assert 'Signature' in s
|
||||
|
|
|
@ -3,7 +3,10 @@ import pytest
|
|||
from umbral import (
|
||||
SecretKey,
|
||||
PublicKey,
|
||||
Signer,
|
||||
GenericError,
|
||||
KeyFrag,
|
||||
CapsuleFrag,
|
||||
encrypt,
|
||||
generate_kfrags,
|
||||
decrypt_original,
|
||||
|
@ -52,7 +55,8 @@ def test_simple_api(num_kfrags, threshold):
|
|||
delegating_pk = PublicKey.from_secret_key(delegating_sk)
|
||||
|
||||
signing_sk = SecretKey.random()
|
||||
signing_pk = PublicKey.from_secret_key(signing_sk)
|
||||
signer = Signer(signing_sk)
|
||||
verifying_pk = PublicKey.from_secret_key(signing_sk)
|
||||
|
||||
# Key Generation (Bob)
|
||||
receiving_sk = SecretKey.random()
|
||||
|
@ -67,29 +71,56 @@ def test_simple_api(num_kfrags, threshold):
|
|||
assert plaintext_decrypted == plaintext
|
||||
|
||||
# Split Re-Encryption Key Generation (aka Delegation)
|
||||
kfrags = generate_kfrags(delegating_sk, receiving_pk, signing_sk, threshold, num_kfrags)
|
||||
kfrags = generate_kfrags(delegating_sk=delegating_sk,
|
||||
receiving_pk=receiving_pk,
|
||||
signer=signer,
|
||||
threshold=threshold,
|
||||
num_kfrags=num_kfrags)
|
||||
|
||||
# Bob requests re-encryption to some set of M ursulas
|
||||
cfrags = list()
|
||||
for kfrag in kfrags[:threshold]:
|
||||
# Ursula checks that the received kfrag is valid
|
||||
assert kfrag.verify(signing_pk, delegating_pk, receiving_pk)
|
||||
|
||||
# Re-encryption by an Ursula
|
||||
cfrag = reencrypt(capsule, kfrag)
|
||||
|
||||
# Bob collects the result
|
||||
cfrags.append(cfrag)
|
||||
|
||||
# Bob checks that the received cfrags are valid
|
||||
assert all(cfrag.verify(capsule, delegating_pk, receiving_pk, signing_pk) for cfrag in cfrags)
|
||||
cfrags = [reencrypt(capsule, kfrag) for kfrag in kfrags]
|
||||
|
||||
# Decryption by Bob
|
||||
plaintext_reenc = decrypt_reencrypted(receiving_sk,
|
||||
delegating_pk,
|
||||
capsule,
|
||||
cfrags[:threshold],
|
||||
ciphertext,
|
||||
plaintext_reenc = decrypt_reencrypted(decrypting_sk=receiving_sk,
|
||||
delegating_pk=delegating_pk,
|
||||
capsule=capsule,
|
||||
verified_cfrags=cfrags[:threshold],
|
||||
ciphertext=ciphertext,
|
||||
)
|
||||
|
||||
assert plaintext_reenc == plaintext
|
||||
|
||||
|
||||
def test_reencrypt_unverified_kfrag(capsule, kfrags):
|
||||
kfrag = KeyFrag.from_bytes(bytes(kfrags[0]))
|
||||
with pytest.raises(TypeError):
|
||||
reencrypt(capsule, kfrag)
|
||||
|
||||
|
||||
def test_decrypt_unverified_cfrag(verification_keys, bobs_keys, capsule_and_ciphertext, kfrags):
|
||||
verifying_pk, delegating_pk, receiving_pk = verification_keys
|
||||
receiving_sk, _receiving_pk = bobs_keys
|
||||
capsule, ciphertext = capsule_and_ciphertext
|
||||
|
||||
cfrags = [reencrypt(capsule, kfrag) for kfrag in kfrags]
|
||||
cfrags[0] = CapsuleFrag.from_bytes(bytes(cfrags[0]))
|
||||
with pytest.raises(TypeError):
|
||||
plaintext_reenc = decrypt_reencrypted(decrypting_sk=receiving_sk,
|
||||
delegating_pk=delegating_pk,
|
||||
capsule=capsule,
|
||||
verified_cfrags=cfrags,
|
||||
ciphertext=ciphertext,
|
||||
)
|
||||
|
||||
|
||||
def test_wrong_num_kfrags(alices_keys, bobs_keys):
|
||||
delegating_sk, signing_sk = alices_keys
|
||||
_receiving_sk, receiving_pk = bobs_keys
|
||||
|
||||
# Trying to create less kfrags than the threshold
|
||||
with pytest.raises(ValueError):
|
||||
generate_kfrags(delegating_sk=delegating_sk,
|
||||
signer=Signer(signing_sk),
|
||||
receiving_pk=receiving_pk,
|
||||
threshold=3,
|
||||
num_kfrags=2)
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
import pytest
|
||||
|
||||
from umbral.keys import PublicKey, SecretKey
|
||||
from umbral.signing import Signature, Signer
|
||||
from umbral.hashing import Hash
|
||||
|
||||
|
||||
@pytest.mark.parametrize('execution_number', range(20)) # Run this test 20 times.
|
||||
def test_sign_and_verify(execution_number):
|
||||
sk = SecretKey.random()
|
||||
pk = PublicKey.from_secret_key(sk)
|
||||
signer = Signer(sk)
|
||||
|
||||
message = b"peace at dawn" + str(execution_number).encode()
|
||||
|
||||
signature = signer.sign(message)
|
||||
assert signature.verify(pk, message)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('execution_number', range(20)) # Run this test 20 times.
|
||||
def test_sign_serialize_and_verify(execution_number):
|
||||
sk = SecretKey.random()
|
||||
pk = PublicKey.from_secret_key(sk)
|
||||
signer = Signer(sk)
|
||||
|
||||
message = b"peace at dawn" + str(execution_number).encode()
|
||||
|
||||
signature = signer.sign(message)
|
||||
|
||||
signature_bytes = bytes(signature)
|
||||
signature_restored = Signature.from_bytes(signature_bytes)
|
||||
|
||||
assert signature_restored.verify(pk, message)
|
||||
|
||||
|
||||
def test_verification_fail():
|
||||
sk = SecretKey.random()
|
||||
pk = PublicKey.from_secret_key(sk)
|
||||
signer = Signer(sk)
|
||||
|
||||
message = b"peace at dawn"
|
||||
signature = signer.sign(message)
|
||||
|
||||
# wrong message
|
||||
wrong_message = b"no peace at dawn"
|
||||
assert not signature.verify(pk, wrong_message)
|
||||
|
||||
# bad signature
|
||||
signature_bytes = bytes(signature)
|
||||
signature_bytes = b'\x00' + signature_bytes[1:]
|
||||
signature_restored = Signature.from_bytes(signature_bytes)
|
||||
|
||||
assert not signature_restored.verify(pk, message)
|
||||
|
||||
|
||||
def test_signature_str():
|
||||
sk = SecretKey.random()
|
||||
pk = PublicKey.from_secret_key(sk)
|
||||
signer = Signer(sk)
|
||||
signature = signer.sign(b'peace at dawn')
|
||||
s = str(signature)
|
||||
assert 'Signature' in s
|
||||
|
||||
|
||||
def test_signature_is_hashable():
|
||||
sk = SecretKey.random()
|
||||
pk = PublicKey.from_secret_key(sk)
|
||||
signer = Signer(sk)
|
||||
|
||||
message = b'peace at dawn'
|
||||
message2 = b'no peace at dawn'
|
||||
|
||||
signature = signer.sign(message)
|
||||
signature2 = signer.sign(message2)
|
||||
|
||||
assert hash(signature) != hash(signature2)
|
||||
|
||||
signature_restored = Signature.from_bytes(bytes(signature))
|
||||
assert signature == signature_restored
|
||||
assert hash(signature) == hash(signature_restored)
|
||||
|
||||
# Different hash, since signing involves some randomness
|
||||
signature3 = signer.sign(message)
|
||||
assert hash(signature) != hash(signature3)
|
||||
|
||||
|
||||
def test_signer_str():
|
||||
signer = Signer(SecretKey.random())
|
||||
s = str(signer)
|
||||
assert s == "Signer:..."
|
||||
|
||||
|
||||
def test_signer_hash():
|
||||
signer = Signer(SecretKey.random())
|
||||
# Insecure Python hash, shouldn't be available.
|
||||
with pytest.raises(RuntimeError):
|
||||
hash(signer)
|
||||
|
||||
|
||||
def test_signer_bytes():
|
||||
signer = Signer(SecretKey.random())
|
||||
# Shouldn't be able to serialize.
|
||||
with pytest.raises(RuntimeError):
|
||||
bytes(signer)
|
||||
|
||||
|
||||
def test_signer_pubkey():
|
||||
sk = SecretKey.random()
|
||||
pk = PublicKey.from_secret_key(sk)
|
||||
signer = Signer(sk)
|
||||
assert signer.verifying_key() == pk
|
|
@ -122,7 +122,7 @@ def test_kfrags():
|
|||
|
||||
for json_kfrag in vector_suite['vectors']:
|
||||
kfrag = KeyFrag.from_bytes(bytes.fromhex(json_kfrag['kfrag']))
|
||||
assert kfrag.verify(signing_pk=verifying_pk,
|
||||
assert kfrag.verify(verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk), \
|
||||
'Invalid KeyFrag {}'.format(bytes(kfrag).hex())
|
||||
|
@ -150,18 +150,17 @@ def test_cfrags():
|
|||
metadata = bytes.fromhex(vector_suite['metadata'])
|
||||
|
||||
for kfrag, cfrag in kfrags_n_cfrags:
|
||||
assert kfrag.verify(signing_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk), \
|
||||
'Invalid KeyFrag {}'.format(bytes(kfrag.to_bytes).hex())
|
||||
verified_kfrag = kfrag.verify(verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk)
|
||||
|
||||
new_cfrag = reencrypt(capsule, kfrag, metadata=metadata)
|
||||
new_cfrag = reencrypt(capsule, verified_kfrag, metadata=metadata).cfrag
|
||||
assert new_cfrag.point_e1 == cfrag.point_e1
|
||||
assert new_cfrag.point_v1 == cfrag.point_v1
|
||||
assert new_cfrag.kfrag_id == cfrag.kfrag_id
|
||||
assert new_cfrag.precursor == cfrag.precursor
|
||||
assert new_cfrag.verify(capsule,
|
||||
signing_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
metadata=metadata)
|
||||
new_cfrag.verify(capsule,
|
||||
verifying_pk=verifying_pk,
|
||||
delegating_pk=delegating_pk,
|
||||
receiving_pk=receiving_pk,
|
||||
metadata=metadata)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__all__ = [
|
||||
"__title__", "__summary__", "__version__", "__author__", "__email__", "__license__", "__copyright__", "__url__"
|
||||
"__title__", "__summary__", "__version__", "__author__",
|
||||
"__email__", "__license__", "__copyright__", "__url__"
|
||||
]
|
||||
|
||||
__title__ = "umbral"
|
||||
|
|
|
@ -3,28 +3,26 @@ from .__about__ import (
|
|||
)
|
||||
|
||||
from .capsule import Capsule
|
||||
from .capsule_frag import CapsuleFrag
|
||||
from .errors import GenericError
|
||||
from .key_frag import KeyFrag, generate_kfrags
|
||||
from .capsule_frag import CapsuleFrag, VerifiedCapsuleFrag
|
||||
from .errors import GenericError, VerificationError
|
||||
from .key_frag import KeyFrag, VerifiedKeyFrag
|
||||
from .keys import SecretKey, PublicKey, SecretKeyFactory
|
||||
from .pre import encrypt, decrypt_original, decrypt_reencrypted, reencrypt
|
||||
from .pre import encrypt, decrypt_original, decrypt_reencrypted, reencrypt, generate_kfrags
|
||||
from .signing import Signature, Signer
|
||||
|
||||
__all__ = [
|
||||
"__title__",
|
||||
"__summary__",
|
||||
"__version__",
|
||||
"__author__",
|
||||
"__license__",
|
||||
"__copyright__",
|
||||
"__email__",
|
||||
"__url__",
|
||||
"SecretKey",
|
||||
"PublicKey",
|
||||
"SecretKeyFactory",
|
||||
"Signature",
|
||||
"Signer",
|
||||
"Capsule",
|
||||
"KeyFrag",
|
||||
"VerifiedKeyFrag",
|
||||
"CapsuleFrag",
|
||||
"VerifiedCapsuleFrag",
|
||||
"GenericError",
|
||||
"VerificationError",
|
||||
"encrypt",
|
||||
"decrypt_original",
|
||||
"generate_kfrags",
|
||||
|
|
|
@ -5,7 +5,6 @@ from .curve_scalar import CurveScalar
|
|||
from .errors import GenericError
|
||||
from .hashing import hash_capsule_points, hash_to_polynomial_arg, hash_to_shared_secret
|
||||
from .keys import PublicKey, SecretKey
|
||||
from .params import PARAMETERS
|
||||
from .serializable import Serializable
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from .capsule_frag import CapsuleFrag
|
||||
|
@ -13,10 +12,10 @@ if TYPE_CHECKING: # pragma: no cover
|
|||
|
||||
def lambda_coeff(xs: Sequence[CurveScalar], i: int) -> CurveScalar:
|
||||
res = CurveScalar.one()
|
||||
for j in range(len(xs)):
|
||||
for j, xs_j in enumerate(xs):
|
||||
if j != i:
|
||||
inv_diff = (xs[j] - xs[i]).invert()
|
||||
res = (res * xs[j]) * inv_diff
|
||||
inv_diff = (xs_j - xs[i]).invert()
|
||||
res = (res * xs_j) * inv_diff
|
||||
return res
|
||||
|
||||
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
from typing import Sequence, Optional
|
||||
from typing import Optional, Tuple
|
||||
|
||||
from .capsule import Capsule
|
||||
from .curve_point import CurvePoint
|
||||
from .curve_scalar import CurveScalar
|
||||
from .hashing import Hash, hash_to_cfrag_verification, hash_to_cfrag_signature
|
||||
from .keys import PublicKey, SecretKey, Signature
|
||||
from .errors import VerificationError
|
||||
from .hashing import hash_to_cfrag_verification, kfrag_signature_message
|
||||
from .keys import PublicKey
|
||||
from .key_frag import KeyFrag, KeyFragID
|
||||
from .params import PARAMETERS
|
||||
from .serializable import Serializable
|
||||
from .signing import Signature
|
||||
|
||||
|
||||
class CapsuleFragProof(Serializable):
|
||||
|
@ -158,11 +160,11 @@ class CapsuleFrag(Serializable):
|
|||
|
||||
def verify(self,
|
||||
capsule: Capsule,
|
||||
verifying_pk: PublicKey,
|
||||
delegating_pk: PublicKey,
|
||||
receiving_pk: PublicKey,
|
||||
signing_pk: PublicKey,
|
||||
metadata: Optional[bytes] = None,
|
||||
) -> bool:
|
||||
) -> 'VerifiedCapsuleFrag':
|
||||
"""
|
||||
Verifies the validity of this fragment.
|
||||
|
||||
|
@ -194,15 +196,49 @@ class CapsuleFrag(Serializable):
|
|||
precursor = self.precursor
|
||||
kfrag_id = self.kfrag_id
|
||||
|
||||
kfrag_signature = hash_to_cfrag_signature(kfrag_id, u1, precursor, delegating_pk, receiving_pk)
|
||||
valid_kfrag_signature = kfrag_signature.verify(signing_pk, self.proof.kfrag_signature)
|
||||
kfrag_message = kfrag_signature_message(kfrag_id=self.kfrag_id,
|
||||
commitment=self.proof.kfrag_commitment,
|
||||
precursor=self.precursor,
|
||||
maybe_delegating_pk=delegating_pk,
|
||||
maybe_receiving_pk=receiving_pk)
|
||||
|
||||
z3 = self.proof.signature
|
||||
correct_reencryption_of_e = e * z3 == e2 + e1 * h
|
||||
correct_reencryption_of_v = v * z3 == v2 + v1 * h
|
||||
correct_rk_commitment = u * z3 == u2 + u1 * h
|
||||
if not self.proof.kfrag_signature.verify(verifying_pk, kfrag_message):
|
||||
raise VerificationError("Invalid KeyFrag signature")
|
||||
|
||||
return (valid_kfrag_signature
|
||||
and correct_reencryption_of_e
|
||||
and correct_reencryption_of_v
|
||||
and correct_rk_commitment)
|
||||
z = self.proof.signature
|
||||
|
||||
# TODO: if one or more of the values here are incorrect,
|
||||
# we'll get the wrong `h` (since they're all hashed into it),
|
||||
# so perhaps it's enough to check only one of these equations.
|
||||
# See https://github.com/nucypher/rust-umbral/issues/46 for details.
|
||||
correct_reencryption_of_e = e * z == e2 + e1 * h
|
||||
correct_reencryption_of_v = v * z == v2 + v1 * h
|
||||
correct_rk_commitment = u * z == u2 + u1 * h
|
||||
|
||||
if not (correct_reencryption_of_e and correct_reencryption_of_v and correct_rk_commitment):
|
||||
raise VerificationError("Failed to verify reencryption proof")
|
||||
|
||||
return VerifiedCapsuleFrag(self)
|
||||
|
||||
|
||||
class VerifiedCapsuleFrag:
|
||||
"""
|
||||
Verified capsule frag, good for decryption.
|
||||
Can be cast to ``bytes``, but cannot be deserialized from bytes directly.
|
||||
It can only be obtained from :py:meth:`CapsuleFrag.verify`.
|
||||
"""
|
||||
|
||||
def __init__(self, cfrag: CapsuleFrag):
|
||||
self.cfrag = cfrag
|
||||
|
||||
def __bytes__(self):
|
||||
return bytes(self.cfrag)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.cfrag == other.cfrag
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.__class__, bytes(self)))
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.__class__.__name__}:{bytes(self).hex()[:16]}"
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
from . import openssl
|
||||
|
||||
# Global Curve Instances
|
||||
|
||||
SECP256R1 = openssl.Curve.from_name('secp256r1')
|
||||
SECP256K1 = openssl.Curve.from_name('secp256k1')
|
||||
SECP384R1 = openssl.Curve.from_name('secp384r1')
|
||||
|
||||
CURVES = (SECP256K1, SECP256R1, SECP384R1)
|
||||
|
||||
CURVE = SECP256K1
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Optional, Tuple
|
||||
from typing import Tuple
|
||||
|
||||
from . import openssl
|
||||
from .curve import CURVE
|
||||
|
@ -26,15 +26,6 @@ class CurvePoint(Serializable):
|
|||
"""
|
||||
return cls.generator() * CurveScalar.random_nonzero()
|
||||
|
||||
@classmethod
|
||||
def from_affine(cls, affine_x: int, affine_y: int) -> 'CurvePoint':
|
||||
"""
|
||||
Returns a CurvePoint object from the given affine coordinates in a tuple in
|
||||
the format of (x, y) and a given curve.
|
||||
"""
|
||||
backend_point = openssl.point_from_affine_coords(CURVE, affine_x, affine_y)
|
||||
return cls(backend_point)
|
||||
|
||||
def to_affine(self) -> Tuple[int, int]:
|
||||
"""
|
||||
Returns a tuple of Python ints in the format of (x, y) that represents
|
||||
|
@ -80,7 +71,7 @@ class CurvePoint(Serializable):
|
|||
"""
|
||||
Performs subtraction by adding the inverse of the `other` to the point.
|
||||
"""
|
||||
return (self + (-other))
|
||||
return self + (-other)
|
||||
|
||||
def __neg__(self) -> 'CurvePoint':
|
||||
"""
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, Union, Tuple
|
||||
from typing import TYPE_CHECKING, Union, Tuple
|
||||
|
||||
from . import openssl
|
||||
from .curve import CURVE
|
||||
|
@ -37,12 +37,12 @@ class CurveScalar(Serializable):
|
|||
|
||||
@classmethod
|
||||
def from_digest(cls, digest: 'Hash') -> 'CurveScalar':
|
||||
# TODO (#39): to be replaced by the standard algroithm.
|
||||
# Currently just matching what we have in RustCrypto stack
|
||||
# TODO (#39): this is used in Umbral scheme itself,
|
||||
# and needs to be able to return a guaranteed nonzero scalar.
|
||||
# Currently just matching what we have in rust-umbral
|
||||
# (taking bytes modulo curve order).
|
||||
# Can produce zeros!
|
||||
bn = openssl.bn_from_bytes(digest.finalize(), apply_modulus=CURVE.bn_order)
|
||||
return cls(bn)
|
||||
return cls(openssl.bn_from_bytes(digest.finalize(), apply_modulus=CURVE.bn_order))
|
||||
|
||||
@classmethod
|
||||
def __take__(cls, data: bytes) -> Tuple['CurveScalar', bytes]:
|
||||
|
@ -66,7 +66,7 @@ class CurveScalar(Serializable):
|
|||
"""
|
||||
Compares the two BIGNUMS or int.
|
||||
"""
|
||||
if type(other) == int:
|
||||
if isinstance(other, int):
|
||||
other = CurveScalar.from_int(other)
|
||||
return openssl.bn_cmp(self._backend_bignum, other._backend_bignum) == 0
|
||||
|
||||
|
@ -83,7 +83,9 @@ class CurveScalar(Serializable):
|
|||
"""
|
||||
if isinstance(other, int):
|
||||
other = CurveScalar.from_int(other)
|
||||
return CurveScalar(openssl.bn_mul(self._backend_bignum, other._backend_bignum, CURVE.bn_order))
|
||||
return CurveScalar(openssl.bn_mul(self._backend_bignum,
|
||||
other._backend_bignum,
|
||||
CURVE.bn_order))
|
||||
|
||||
def __add__(self, other : Union[int, 'CurveScalar']) -> 'CurveScalar':
|
||||
"""
|
||||
|
@ -91,7 +93,9 @@ class CurveScalar(Serializable):
|
|||
"""
|
||||
if isinstance(other, int):
|
||||
other = CurveScalar.from_int(other)
|
||||
return CurveScalar(openssl.bn_add(self._backend_bignum, other._backend_bignum, CURVE.bn_order))
|
||||
return CurveScalar(openssl.bn_add(self._backend_bignum,
|
||||
other._backend_bignum,
|
||||
CURVE.bn_order))
|
||||
|
||||
def __sub__(self, other : Union[int, 'CurveScalar']) -> 'CurveScalar':
|
||||
"""
|
||||
|
@ -99,7 +103,9 @@ class CurveScalar(Serializable):
|
|||
"""
|
||||
if isinstance(other, int):
|
||||
other = CurveScalar.from_int(other)
|
||||
return CurveScalar(openssl.bn_sub(self._backend_bignum, other._backend_bignum, CURVE.bn_order))
|
||||
return CurveScalar(openssl.bn_sub(self._backend_bignum,
|
||||
other._backend_bignum,
|
||||
CURVE.bn_order))
|
||||
|
||||
def invert(self) -> 'CurveScalar':
|
||||
"""
|
||||
|
|
|
@ -52,18 +52,18 @@ class DEM:
|
|||
def decrypt(self, nonce_and_ciphertext: bytes, authenticated_data: bytes = b"") -> bytes:
|
||||
|
||||
if len(nonce_and_ciphertext) < self.NONCE_SIZE:
|
||||
raise ValueError(f"The ciphertext must include the nonce")
|
||||
raise ValueError("The ciphertext must include the nonce")
|
||||
|
||||
nonce = nonce_and_ciphertext[:self.NONCE_SIZE]
|
||||
ciphertext = nonce_and_ciphertext[self.NONCE_SIZE:]
|
||||
|
||||
# Prevent an out of bounds error deep in NaCl
|
||||
if len(ciphertext) < self.TAG_SIZE:
|
||||
raise ValueError(f"The authentication tag is missing or malformed")
|
||||
raise ValueError("The authentication tag is missing or malformed")
|
||||
|
||||
try:
|
||||
return xchacha_decrypt(ciphertext, authenticated_data, nonce, self._key)
|
||||
except nacl.exceptions.CryptoError:
|
||||
except nacl.exceptions.CryptoError as e:
|
||||
raise GenericError("Decryption of ciphertext failed: "
|
||||
"either someone tampered with the ciphertext or "
|
||||
"you are using an incorrect decryption key.")
|
||||
"you are using an incorrect decryption key.") from e
|
||||
|
|
|
@ -2,4 +2,9 @@ class GenericError(Exception):
|
|||
"""
|
||||
An interal Umbral error, see the message for details.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class VerificationError(GenericError):
|
||||
"""
|
||||
Integrity of the data cannot be verified, see the message for details.
|
||||
"""
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import TYPE_CHECKING, Optional, Type, Iterable, Union
|
||||
from typing import TYPE_CHECKING, Optional, Iterable, Union, List, cast
|
||||
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
|
||||
|
@ -6,23 +6,24 @@ from .openssl import backend, ErrorInvalidCompressedPoint
|
|||
from .curve import CURVE
|
||||
from .curve_scalar import CurveScalar
|
||||
from .curve_point import CurvePoint
|
||||
from .keys import PublicKey, SecretKey, Signature
|
||||
from .serializable import Serializable, serialize_bool
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from .key_frag import KeyFragID
|
||||
from .keys import PublicKey
|
||||
|
||||
|
||||
class Hash:
|
||||
|
||||
OUTPUT_SIZE = 32
|
||||
|
||||
def __init__(self, dst: bytes):
|
||||
def __init__(self, dst: Optional[bytes] = None):
|
||||
self._backend_hash_algorithm = hashes.SHA256()
|
||||
self._hash = hashes.Hash(self._backend_hash_algorithm, backend=backend)
|
||||
|
||||
len_dst = len(dst).to_bytes(4, byteorder='big')
|
||||
self.update(len_dst + dst)
|
||||
if dst is not None:
|
||||
len_dst = len(dst).to_bytes(4, byteorder='big')
|
||||
self.update(len_dst + dst)
|
||||
|
||||
def update(self, data: Union[bytes, Serializable]) -> None:
|
||||
self._hash.update(bytes(data))
|
||||
|
@ -62,8 +63,9 @@ def hash_to_shared_secret(precursor: CurvePoint,
|
|||
return CurveScalar.from_digest(digest)
|
||||
|
||||
|
||||
|
||||
def hash_to_cfrag_verification(points: Iterable[CurvePoint], metadata: Optional[bytes] = None) -> CurveScalar:
|
||||
def hash_to_cfrag_verification(points: Iterable[CurvePoint],
|
||||
metadata: Optional[bytes] = None
|
||||
) -> CurveScalar:
|
||||
digest = Hash(b"CFRAG_VERIFICATION")
|
||||
for point in points:
|
||||
digest.update(point)
|
||||
|
@ -72,46 +74,29 @@ def hash_to_cfrag_verification(points: Iterable[CurvePoint], metadata: Optional[
|
|||
return CurveScalar.from_digest(digest)
|
||||
|
||||
|
||||
def hash_to_cfrag_signature(kfrag_id: 'KeyFragID',
|
||||
def kfrag_signature_message(kfrag_id: 'KeyFragID',
|
||||
commitment: CurvePoint,
|
||||
precursor: CurvePoint,
|
||||
maybe_delegating_pk: Optional[PublicKey],
|
||||
maybe_receiving_pk: Optional[PublicKey],
|
||||
) -> 'SignatureDigest':
|
||||
maybe_delegating_pk: Optional['PublicKey'],
|
||||
maybe_receiving_pk: Optional['PublicKey'],
|
||||
) -> bytes:
|
||||
|
||||
digest = SignatureDigest(b"CFRAG_SIGNATURE")
|
||||
digest.update(kfrag_id)
|
||||
digest.update(commitment)
|
||||
digest.update(precursor)
|
||||
# Have to convert to bytes manually because `mypy` is not smart enough to resolve types.
|
||||
|
||||
if maybe_delegating_pk:
|
||||
digest.update(serialize_bool(True))
|
||||
digest.update(maybe_delegating_pk)
|
||||
else:
|
||||
digest.update(serialize_bool(False))
|
||||
delegating_part = ([serialize_bool(True), bytes(maybe_delegating_pk)]
|
||||
if maybe_delegating_pk
|
||||
else [serialize_bool(False)])
|
||||
cast(List[Serializable], delegating_part)
|
||||
|
||||
if maybe_receiving_pk:
|
||||
digest.update(serialize_bool(True))
|
||||
digest.update(maybe_receiving_pk)
|
||||
else:
|
||||
digest.update(serialize_bool(False))
|
||||
receiving_part = ([serialize_bool(True), bytes(maybe_receiving_pk)]
|
||||
if maybe_receiving_pk
|
||||
else [serialize_bool(False)])
|
||||
|
||||
return digest
|
||||
components = ([bytes(kfrag_id), bytes(commitment), bytes(precursor)] +
|
||||
delegating_part +
|
||||
receiving_part)
|
||||
|
||||
|
||||
class SignatureDigest:
|
||||
|
||||
def __init__(self, dst: bytes):
|
||||
self._digest = Hash(dst)
|
||||
|
||||
def update(self, value):
|
||||
self._digest.update(value)
|
||||
|
||||
def sign(self, sk: SecretKey) -> Signature:
|
||||
return sk.sign_digest(self._digest)
|
||||
|
||||
def verify(self, pk: PublicKey, sig: Signature):
|
||||
return sig.verify_digest(pk, self._digest)
|
||||
return b''.join(components)
|
||||
|
||||
|
||||
def unsafe_hash_to_point(dst: bytes, data: bytes) -> CurvePoint:
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import os
|
||||
from typing import Tuple, List, Optional
|
||||
from typing import List, Optional
|
||||
|
||||
from .curve_point import CurvePoint
|
||||
from .curve_scalar import CurveScalar
|
||||
from .hashing import hash_to_shared_secret, hash_to_cfrag_signature, hash_to_polynomial_arg
|
||||
from .keys import PublicKey, SecretKey, Signature
|
||||
from .errors import VerificationError
|
||||
from .hashing import hash_to_shared_secret, kfrag_signature_message, hash_to_polynomial_arg
|
||||
from .keys import PublicKey, SecretKey
|
||||
from .params import PARAMETERS
|
||||
from .serializable import Serializable, serialize_bool, take_bool
|
||||
from .signing import Signature, Signer
|
||||
|
||||
|
||||
class KeyFragID(Serializable):
|
||||
|
@ -46,27 +48,29 @@ class KeyFragProof(Serializable):
|
|||
params = PARAMETERS
|
||||
|
||||
kfrag_precursor = base.precursor
|
||||
signing_sk = base.signing_sk
|
||||
signer = base.signer
|
||||
delegating_pk = base.delegating_pk
|
||||
receiving_pk = base.receiving_pk
|
||||
|
||||
commitment = params.u * kfrag_key
|
||||
|
||||
signature_for_receiver = hash_to_cfrag_signature(kfrag_id,
|
||||
commitment,
|
||||
kfrag_precursor,
|
||||
delegating_pk,
|
||||
receiving_pk,
|
||||
).sign(signing_sk)
|
||||
message_for_receiver = kfrag_signature_message(kfrag_id=kfrag_id,
|
||||
commitment=commitment,
|
||||
precursor=kfrag_precursor,
|
||||
maybe_delegating_pk=delegating_pk,
|
||||
maybe_receiving_pk=receiving_pk,
|
||||
)
|
||||
signature_for_receiver = signer.sign(message_for_receiver)
|
||||
|
||||
maybe_delegating_pk = delegating_pk if sign_delegating_key else None
|
||||
maybe_receiving_pk = receiving_pk if sign_receiving_key else None
|
||||
signature_for_proxy = hash_to_cfrag_signature(kfrag_id,
|
||||
commitment,
|
||||
kfrag_precursor,
|
||||
maybe_delegating_pk,
|
||||
maybe_receiving_pk
|
||||
).sign(signing_sk)
|
||||
message_for_proxy = kfrag_signature_message(kfrag_id=kfrag_id,
|
||||
commitment=commitment,
|
||||
precursor=kfrag_precursor,
|
||||
maybe_delegating_pk=maybe_delegating_pk,
|
||||
maybe_receiving_pk=maybe_receiving_pk,
|
||||
)
|
||||
signature_for_proxy = signer.sign(message_for_proxy)
|
||||
|
||||
return cls(commitment,
|
||||
signature_for_proxy,
|
||||
|
@ -194,10 +198,10 @@ class KeyFrag(Serializable):
|
|||
return cls(kfrag_id, rk, base.precursor, proof)
|
||||
|
||||
def verify(self,
|
||||
signing_pk: PublicKey,
|
||||
verifying_pk: PublicKey,
|
||||
delegating_pk: Optional[PublicKey] = None,
|
||||
receiving_pk: Optional[PublicKey] = None,
|
||||
) -> bool:
|
||||
) -> 'VerifiedKeyFrag':
|
||||
"""
|
||||
Verifies the validity of this fragment.
|
||||
|
||||
|
@ -212,25 +216,51 @@ class KeyFrag(Serializable):
|
|||
commitment = self.proof.commitment
|
||||
precursor = self.precursor
|
||||
|
||||
# We check that the commitment is well-formed
|
||||
if commitment != u * key:
|
||||
return False
|
||||
raise VerificationError("Invalid kfrag commitment")
|
||||
|
||||
# A shortcut, perhaps not necessary
|
||||
delegating_key_missing = self.proof.delegating_key_signed and not bool(delegating_pk)
|
||||
receiving_key_missing = self.proof.receiving_key_signed and not bool(receiving_pk)
|
||||
if self.proof.delegating_key_signed and not bool(delegating_pk):
|
||||
raise VerificationError("A signature of a delegating key was included in this kfrag, "
|
||||
"but the key is not provided")
|
||||
|
||||
if delegating_key_missing or receiving_key_missing:
|
||||
return False
|
||||
if self.proof.receiving_key_signed and not bool(receiving_pk):
|
||||
raise VerificationError("A signature of a receiving key was included in this kfrag, "
|
||||
"but the key is not provided")
|
||||
|
||||
delegating_pk = delegating_pk if self.proof.delegating_key_signed else None
|
||||
receiving_pk = receiving_pk if self.proof.receiving_key_signed else None
|
||||
sig = hash_to_cfrag_signature(kfrag_id,
|
||||
commitment,
|
||||
precursor,
|
||||
delegating_pk,
|
||||
receiving_pk)
|
||||
return sig.verify(signing_pk, self.proof.signature_for_proxy)
|
||||
kfrag_message = kfrag_signature_message(kfrag_id=kfrag_id,
|
||||
commitment=commitment,
|
||||
precursor=precursor,
|
||||
maybe_delegating_pk=delegating_pk,
|
||||
maybe_receiving_pk=receiving_pk)
|
||||
if not self.proof.signature_for_proxy.verify(verifying_pk, kfrag_message):
|
||||
raise VerificationError("Failed to verify the kfrag signature")
|
||||
|
||||
return VerifiedKeyFrag(self)
|
||||
|
||||
|
||||
class VerifiedKeyFrag:
|
||||
"""
|
||||
Verified kfrag, good for reencryption.
|
||||
Can be cast to ``bytes``, but cannot be deserialized from bytes directly.
|
||||
It can only be obtained from :py:meth:`KeyFrag.verify`.
|
||||
"""
|
||||
|
||||
def __init__(self, kfrag: KeyFrag):
|
||||
self.kfrag = kfrag
|
||||
|
||||
def __bytes__(self):
|
||||
return bytes(self.kfrag)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.kfrag == other.kfrag
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.__class__, bytes(self)))
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.__class__.__name__}:{bytes(self).hex()[:16]}"
|
||||
|
||||
|
||||
class KeyFragBase:
|
||||
|
@ -238,7 +268,7 @@ class KeyFragBase:
|
|||
def __init__(self,
|
||||
delegating_sk: SecretKey,
|
||||
receiving_pk: PublicKey,
|
||||
signing_sk: SecretKey,
|
||||
signer: Signer,
|
||||
threshold: int,
|
||||
):
|
||||
|
||||
|
@ -273,33 +303,9 @@ class KeyFragBase:
|
|||
delegating_sk.secret_scalar() * d.invert(),
|
||||
*[CurveScalar.random_nonzero() for _ in range(threshold-1)]]
|
||||
|
||||
self.signing_sk = signing_sk
|
||||
self.signer = signer
|
||||
self.precursor = precursor
|
||||
self.dh_point = dh_point
|
||||
self.delegating_pk = delegating_pk
|
||||
self.receiving_pk = receiving_pk
|
||||
self.coefficients = coefficients
|
||||
|
||||
|
||||
def generate_kfrags(delegating_sk: SecretKey,
|
||||
receiving_pk: PublicKey,
|
||||
signing_sk: SecretKey,
|
||||
threshold: int,
|
||||
num_kfrags: int,
|
||||
sign_delegating_key: bool = True,
|
||||
sign_receiving_key: bool = True,
|
||||
) -> List[KeyFrag]:
|
||||
"""
|
||||
Generates ``num_kfrags`` key fragments to pass to proxies for re-encryption.
|
||||
At least ``threshold`` of them will be needed for decryption.
|
||||
If ``sign_delegating_key`` or ``sign_receiving_key`` are ``True``,
|
||||
the corresponding keys will have to be provided to :py:meth:`KeyFrag.verify`.
|
||||
"""
|
||||
|
||||
base = KeyFragBase(delegating_sk, receiving_pk, signing_sk, threshold)
|
||||
|
||||
# Technically we could allow it, but what would be the use of these kfrags?
|
||||
if num_kfrags < threshold:
|
||||
raise ValueError(f"Creating less kfrags ({num_kfrags}) than threshold ({threshold}) makes them useless")
|
||||
|
||||
return [KeyFrag.from_base(base, sign_delegating_key, sign_receiving_key) for _ in range(num_kfrags)]
|
||||
|
|
|
@ -1,20 +1,12 @@
|
|||
import os
|
||||
from typing import TYPE_CHECKING, Tuple
|
||||
from typing import Tuple
|
||||
|
||||
from cryptography.exceptions import InvalidSignature
|
||||
from cryptography.hazmat.primitives.asymmetric import utils
|
||||
from cryptography.hazmat.primitives.asymmetric.ec import ECDSA
|
||||
|
||||
from . import openssl
|
||||
from .curve import CURVE
|
||||
from .curve_scalar import CurveScalar
|
||||
from .curve_point import CurvePoint
|
||||
from .dem import kdf
|
||||
from .hashing import Hash
|
||||
from .serializable import Serializable
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from .hashing import Hash
|
||||
|
||||
|
||||
class SecretKey(Serializable):
|
||||
"""
|
||||
|
@ -45,7 +37,7 @@ class SecretKey(Serializable):
|
|||
return f"{self.__class__.__name__}:..."
|
||||
|
||||
def __hash__(self):
|
||||
raise NotImplementedError("Hashing secret objects is insecure")
|
||||
raise RuntimeError("Hashing secret objects is not secure")
|
||||
|
||||
def secret_scalar(self):
|
||||
return self._scalar_key
|
||||
|
@ -58,66 +50,6 @@ class SecretKey(Serializable):
|
|||
def __bytes__(self) -> bytes:
|
||||
return bytes(self._scalar_key)
|
||||
|
||||
def sign_digest(self, digest: 'Hash') -> 'Signature':
|
||||
|
||||
signature_algorithm = ECDSA(utils.Prehashed(digest._backend_hash_algorithm))
|
||||
message = digest.finalize()
|
||||
|
||||
backend_sk = openssl.bn_to_privkey(CURVE, self._scalar_key._backend_bignum)
|
||||
signature_der_bytes = backend_sk.sign(message, signature_algorithm)
|
||||
r_int, s_int = utils.decode_dss_signature(signature_der_bytes)
|
||||
|
||||
# Normalize s
|
||||
# s is public, so no constant-timeness required here
|
||||
if s_int > (CURVE.order >> 1):
|
||||
s_int = CURVE.order - s_int
|
||||
|
||||
# Already normalized, don't waste time
|
||||
r = CurveScalar.from_int(r_int, check_normalization=False)
|
||||
s = CurveScalar.from_int(s_int, check_normalization=False)
|
||||
|
||||
return Signature(r, s)
|
||||
|
||||
|
||||
class Signature(Serializable):
|
||||
"""
|
||||
Wrapper for ECDSA signatures.
|
||||
"""
|
||||
|
||||
def __init__(self, r: CurveScalar, s: CurveScalar):
|
||||
self.r = r
|
||||
self.s = s
|
||||
|
||||
def __repr__(self):
|
||||
return f"ECDSA Signature: {bytes(self).hex()[:15]}"
|
||||
|
||||
def verify_digest(self, verifying_key: 'PublicKey', digest: 'Hash') -> bool:
|
||||
backend_pk = openssl.point_to_pubkey(CURVE, verifying_key.point()._backend_point)
|
||||
signature_algorithm = ECDSA(utils.Prehashed(digest._backend_hash_algorithm))
|
||||
|
||||
message = digest.finalize()
|
||||
signature_der_bytes = utils.encode_dss_signature(int(self.r), int(self.s))
|
||||
|
||||
# TODO: Raise error instead of returning boolean
|
||||
try:
|
||||
backend_pk.verify(signature=signature_der_bytes,
|
||||
data=message,
|
||||
signature_algorithm=signature_algorithm)
|
||||
except InvalidSignature:
|
||||
return False
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def __take__(cls, data):
|
||||
(r, s), data = cls.__take_types__(data, CurveScalar, CurveScalar)
|
||||
return cls(r, s), data
|
||||
|
||||
def __bytes__(self):
|
||||
return bytes(self.r) + bytes(self.s)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.r == other.r and self.s == other.s
|
||||
|
||||
|
||||
class PublicKey(Serializable):
|
||||
"""
|
||||
|
@ -183,7 +115,6 @@ class SecretKeyFactory(Serializable):
|
|||
tag = b"KEY_DERIVATION/" + label
|
||||
key = kdf(self.__key_seed, self._DERIVED_KEY_SIZE, info=tag)
|
||||
|
||||
from .hashing import Hash
|
||||
digest = Hash(tag)
|
||||
digest.update(key)
|
||||
scalar_key = CurveScalar.from_digest(digest)
|
||||
|
@ -202,4 +133,4 @@ class SecretKeyFactory(Serializable):
|
|||
return f"{self.__class__.__name__}:..."
|
||||
|
||||
def __hash__(self):
|
||||
raise NotImplementedError("Hashing secret objects is insecure")
|
||||
raise RuntimeError("Hashing secret objects is not secure")
|
||||
|
|
|
@ -1,9 +1,19 @@
|
|||
from contextlib import contextmanager
|
||||
from typing import Tuple
|
||||
|
||||
from cryptography.exceptions import InternalError
|
||||
from cryptography.exceptions import InternalError, InvalidSignature
|
||||
from cryptography.hazmat.backends.openssl import backend
|
||||
from cryptography.hazmat.backends.openssl.ec import _EllipticCurvePrivateKey, _EllipticCurvePublicKey
|
||||
from cryptography.hazmat.backends.openssl.ec import (_EllipticCurvePrivateKey,
|
||||
_EllipticCurvePublicKey)
|
||||
from cryptography.hazmat.primitives.asymmetric import utils
|
||||
from cryptography.hazmat.primitives.asymmetric.ec import ECDSA
|
||||
|
||||
|
||||
BACKEND_LIB = backend._lib
|
||||
BACKEND_FFI = backend._ffi
|
||||
|
||||
|
||||
def tmp_bn_ctx():
|
||||
return backend._tmp_bn_ctx()
|
||||
|
||||
|
||||
class Curve:
|
||||
|
@ -15,9 +25,7 @@ class Curve:
|
|||
"""
|
||||
|
||||
_supported_curves = {
|
||||
415: 'secp256r1',
|
||||
714: 'secp256k1',
|
||||
715: 'secp384r1'
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
|
@ -26,8 +34,8 @@ class Curve:
|
|||
Returns the group of a given curve via its OpenSSL nid. This must be freed
|
||||
after each use otherwise it leaks memory.
|
||||
"""
|
||||
group = backend._lib.EC_GROUP_new_by_curve_name(nid)
|
||||
backend.openssl_assert(group != backend._ffi.NULL)
|
||||
group = BACKEND_LIB.EC_GROUP_new_by_curve_name(nid)
|
||||
backend.openssl_assert(group != BACKEND_FFI.NULL)
|
||||
return group
|
||||
|
||||
@staticmethod
|
||||
|
@ -36,8 +44,8 @@ class Curve:
|
|||
Returns the order of a given curve via its OpenSSL EC_GROUP.
|
||||
"""
|
||||
ec_order = _bn_new()
|
||||
with backend._tmp_bn_ctx() as bn_ctx:
|
||||
res = backend._lib.EC_GROUP_get_order(ec_group, ec_order, bn_ctx)
|
||||
with tmp_bn_ctx() as bn_ctx:
|
||||
res = BACKEND_LIB.EC_GROUP_get_order(ec_group, ec_order, bn_ctx)
|
||||
backend.openssl_assert(res == 1)
|
||||
return ec_order
|
||||
|
||||
|
@ -46,9 +54,9 @@ class Curve:
|
|||
"""
|
||||
Returns the generator point of a given curve via its OpenSSL EC_GROUP.
|
||||
"""
|
||||
generator = backend._lib.EC_GROUP_get0_generator(ec_group)
|
||||
backend.openssl_assert(generator != backend._ffi.NULL)
|
||||
generator = backend._ffi.gc(generator, backend._lib.EC_POINT_clear_free)
|
||||
generator = BACKEND_LIB.EC_GROUP_get0_generator(ec_group)
|
||||
backend.openssl_assert(generator != BACKEND_FFI.NULL)
|
||||
generator = BACKEND_FFI.gc(generator, BACKEND_LIB.EC_POINT_clear_free)
|
||||
|
||||
return generator
|
||||
|
||||
|
@ -58,7 +66,7 @@ class Curve:
|
|||
Returns the number of bits needed to represent the order of the finite
|
||||
field upon the curve is based.
|
||||
"""
|
||||
return backend._lib.EC_GROUP_get_degree(ec_group)
|
||||
return BACKEND_LIB.EC_GROUP_get_degree(ec_group)
|
||||
|
||||
def __init__(self, nid: int):
|
||||
"""
|
||||
|
@ -69,8 +77,8 @@ class Curve:
|
|||
|
||||
try:
|
||||
self.name = self._supported_curves[nid]
|
||||
except KeyError:
|
||||
raise NotImplementedError("Curve NID {} is not supported.".format(nid))
|
||||
except KeyError as e:
|
||||
raise NotImplementedError("Curve NID {} is not supported.".format(nid)) from e
|
||||
|
||||
self.nid = nid
|
||||
|
||||
|
@ -120,12 +128,12 @@ def _bn_new():
|
|||
"""
|
||||
Returns a new and initialized OpenSSL BIGNUM.
|
||||
"""
|
||||
new_bn = backend._lib.BN_new()
|
||||
backend.openssl_assert(new_bn != backend._ffi.NULL)
|
||||
new_bn = backend._ffi.gc(new_bn, backend._lib.BN_clear_free)
|
||||
new_bn = BACKEND_LIB.BN_new()
|
||||
backend.openssl_assert(new_bn != BACKEND_FFI.NULL)
|
||||
new_bn = BACKEND_FFI.gc(new_bn, BACKEND_LIB.BN_clear_free)
|
||||
|
||||
# Always use constant time operations.
|
||||
backend._lib.BN_set_flags(new_bn, backend._lib.BN_FLG_CONSTTIME)
|
||||
BACKEND_LIB.BN_set_flags(new_bn, BACKEND_LIB.BN_FLG_CONSTTIME)
|
||||
return new_bn
|
||||
|
||||
|
||||
|
@ -134,11 +142,11 @@ def bn_is_normalized(check_bn, modulus):
|
|||
Returns ``True`` if ``check_bn`` is in ``[0, modulus)``, ``False`` otherwise.
|
||||
"""
|
||||
zero = backend._int_to_bn(0)
|
||||
zero = backend._ffi.gc(zero, backend._lib.BN_clear_free)
|
||||
zero = BACKEND_FFI.gc(zero, BACKEND_LIB.BN_clear_free)
|
||||
|
||||
check_sign = backend._lib.BN_cmp(check_bn, zero)
|
||||
range_check = backend._lib.BN_cmp(check_bn, modulus)
|
||||
return (check_sign == 1 or check_sign == 0) and range_check == -1
|
||||
check_sign = BACKEND_LIB.BN_cmp(check_bn, zero)
|
||||
range_check = BACKEND_LIB.BN_cmp(check_bn, modulus)
|
||||
return check_sign in (0, 1) and range_check == -1
|
||||
|
||||
|
||||
def bn_from_int(py_int: int, check_modulus=None):
|
||||
|
@ -147,12 +155,12 @@ def bn_from_int(py_int: int, check_modulus=None):
|
|||
provided, it will check if the Python integer is within ``[0, modulus)``.
|
||||
"""
|
||||
conv_bn = backend._int_to_bn(py_int)
|
||||
conv_bn = backend._ffi.gc(conv_bn, backend._lib.BN_clear_free)
|
||||
conv_bn = BACKEND_FFI.gc(conv_bn, BACKEND_LIB.BN_clear_free)
|
||||
|
||||
if check_modulus and not bn_is_normalized(conv_bn, check_modulus):
|
||||
raise ValueError(f"The Python integer given ({py_int}) is not under the provided modulus.")
|
||||
|
||||
backend._lib.BN_set_flags(conv_bn, backend._lib.BN_FLG_CONSTTIME)
|
||||
BACKEND_LIB.BN_set_flags(conv_bn, BACKEND_LIB.BN_FLG_CONSTTIME)
|
||||
return conv_bn
|
||||
|
||||
|
||||
|
@ -161,8 +169,8 @@ def bn_from_bytes(bytes_seq: bytes, check_modulus=None, apply_modulus=None):
|
|||
Converts the given byte sequence to an OpenSSL BIGNUM.
|
||||
"""
|
||||
bn = _bn_new()
|
||||
backend._lib.BN_bin2bn(bytes_seq, len(bytes_seq), bn)
|
||||
backend.openssl_assert(bn != backend._ffi.NULL)
|
||||
BACKEND_LIB.BN_bin2bn(bytes_seq, len(bytes_seq), bn)
|
||||
backend.openssl_assert(bn != BACKEND_FFI.NULL)
|
||||
|
||||
if check_modulus and not bn_is_normalized(bn, check_modulus):
|
||||
raise ValueError(f"The integer encoded with given bytes ({repr(bytes_seq)}) "
|
||||
|
@ -170,12 +178,12 @@ def bn_from_bytes(bytes_seq: bytes, check_modulus=None, apply_modulus=None):
|
|||
|
||||
if apply_modulus:
|
||||
bignum =_bn_new()
|
||||
with backend._tmp_bn_ctx() as bn_ctx:
|
||||
res = backend._lib.BN_mod(bignum, bn, apply_modulus, bn_ctx)
|
||||
with tmp_bn_ctx() as bn_ctx:
|
||||
res = BACKEND_LIB.BN_mod(bignum, bn, apply_modulus, bn_ctx)
|
||||
backend.openssl_assert(res == 1)
|
||||
return bignum
|
||||
else:
|
||||
return bn
|
||||
|
||||
return bn
|
||||
|
||||
|
||||
def bn_to_bytes(bn, length: int):
|
||||
|
@ -186,17 +194,17 @@ def bn_to_bytes(bn, length: int):
|
|||
"""
|
||||
|
||||
# Sanity check, CurveScalar ensures it won't happen.
|
||||
bn_num_bytes = backend._lib.BN_num_bytes(bn)
|
||||
bn_num_bytes = BACKEND_LIB.BN_num_bytes(bn)
|
||||
assert bn_num_bytes <= length, f"Input BIGNUM doesn't fit in {length} B"
|
||||
|
||||
bin_ptr = backend._ffi.new("unsigned char []", length)
|
||||
bin_len = backend._lib.BN_bn2bin(bn, bin_ptr)
|
||||
return bytes.rjust(backend._ffi.buffer(bin_ptr, bin_len)[:], length, b'\0')
|
||||
bin_ptr = BACKEND_FFI.new("unsigned char []", length)
|
||||
bin_len = BACKEND_LIB.BN_bn2bin(bn, bin_ptr)
|
||||
return bytes.rjust(BACKEND_FFI.buffer(bin_ptr, bin_len)[:], length, b'\0')
|
||||
|
||||
|
||||
def bn_random_nonzero(modulus):
|
||||
|
||||
one = backend._lib.BN_value_one()
|
||||
one = BACKEND_LIB.BN_value_one()
|
||||
|
||||
# TODO: in most cases, we want this number to be secret.
|
||||
# OpenSSL 1.1.1 has `BN_priv_rand_range()`, but it is not
|
||||
|
@ -205,37 +213,37 @@ def bn_random_nonzero(modulus):
|
|||
|
||||
# Calculate `modulus - 1`
|
||||
modulus_minus_1 = _bn_new()
|
||||
res = backend._lib.BN_sub(modulus_minus_1, modulus, one)
|
||||
res = BACKEND_LIB.BN_sub(modulus_minus_1, modulus, one)
|
||||
backend.openssl_assert(res == 1)
|
||||
|
||||
# Get a random in range `[0, modulus - 1)`
|
||||
new_rand_bn = _bn_new()
|
||||
res = backend._lib.BN_rand_range(new_rand_bn, modulus_minus_1)
|
||||
res = BACKEND_LIB.BN_rand_range(new_rand_bn, modulus_minus_1)
|
||||
backend.openssl_assert(res == 1)
|
||||
|
||||
# Turn it into a random in range `[1, modulus)`
|
||||
op_sum = _bn_new()
|
||||
res = backend._lib.BN_add(op_sum, new_rand_bn, one)
|
||||
res = BACKEND_LIB.BN_add(op_sum, new_rand_bn, one)
|
||||
backend.openssl_assert(res == 1)
|
||||
|
||||
return op_sum
|
||||
|
||||
|
||||
def _bn_size(bn):
|
||||
return backend._lib.BN_num_bytes(bn)
|
||||
return BACKEND_LIB.BN_num_bytes(bn)
|
||||
|
||||
|
||||
def bn_to_int(bn):
|
||||
def bn_to_int(bn) -> int:
|
||||
return backend._bn_to_int(bn)
|
||||
|
||||
|
||||
def bn_cmp(bn1, bn2):
|
||||
# -1 less than, 0 is equal to, 1 is greater than
|
||||
return backend._lib.BN_cmp(bn1, bn2)
|
||||
return BACKEND_LIB.BN_cmp(bn1, bn2)
|
||||
|
||||
|
||||
def bn_one():
|
||||
return backend._lib.BN_value_one()
|
||||
return BACKEND_LIB.BN_value_one()
|
||||
|
||||
|
||||
def bn_is_zero(bn):
|
||||
|
@ -244,47 +252,47 @@ def bn_is_zero(bn):
|
|||
|
||||
|
||||
def bn_invert(bn, modulus):
|
||||
with backend._tmp_bn_ctx() as bn_ctx:
|
||||
inv = backend._lib.BN_mod_inverse(backend._ffi.NULL, bn, modulus, bn_ctx)
|
||||
backend.openssl_assert(inv != backend._ffi.NULL)
|
||||
inv = backend._ffi.gc(inv, backend._lib.BN_clear_free)
|
||||
with tmp_bn_ctx() as bn_ctx:
|
||||
inv = BACKEND_LIB.BN_mod_inverse(BACKEND_FFI.NULL, bn, modulus, bn_ctx)
|
||||
backend.openssl_assert(inv != BACKEND_FFI.NULL)
|
||||
inv = BACKEND_FFI.gc(inv, BACKEND_LIB.BN_clear_free)
|
||||
return inv
|
||||
|
||||
|
||||
def bn_sub(bn1, bn2, modulus):
|
||||
diff = _bn_new()
|
||||
with backend._tmp_bn_ctx() as bn_ctx:
|
||||
res = backend._lib.BN_mod_sub(diff, bn1, bn2, modulus, bn_ctx)
|
||||
with tmp_bn_ctx() as bn_ctx:
|
||||
res = BACKEND_LIB.BN_mod_sub(diff, bn1, bn2, modulus, bn_ctx)
|
||||
backend.openssl_assert(res == 1)
|
||||
return diff
|
||||
|
||||
|
||||
def bn_add(bn1, bn2, modulus):
|
||||
op_sum = _bn_new()
|
||||
with backend._tmp_bn_ctx() as bn_ctx:
|
||||
res = backend._lib.BN_mod_add(op_sum, bn1, bn2, modulus, bn_ctx)
|
||||
with tmp_bn_ctx() as bn_ctx:
|
||||
res = BACKEND_LIB.BN_mod_add(op_sum, bn1, bn2, modulus, bn_ctx)
|
||||
backend.openssl_assert(res == 1)
|
||||
return op_sum
|
||||
|
||||
|
||||
def bn_mul(bn1, bn2, modulus):
|
||||
product = _bn_new()
|
||||
with backend._tmp_bn_ctx() as bn_ctx:
|
||||
res = backend._lib.BN_mod_mul(product, bn1, bn2, modulus, bn_ctx)
|
||||
with tmp_bn_ctx() as bn_ctx:
|
||||
res = BACKEND_LIB.BN_mod_mul(product, bn1, bn2, modulus, bn_ctx)
|
||||
backend.openssl_assert(res == 1)
|
||||
return product
|
||||
|
||||
|
||||
def bn_to_privkey(curve: Curve, bn):
|
||||
|
||||
ec_key = backend._lib.EC_KEY_new()
|
||||
backend.openssl_assert(ec_key != backend._ffi.NULL)
|
||||
ec_key = backend._ffi.gc(ec_key, backend._lib.EC_KEY_free)
|
||||
ec_key = BACKEND_LIB.EC_KEY_new()
|
||||
backend.openssl_assert(ec_key != BACKEND_FFI.NULL)
|
||||
ec_key = BACKEND_FFI.gc(ec_key, BACKEND_LIB.EC_KEY_free)
|
||||
|
||||
set_group_result = backend._lib.EC_KEY_set_group(ec_key, curve.ec_group)
|
||||
set_group_result = BACKEND_LIB.EC_KEY_set_group(ec_key, curve.ec_group)
|
||||
backend.openssl_assert(set_group_result == 1)
|
||||
|
||||
set_privkey_result = backend._lib.EC_KEY_set_private_key(ec_key, bn)
|
||||
set_privkey_result = BACKEND_LIB.EC_KEY_set_private_key(ec_key, bn)
|
||||
backend.openssl_assert(set_privkey_result == 1)
|
||||
|
||||
evp_pkey = backend._ec_cdata_to_evp_pkey(ec_key)
|
||||
|
@ -301,30 +309,13 @@ def _point_new(ec_group):
|
|||
Returns a new and initialized OpenSSL EC_POINT given the group of a curve.
|
||||
If __curve_nid is provided, it retrieves the group from the curve provided.
|
||||
"""
|
||||
new_point = backend._lib.EC_POINT_new(ec_group)
|
||||
backend.openssl_assert(new_point != backend._ffi.NULL)
|
||||
new_point = backend._ffi.gc(new_point, backend._lib.EC_POINT_clear_free)
|
||||
new_point = BACKEND_LIB.EC_POINT_new(ec_group)
|
||||
backend.openssl_assert(new_point != BACKEND_FFI.NULL)
|
||||
new_point = BACKEND_FFI.gc(new_point, BACKEND_LIB.EC_POINT_clear_free)
|
||||
|
||||
return new_point
|
||||
|
||||
|
||||
def point_from_affine_coords(curve: Curve, affine_x: int, affine_y: int):
|
||||
"""
|
||||
Returns an EC_POINT given the group of a curve and the affine coordinates
|
||||
provided.
|
||||
"""
|
||||
bn_affine_x = bn_from_int(affine_x)
|
||||
bn_affine_y = bn_from_int(affine_y)
|
||||
|
||||
new_point = _point_new(curve.ec_group)
|
||||
with backend._tmp_bn_ctx() as bn_ctx:
|
||||
res = backend._lib.EC_POINT_set_affine_coordinates_GFp(
|
||||
curve.ec_group, new_point, bn_affine_x, bn_affine_y, bn_ctx
|
||||
)
|
||||
backend.openssl_assert(res == 1)
|
||||
return new_point
|
||||
|
||||
|
||||
def point_to_affine_coords(curve: Curve, point) -> Tuple[int, int]:
|
||||
"""
|
||||
Returns the affine coordinates of a given point on the provided ec_group.
|
||||
|
@ -332,11 +323,14 @@ def point_to_affine_coords(curve: Curve, point) -> Tuple[int, int]:
|
|||
affine_x = _bn_new()
|
||||
affine_y = _bn_new()
|
||||
|
||||
with backend._tmp_bn_ctx() as bn_ctx:
|
||||
res = backend._lib.EC_POINT_get_affine_coordinates_GFp(
|
||||
curve.ec_group, point, affine_x, affine_y, bn_ctx
|
||||
)
|
||||
backend.openssl_assert(res == 1)
|
||||
try:
|
||||
with tmp_bn_ctx() as bn_ctx:
|
||||
res = BACKEND_LIB.EC_POINT_get_affine_coordinates_GFp(
|
||||
curve.ec_group, point, affine_x, affine_y, bn_ctx
|
||||
)
|
||||
backend.openssl_assert(res == 1)
|
||||
except InternalError as e:
|
||||
raise ValueError("Cannot get affine coordinates of an identity point")
|
||||
|
||||
return bn_to_int(affine_x), bn_to_int(affine_y)
|
||||
|
||||
|
@ -352,8 +346,8 @@ class ErrorInvalidPointEncoding(Exception):
|
|||
def point_from_bytes(curve: Curve, data):
|
||||
point = _point_new(curve.ec_group)
|
||||
try:
|
||||
with backend._tmp_bn_ctx() as bn_ctx:
|
||||
res = backend._lib.EC_POINT_oct2point(curve.ec_group, point, data, len(data), bn_ctx);
|
||||
with tmp_bn_ctx() as bn_ctx:
|
||||
res = BACKEND_LIB.EC_POINT_oct2point(curve.ec_group, point, data, len(data), bn_ctx)
|
||||
backend.openssl_assert(res == 1)
|
||||
except InternalError as e:
|
||||
# We want to catch specific InternalExceptions.
|
||||
|
@ -361,35 +355,35 @@ def point_from_bytes(curve: Curve, data):
|
|||
# There is also EC_R_POINT_IS_NOT_ON_CURVE (code 107),
|
||||
# but somehow it is never triggered during deserialization.
|
||||
if e.err_code[0].reason == 110: # EC_R_INVALID_COMPRESSED_POINT
|
||||
raise ErrorInvalidCompressedPoint
|
||||
elif e.err_code[0].reason == 102: # EC_R_INVALID_ENCODING
|
||||
raise ErrorInvalidPointEncoding
|
||||
else:
|
||||
# Any other exception, we raise it.
|
||||
# (although at the moment I'm not sure what should one do to cause it)
|
||||
raise e # pragma: no cover
|
||||
raise ErrorInvalidCompressedPoint from e
|
||||
if e.err_code[0].reason == 102: # EC_R_INVALID_ENCODING
|
||||
raise ErrorInvalidPointEncoding from e
|
||||
|
||||
# Any other exception, we raise it.
|
||||
# (although at the moment I'm not sure what should one do to cause it)
|
||||
raise # pragma: no cover
|
||||
return point
|
||||
|
||||
|
||||
def point_to_bytes_compressed(curve: Curve, point):
|
||||
point_conversion_form = backend._lib.POINT_CONVERSION_COMPRESSED
|
||||
point_conversion_form = BACKEND_LIB.POINT_CONVERSION_COMPRESSED
|
||||
|
||||
size = curve.field_element_size + 1 # compressed point size
|
||||
|
||||
bin_ptr = backend._ffi.new("unsigned char[]", size)
|
||||
with backend._tmp_bn_ctx() as bn_ctx:
|
||||
bin_len = backend._lib.EC_POINT_point2oct(
|
||||
bin_ptr = BACKEND_FFI.new("unsigned char[]", size)
|
||||
with tmp_bn_ctx() as bn_ctx:
|
||||
bin_len = BACKEND_LIB.EC_POINT_point2oct(
|
||||
curve.ec_group, point, point_conversion_form,
|
||||
bin_ptr, size, bn_ctx
|
||||
)
|
||||
backend.openssl_assert(bin_len != 0)
|
||||
|
||||
return bytes(backend._ffi.buffer(bin_ptr, bin_len)[:])
|
||||
return bytes(BACKEND_FFI.buffer(bin_ptr, bin_len)[:])
|
||||
|
||||
|
||||
def point_eq(curve: Curve, point1, point2):
|
||||
with backend._tmp_bn_ctx() as bn_ctx:
|
||||
is_equal = backend._lib.EC_POINT_cmp(curve.ec_group, point1, point2, bn_ctx)
|
||||
with tmp_bn_ctx() as bn_ctx:
|
||||
is_equal = BACKEND_LIB.EC_POINT_cmp(curve.ec_group, point1, point2, bn_ctx)
|
||||
backend.openssl_assert(is_equal != -1)
|
||||
|
||||
# 1 is not-equal, 0 is equal, -1 is error
|
||||
|
@ -398,27 +392,27 @@ def point_eq(curve: Curve, point1, point2):
|
|||
|
||||
def point_mul_bn(curve: Curve, point, bn):
|
||||
prod = _point_new(curve.ec_group)
|
||||
with backend._tmp_bn_ctx() as bn_ctx:
|
||||
res = backend._lib.EC_POINT_mul(curve.ec_group, prod, backend._ffi.NULL, point, bn, bn_ctx)
|
||||
with tmp_bn_ctx() as bn_ctx:
|
||||
res = BACKEND_LIB.EC_POINT_mul(curve.ec_group, prod, BACKEND_FFI.NULL, point, bn, bn_ctx)
|
||||
backend.openssl_assert(res == 1)
|
||||
return prod
|
||||
|
||||
|
||||
def point_add(curve: Curve, point1, point2):
|
||||
op_sum = _point_new(curve.ec_group)
|
||||
with backend._tmp_bn_ctx() as bn_ctx:
|
||||
res = backend._lib.EC_POINT_add(curve.ec_group, op_sum, point1, point2, bn_ctx)
|
||||
with tmp_bn_ctx() as bn_ctx:
|
||||
res = BACKEND_LIB.EC_POINT_add(curve.ec_group, op_sum, point1, point2, bn_ctx)
|
||||
backend.openssl_assert(res == 1)
|
||||
return op_sum
|
||||
|
||||
|
||||
def point_neg(curve: Curve, point):
|
||||
inv = backend._lib.EC_POINT_dup(point, curve.ec_group)
|
||||
backend.openssl_assert(inv != backend._ffi.NULL)
|
||||
inv = backend._ffi.gc(inv, backend._lib.EC_POINT_clear_free)
|
||||
inv = BACKEND_LIB.EC_POINT_dup(point, curve.ec_group)
|
||||
backend.openssl_assert(inv != BACKEND_FFI.NULL)
|
||||
inv = BACKEND_FFI.gc(inv, BACKEND_LIB.EC_POINT_clear_free)
|
||||
|
||||
with backend._tmp_bn_ctx() as bn_ctx:
|
||||
res = backend._lib.EC_POINT_invert(curve.ec_group, inv, bn_ctx)
|
||||
with tmp_bn_ctx() as bn_ctx:
|
||||
res = BACKEND_LIB.EC_POINT_invert(curve.ec_group, inv, bn_ctx)
|
||||
backend.openssl_assert(res == 1)
|
||||
|
||||
return inv
|
||||
|
@ -426,15 +420,45 @@ def point_neg(curve: Curve, point):
|
|||
|
||||
def point_to_pubkey(curve: Curve, point):
|
||||
|
||||
ec_key = backend._lib.EC_KEY_new()
|
||||
backend.openssl_assert(ec_key != backend._ffi.NULL)
|
||||
ec_key = backend._ffi.gc(ec_key, backend._lib.EC_KEY_free)
|
||||
ec_key = BACKEND_LIB.EC_KEY_new()
|
||||
backend.openssl_assert(ec_key != BACKEND_FFI.NULL)
|
||||
ec_key = BACKEND_FFI.gc(ec_key, BACKEND_LIB.EC_KEY_free)
|
||||
|
||||
set_group_result = backend._lib.EC_KEY_set_group(ec_key, curve.ec_group)
|
||||
set_group_result = BACKEND_LIB.EC_KEY_set_group(ec_key, curve.ec_group)
|
||||
backend.openssl_assert(set_group_result == 1)
|
||||
|
||||
set_pubkey_result = backend._lib.EC_KEY_set_public_key(ec_key, point)
|
||||
set_pubkey_result = BACKEND_LIB.EC_KEY_set_public_key(ec_key, point)
|
||||
backend.openssl_assert(set_pubkey_result == 1)
|
||||
|
||||
evp_pkey = backend._ec_cdata_to_evp_pkey(ec_key)
|
||||
return _EllipticCurvePublicKey(backend, ec_key, evp_pkey)
|
||||
|
||||
|
||||
#
|
||||
# Signing
|
||||
#
|
||||
|
||||
def ecdsa_sign(curve: Curve,
|
||||
secret_bn,
|
||||
prehashed_message: bytes,
|
||||
hash_algorithm
|
||||
) -> Tuple[int, int]:
|
||||
signature_algorithm = ECDSA(utils.Prehashed(hash_algorithm))
|
||||
private_key = bn_to_privkey(curve, secret_bn)
|
||||
signature_der_bytes = private_key.sign(prehashed_message, signature_algorithm)
|
||||
r_int, s_int = utils.decode_dss_signature(signature_der_bytes)
|
||||
return r_int, s_int
|
||||
|
||||
def ecdsa_verify(curve: Curve, sig_r: int, sig_s: int, public_point,
|
||||
prehashed_message: bytes, hash_algorithm) -> bool:
|
||||
signature_algorithm = ECDSA(utils.Prehashed(hash_algorithm))
|
||||
public_key = point_to_pubkey(curve, public_point)
|
||||
signature_der_bytes = utils.encode_dss_signature(sig_r, sig_s)
|
||||
|
||||
try:
|
||||
public_key.verify(signature=signature_der_bytes,
|
||||
data=prehashed_message,
|
||||
signature_algorithm=signature_algorithm)
|
||||
except InvalidSignature:
|
||||
return False
|
||||
return True
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
from typing import Tuple, Optional, Sequence
|
||||
from typing import Tuple, Optional, Sequence, List
|
||||
|
||||
from .capsule import Capsule
|
||||
from .capsule_frag import CapsuleFrag
|
||||
from .capsule_frag import VerifiedCapsuleFrag, CapsuleFrag
|
||||
from .dem import DEM
|
||||
from .keys import PublicKey, SecretKey
|
||||
from .key_frag import KeyFrag
|
||||
from .key_frag import VerifiedKeyFrag, KeyFrag, KeyFragBase
|
||||
from .signing import Signer
|
||||
|
||||
|
||||
def encrypt(pk: PublicKey, plaintext: bytes) -> Tuple[Capsule, bytes]:
|
||||
|
@ -30,7 +31,39 @@ def decrypt_original(sk: SecretKey, capsule: Capsule, ciphertext: bytes) -> byte
|
|||
return dem.decrypt(ciphertext, authenticated_data=bytes(capsule))
|
||||
|
||||
|
||||
def reencrypt(capsule: Capsule, kfrag: KeyFrag, metadata: Optional[bytes] = None) -> CapsuleFrag:
|
||||
def generate_kfrags(delegating_sk: SecretKey,
|
||||
receiving_pk: PublicKey,
|
||||
signer: Signer,
|
||||
threshold: int,
|
||||
num_kfrags: int,
|
||||
sign_delegating_key: bool = True,
|
||||
sign_receiving_key: bool = True,
|
||||
) -> List[VerifiedKeyFrag]:
|
||||
"""
|
||||
Generates ``num_kfrags`` key fragments to pass to proxies for re-encryption.
|
||||
At least ``threshold`` of them will be needed for decryption.
|
||||
If ``sign_delegating_key`` or ``sign_receiving_key`` are ``True``,
|
||||
the corresponding keys will have to be provided to :py:meth:`KeyFrag.verify`.
|
||||
"""
|
||||
|
||||
base = KeyFragBase(delegating_sk, receiving_pk, signer, threshold)
|
||||
|
||||
# Technically we could allow it, but what would be the use of these kfrags?
|
||||
if num_kfrags < threshold:
|
||||
raise ValueError(f"Creating less kfrags ({num_kfrags}) "
|
||||
f"than threshold ({threshold}) makes them useless")
|
||||
|
||||
kfrags = [KeyFrag.from_base(base, sign_delegating_key, sign_receiving_key)
|
||||
for _ in range(num_kfrags)]
|
||||
|
||||
# Make them verified - we know they're good.
|
||||
return [VerifiedKeyFrag(kfrag) for kfrag in kfrags]
|
||||
|
||||
|
||||
def reencrypt(capsule: Capsule,
|
||||
kfrag: VerifiedKeyFrag,
|
||||
metadata: Optional[bytes] = None
|
||||
) -> VerifiedCapsuleFrag:
|
||||
"""
|
||||
Creates a capsule fragment using the given key fragment.
|
||||
Capsule fragments can later be used to decrypt the ciphertext.
|
||||
|
@ -38,20 +71,30 @@ def reencrypt(capsule: Capsule, kfrag: KeyFrag, metadata: Optional[bytes] = None
|
|||
If `metadata` is provided, it will have to be used for verification in
|
||||
:py:meth:`CapsuleFrag.verify`.
|
||||
"""
|
||||
return CapsuleFrag.reencrypted(capsule, kfrag, metadata)
|
||||
# We could let duck typing do its work,
|
||||
# but it's better to make a common error more understandable.
|
||||
if isinstance(kfrag, KeyFrag) and not isinstance(kfrag, VerifiedKeyFrag):
|
||||
raise TypeError("KeyFrag must be verified before reencryption")
|
||||
|
||||
return VerifiedCapsuleFrag(CapsuleFrag.reencrypted(capsule, kfrag.kfrag, metadata))
|
||||
|
||||
|
||||
def decrypt_reencrypted(decrypting_sk: SecretKey,
|
||||
delegating_pk: PublicKey,
|
||||
capsule: Capsule,
|
||||
cfrags: Sequence[CapsuleFrag],
|
||||
verified_cfrags: Sequence[VerifiedCapsuleFrag],
|
||||
ciphertext: bytes,
|
||||
) -> bytes:
|
||||
"""
|
||||
Decrypts the ciphertext using the original capsule and the reencrypted capsule fragments.
|
||||
"""
|
||||
# We could let duck typing do its work,
|
||||
# but it's better to make a common error more understandable.
|
||||
for cfrag in verified_cfrags:
|
||||
if isinstance(cfrag, CapsuleFrag) and not isinstance(cfrag, VerifiedCapsuleFrag):
|
||||
raise TypeError("All CapsuleFrags must be verified before decryption")
|
||||
|
||||
cfrags = [vcfrag.cfrag for vcfrag in verified_cfrags]
|
||||
key_seed = capsule.open_reencrypted(decrypting_sk, delegating_pk, cfrags)
|
||||
dem = DEM(bytes(key_seed))
|
||||
return dem.decrypt(ciphertext, authenticated_data=bytes(capsule))
|
||||
|
||||
|
|
|
@ -25,7 +25,8 @@ class Serializable(ABC):
|
|||
Takes ``size`` bytes from the bytestring and returns them along with the remainder.
|
||||
"""
|
||||
if len(data) < size:
|
||||
raise ValueError(f"{cls} cannot take {size} bytes from a bytestring of size {len(data)}")
|
||||
raise ValueError(f"{cls} cannot take {size} bytes "
|
||||
f"from a bytestring of size {len(data)}")
|
||||
return data[:size], data[size:]
|
||||
|
||||
@classmethod
|
||||
|
@ -70,5 +71,6 @@ def take_bool(data: bytes) -> Tuple[bool, bytes]:
|
|||
elif bool_bytes == b'\x00':
|
||||
b = False
|
||||
else:
|
||||
raise ValueError(f"Incorrectly serialized boolean; expected b'\\x00' or b'\\x01', got {repr(bool_bytes)}")
|
||||
raise ValueError("Incorrectly serialized boolean; "
|
||||
f"expected b'\\x00' or b'\\x01', got {repr(bool_bytes)}")
|
||||
return b, data
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
from . import openssl
|
||||
from .curve import CURVE
|
||||
from .curve_scalar import CurveScalar
|
||||
from .hashing import Hash
|
||||
from .keys import SecretKey, PublicKey
|
||||
from .serializable import Serializable
|
||||
|
||||
|
||||
def digest_for_signing(message: bytes) -> Hash:
|
||||
# Not using a DST here to make life easier for third-party verifiers
|
||||
digest = Hash()
|
||||
digest.update(message)
|
||||
return digest
|
||||
|
||||
|
||||
class Signer:
|
||||
"""
|
||||
An object possessing the capability to create signatures.
|
||||
For safety reasons serialization is prohibited.
|
||||
"""
|
||||
|
||||
def __init__(self, secret_key: SecretKey):
|
||||
self.__secret_key = secret_key
|
||||
|
||||
def sign_digest(self, digest: 'Hash') -> 'Signature':
|
||||
|
||||
secret_bn = self.__secret_key.secret_scalar()._backend_bignum
|
||||
r_int, s_int = openssl.ecdsa_sign(curve=CURVE,
|
||||
secret_bn=secret_bn,
|
||||
prehashed_message=digest.finalize(),
|
||||
hash_algorithm=digest._backend_hash_algorithm)
|
||||
|
||||
# Normalize s. This is a non-malleability measure, which OpenSSL doesn't do.
|
||||
# See Bitcoin's BIP-0062 for more details:
|
||||
# https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#Low_S_values_in_signatures
|
||||
|
||||
# s is public, so no constant-timeness required here
|
||||
if s_int > (CURVE.order >> 1):
|
||||
s_int = CURVE.order - s_int
|
||||
|
||||
# Already normalized, don't waste time
|
||||
r = CurveScalar.from_int(r_int, check_normalization=False)
|
||||
s = CurveScalar.from_int(s_int, check_normalization=False)
|
||||
|
||||
return Signature(r, s)
|
||||
|
||||
def sign(self, message: bytes) -> 'Signature':
|
||||
"""
|
||||
Hashes and signs the message.
|
||||
"""
|
||||
return self.sign_digest(digest_for_signing(message))
|
||||
|
||||
def verifying_key(self) -> PublicKey:
|
||||
"""
|
||||
Returns the public verification key corresponding to the secret key used for signing.
|
||||
"""
|
||||
return PublicKey.from_secret_key(self.__secret_key)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.__class__.__name__}:..."
|
||||
|
||||
def __hash__(self):
|
||||
raise RuntimeError(f"{self.__class__.__name__} objects do not support hashing")
|
||||
|
||||
def __bytes__(self):
|
||||
raise RuntimeError(f"{self.__class__.__name__} objects do not support serialization")
|
||||
|
||||
|
||||
class Signature(Serializable):
|
||||
"""
|
||||
Wrapper for ECDSA signatures.
|
||||
"""
|
||||
|
||||
def __init__(self, r: CurveScalar, s: CurveScalar):
|
||||
self.r = r
|
||||
self.s = s
|
||||
|
||||
def verify_digest(self, verifying_key: 'PublicKey', digest: 'Hash') -> bool:
|
||||
return openssl.ecdsa_verify(curve=CURVE,
|
||||
sig_r=int(self.r),
|
||||
sig_s=int(self.s),
|
||||
public_point=verifying_key.point()._backend_point,
|
||||
prehashed_message=digest.finalize(),
|
||||
hash_algorithm=digest._backend_hash_algorithm)
|
||||
|
||||
def verify(self, verifying_key: PublicKey, message: bytes) -> bool:
|
||||
"""
|
||||
Returns ``True`` if the ``message`` was signed by someone possessing the secret counterpart
|
||||
to ``verifying_key``.
|
||||
"""
|
||||
digest = digest_for_signing(message)
|
||||
return self.verify_digest(verifying_key, digest)
|
||||
|
||||
@classmethod
|
||||
def __take__(cls, data):
|
||||
(r, s), data = cls.__take_types__(data, CurveScalar, CurveScalar)
|
||||
return cls(r, s), data
|
||||
|
||||
def __bytes__(self):
|
||||
return bytes(self.r) + bytes(self.s)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.__class__.__name__}:{bytes(self).hex()[:16]}"
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.r == other.r and self.s == other.s
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash((self.__class__, bytes(self)))
|
|
@ -1,7 +1,9 @@
|
|||
import json
|
||||
import os
|
||||
|
||||
from umbral import SecretKey, PublicKey, encrypt, generate_kfrags, reencrypt
|
||||
from umbral import (
|
||||
SecretKey, PublicKey, Signer, KeyFrag, CapsuleFrag,
|
||||
encrypt, generate_kfrags, reencrypt)
|
||||
from umbral.curve_scalar import CurveScalar
|
||||
from umbral.curve_point import CurvePoint
|
||||
from umbral.hashing import Hash, unsafe_hash_to_point
|
||||
|
@ -15,9 +17,7 @@ from umbral.dem import DEM, kdf
|
|||
def hexlify(data):
|
||||
if isinstance(data, int):
|
||||
return hex(data)[2:]
|
||||
try:
|
||||
return data.to_bytes().hex()
|
||||
except AttributeError:
|
||||
else:
|
||||
return bytes(data).hex()
|
||||
|
||||
|
||||
|
@ -50,7 +50,7 @@ receiving_pk = PublicKey.from_secret_key(receiving_sk)
|
|||
|
||||
kfrags = generate_kfrags(delegating_sk=delegating_sk,
|
||||
receiving_pk=receiving_pk,
|
||||
signing_sk=signing_sk,
|
||||
signer=Signer(signing_sk),
|
||||
threshold=6,
|
||||
num_kfrags=10,
|
||||
)
|
||||
|
@ -59,7 +59,7 @@ plain_data = b'peace at dawn'
|
|||
|
||||
capsule, ciphertext = encrypt(delegating_pk, plain_data)
|
||||
|
||||
cfrag = reencrypt(capsule, kfrags[0])
|
||||
cfrag = CapsuleFrag.from_bytes(bytes(reencrypt(capsule, kfrags[0])))
|
||||
points = [capsule.point_e, cfrag.point_e1, cfrag.proof.point_e2,
|
||||
capsule.point_v, cfrag.point_v1, cfrag.proof.point_v2,
|
||||
cfrag.proof.kfrag_commitment, cfrag.proof.kfrag_pok]
|
||||
|
@ -207,7 +207,8 @@ create_test_vector_file(vector_suite, 'vectors_unsafe_hash_to_point.json', gener
|
|||
|
||||
vectors = list()
|
||||
for kfrag in kfrags:
|
||||
assert kfrag.verify(verifying_pk, delegating_pk, receiving_pk)
|
||||
kfrag = KeyFrag.from_bytes(bytes(kfrag))
|
||||
kfrag.verify(verifying_pk, delegating_pk, receiving_pk)
|
||||
|
||||
json_input = {'kfrag': hexlify(kfrag)}
|
||||
|
||||
|
|
|
@ -2,51 +2,51 @@
|
|||
"name": "Test vectors for CFrags",
|
||||
"description": "This is a collection of CFrags, originated from the enclosed Capsule, under the enclosed delegating, verifying and receiving keys. Each CFrag must deserialize correctly and can be replicated with a call to `reencrypt(kfrag, capsule, , b'kfrag_metadata')`",
|
||||
"params": "default",
|
||||
"capsule": "02a03893438c0502dd13818f65c039b2ef4fce33bfed150c6ad166554b4e8a51c2028da9ebf8cc0966bc010152fd3917a8f12dfff0af3b06e34e17f300d622893159367ce07602310c78fc65a8b6115d75f65d362abdf2fd799bebc55aa0cda44dbb",
|
||||
"capsule": "02558f1de19a58e73a94e8fbbc6d3b1de2d312d90746ea74cb29f046943bf5787102906780e9484aec2102a01a157f10ced5aec952cd00631d94d5ea2edfa9b6808361b109353b0827b7e4013ab92a70eb3337a37f6fe34b3ccb058592caa246c974",
|
||||
"metadata": "6b667261675f6d65746164617461",
|
||||
"verifying_pk": "03f24761ac8b02de08ad1622d023f669d6214c3bab81a33087ed3ec5505e4d43db",
|
||||
"delegating_pk": "03a73623a2e72fd52b2d313214c7495580c14fe6cd8de7ad0d63bbfbfd6fb6bd4d",
|
||||
"receiving_pk": "02952a1903b9c929f0d93d935b34b272ea25a84833a04e22d887f27bc3bf0cc409",
|
||||
"verifying_pk": "030b95b3f249297824b32d3391392d62a9aff32e8698fa78c7e8ce4a9d17071f56",
|
||||
"delegating_pk": "02d67029bb92522059225d190038230c23466e28d132d48f714f9098168a562b8a",
|
||||
"receiving_pk": "03b0d0243e8954b408047eee3b09b5ed132ccc25ec70e99fc74b6e9f54e5ecf9c7",
|
||||
"vectors": [
|
||||
{
|
||||
"kfrag": "3f3453856117dedb3d7518d0435c04b10734700c8aca48fa5a8b85eded515cdffefbefddcd3cb728dcc6d05061b5e201aa1cef55ce89e94c34b6887b307d5ab2025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb7490374d2e59ea274c8011f6bf26ca8fe8eb8e7837cafed8547485e3fde6ffe0368e98d26b0d7e12095941daffae8ca429147d9686dc3285ea182c0d7b15db41c7afd3fae3c88100707ef28b53d7cf93961dc509864eb319f0cce274544306c96099b5792af0b820bf758f5c8f2a69cfc1e0a5f91fab96ab82c10c7740602f90efdd315ff5dbd07323526ca1c9a93132b4d008fdf1796a55b92e2fe75c544652256c80101",
|
||||
"cfrag": "02ecbc4dc0aed60efa211c7bf0e238593d292a042373b891928bcee459151c2f440281171b7e330ebd097575dadb210e8a405bc162e293881457a301da03f7571c7a3f3453856117dedb3d7518d0435c04b10734700c8aca48fa5a8b85eded515cdf025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb74902889960dbc86c87e5a1275f2c1df31e43ed0b3e4616126845a7394b27a83f6d1e03f0b7c60a76c7c9f590c9ac2d1f0ebf6aecaa9d371e2dcd04e19caa134e9c1b530374d2e59ea274c8011f6bf26ca8fe8eb8e7837cafed8547485e3fde6ffe0368e902660d6c64d749050f027983ebd4631838373a47c887537bea95aa139d53bfe38ea532a6b7464b0b5f45522c495a2b8a772b98c4950aa2bb830f6602e7636a1bd95792af0b820bf758f5c8f2a69cfc1e0a5f91fab96ab82c10c7740602f90efdd315ff5dbd07323526ca1c9a93132b4d008fdf1796a55b92e2fe75c544652256c8"
|
||||
"kfrag": "2565903141941fecb01fb92dfbdd66a0a1d4eb94d3226beb2f7adcbb8282ffd0b7934320225868d8f9ace7784fd3ae0c20a09c5a2b698fae0554d71b1f016670036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b026cb94f302809d19aacc81da19f2156db9c610498310b930d7787d8a2366dadd3d977c6befcff3088016d5d9050f4932cb4a9ce483dd7cf27e1f157f8d23f598248d5027a8961a09c874c82a8c479fbf074675790edff37e6927a7d4ea269e600685dc9469c87e6d9d469656b2f40b33e6d6813ec3519fc065a4ffc0eeb8abd324c1914451341cdb7abd7c5aa01adade220b2894be5a33caa9ee7d3b4637bdccf0101",
|
||||
"cfrag": "025e6a08eb9376adfea3a92e05fea213c493fe051461fdf5639a7108e8687eeacf03fcfdb46bf83a68e0d674e7d5b7c0365c8fa05dd418f2ba1a4aea2abcbcd12a192565903141941fecb01fb92dfbdd66a0a1d4eb94d3226beb2f7adcbb8282ffd0036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b02c6348049682bd1e8fc6d4fa0b60a44a50944d497fffc63a4a1c15d7a6bf707e103e2966028c41d81f1bbae136279db8edca069a26183fec4bd12f253ae92d03044026cb94f302809d19aacc81da19f2156db9c610498310b930d7787d8a2366dadd30360288316249f090306991e6a604d8f0da56ebe3275abf4353f223391c95ad06db8c00bc92cef528117fbe10f7e70310aca5f0223a5d22c6ae36e6d26a116f0df685dc9469c87e6d9d469656b2f40b33e6d6813ec3519fc065a4ffc0eeb8abd324c1914451341cdb7abd7c5aa01adade220b2894be5a33caa9ee7d3b4637bdccf"
|
||||
},
|
||||
{
|
||||
"kfrag": "d15ac028be9938b5e2d7a9fb9957b416db538a11d141d320a5f656ab4e3cb0cab3a2ddd2672f3514e7da2f29cbe3815c83b6d704e09d595a68fdd5aeff52ef8a025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb749033d6984555d41614a2ba08c2182e27a7105cb60ed414c9732a156c3e44d196dd3507335e3781d6c9a4543e3ae81a4c7538cf280292c9c0d92e4f513e4e073721f2f72a1ea0e69912e21754e32edf9cefd3a96183f5501266bedb301f291709ffb25ed5213660db4c8bfc086e794650455bfde1251f92e1fe49f1feb016ad44fe859b342964db14dddfa6a33eba53021149d8663d306850b8907f9dabf4a5d3ecd0101",
|
||||
"cfrag": "03a98cc0d807a4f2b6183dfb9b7ff589f376183b33f88ae07a50323edaac946d9b02fc04f97b7afa5c8664082e4433a24184d54724e9e18afd44922bd052bea87e49d15ac028be9938b5e2d7a9fb9957b416db538a11d141d320a5f656ab4e3cb0ca025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb74903bf5c856a6b918df7a70a10db9854d43009ee517e7fc4403185c99eb05f42638c0213c86d5b3f3816a4807bf797731b8b23ef2563e6698e9380a0ee4044755504a9033d6984555d41614a2ba08c2182e27a7105cb60ed414c9732a156c3e44d196dd303de157a0d01a46d89e57d5586bee352b17bb123ea52dea60ef283456fa50cb5a98eca7141ac4bd117511c10922216c69e548c5005e49571087fefb69d50cecc8225ed5213660db4c8bfc086e794650455bfde1251f92e1fe49f1feb016ad44fe859b342964db14dddfa6a33eba53021149d8663d306850b8907f9dabf4a5d3ecd"
|
||||
"kfrag": "ae85e679cf44b1877ff36e48c4965144724f17cc7605f53e50007aabbc2c7ab3871d04e6b5666b81a99ba0c6a70ba8675f2122a39eaec04a62c8496d5149ac9d036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b02e3e7722bffcb6674987b0089f6b8ac0d6cb220d9661edb5ed9dca5fcd33d5bdb1e41b92c9a8e4346b2dd1072389e4ce36a6230eecb59b7e0e9d84f35bf14f0f23014a1263e17d07a94c5d9c248c692686c745df3c5d11566b9ca17ec62e59a5265749ef2701a58483bd106be985c3e4a03750e3c0c21424cf7f59682224c4f6e29c242904ade5ac377974eaa662b6ed6eed13fd30509b9cb332b4fa89043a2a70101",
|
||||
"cfrag": "039715d1c5678c3fb28900a95332eb37beedeffc8cb4862cd11248bcf6ee0c316002fe9dd2d4e6afc607a0ddcfba92ac81b008feb182b516898659a3fc9ec53dae4aae85e679cf44b1877ff36e48c4965144724f17cc7605f53e50007aabbc2c7ab3036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b02a745ff6a18340f1c7657c03e5ea3523971604f71ecaae1183a7b88cde1780c4003d8b1d2e220512be9f375c518e4e73ff73f0e49d3b12b328ccd2706ad59dd6e7702e3e7722bffcb6674987b0089f6b8ac0d6cb220d9661edb5ed9dca5fcd33d5bdb036e2625fb8bd22e84f82ffa8009e8366b141be7b99a0fc74cfed82558d98b3c1183b0dfa5571608f200d7a1c546677a8186535306a210eec6add04429eeb81b3f65749ef2701a58483bd106be985c3e4a03750e3c0c21424cf7f59682224c4f6e29c242904ade5ac377974eaa662b6ed6eed13fd30509b9cb332b4fa89043a2a7"
|
||||
},
|
||||
{
|
||||
"kfrag": "f780e25b78581e70d28f102264e1f04b482eb9ecd45c188f2f9cd90026627f904b903c6da7529805e1d91fbaebc384588083e2c5f235c31e7f768b8d0df43513025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb749032f4d57c068c255281703ba6d449345e2f6240a4b8b3047209ff2aca5edec0ad2394020e796b7b9f9130c0ab02b4c8151d050f38f3d0ff5f38dc164e4d254ad2737758c4b67c0b54267b113692f11a410ffc5fe3e41c2f8ec9246854baa63dbfaebb58f0cc89c528e119788c521bbfa8dd33c69129c1a05ed454d7534224c9df35007ef11b38769ee8d2788c72745e50e14e32b0c2b9d988e2550dd3f89cbd6b50101",
|
||||
"cfrag": "03ec5772868ec577fb8e054a7f0717dc56b7eded542a06c593ac7166093ae196c10394fc79d3d700a9536b10233ad1cf145a533a43d35c48028c7b2a6137a8d6097ff780e25b78581e70d28f102264e1f04b482eb9ecd45c188f2f9cd90026627f90025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb74903ad08b8333f7a44acf71a2738e7e6213d715d7cee759a825abce04b72ca8d56d0033eba87004940ec899c4eb593265e55138f2d17e8b4c712027009388c18724bd0032f4d57c068c255281703ba6d449345e2f6240a4b8b3047209ff2aca5edec0ad2037403376f5789c4d7c755e4a0b45541a88cd045c77fe61a615e9b6ab6af9e97bbd868593f2b973cd492439c4fdbc6351739e8e9e7f5ba501fb9bbc96605dcf144ebb58f0cc89c528e119788c521bbfa8dd33c69129c1a05ed454d7534224c9df35007ef11b38769ee8d2788c72745e50e14e32b0c2b9d988e2550dd3f89cbd6b5"
|
||||
"kfrag": "0bb747aeafa005ceb7be0d1f7fac93094150c5d1c4a08b7705dfe98d38a901ddc7eb5aad9d622148f2c229f53d46b8a17dab61b37eb19bdd6c062fa81d725c93036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b038ab4abc7c62834517b7a296199e43c62da3dfa6c4ecadb4a3aa7aac5f4d9f301cdaacf4115acea35edd9858ee8a04a05cbcf346374ca4a3daa54da89754e018222f869edbd7224f49fd705b53cd11af90b078d77b58b272e1e39a10be6a9966db3d3ba5ba267c360b96cf2aaeb28e87f87f76f7216af4e1594b67f71e8ba195f4c305d98fe469e738caf771745f3865ebf7fd114efc09f8b69383bae8020ae2f0101",
|
||||
"cfrag": "023c4dada5a0b7c98e1c11e6f9c3b799cd82f0aaa690884f9249267fc6651be2430362037688c3de037562c09246afef492b8884c3ab75e3ce1c5faa4c5dda7c42450bb747aeafa005ceb7be0d1f7fac93094150c5d1c4a08b7705dfe98d38a901dd036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b03996e89a45de805aa37dbfa3b152e2021777a760fdfe72f0d401daa7506b56fa503e7c4198f54d702d66c1c042fbda485b93f5bb9c815d7dcb9f2a84f36834f82b5038ab4abc7c62834517b7a296199e43c62da3dfa6c4ecadb4a3aa7aac5f4d9f301031f4d53675c072150ad5d10251ec10b70cf84faa58a93357e426050d7ed23be5fa3fa015b98b321d5dc05d92cbd3aea001d408bfc4121ed9f8d2d13d29c5e94acb3d3ba5ba267c360b96cf2aaeb28e87f87f76f7216af4e1594b67f71e8ba195f4c305d98fe469e738caf771745f3865ebf7fd114efc09f8b69383bae8020ae2f"
|
||||
},
|
||||
{
|
||||
"kfrag": "afdbd2183491cec86259c4e6785c9048f17e1f0c86df597983e78f50eb9e88ebfc725b6addb07ce67e5e33e404237dfd9baf15825329d780bbcf07952d899709025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb74902fbba98644ea41f7abbef7f0a80d645d428844eb6a08c848b73122057f02cc264f27b1b019d667b1a3c89e176b9203870c42dcf3bb6af9191a89db98b2cd1a1b82c61d188f2d2a5d8e1c92a64d3402e98ca09e4594dd67ad74a9583e47b5ee2fd0d38772f8dee198e6e7fa2f7acca079a90b280f98e880106bc337c314bdea20b1e8d1d43ed0912a4a55475c2587ba81a16b9775681774a8bc9d1af2395875e000101",
|
||||
"cfrag": "02b6b320eb5ef6bb58adc6b0379b3052d7fe3ce290d62d8a9edc5d9560c7472f75036dd5f864310b2f9f7239bca239877edf63b42ac00637fb6cdcdcf944fb0ef2f2afdbd2183491cec86259c4e6785c9048f17e1f0c86df597983e78f50eb9e88eb025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb749037b55bdc05a83cf07d672c695d0c57a961be2a7289d9386b6e86953d6abe90f17036e5e32b140cf076873542eb4551c328608c8f2d951a3d52083b7a2f6612c21d902fbba98644ea41f7abbef7f0a80d645d428844eb6a08c848b73122057f02cc264027ddbf0d8eec3118c1765eb0c636184375b5ce593c1fd83bfbf501d94687695954edccdff64dd78e9ae94aa137754c502c03cacbaeeb09b1dcb798bb8442476ba0d38772f8dee198e6e7fa2f7acca079a90b280f98e880106bc337c314bdea20b1e8d1d43ed0912a4a55475c2587ba81a16b9775681774a8bc9d1af2395875e00"
|
||||
"kfrag": "4ace898ce8231afe709556f0816b7c3b18a9aaa50fd6afe4596cc32b5cad26a68634f36bf1374f4a915477f9cdb0b8ae2ad6d4b2fc149c693a2cef1a248452c5036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b027c2de1ca923a4f1c7783d42dd0d145efeb1fb8b352168a255ec4661a7ad5532b9653705171ebc24147bb8c9f97500b25f2a3a5304e3d8dfc91d2a1f8dc0d4a5e29044bc078fbe2d8c9b6e500a70af07fbce661f4ecb86cdb2c847b11c136782100962b6d129d9cdb3fa930980c8fe7326fc0897e5a40cdf01f2984fa017c19fb399a0157286cd368653d27522d8775557009377051c9b56b69b014d051ae8b1a0101",
|
||||
"cfrag": "033c0f532b1e80753d70dc8088fec6132412308e4b27503875878f47475451169b03bd063c6a2189baf14c826a187b2b4077e536775504d0b302e4006f5180f92c284ace898ce8231afe709556f0816b7c3b18a9aaa50fd6afe4596cc32b5cad26a6036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b03f5b99feb5baf4c4aa52bab260270028e11cbcaadfafc740a078e222da31e6cea038348e03d9cb890cdd87ff58b041f1b08724706785352950c321173471eeb917b027c2de1ca923a4f1c7783d42dd0d145efeb1fb8b352168a255ec4661a7ad5532b02bcc145a4a94674c87de586a97eb1b3255ec3e07184916495243f73c71b106c8132071b0325743caec3d1e264ddcc9a8dfca5e7a971ae00c4d79112ea5460787000962b6d129d9cdb3fa930980c8fe7326fc0897e5a40cdf01f2984fa017c19fb399a0157286cd368653d27522d8775557009377051c9b56b69b014d051ae8b1a"
|
||||
},
|
||||
{
|
||||
"kfrag": "831f7b7b14181746fcfd7e26e03e3fb63e7a8903acff3dd3c7ad0c2c94550d9abcced3aacb62fa59fd2847a2b18cc6a6f0a6f646e39ec94f05ef186186dfbe10025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb749020db8647602d7401b47c556f25540bd45da99e69462ee8eef1b9c26a26a3757c77f90b015143d8516a5bf2ada51a24b8192e1326d38bf47c0f54591619db42c7c122fd0d955f788dfdeee8d762022887216a3de332632d44092f1f06793eb351fd6acaf0f2060ace737a11e1c1cec72ba361ce754c913765113e1695de323225f24c3f0bbf832c9062d004b69e40090930b40d5986eb9ede462e5d044083127450101",
|
||||
"cfrag": "038a54e78c4dd408df7b242610d5c21bc6a34f7b16af21a059ee8e44eea24337c702d4584beebc883104f375e922aba70ad1449d54f6a835ba6716b36271bfae8e53831f7b7b14181746fcfd7e26e03e3fb63e7a8903acff3dd3c7ad0c2c94550d9a025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb74903c1d11486753d8d4b60a4e8a890007d021ea00aaed7d608b25475e69364e5f3120304ef459543d9482aa3b48c5605176e87bf55c0bef3f03244bac83446dd84fe3d020db8647602d7401b47c556f25540bd45da99e69462ee8eef1b9c26a26a3757c702182da47b2bef272ed9840eb2cff17f8f62d3e9544cfc699905e40e8ab061d4d17dc4e840d39308e81fae434b30ed124ce08f846a1a9ab73c926a6a222d15657ad6acaf0f2060ace737a11e1c1cec72ba361ce754c913765113e1695de323225f24c3f0bbf832c9062d004b69e40090930b40d5986eb9ede462e5d04408312745"
|
||||
"kfrag": "ccc346110f4ab3fa3b0aeca1630e077537ac5e2c74f31a6d09de1a74e5db4f044a1e816cd104fdfabc92bbb40c6f9361071260c13a14b866097749062af79d83036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b03c18e0774891c9d7bb8502e35a2dc2aabeb461f4f0cf43a78a75786869007d60895a31ea32286ff5516b3510559e1e7e3bbbebcedd1c7540b002764e6901816244a073e19a1d9c5e460fbec5dbd33717e9958c89f6adab0484cbd40d1163b8ea71a7208d0de602d4d12c024c0974568fc2aaf23aafb1405157cbcf97738fc9dc0076b9f77d53e20bab18afba1ef40232b55335dbf33ccc365df277fe1a8ecaa530101",
|
||||
"cfrag": "02a6dd1684794a82183794970974fffc79009ddd99d67a8e4ccf331b66b52b74ed0212f0c112b1e35a9bed7e7c623ae0330010b02a7e1a273b93e4f1fb1ef994dc98ccc346110f4ab3fa3b0aeca1630e077537ac5e2c74f31a6d09de1a74e5db4f04036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b025b53b9f0a4881f2a830fa0a5b851eb616580aba7fb111348183031527a2476aa039ae97d9f19a6b4dbdf1f413f1eb986b5b5deb31f3fccf18ff6c160106064140403c18e0774891c9d7bb8502e35a2dc2aabeb461f4f0cf43a78a75786869007d608024ddf944ec195e26813a514b9a700a27ab4c5ae341b49fff234c61c7d3f0f3a47eccb3bc2212c779b4df0685192f77b57cb25f9849baee3f8c7f7849eeca622d41a7208d0de602d4d12c024c0974568fc2aaf23aafb1405157cbcf97738fc9dc0076b9f77d53e20bab18afba1ef40232b55335dbf33ccc365df277fe1a8ecaa53"
|
||||
},
|
||||
{
|
||||
"kfrag": "c63acdf5fb6820df50354e74e65eefacaf75e7e22c780b2b5e2c49a0db9d353e7217ca6a942fce879bd4b596aabd489e0c5af75bd94b72aed37999799e9c8dc9025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb74902fcaa0a22aabe3b4564972a9368d6a752bc5e359b306cfaff1626b49911158cda599e662db88909f430575f44b3677a8161a5003519e48cf0da635cb20b15f18d632a1bf41eb525b9ee9fd47f196fdd15059d989f9166e5b437cbbd66459e03fad404248f1da8048a5bf9dd9650fbdd50d1afcbadabbcd7a5aca1882b5eeb803443cd4caff8c4b090bc263f56f496aca086bb6f1fedfd5a99e1715ebfe2c6b5010101",
|
||||
"cfrag": "038caa0566b556fb81617617ee8d4a4808cfaac1fa65b1e1999b58bbefafb30623022a43ae7cd2595e155f3cc7cf5e716168f2b959d574e07f7037ba30329dc384dec63acdf5fb6820df50354e74e65eefacaf75e7e22c780b2b5e2c49a0db9d353e025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb74903361957fd737be52d9423a400e677264d8e57ffc1ab35f19aff29ac7d13275ece03a1b57ec36f35089242d2586be843853ce830f1fff20cea9e6a354598ec10c1e002fcaa0a22aabe3b4564972a9368d6a752bc5e359b306cfaff1626b49911158cda0300a120a88ee5994de9a4a5287dbb2e63bd1cd3fbca77740ddad0789dc4a40547a792377ec089eadb1771196797c6835cf01bd4307c6c33be4e61acdb6e05f583d404248f1da8048a5bf9dd9650fbdd50d1afcbadabbcd7a5aca1882b5eeb803443cd4caff8c4b090bc263f56f496aca086bb6f1fedfd5a99e1715ebfe2c6b501"
|
||||
"kfrag": "3166d84565cc545cd994957f2aee5009edf3611b5b348e6d39eb27c02198f3cf722cd82f01fd45953cc999741fedf34ea363a229b4414340dbacd0a3fbefb13c036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b02e307917315eab38d97ba09a5fda8c278b4678ad9c8486b17b79739fdd2c9b088ff59ee77f0f2a5455e4d31439fe3652a284839c2c0fd1e989b5f80179501873b13b84ac39b7f9f0de069eedfa3c79d4781dfcceba1c344e0f003f4053ba938465b0e56d5066adea34ff1365e77358dc2a44a319d9a0a7edc283d05790cf9a8152bfab400aefd27bd41374b761de99974a94c4d1076d78269cadb4011cb06b1180101",
|
||||
"cfrag": "02af56a5bad7fef91e011ac17e1d2066842be5b0fca15cbe1b6ac561281756b4ee02ff6d03924099b91ad03484b4eed47c1559f9869c239d7a42edefd2622a74c9e63166d84565cc545cd994957f2aee5009edf3611b5b348e6d39eb27c02198f3cf036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b038744e4145d2a32bdca6c10199087b720891c9d8510516eb13f6d4a19ee304c5902c9e81da5bc322c674740a9ffb2ea36238628911aa0420fb87fdc53587cc8129c02e307917315eab38d97ba09a5fda8c278b4678ad9c8486b17b79739fdd2c9b08803bd8be6d162bd571a59d0980694944b7e1bf315b6fae53413bf3c1317ad25df26bf5c8477011a67963c77b4eda856b0128d32d58a1be455b5956b93b7ff2a8c585b0e56d5066adea34ff1365e77358dc2a44a319d9a0a7edc283d05790cf9a8152bfab400aefd27bd41374b761de99974a94c4d1076d78269cadb4011cb06b118"
|
||||
},
|
||||
{
|
||||
"kfrag": "1365f76b3cecb0d27cd839263d6e91e8a3e703cb10590fc4ee8c533caed2fcb4e390938ab2eb832d51d7436058182fb46fb4288c9409a2465c25e447919e61eb025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb74903ffe0345c282a9890aa6759dadd14afdd50a82c19123a110d37f4582a1549ce5d4308de0dbbc76897e910253bd1fdb10e65bbbe45cede7dcbf494eba5dee18f9c141cc095ff275208485abe81b229b730c11a1fd87de00756e3d705faff9e6f508cff3f81aec66079b4737c5d55ada03f7a749da2605e6b1bb57324528c373cac773526c02a0cf876744a5e7cd7dee1bad8ccf1e81a46d4c7049743cabca94dad0101",
|
||||
"cfrag": "03e39b8d144411b2db704a4394b9291bc8897ce619df95e2a8355066a9da8fe91b02037fe5e553f4e7e711502abe59bff33fae5ed0eee63747252744701ad1c550f31365f76b3cecb0d27cd839263d6e91e8a3e703cb10590fc4ee8c533caed2fcb4025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb74903a0bf927bc8b75413f899b06ec3bb3ebba8b73f2a5d22c007e157440c2ec6496703be800d325be2e0d10d3cf81d9fe65e035a31d9f4b857b81af38d52d1a815a40b03ffe0345c282a9890aa6759dadd14afdd50a82c19123a110d37f4582a1549ce5d02518eea3159155d5ec2437907ae06a3bf0ece2e8747e13c1528ccffc62eedeebeb50690a4f2f1e5ebcec48789e7d08039ae4853de86a2a2fd991e70ba37e7dc1c8cff3f81aec66079b4737c5d55ada03f7a749da2605e6b1bb57324528c373cac773526c02a0cf876744a5e7cd7dee1bad8ccf1e81a46d4c7049743cabca94dad"
|
||||
"kfrag": "71c8673926b3df970da991a3d53cd6cff27963ac7d88ad2921e84ae47e8f3c930112609fb5f87ef70ebdbdec2d9cc58fd1f171bea4b93fb4a57de058666fdcc5036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b033c83e00f04744ed4ac3a6cadc64568dfe526e579f56f5c26e5749a0fe795b0339700c611b793210edfdc823f5332ed4640f6cf09e419336f3e13b71b29de065f7cd643768ebea6137a612bfb8328cb0868ac6e001e9bf8270817446b15027a1d6e6b066214a61c379b54d71b608774172181d09ff6b14ab43dae3ad68fb18abe2fad7b818fe6bee1c27158d5bc3c85c114611c43bfe52e4f6969b9a53c7db1240101",
|
||||
"cfrag": "0249811dd5bab624b9501be1cfff695d94b44f80d2aea9a107fdaa6e0fac70784c0370888b3ceed890b616afe29cd580fc0808b5f4fb5dde04f6e91382a39e1fef1671c8673926b3df970da991a3d53cd6cff27963ac7d88ad2921e84ae47e8f3c93036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b0240fdfd21499d29990d5c44133fe7ad4597337f7bc18d7768ffc50f6a5661d14903dc2ab1e56a45fa98de15f0c32d46adf0ae39884736ea884a1dd1f4c4c7e8669d033c83e00f04744ed4ac3a6cadc64568dfe526e579f56f5c26e5749a0fe795b03303d4d12caf9a7337897a9f0bf47a232c26347a78eb4e8920900a692d9c87ce13805c978b4b22177a905407452d108a654e28ddce1d9480265bfee554587a6fc7ac6e6b066214a61c379b54d71b608774172181d09ff6b14ab43dae3ad68fb18abe2fad7b818fe6bee1c27158d5bc3c85c114611c43bfe52e4f6969b9a53c7db124"
|
||||
},
|
||||
{
|
||||
"kfrag": "d961d60a31b197ee26437b1ff6b484c63bcfd208f509af1225a8db8f65240e366f7924ae66d6cd64c25c74761067bcb3a388cf2d4d2e90738666252868e790b0025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb749037c88f9bf80bb6a406843e339dcc8548b3f8bf16e525be9c94d5e3b8c243f466fbb19cf3eec376f9c46d9c52040555927c7eb506af29718ed9b728ac210d43b2b4958eae22852a1e3761a71cedff210a52f5d312e5cc1b12bdbb2edbe3f955f5535b8b1ce9e3e8b04a010a2dd227c9d906d7806fdf9df07d8ce379597bf7513c23db95d84e7774a3fe0de392cd7390c6ec7cab60ad22317d8c00de0865bd0ceb80101",
|
||||
"cfrag": "03367a497f07271e9b505f58d762527cfd8b0bd30f4b925219b495c8ff825c8cef023b856c54ee517300280f9b9109ee6f8e260341c4013a0b74911fda9eac562b71d961d60a31b197ee26437b1ff6b484c63bcfd208f509af1225a8db8f65240e36025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb74902d5dd9d1d29e06800648c0b2b45a2755f5a36ed4e7179d17c5ed9506d1d455daf02fe8deea5266b7059e6bdf53cb4f23c3f27814e14f955eb6236ca911639c3d6f8037c88f9bf80bb6a406843e339dcc8548b3f8bf16e525be9c94d5e3b8c243f466f03bdd9ce48dbeafe54277c44c4cf3cb5d5eb10e036640180c0d0e197594f2bebe029f79a6eafcac19331d83eab043df3aa6486a70409c46c2509a4b03ead49666b35b8b1ce9e3e8b04a010a2dd227c9d906d7806fdf9df07d8ce379597bf7513c23db95d84e7774a3fe0de392cd7390c6ec7cab60ad22317d8c00de0865bd0ceb8"
|
||||
"kfrag": "4e27b679bb415c4fb50a84e342b7a6405c03b015199f8178d825be10c304976bcb91e3038cf7f69cf437fab1a1d55a7ae61710248d1cd45ce31055492c9f9d2c036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b024f2493f41095fec4b28b7dc3d9a91ce656ac98f23f35e4ff0e87d27e422bb445a01e102936f9c672c72adf3dd9a659875b93a8a4fa5ce35dc27fae52e3b7274c110a3cf0dfc988a3dfeda1621831686c00c7c164747a484f3f254ffd05a453f7b84772259002ac4555054edfc31a58a597ef47e8dcbca0860acc2668d646d5411ff0e2b9f5bfe651197a66927dbd57a973d7b18c1e1ffc0ad29c6ccb9c07698e0101",
|
||||
"cfrag": "02e1d44d51eb0b901c9e7ae75012365fa614ac37352c39abcf5111503f1fce8a0a02265e4caa6bb349c83409ceb4d697e10755051426a60f64455d427dd2d13b4c754e27b679bb415c4fb50a84e342b7a6405c03b015199f8178d825be10c304976b036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b02f70caa9664f731c6a4e510f366ec1cb30cf8f99bd90064f60e1150a97bdcf71402bcf647a3765a1bd64178900716f9a8c699d20a08fb0768227a377a0bf103874e024f2493f41095fec4b28b7dc3d9a91ce656ac98f23f35e4ff0e87d27e422bb4450221b9645b560128d07ff5ad6cabc8c960655563552eac678f237ffbdfa52031043e921e438182a1cb952ef26c3efc71457653345c3e646274556b8d4f588e3ed2b84772259002ac4555054edfc31a58a597ef47e8dcbca0860acc2668d646d5411ff0e2b9f5bfe651197a66927dbd57a973d7b18c1e1ffc0ad29c6ccb9c07698e"
|
||||
},
|
||||
{
|
||||
"kfrag": "8618ade86dd8b8f15c206274caba6955c30171e466e220ef2344af25f3ca5976ea2eb761d4e8d083e4bf30052c90f6fde525716bd19b5abe98d66bdd48745f85025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb74902bb441051315ea81c8d9d9cc4e63d3f66e6fe3ef52217e8639e0af421d5dbba1be604f5168408cc4bf118346126b9a105b57524b741e141d5cebca15c8964669858bed28994196a23e4f99706cdb8d912d9c53b7c58f98e6d5eb5a4ef3aa2b7b9e0a270af089c667647613c6abe1b7aba8103ee386a04df80341e51e132d6d35d28753fa65e7f8d8c8f3a10d8adc8499a174bcb8041cf6078520ef5e9e00853290101",
|
||||
"cfrag": "03ae6db34ac0125757de78dc64cb563d32ef5ce3983b67f8053cbb9e3539f5240c03855d0862b9930d7fa36e5c60785352de497b84e6ca6d1712627a35fa49df79688618ade86dd8b8f15c206274caba6955c30171e466e220ef2344af25f3ca5976025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb749021594688234f9a0ba6331cf6d341dcea4992d0354492247c528a011620fe7271a03ebb8652e960aa91511db011d16dc3f15df71d81b6e5555a41dc29480158fd8e302bb441051315ea81c8d9d9cc4e63d3f66e6fe3ef52217e8639e0af421d5dbba1b0398e26bb2caa42e1cc1f55f3688bfcaaadc7714a9f79f1910f5c158faa0d53b370668c081a5622181957a2af1fed562695ec390b01b8855411518f401638e185de0a270af089c667647613c6abe1b7aba8103ee386a04df80341e51e132d6d35d28753fa65e7f8d8c8f3a10d8adc8499a174bcb8041cf6078520ef5e9e0085329"
|
||||
"kfrag": "7a359c5e31c6bf94bfc09eaa7c199ccda576fdda37d74360d19ddf71930e9423ffb95215a64396ac14f860092c15a7079d58c725484016226a85967c55166602036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b02417fb0a631dc12df3aa4a94c5f838bb2a08aee9c98efae3d5dec6f10d8addd579a3d0eedb2d7826fb6bb8a9fe9b17696ecffd03070afec2f12a315d1dc344470300b9d4641d4cb30760463639a8949444fe5fc08a44d4f36e15640d7945020e6f372b8fce1db831621f1dc7049c5d63140c95dd9ed48de402d09e0eb9a96afbd4a8e539d507cb863bbd5b4cf939271809e4850bbcfb5ca1ff3fef7c377f433490101",
|
||||
"cfrag": "02b3090b199b3e6d2d179e349c924e934d697b76e1a1dccce61e4c7f463282c7fa037a7f8b1433f7826def664c0ce880fd4f696887e70e29717fa734fe48f07c5b5d7a359c5e31c6bf94bfc09eaa7c199ccda576fdda37d74360d19ddf71930e9423036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b03f1ecde0dec752cf8fbb3ff58adf5504b2f97faf3cf15696038335b7e91b0d11e037548274cdb2390bb55b4ee3c0b17b3691e293bb7ec6f4fa093cb567868954eda02417fb0a631dc12df3aa4a94c5f838bb2a08aee9c98efae3d5dec6f10d8addd5702369696156202061fce67ab68d0f037dca93bd18ad31161b31d80421d541fafad37608b9329e45b9fba642ff5aed153ee1813454febedcc1e92e978172afed57bf372b8fce1db831621f1dc7049c5d63140c95dd9ed48de402d09e0eb9a96afbd4a8e539d507cb863bbd5b4cf939271809e4850bbcfb5ca1ff3fef7c377f43349"
|
||||
},
|
||||
{
|
||||
"kfrag": "939cfdfc368ae2c011ade7b7d18543f66f6b2f5aea0ed6732830d8ab281ec492cd90cd1756a44414e51d741e99f9a7d46cbedbfc7bdb60f6b8d33ffb1d4d6b31025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb749020d6a191832eed71367b495a514ee4ac442ce19040c00c4e6ab331f844b2fff11d1db98034e5ff8f86a5b2d015cfa439774dd83644adb80bcba1881f09bdb1b105e37329495d03775e99da0f1c99e753e6868fbe04766572a086ce8e1c575e0d253698578672fbfdcdf2607513d0d0c03f346cb8183506d179e9b999988c7ca317c10e8606e3f7a18ac9146dcc2f484dc6c46a149c371c7a22b17c14f0e3e84220101",
|
||||
"cfrag": "03b45ef82c8e3439a698e3cc4383cd223d6ae84a6c1c7e6ea6b1e89fb501273ef1024e2b1a83a2e675e7f3e4f1d803f456dc83d6536bc33c07b01fc521380cec39a4939cfdfc368ae2c011ade7b7d18543f66f6b2f5aea0ed6732830d8ab281ec492025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb74903893bc5023c9da3e0acf0028256ae37fe1015e09b8fcaea89b3aff10a49b1ac5d03c295e648f0dc3df65314ce141ff21b04fcf53432300ff8994ba765d8205bd90d020d6a191832eed71367b495a514ee4ac442ce19040c00c4e6ab331f844b2fff110390d4511e87f7dee7091cbffb952da38c7efbf1ee5a6890ea8afcfa22ee425c0cecd183c8351af7f917ccaa9bd7771de0ef9cf240bc02a7dc32c10e0bd4ed725653698578672fbfdcdf2607513d0d0c03f346cb8183506d179e9b999988c7ca317c10e8606e3f7a18ac9146dcc2f484dc6c46a149c371c7a22b17c14f0e3e8422"
|
||||
"kfrag": "df55683a69e4136205a61c895959d86eb64840bb2175d5d15e4491b27e6a38bc80dc89e8f1631175607e6c67a34a758020c74693337cf3714a6cf78d355da17a036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b03ab6ffe8768ecd246956362065ca48488183f96c3ee5957be7a7ce02f3ef9cb12bab3cf7756f986806106919c948a4b191bbf84df94503a2b0a81a5141cb9e1e17de0ee2599d0bbafe972bd9e567eece93c262fc634ed2690a1914abda632fac2ae3cc293a58554a55dbc50c0e111c6e9bb0208631833da5e66b1adb2aa1ecdd615c09098fba7af4b03763b846e1f5358a6bac27c36eadd6cd2c98fd58c277e0b0101",
|
||||
"cfrag": "03a3e0b6b2fa9f634acac1d4ed682dbf0c08ba27889087854059d80d021797d7b403a64ced5bc32ad0cf5746eb5ab1ebdc12a1d1bbbd0f45d0fc90c3e4b56ba70546df55683a69e4136205a61c895959d86eb64840bb2175d5d15e4491b27e6a38bc036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b02ef471b06988f07ce34c7bfa5825603eedbde4138c05296055cff54f6204d245a02119417e7aa9c207a71540abefb8de8e04c977db7d11a82e2f98a1ea3fff5519e03ab6ffe8768ecd246956362065ca48488183f96c3ee5957be7a7ce02f3ef9cb1202e8febd066a999b83b4441662636c6c978cb8789553914b5ed94c02d4784432d74e9fffcb5ce10b65d95624b23940415f0dbe29e174a6b73c78cb3d5d380d8882ae3cc293a58554a55dbc50c0e111c6e9bb0208631833da5e66b1adb2aa1ecdd615c09098fba7af4b03763b846e1f5358a6bac27c36eadd6cd2c98fd58c277e0b"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -2,39 +2,39 @@
|
|||
"name": "Test vectors for KFrags",
|
||||
"description": "This is a collection of KFrags generated under the enclosed delegating, verifying and receiving keys. Each of them must deserialize correctly and the call to verify() must succeed.",
|
||||
"params": "default",
|
||||
"verifying_pk": "03f24761ac8b02de08ad1622d023f669d6214c3bab81a33087ed3ec5505e4d43db",
|
||||
"delegating_pk": "03a73623a2e72fd52b2d313214c7495580c14fe6cd8de7ad0d63bbfbfd6fb6bd4d",
|
||||
"receiving_pk": "02952a1903b9c929f0d93d935b34b272ea25a84833a04e22d887f27bc3bf0cc409",
|
||||
"verifying_pk": "030b95b3f249297824b32d3391392d62a9aff32e8698fa78c7e8ce4a9d17071f56",
|
||||
"delegating_pk": "02d67029bb92522059225d190038230c23466e28d132d48f714f9098168a562b8a",
|
||||
"receiving_pk": "03b0d0243e8954b408047eee3b09b5ed132ccc25ec70e99fc74b6e9f54e5ecf9c7",
|
||||
"vectors": [
|
||||
{
|
||||
"kfrag": "3f3453856117dedb3d7518d0435c04b10734700c8aca48fa5a8b85eded515cdffefbefddcd3cb728dcc6d05061b5e201aa1cef55ce89e94c34b6887b307d5ab2025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb7490374d2e59ea274c8011f6bf26ca8fe8eb8e7837cafed8547485e3fde6ffe0368e98d26b0d7e12095941daffae8ca429147d9686dc3285ea182c0d7b15db41c7afd3fae3c88100707ef28b53d7cf93961dc509864eb319f0cce274544306c96099b5792af0b820bf758f5c8f2a69cfc1e0a5f91fab96ab82c10c7740602f90efdd315ff5dbd07323526ca1c9a93132b4d008fdf1796a55b92e2fe75c544652256c80101"
|
||||
"kfrag": "2565903141941fecb01fb92dfbdd66a0a1d4eb94d3226beb2f7adcbb8282ffd0b7934320225868d8f9ace7784fd3ae0c20a09c5a2b698fae0554d71b1f016670036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b026cb94f302809d19aacc81da19f2156db9c610498310b930d7787d8a2366dadd3d977c6befcff3088016d5d9050f4932cb4a9ce483dd7cf27e1f157f8d23f598248d5027a8961a09c874c82a8c479fbf074675790edff37e6927a7d4ea269e600685dc9469c87e6d9d469656b2f40b33e6d6813ec3519fc065a4ffc0eeb8abd324c1914451341cdb7abd7c5aa01adade220b2894be5a33caa9ee7d3b4637bdccf0101"
|
||||
},
|
||||
{
|
||||
"kfrag": "d15ac028be9938b5e2d7a9fb9957b416db538a11d141d320a5f656ab4e3cb0cab3a2ddd2672f3514e7da2f29cbe3815c83b6d704e09d595a68fdd5aeff52ef8a025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb749033d6984555d41614a2ba08c2182e27a7105cb60ed414c9732a156c3e44d196dd3507335e3781d6c9a4543e3ae81a4c7538cf280292c9c0d92e4f513e4e073721f2f72a1ea0e69912e21754e32edf9cefd3a96183f5501266bedb301f291709ffb25ed5213660db4c8bfc086e794650455bfde1251f92e1fe49f1feb016ad44fe859b342964db14dddfa6a33eba53021149d8663d306850b8907f9dabf4a5d3ecd0101"
|
||||
"kfrag": "ae85e679cf44b1877ff36e48c4965144724f17cc7605f53e50007aabbc2c7ab3871d04e6b5666b81a99ba0c6a70ba8675f2122a39eaec04a62c8496d5149ac9d036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b02e3e7722bffcb6674987b0089f6b8ac0d6cb220d9661edb5ed9dca5fcd33d5bdb1e41b92c9a8e4346b2dd1072389e4ce36a6230eecb59b7e0e9d84f35bf14f0f23014a1263e17d07a94c5d9c248c692686c745df3c5d11566b9ca17ec62e59a5265749ef2701a58483bd106be985c3e4a03750e3c0c21424cf7f59682224c4f6e29c242904ade5ac377974eaa662b6ed6eed13fd30509b9cb332b4fa89043a2a70101"
|
||||
},
|
||||
{
|
||||
"kfrag": "f780e25b78581e70d28f102264e1f04b482eb9ecd45c188f2f9cd90026627f904b903c6da7529805e1d91fbaebc384588083e2c5f235c31e7f768b8d0df43513025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb749032f4d57c068c255281703ba6d449345e2f6240a4b8b3047209ff2aca5edec0ad2394020e796b7b9f9130c0ab02b4c8151d050f38f3d0ff5f38dc164e4d254ad2737758c4b67c0b54267b113692f11a410ffc5fe3e41c2f8ec9246854baa63dbfaebb58f0cc89c528e119788c521bbfa8dd33c69129c1a05ed454d7534224c9df35007ef11b38769ee8d2788c72745e50e14e32b0c2b9d988e2550dd3f89cbd6b50101"
|
||||
"kfrag": "0bb747aeafa005ceb7be0d1f7fac93094150c5d1c4a08b7705dfe98d38a901ddc7eb5aad9d622148f2c229f53d46b8a17dab61b37eb19bdd6c062fa81d725c93036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b038ab4abc7c62834517b7a296199e43c62da3dfa6c4ecadb4a3aa7aac5f4d9f301cdaacf4115acea35edd9858ee8a04a05cbcf346374ca4a3daa54da89754e018222f869edbd7224f49fd705b53cd11af90b078d77b58b272e1e39a10be6a9966db3d3ba5ba267c360b96cf2aaeb28e87f87f76f7216af4e1594b67f71e8ba195f4c305d98fe469e738caf771745f3865ebf7fd114efc09f8b69383bae8020ae2f0101"
|
||||
},
|
||||
{
|
||||
"kfrag": "afdbd2183491cec86259c4e6785c9048f17e1f0c86df597983e78f50eb9e88ebfc725b6addb07ce67e5e33e404237dfd9baf15825329d780bbcf07952d899709025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb74902fbba98644ea41f7abbef7f0a80d645d428844eb6a08c848b73122057f02cc264f27b1b019d667b1a3c89e176b9203870c42dcf3bb6af9191a89db98b2cd1a1b82c61d188f2d2a5d8e1c92a64d3402e98ca09e4594dd67ad74a9583e47b5ee2fd0d38772f8dee198e6e7fa2f7acca079a90b280f98e880106bc337c314bdea20b1e8d1d43ed0912a4a55475c2587ba81a16b9775681774a8bc9d1af2395875e000101"
|
||||
"kfrag": "4ace898ce8231afe709556f0816b7c3b18a9aaa50fd6afe4596cc32b5cad26a68634f36bf1374f4a915477f9cdb0b8ae2ad6d4b2fc149c693a2cef1a248452c5036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b027c2de1ca923a4f1c7783d42dd0d145efeb1fb8b352168a255ec4661a7ad5532b9653705171ebc24147bb8c9f97500b25f2a3a5304e3d8dfc91d2a1f8dc0d4a5e29044bc078fbe2d8c9b6e500a70af07fbce661f4ecb86cdb2c847b11c136782100962b6d129d9cdb3fa930980c8fe7326fc0897e5a40cdf01f2984fa017c19fb399a0157286cd368653d27522d8775557009377051c9b56b69b014d051ae8b1a0101"
|
||||
},
|
||||
{
|
||||
"kfrag": "831f7b7b14181746fcfd7e26e03e3fb63e7a8903acff3dd3c7ad0c2c94550d9abcced3aacb62fa59fd2847a2b18cc6a6f0a6f646e39ec94f05ef186186dfbe10025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb749020db8647602d7401b47c556f25540bd45da99e69462ee8eef1b9c26a26a3757c77f90b015143d8516a5bf2ada51a24b8192e1326d38bf47c0f54591619db42c7c122fd0d955f788dfdeee8d762022887216a3de332632d44092f1f06793eb351fd6acaf0f2060ace737a11e1c1cec72ba361ce754c913765113e1695de323225f24c3f0bbf832c9062d004b69e40090930b40d5986eb9ede462e5d044083127450101"
|
||||
"kfrag": "ccc346110f4ab3fa3b0aeca1630e077537ac5e2c74f31a6d09de1a74e5db4f044a1e816cd104fdfabc92bbb40c6f9361071260c13a14b866097749062af79d83036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b03c18e0774891c9d7bb8502e35a2dc2aabeb461f4f0cf43a78a75786869007d60895a31ea32286ff5516b3510559e1e7e3bbbebcedd1c7540b002764e6901816244a073e19a1d9c5e460fbec5dbd33717e9958c89f6adab0484cbd40d1163b8ea71a7208d0de602d4d12c024c0974568fc2aaf23aafb1405157cbcf97738fc9dc0076b9f77d53e20bab18afba1ef40232b55335dbf33ccc365df277fe1a8ecaa530101"
|
||||
},
|
||||
{
|
||||
"kfrag": "c63acdf5fb6820df50354e74e65eefacaf75e7e22c780b2b5e2c49a0db9d353e7217ca6a942fce879bd4b596aabd489e0c5af75bd94b72aed37999799e9c8dc9025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb74902fcaa0a22aabe3b4564972a9368d6a752bc5e359b306cfaff1626b49911158cda599e662db88909f430575f44b3677a8161a5003519e48cf0da635cb20b15f18d632a1bf41eb525b9ee9fd47f196fdd15059d989f9166e5b437cbbd66459e03fad404248f1da8048a5bf9dd9650fbdd50d1afcbadabbcd7a5aca1882b5eeb803443cd4caff8c4b090bc263f56f496aca086bb6f1fedfd5a99e1715ebfe2c6b5010101"
|
||||
"kfrag": "3166d84565cc545cd994957f2aee5009edf3611b5b348e6d39eb27c02198f3cf722cd82f01fd45953cc999741fedf34ea363a229b4414340dbacd0a3fbefb13c036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b02e307917315eab38d97ba09a5fda8c278b4678ad9c8486b17b79739fdd2c9b088ff59ee77f0f2a5455e4d31439fe3652a284839c2c0fd1e989b5f80179501873b13b84ac39b7f9f0de069eedfa3c79d4781dfcceba1c344e0f003f4053ba938465b0e56d5066adea34ff1365e77358dc2a44a319d9a0a7edc283d05790cf9a8152bfab400aefd27bd41374b761de99974a94c4d1076d78269cadb4011cb06b1180101"
|
||||
},
|
||||
{
|
||||
"kfrag": "1365f76b3cecb0d27cd839263d6e91e8a3e703cb10590fc4ee8c533caed2fcb4e390938ab2eb832d51d7436058182fb46fb4288c9409a2465c25e447919e61eb025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb74903ffe0345c282a9890aa6759dadd14afdd50a82c19123a110d37f4582a1549ce5d4308de0dbbc76897e910253bd1fdb10e65bbbe45cede7dcbf494eba5dee18f9c141cc095ff275208485abe81b229b730c11a1fd87de00756e3d705faff9e6f508cff3f81aec66079b4737c5d55ada03f7a749da2605e6b1bb57324528c373cac773526c02a0cf876744a5e7cd7dee1bad8ccf1e81a46d4c7049743cabca94dad0101"
|
||||
"kfrag": "71c8673926b3df970da991a3d53cd6cff27963ac7d88ad2921e84ae47e8f3c930112609fb5f87ef70ebdbdec2d9cc58fd1f171bea4b93fb4a57de058666fdcc5036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b033c83e00f04744ed4ac3a6cadc64568dfe526e579f56f5c26e5749a0fe795b0339700c611b793210edfdc823f5332ed4640f6cf09e419336f3e13b71b29de065f7cd643768ebea6137a612bfb8328cb0868ac6e001e9bf8270817446b15027a1d6e6b066214a61c379b54d71b608774172181d09ff6b14ab43dae3ad68fb18abe2fad7b818fe6bee1c27158d5bc3c85c114611c43bfe52e4f6969b9a53c7db1240101"
|
||||
},
|
||||
{
|
||||
"kfrag": "d961d60a31b197ee26437b1ff6b484c63bcfd208f509af1225a8db8f65240e366f7924ae66d6cd64c25c74761067bcb3a388cf2d4d2e90738666252868e790b0025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb749037c88f9bf80bb6a406843e339dcc8548b3f8bf16e525be9c94d5e3b8c243f466fbb19cf3eec376f9c46d9c52040555927c7eb506af29718ed9b728ac210d43b2b4958eae22852a1e3761a71cedff210a52f5d312e5cc1b12bdbb2edbe3f955f5535b8b1ce9e3e8b04a010a2dd227c9d906d7806fdf9df07d8ce379597bf7513c23db95d84e7774a3fe0de392cd7390c6ec7cab60ad22317d8c00de0865bd0ceb80101"
|
||||
"kfrag": "4e27b679bb415c4fb50a84e342b7a6405c03b015199f8178d825be10c304976bcb91e3038cf7f69cf437fab1a1d55a7ae61710248d1cd45ce31055492c9f9d2c036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b024f2493f41095fec4b28b7dc3d9a91ce656ac98f23f35e4ff0e87d27e422bb445a01e102936f9c672c72adf3dd9a659875b93a8a4fa5ce35dc27fae52e3b7274c110a3cf0dfc988a3dfeda1621831686c00c7c164747a484f3f254ffd05a453f7b84772259002ac4555054edfc31a58a597ef47e8dcbca0860acc2668d646d5411ff0e2b9f5bfe651197a66927dbd57a973d7b18c1e1ffc0ad29c6ccb9c07698e0101"
|
||||
},
|
||||
{
|
||||
"kfrag": "8618ade86dd8b8f15c206274caba6955c30171e466e220ef2344af25f3ca5976ea2eb761d4e8d083e4bf30052c90f6fde525716bd19b5abe98d66bdd48745f85025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb74902bb441051315ea81c8d9d9cc4e63d3f66e6fe3ef52217e8639e0af421d5dbba1be604f5168408cc4bf118346126b9a105b57524b741e141d5cebca15c8964669858bed28994196a23e4f99706cdb8d912d9c53b7c58f98e6d5eb5a4ef3aa2b7b9e0a270af089c667647613c6abe1b7aba8103ee386a04df80341e51e132d6d35d28753fa65e7f8d8c8f3a10d8adc8499a174bcb8041cf6078520ef5e9e00853290101"
|
||||
"kfrag": "7a359c5e31c6bf94bfc09eaa7c199ccda576fdda37d74360d19ddf71930e9423ffb95215a64396ac14f860092c15a7079d58c725484016226a85967c55166602036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b02417fb0a631dc12df3aa4a94c5f838bb2a08aee9c98efae3d5dec6f10d8addd579a3d0eedb2d7826fb6bb8a9fe9b17696ecffd03070afec2f12a315d1dc344470300b9d4641d4cb30760463639a8949444fe5fc08a44d4f36e15640d7945020e6f372b8fce1db831621f1dc7049c5d63140c95dd9ed48de402d09e0eb9a96afbd4a8e539d507cb863bbd5b4cf939271809e4850bbcfb5ca1ff3fef7c377f433490101"
|
||||
},
|
||||
{
|
||||
"kfrag": "939cfdfc368ae2c011ade7b7d18543f66f6b2f5aea0ed6732830d8ab281ec492cd90cd1756a44414e51d741e99f9a7d46cbedbfc7bdb60f6b8d33ffb1d4d6b31025141c7f166303d33491fb9aae65c941fd7f40e5c9270a9600c20281090dbb749020d6a191832eed71367b495a514ee4ac442ce19040c00c4e6ab331f844b2fff11d1db98034e5ff8f86a5b2d015cfa439774dd83644adb80bcba1881f09bdb1b105e37329495d03775e99da0f1c99e753e6868fbe04766572a086ce8e1c575e0d253698578672fbfdcdf2607513d0d0c03f346cb8183506d179e9b999988c7ca317c10e8606e3f7a18ac9146dcc2f484dc6c46a149c371c7a22b17c14f0e3e84220101"
|
||||
"kfrag": "df55683a69e4136205a61c895959d86eb64840bb2175d5d15e4491b27e6a38bc80dc89e8f1631175607e6c67a34a758020c74693337cf3714a6cf78d355da17a036523005d1234abcd44d36704620cfcff444edac7a64dfc256281966351a7803b03ab6ffe8768ecd246956362065ca48488183f96c3ee5957be7a7ce02f3ef9cb12bab3cf7756f986806106919c948a4b191bbf84df94503a2b0a81a5141cb9e1e17de0ee2599d0bbafe972bd9e567eece93c262fc634ed2690a1914abda632fac2ae3cc293a58554a55dbc50c0e111c6e9bb0208631833da5e66b1adb2aa1ecdd615c09098fba7af4b03763b846e1f5358a6bac27c36eadd6cd2c98fd58c277e0b0101"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,37 +1,37 @@
|
|||
{
|
||||
"name": "Test vectors for CurvePoint operations",
|
||||
"params": "default",
|
||||
"first CurvePoint operand": "02eb0184eedd9d14e10ad0714afd9915c58b2b40b582283e3e741d0141189246c0",
|
||||
"second CurvePoint operand": "02b925f594ea60040f470195c72fc7aa8caeac7161af3abe65dceb2908bc866754",
|
||||
"CurveScalar operand": "d63d8806eba7bfc2f5fd77d21aa5d7cc7cffcee26ac096f7c5904629c0db1c12",
|
||||
"first CurvePoint operand": "03945c237f3b4cab9638d89bba3a098d37a8f4c981788969c2846e988748315bfd",
|
||||
"second CurvePoint operand": "03d495c93def84d2b7c709d5896d64339129a28db5a6a2cd4c686c895da538228e",
|
||||
"CurveScalar operand": "0a686fbc44fdc4713b7901c88fe416cc9b187501e671a4c70781742f3bcef1ec",
|
||||
"vectors": [
|
||||
{
|
||||
"operation": "Addition",
|
||||
"result": "02de2d20749111f538575c81e0abc406c71cf6d4c7c1b3555476d6f8778f271d5a"
|
||||
"result": "02338b0a976b3701353558685966d2b166174dbce6d697d2e50069833a06157bf9"
|
||||
},
|
||||
{
|
||||
"operation": "Subtraction",
|
||||
"result": "031bd3e6f5b33b3f94601d3a243efaf2c359c3b097aff1aa3fa8fbf5210f110b8d"
|
||||
"result": "02864a1ee4df38dffb51940819fca1a89624521ed14b8ec873e4b701fa6d8c1f5b"
|
||||
},
|
||||
{
|
||||
"operation": "Multiplication",
|
||||
"result": "020fd46d21ec56d94a787c6d717222489b7a070a4f57065f442f588789d1feed87"
|
||||
"result": "03e7882ab867f7006915d16738ef9adebc2a1946fea829478e7e444e6113ecf1f1"
|
||||
},
|
||||
{
|
||||
"operation": "Inversion",
|
||||
"result": "03eb0184eedd9d14e10ad0714afd9915c58b2b40b582283e3e741d0141189246c0"
|
||||
"result": "02945c237f3b4cab9638d89bba3a098d37a8f4c981788969c2846e988748315bfd"
|
||||
},
|
||||
{
|
||||
"operation": "To_affine.X",
|
||||
"result": "eb0184eedd9d14e10ad0714afd9915c58b2b40b582283e3e741d0141189246c0"
|
||||
"result": "945c237f3b4cab9638d89bba3a098d37a8f4c981788969c2846e988748315bfd"
|
||||
},
|
||||
{
|
||||
"operation": "To_affine.Y",
|
||||
"result": "d9bed51d198e8ccd919b54a6eabfed2032cc737d410e0364643716986de89afc"
|
||||
"result": "fd0576e382f8f0ce0849c72789c3bd2fe2ee453efc606ff8815108e734e088ef"
|
||||
},
|
||||
{
|
||||
"operation": "kdf",
|
||||
"result": "40b49492ba7924c421dd61ea39bf94ac6566feff43a1ef14e7adc2b9af3f6664"
|
||||
"result": "26f9fa1e3d2bd1fe3b14ea0a6e1276a214b1f5c59ca01cb3b74a7cb74e327f1c"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -24,69 +24,69 @@
|
|||
"input": [
|
||||
{
|
||||
"class": "CurvePoint",
|
||||
"bytes": "02a03893438c0502dd13818f65c039b2ef4fce33bfed150c6ad166554b4e8a51c2"
|
||||
"bytes": "02558f1de19a58e73a94e8fbbc6d3b1de2d312d90746ea74cb29f046943bf57871"
|
||||
}
|
||||
],
|
||||
"output": "cd175898869252f3d6c6e77eaed94a72e74410d99534b349f27df2362c35745a"
|
||||
"output": "5dfe037b1041c4f4d89bed6305061d5d0f7f996f51cab49af958c9e635c47792"
|
||||
},
|
||||
{
|
||||
"input": [
|
||||
{
|
||||
"class": "CurveScalar",
|
||||
"bytes": "5e8601ee29241f263bf49b9999594413f863193fa1b8a985fff981cda7cc9087"
|
||||
"bytes": "7a44f4f0e25258ed69f205b3770070c557d288c69a3cc453b2a42205d8c1c196"
|
||||
}
|
||||
],
|
||||
"output": "2b83903fedca70169024365a4a5b387536a9ba38bd7b9fa0462f5f932f41a493"
|
||||
"output": "93134c97fd051748346bf8ee6dc9f3dd920effc2faa81f7c243d0565b10ebe5e"
|
||||
},
|
||||
{
|
||||
"input": [
|
||||
{
|
||||
"class": "CurvePoint",
|
||||
"bytes": "02a03893438c0502dd13818f65c039b2ef4fce33bfed150c6ad166554b4e8a51c2"
|
||||
"bytes": "02558f1de19a58e73a94e8fbbc6d3b1de2d312d90746ea74cb29f046943bf57871"
|
||||
},
|
||||
{
|
||||
"class": "CurveScalar",
|
||||
"bytes": "5e8601ee29241f263bf49b9999594413f863193fa1b8a985fff981cda7cc9087"
|
||||
"bytes": "7a44f4f0e25258ed69f205b3770070c557d288c69a3cc453b2a42205d8c1c196"
|
||||
}
|
||||
],
|
||||
"output": "9f7cea094a5ed29ab2ec83391527db31850f915781c07c0b13853869e9885968"
|
||||
"output": "3cd3272ccea4e738abe18c100656a6ed2ba30e6e5723c1205641c8ba72aef03c"
|
||||
},
|
||||
{
|
||||
"input": [
|
||||
{
|
||||
"class": "CurvePoint",
|
||||
"bytes": "02a03893438c0502dd13818f65c039b2ef4fce33bfed150c6ad166554b4e8a51c2"
|
||||
"bytes": "02558f1de19a58e73a94e8fbbc6d3b1de2d312d90746ea74cb29f046943bf57871"
|
||||
},
|
||||
{
|
||||
"class": "CurvePoint",
|
||||
"bytes": "02ecbc4dc0aed60efa211c7bf0e238593d292a042373b891928bcee459151c2f44"
|
||||
"bytes": "025e6a08eb9376adfea3a92e05fea213c493fe051461fdf5639a7108e8687eeacf"
|
||||
},
|
||||
{
|
||||
"class": "CurvePoint",
|
||||
"bytes": "02aa6a09c61286e36d82f6371038f1c33b2095b3b6dc8d09de7489f516c2dfe49a"
|
||||
"bytes": "030d7ea7752848f5af2aa01bde8b45e180089fc7cdbc60b59235207a6527773d73"
|
||||
},
|
||||
{
|
||||
"class": "CurvePoint",
|
||||
"bytes": "028da9ebf8cc0966bc010152fd3917a8f12dfff0af3b06e34e17f300d622893159"
|
||||
"bytes": "02906780e9484aec2102a01a157f10ced5aec952cd00631d94d5ea2edfa9b68083"
|
||||
},
|
||||
{
|
||||
"class": "CurvePoint",
|
||||
"bytes": "0281171b7e330ebd097575dadb210e8a405bc162e293881457a301da03f7571c7a"
|
||||
"bytes": "03fcfdb46bf83a68e0d674e7d5b7c0365c8fa05dd418f2ba1a4aea2abcbcd12a19"
|
||||
},
|
||||
{
|
||||
"class": "CurvePoint",
|
||||
"bytes": "03e2869b26bbf46a2e1f46116d8d9eeeb45f18acf4a808defee52040221dd08af9"
|
||||
"bytes": "02d45ec4ea9bf9d0acfba0422c6d4cfb087bd2f0084127eb90debdd94e391927f7"
|
||||
},
|
||||
{
|
||||
"class": "CurvePoint",
|
||||
"bytes": "0374d2e59ea274c8011f6bf26ca8fe8eb8e7837cafed8547485e3fde6ffe0368e9"
|
||||
"bytes": "026cb94f302809d19aacc81da19f2156db9c610498310b930d7787d8a2366dadd3"
|
||||
},
|
||||
{
|
||||
"class": "CurvePoint",
|
||||
"bytes": "024526ff9ab3c9c4cf619166ff897b8c023a6ff01f54c42a921ec1ab564d5a65eb"
|
||||
"bytes": "03711b30de53e38ba240d34e796e09b8eabe11c385a02a6f87eb8512e1c3fff690"
|
||||
}
|
||||
],
|
||||
"output": "072c408c4631491eb12b00b38b8f7f20080b802e3e7c5c421f89887055248b1a"
|
||||
"output": "fb39d851bd5f661406a4f2101b18023aadba39b966f605402179d95c07696f16"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,24 +1,24 @@
|
|||
{
|
||||
"name": "Test vectors for CurveScalar operations",
|
||||
"params": "default",
|
||||
"first operand": "d63d8806eba7bfc2f5fd77d21aa5d7cc7cffcee26ac096f7c5904629c0db1c12",
|
||||
"second operand": "c2cc9d2f0b39201a5d4d4aa755c0506eab19c1abc89068d216f23f4965427ac4",
|
||||
"first operand": "0a686fbc44fdc4713b7901c88fe416cc9b187501e671a4c70781742f3bcef1ec",
|
||||
"second operand": "6af63df254cc9dd5728e098ffe9ad3cc1e0252b2e3562522907cab1a41656895",
|
||||
"vectors": [
|
||||
{
|
||||
"operation": "Addition",
|
||||
"result": "990a2535f6e0dfdd534ac2797066283c6d6ab3a784085f8e1cb026e655e75595"
|
||||
"result": "755eadae99ca6246ae070b588e7eea98b91ac7b4c9c7c9e997fe1f497d345a81"
|
||||
},
|
||||
{
|
||||
"operation": "Subtraction",
|
||||
"result": "1370ead7e06e9fa898b02d2ac4e5875dd1e60d36a2302e25ae9e06e05b98a14e"
|
||||
"result": "9f7231c9f031269bc8eaf838914942ff37c4ff35b2641fe036d727a1ca9fca98"
|
||||
},
|
||||
{
|
||||
"operation": "Multiplication",
|
||||
"result": "88cdbd2959262c74f26d4315e65b7e8c4fb5d1326fb9f1c6dbfd7c951d43485f"
|
||||
"result": "a0bc896003f0e4feca2176f978b2cfa99ca73af19bf38782064bc137d9f00169"
|
||||
},
|
||||
{
|
||||
"operation": "Inverse",
|
||||
"result": "663c74e198bd4dcd2db7b78895fe8994a727d8bcba073818475a22483bb0103a"
|
||||
"result": "e84f604508a66bfa6df07529238588040aee19b38c68330c031715f478426873"
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue