Skip to content

Commit

Permalink
Add generate_kfrags()
Browse files Browse the repository at this point in the history
  • Loading branch information
fjarri committed Mar 17, 2021
1 parent ebd824d commit d413c64
Show file tree
Hide file tree
Showing 6 changed files with 457 additions and 1 deletion.
37 changes: 37 additions & 0 deletions tests/test_compatibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,40 @@ def test_encrypt_decrypt_original(implementations):
# Decrypt on the source side
plaintext_decrypted = umbral_src.decrypt_original(sk_src, capsule_src, ciphertext)
assert plaintext_decrypted == plaintext


def test_kfrags(implementations):

umbral_src, umbral_dst = implementations

threshold = 2
num_frags = 3

sk_src = umbral_src.SecretKey.random()
pk_src = umbral_src.PublicKey.from_secret_key(sk_src)

# Create kfrags
pk_dst = umbral_dst.PublicKey.from_bytes(bytes(pk_src))

delegating_sk_dst = umbral_dst.SecretKey.random()
delegating_pk_dst = umbral_dst.PublicKey.from_secret_key(delegating_sk_dst)

signing_sk_dst = umbral_dst.SecretKey.random()
signing_pk_dst = umbral_dst.PublicKey.from_secret_key(signing_sk_dst)

kfrags_dst = umbral_dst.generate_kfrags(
delegating_sk_dst,
pk_dst,
signing_sk_dst,
threshold,
num_frags,
True,
True,
)

# Transfer the capsule to the source side
delegating_pk_src = umbral_src.PublicKey.from_bytes(bytes(delegating_pk_dst))
signing_pk_src = umbral_src.PublicKey.from_bytes(bytes(signing_pk_dst))

kfrags_src = [umbral_src.KeyFrag.from_bytes(bytes(kfrag)) for kfrag in kfrags_dst]
assert all(kfrag.verify(signing_pk_src, delegating_pk_src, pk_src) for kfrag in kfrags_src)
2 changes: 2 additions & 0 deletions umbral/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
)

from .capsule import Capsule
from .key_frag import KeyFrag, generate_kfrags
from .keys import SecretKey, PublicKey
from .pre import encrypt, decrypt_original

Expand All @@ -20,4 +21,5 @@
"Capsule",
"encrypt",
"decrypt_original",
"generate_kfrags",
]
72 changes: 71 additions & 1 deletion umbral/hashing.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
from .curve import CURVE
from .curve_scalar import CurveScalar
from .curve_point import CurvePoint
from .keys import PublicKey, SecretKey
from .serializable import serialize_bool
from .signing import Signature, Signer


class Hash:
Expand Down Expand Up @@ -38,14 +41,81 @@ def digest_to_scalar(digest: Hash) -> CurveScalar:
return CurveScalar(bignum)


def hash_to_polynomial_arg(precursor: CurvePoint,
pubkey: CurvePoint,
dh_point: CurvePoint,
kfrag_id: 'KeyFragID',
) -> CurveScalar:
digest = Hash(b"POLYNOMIAL_ARG")
digest.update(bytes(precursor))
digest.update(bytes(pubkey))
digest.update(bytes(dh_point))
digest.update(bytes(kfrag_id))
return digest_to_scalar(digest)


def hash_capsule_points(e: CurvePoint, v: CurvePoint) -> CurveScalar:
digest = Hash(b"CAPSULE_POINTS")
digest.update(bytes(e))
digest.update(bytes(v))
return digest_to_scalar(digest)


def unsafe_hash_to_point(dst: bytes, data: bytes) -> 'Point':
def hash_to_shared_secret(precursor: CurvePoint,
pubkey: CurvePoint,
dh_point: CurvePoint
) -> CurveScalar:
digest = Hash(b"SHARED_SECRET")
digest.update(bytes(precursor))
digest.update(bytes(pubkey))
digest.update(bytes(dh_point))
return digest_to_scalar(digest)


def hash_to_cfrag_signature(kfrag_id: 'KeyFragID',
commitment: CurvePoint,
precursor: CurvePoint,
maybe_delegating_pk: Optional[PublicKey],
maybe_receiving_pk: Optional[PublicKey],
) -> 'SignatureDigest':

digest = SignatureDigest(b"CFRAG_SIGNATURE")
digest.update(bytes(kfrag_id))
digest.update(bytes(commitment))
digest.update(bytes(precursor))

if maybe_delegating_pk:
digest.update(serialize_bool(True))
digest.update(bytes(maybe_delegating_pk))
else:
digest.update(serialize_bool(False))

if maybe_receiving_pk:
digest.update(serialize_bool(True))
digest.update(bytes(maybe_receiving_pk))
else:
digest.update(serialize_bool(False))

return digest


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:
signer = Signer(sk, hashes.SHA256)
return signer.sign_digest(self._digest)

def verify(self, pk: PublicKey, sig: Signature):
return sig.verify_digest(pk, self._digest, hashes.SHA256)


def unsafe_hash_to_point(dst: bytes, data: bytes) -> CurvePoint:
"""
Hashes arbitrary data into a valid EC point of the specified curve,
using the try-and-increment method.
Expand Down
Loading

0 comments on commit d413c64

Please sign in to comment.