Attach a proof to a cfrag on creation unconditionally

pull/258/head
Bogdan Opanchuk 2020-06-03 21:56:50 -07:00
parent 42f1b9db78
commit ca86304432
8 changed files with 108 additions and 217 deletions

View File

@ -114,24 +114,6 @@ def test_cheating_ursula_sends_garbage(kfrags, bobs_keys, ciphertext_and_prepare
assert cleartext == message
def test_cfrag_with_missing_proof_cannot_be_verified(kfrags, prepared_capsule):
cfrags = []
for kfrag in kfrags:
cfrag = pre.reencrypt(kfrag, prepared_capsule)
cfrags.append(cfrag)
# If the proof is lost (e.g., it is chopped off a serialized CFrag or similar),
#  then the CFrag cannot be attached.
cfrags[0].proof = None
with pytest.raises(CapsuleFrag.NoProofProvided):
prepared_capsule.verify_cfrag(cfrags[0])
# The remaining CFrags are fine, so they can be attached correctly
for cfrag in cfrags[1:]:
assert prepared_capsule.verify_cfrag(cfrag)
def test_kfrags_signed_without_correctness_keys(alices_keys, bobs_keys, capsule):
delegating_privkey, signing_privkey = alices_keys
delegating_pubkey = delegating_privkey.get_pubkey()

View File

@ -171,9 +171,9 @@ def test_cfrags():
CapsuleFrag.from_bytes(bytes.fromhex(json_kfrag['cfrag'])))
for json_kfrag in vector_suite['vectors']]
capsule = capsule.with_correctness_keys(delegating=delegating_key,
receiving=receiving_key,
verifying=verifying_key)
prepared_capsule = capsule.with_correctness_keys(delegating=delegating_key,
receiving=receiving_key,
verifying=verifying_key)
for kfrag, cfrag in kfrags_n_cfrags:
assert kfrag.verify(signing_pubkey=verifying_key,
@ -181,10 +181,9 @@ def test_cfrags():
receiving_pubkey=receiving_key), \
'Invalid KFrag {}'.format(kfrag.to_bytes().hex())
new_cfrag = pre.reencrypt(kfrag, capsule, provide_proof=False)
new_cfrag = pre.reencrypt(kfrag, prepared_capsule)
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.point_precursor == cfrag.point_precursor
assert new_cfrag.proof is None
assert cfrag.to_bytes() == new_cfrag.to_bytes()
assert prepared_capsule.verify_cfrag(new_cfrag)

View File

@ -1,53 +0,0 @@
"""
This file is part of pyUmbral.
pyUmbral is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
pyUmbral is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with pyUmbral. If not, see <https://www.gnu.org/licenses/>.
"""
import os
import pytest
from umbral.curvebn import CurveBN
from umbral.cfrags import CapsuleFrag
from umbral.keys import UmbralPrivateKey
from umbral.point import Point
from umbral.pre import Capsule
from umbral.config import default_params
def test_cannot_attach_cfrag_without_proof():
"""
However, even when properly attaching keys, we can't attach the CFrag
if it is unproven.
"""
params = default_params()
capsule = Capsule(params,
point_e=Point.gen_rand(),
point_v=Point.gen_rand(),
bn_sig=CurveBN.gen_rand())
cfrag = CapsuleFrag(point_e1=Point.gen_rand(),
point_v1=Point.gen_rand(),
kfrag_id=os.urandom(10),
point_precursor=Point.gen_rand(),
)
prepared_capsule = capsule.with_correctness_keys(
UmbralPrivateKey.gen_key().get_pubkey(),
UmbralPrivateKey.gen_key().get_pubkey(),
UmbralPrivateKey.gen_key().get_pubkey())
with pytest.raises(cfrag.NoProofProvided):
prepared_capsule.verify_cfrag(cfrag)

View File

@ -19,12 +19,12 @@ from umbral import pre
from umbral.cfrags import CapsuleFrag, CorrectnessProof
def test_cfrag_serialization_with_proof_and_metadata(prepared_capsule, kfrags):
def test_cfrag_serialization_with_metadata(prepared_capsule, kfrags):
# Example of potential metadata to describe the re-encryption request
metadata = b'This is an example of metadata for re-encryption request'
for kfrag in kfrags:
cfrag = pre.reencrypt(kfrag, prepared_capsule, provide_proof=True, metadata=metadata)
cfrag = pre.reencrypt(kfrag, prepared_capsule, metadata=metadata)
cfrag_bytes = cfrag.to_bytes()
proof = cfrag.proof
@ -48,10 +48,10 @@ def test_cfrag_serialization_with_proof_and_metadata(prepared_capsule, kfrags):
assert new_proof.metadata == proof.metadata
def test_cfrag_serialization_with_proof_but_no_metadata(prepared_capsule, kfrags):
def test_cfrag_serialization_no_metadata(prepared_capsule, kfrags):
for kfrag in kfrags:
cfrag = pre.reencrypt(kfrag, prepared_capsule, provide_proof=True)
cfrag = pre.reencrypt(kfrag, prepared_capsule)
cfrag_bytes = cfrag.to_bytes()
proof = cfrag.proof
@ -78,29 +78,8 @@ def test_cfrag_serialization_with_proof_but_no_metadata(prepared_capsule, kfrags
assert new_proof.metadata is None
def test_cfrag_serialization_no_proof_no_metadata(prepared_capsule, kfrags):
for kfrag in kfrags:
cfrag = pre.reencrypt(kfrag, prepared_capsule, provide_proof=False)
cfrag_bytes = cfrag.to_bytes()
proof = cfrag.proof
assert proof is None
assert len(cfrag_bytes) == CapsuleFrag.expected_bytes_length()
new_cfrag = CapsuleFrag.from_bytes(cfrag_bytes)
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.point_precursor == cfrag.point_precursor
new_proof = new_cfrag.proof
assert new_proof is None
def test_correctness_proof_serialization(prepared_capsule, kfrags):
# Example of potential metadata to describe the re-encryption request
metadata = b"This is an example of metadata for re-encryption request"
@ -123,4 +102,3 @@ def test_correctness_proof_serialization(prepared_capsule, kfrags):
assert new_proof.kfrag_signature == proof.kfrag_signature
assert new_proof.metadata == proof.metadata

View File

@ -51,6 +51,56 @@ class CorrectnessProof:
return (bn_size * 3) + (point_size * 4)
@classmethod
def from_kfrag_and_cfrag(cls,
capsule,
kfrag,
cfrag_e1,
cfrag_v1,
metadata: Optional[bytes] = None):
params = capsule.params
# Check correctness of original ciphertext
if not capsule.verify():
raise capsule.NotValid("Capsule verification failed.")
rk = kfrag.bn_key
t = CurveBN.gen_rand(params.curve)
####
# Here are the formulaic constituents shared with `verify_correctness`.
####
e = capsule.point_e
v = capsule.point_v
e1 = cfrag_e1
v1 = cfrag_v1
u = params.u
u1 = kfrag.point_commitment
e2 = t * e # type: Any
v2 = t * v # type: Any
u2 = t * u # type: Any
hash_input = [e, e1, e2, v, v1, v2, u, u1, u2]
if metadata is not None:
hash_input.append(metadata)
h = hash_to_curvebn(*hash_input, params=params, hash_class=ExtendedKeccak)
########
z3 = t + h * rk
return cls(point_e2=e2,
point_v2=v2,
point_kfrag_commitment=u1,
point_kfrag_pok=u2,
bn_sig=z3,
kfrag_signature=kfrag.signature_for_bob,
metadata=metadata,
)
@classmethod
def from_bytes(cls, data: bytes, curve: Optional[Curve] = None) -> 'CorrectnessProof':
"""
@ -98,18 +148,33 @@ class CorrectnessProof:
class CapsuleFrag:
def __init__(self,
point_e1: Point,
point_v1: Point,
kfrag_id: bytes,
point_precursor: Point,
proof: Optional[CorrectnessProof] = None) -> None:
proof: CorrectnessProof) -> None:
self.point_e1 = point_e1
self.point_v1 = point_v1
self.kfrag_id = kfrag_id
self.point_precursor = point_precursor
self.proof = proof
@classmethod
def from_kfrag(cls, capsule, kfrag, metadata):
rk = kfrag.bn_key
e1 = rk * capsule.point_e # type: Any
v1 = rk * capsule.point_v # type: Any
proof = CorrectnessProof.from_kfrag_and_cfrag(capsule, kfrag, e1, v1, metadata)
return cls(point_e1=e1,
point_v1=v1,
kfrag_id=kfrag.id,
point_precursor=kfrag.point_precursor,
proof=proof)
class NoProofProvided(TypeError):
"""
Raised when a cfrag is assessed for correctness, but no proof is attached.
@ -147,8 +212,8 @@ class CapsuleFrag:
)
components = splitter(data, return_remainder=True)
proof = components.pop() or None
components.append(CorrectnessProof.from_bytes(proof, curve) if proof else None)
proof = components.pop()
components.append(CorrectnessProof.from_bytes(proof, curve))
return cls(*components)
@ -160,56 +225,11 @@ class CapsuleFrag:
v1 = self.point_v1.to_bytes()
precursor = self.point_precursor.to_bytes()
serialized_cfrag = e1 + v1 + self.kfrag_id + precursor
if self.proof is not None:
serialized_cfrag += self.proof.to_bytes()
serialized_cfrag = e1 + v1 + self.kfrag_id + precursor + self.proof.to_bytes()
return serialized_cfrag
def prove_correctness(self,
capsule,
kfrag,
metadata: Optional[bytes] = None):
params = capsule.params
# Check correctness of original ciphertext
if not capsule.verify():
raise capsule.NotValid("Capsule verification failed.")
rk = kfrag.bn_key
t = CurveBN.gen_rand(params.curve)
####
# Here are the formulaic constituents shared with `verify_correctness`.
####
e = capsule.point_e
v = capsule.point_v
e1 = self.point_e1
v1 = self.point_v1
u = params.u
u1 = kfrag.point_commitment
e2 = t * e # type: Any
v2 = t * v # type: Any
u2 = t * u # type: Any
hash_input = [e, e1, e2, v, v1, v2, u, u1, u2]
if metadata is not None:
hash_input.append(metadata)
h = hash_to_curvebn(*hash_input, params=params, hash_class=ExtendedKeccak)
########
z3 = t + h * rk
self.attach_proof(e2, v2, u1, u2, metadata=metadata, z3=z3, kfrag_signature=kfrag.signature_for_bob)
def verify_correctness(self, capsule, delegating_pubkey, signing_pubkey, receiving_pubkey) -> bool:
if self.proof is None:
raise CapsuleFrag.NoProofProvided
params = capsule.params
@ -256,24 +276,6 @@ class CapsuleFrag:
& correct_reencryption_of_v \
& correct_rk_commitment
def attach_proof(self,
e2: Point,
v2: Point,
u1: Point,
u2: Point,
z3: CurveBN,
kfrag_signature: Signature,
metadata: Optional[bytes]) -> None:
self.proof = CorrectnessProof(point_e2=e2,
point_v2=v2,
point_kfrag_commitment=u1,
point_kfrag_pok=u2,
bn_sig=z3,
kfrag_signature=kfrag_signature,
metadata=metadata,
)
def __bytes__(self) -> bytes:
return self.to_bytes()

View File

@ -313,33 +313,20 @@ def generate_kfrags(delegating_privkey: UmbralPrivateKey,
def reencrypt(kfrag: KFrag,
prepared_capsule: PreparedCapsule,
provide_proof: bool = True,
metadata: Optional[bytes] = None,
verify_kfrag: bool = True) -> CapsuleFrag:
if not isinstance(prepared_capsule, PreparedCapsule):
raise Capsule.NotValid
capsule = prepared_capsule.capsule
if not capsule.verify():
if not prepared_capsule.verify():
raise Capsule.NotValid
if verify_kfrag:
if not isinstance(kfrag, KFrag) or not prepared_capsule.verify_kfrag(kfrag):
raise KFrag.NotValid
rk = kfrag.bn_key
e1 = rk * capsule.point_e # type: Any
v1 = rk * capsule.point_v # type: Any
cfrag = CapsuleFrag(point_e1=e1, point_v1=v1, kfrag_id=kfrag.id,
point_precursor=kfrag.point_precursor)
if provide_proof:
cfrag.prove_correctness(capsule, kfrag, metadata)
return cfrag
return CapsuleFrag.from_kfrag(prepared_capsule.capsule, kfrag, metadata)
def _encapsulate(alice_pubkey: UmbralPublicKey,

View File

@ -253,7 +253,7 @@ prepared_capsule = capsule.with_correctness_keys(delegating=delegating_key,
vectors = list()
for kfrag in kfrags:
cfrag = pre.reencrypt(kfrag, prepared_capsule, provide_proof=False)
cfrag = pre.reencrypt(kfrag, prepared_capsule)
json_input = {'kfrag': hexlify(kfrag), 'cfrag': hexlify(cfrag)}
vectors.append(json_input)
@ -263,7 +263,7 @@ vector_suite = {
'enclosed Capsule, under the enclosed delegating, '
'verifying and receiving keys. Each CFrag must deserialize '
'correctly and can be replicated with a call to '
'`pre.reencrypt(kfrag, capsule, provide_proof=False)`'),
'`pre.reencrypt(kfrag, capsule)`'),
'params': 'default',
'capsule': hexlify(capsule),
'verifying_key': hexlify(verifying_key),
@ -274,7 +274,3 @@ vector_suite = {
#print(json.dumps(vector_suite, indent=2))
create_test_vector_file(vector_suite, 'vectors_cfrags.json', generate_again=generate_again)

View File

@ -1,51 +1,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 `pre.reencrypt(kfrag, capsule, provide_proof=False)`",
"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 `pre.reencrypt(kfrag, capsule)`",
"params": "default",
"capsule": "03cdaadd5e0493c8426fd65004ea1e10ddcd3fcb37ac87ce84d0ffdda36d8d60720278adf9ca33ea46b2c0fb7b5a14a2820b171a97f8c69846e9866194ed1315438a1a525f615e246d744b82f7283aeba923f38cff0181e9013cfefe4747e32dc076",
"verifying_key": "03714109aee5bded1ea98ced8660ad1d49697e14f2a1bbefd5944e4ce443493d08",
"delegating_key": "021c0e2868064f20441df0050bf501137ec84db6ca3596b88a967308e14bea2caa",
"receiving_key": "036285c48fbb7c38bccceb6e15959a33ed3dd5ab5c96daaff67636b8557d6885d4",
"capsule": "03d74b01025e8f70b5b87ae822b072bcfb95c04050f8ea66f6f14b46a5a81bd48b02b44cfc713495180f81cebf6e8c23dd65caea67576984fd0887959214cce6a21f2c3832da94bbaedc2c99adc14b755fde065a6817d967724bb8a21eba53871426",
"verifying_key": "022cd71400ce39fa3960e8b2e1d49caff02872568eec3059d58d1815dd281ebeb8",
"delegating_key": "029f1aa43e74b0c1066f170f08b4d0cd0d04bee9d43e8ffabe4a5d5b8d5e0680b5",
"receiving_key": "03f4ced4b78d28f0bebcdc0a5b2e4e09cfc3e8e1f9f60694a6a18a0fe4df1407f0",
"vectors": [
{
"kfrag": "417225b396fb91a82f0ed97b4dfb235200742a58d9632d46e352e507c5c716863b349c46905501861f950d11aefd2c69a1f4fe31ae91b4c8624c7556ec7d01ef026fa5450221297328a37043220b0f82a7fdf2a4ab01c9b30cd572181736390ad303b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f4103428244169c9d2d3cfefa6b88251e7600c4a6f9a4edb5e371a0af7bc5134bf68ce9ad3b8a1acbd66926687e2cf7a30762527a85d41b1eaee133866df9dc4fe49b43601bb4d9b496f59e44e2e172141f9480bad0cfda18e5dd6c8dd7a5e72b4bc59281ed11ba75b87f7f1919c30b56d7f0c522b77fd15d37f893fc784eb77d1493",
"cfrag": "02aa6a41b809ba8d2816444788d597e6af5b81c56f7645f67e8dde417fca052828027adba799a3cf3935abb5366b5ec3f132f05a9baa0647734e7be50952e3309bd2417225b396fb91a82f0ed97b4dfb235200742a58d9632d46e352e507c5c7168603b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f41"
"kfrag": "c94bd4e8f40ebc7c419072017dee1d1b04fa4a479cc7ec089bf9701cd20ade01e66c779fe816f9fa2f32c29aecd997c895e2edf6e473e84082c7eabd83816437023d0b6563680361fed39a65e2df3015ac19495e4d585c01054c368d4c008302ec029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c1703d78121d9986b58ceb0f54aa52545268d0e3dc854313d2f0af9acb5f6d0518829a90c4377efb6b944c1909213a79b7e62084c338e1e417417d16c845c7a62cab81026dedfc8207f85142781934ed19238d15cc51fad435946d2b781acdbb677c5e44184ac96775dbf93b80c2ec72794d76a4be74a8f97bd3ebf67d4ab597848b6",
"cfrag": "03d22a6266547f90269ad6f33a9c70085062ec87335aaff8b4650094801eaea64d02deff505d8858d202405e63c037d7cc2544c5ad5bf03e6dcfdc147c265c0177ddc94bd4e8f40ebc7c419072017dee1d1b04fa4a479cc7ec089bf9701cd20ade01029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c17022a80eede24a533aabd47f1318a3fe505dc6abe381d68f5aa529719d082eb0d91027b5366d5de9da98c9e6f090e4f35f730af31a323c7ea91c7e248a7296ac7a5b7023d0b6563680361fed39a65e2df3015ac19495e4d585c01054c368d4c008302ec02c200aa2672c0855e9b678089e95f8423ed7156f758fa9f47c7e6a30dc6b972ffe75ddb893571948303b144d415fb9d6d206289f477674afbfaddbbfa5b624bd91026dedfc8207f85142781934ed19238d15cc51fad435946d2b781acdbb677c5e44184ac96775dbf93b80c2ec72794d76a4be74a8f97bd3ebf67d4ab597848b6"
},
{
"kfrag": "fe11bce6ea1d451fbe396c6c7d00747264324eebc93bd6ca9e949c2970be214e56571ecd1c02064be2058043cbe5d7ddde90771c5709c1cb48f2a4866bef246b03cb7014d5978aba65b7849bc5756d0e94ce515cc31725ed86550e4e38424b63d903b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f4103adbaf6ef97a68ad61ca39b1ab244b5d1881b00fbf7e2f0eec06907a0078ec4fcb573d101c2d1976985fa7d6d7c96b327030333ac3c66fc0223b456a70e996e19a31822dea4781891b054e86ff34abbfcce05f7c613b7296133ad5b10455061368a102dff42a913edb8e5d248a8d979879a3cfca1f8d3fbf6b8a24ca5357ae057",
"cfrag": "03bfcdf5dafbc9482fab6da942ed7849869d92333a815e9e81116eeff31a97ac680243d1d352ea857eef383300d41f1e1df14d00beb54abd43bc112c2d8af98e4be7fe11bce6ea1d451fbe396c6c7d00747264324eebc93bd6ca9e949c2970be214e03b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f41"
"kfrag": "346750cc1e84357a4d021156582636d34d56c68a5318c7bfe0b4808d5fc2b757e9c457cc80aae0def31acbb69b0a409d24a56c4c8f003af3b11fa9743d8a3ce003c9182c5702d8315fbcfe2e0554b8827abfde1e03fab05c5c883892f5bf744f83029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c1703f3724721e57e61dbf36ab345b4c193e86255270fa059e89e3d74671f0efe2aae36c0f4e87ffa1583dc505b6653d015d48c98eb72e9739ad072d2e35f77081d1a596be7e93bf8f4f629320fa7be3a30c5ef4f95801a57857d512098589b0f4ad8f973cc70c61e43048c94d583bee6f9b433db57b2e9d077779d3f15df029b4cb8",
"cfrag": "0384a12bb38a7690a3f36349b45b602ded0cc0bfb6c3447320c5baa54fe7b810b70202d8beff7024c2f4acb79e288f8d966c0bd1ff99f843e9362fe762bce574ce3f346750cc1e84357a4d021156582636d34d56c68a5318c7bfe0b4808d5fc2b757029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c1703bc426be443826cd6389856361042efda977f33754eec76b2aacd9a992d33c87f02e3a2fa88b5333aaed3f69a95ee3c12ba114cdfe791bb07f54e06a658baffeb4a03c9182c5702d8315fbcfe2e0554b8827abfde1e03fab05c5c883892f5bf744f830306d77dd485835aa62e768fa4cd5385949b4ca1b0e99295d1435994eeba7dddc1a07817f4f2f4b99a733d08c604815ecf90276ba195635c7cbddd38b1c505fff0596be7e93bf8f4f629320fa7be3a30c5ef4f95801a57857d512098589b0f4ad8f973cc70c61e43048c94d583bee6f9b433db57b2e9d077779d3f15df029b4cb8"
},
{
"kfrag": "4edffcacb49f5620c1cebd67f43366aa22dc380dd9fd0f4853ffbbd44e31986f4a99f953e5c553f08a83cb16c0b5c793a4f691d4d3d239e29f232d2b058970d903041b77b8891d845c240a8a12b71dfe9651de67ceb817b54eb578636fe8a9605103b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f41035ba90e2a06117e205dd807c780b5687ff6dadf19454fffb367e7af6b3f9cadf03572dc3311c0e1706354ba3340d1b1f915afc82007f9e09ddd34ce07a038a7bb7ecc7343b1532b175e5b8c7d3c712e3eecb18ff69c22237ba9ab6b47b4572529a35b29c48874f396def9971c0230a51e26975a953ff87af8fdbfd53bf42aae07",
"cfrag": "02c6870bd1336ec336752ce7d6b99f36d3ae69983d7a06cb5a743f20c562c0b2ba037fb7d9db1faf763c49e257f906e3345e33df144eeba8b9794462a31a305459c44edffcacb49f5620c1cebd67f43366aa22dc380dd9fd0f4853ffbbd44e31986f03b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f41"
"kfrag": "f3f77f104f3233411cf92ac06193dbd9c0d9b777811fdc9f390b970c190f310f683e6d3e1818dba5cf761e504e7e91ee65cd2077243923831d13c4914d5d841e022da6c0726594b2d0d069a99813c37ca0c3678b24db738e9519f51008359d0448029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c1703b9e92d952024c509c8e5b60a92a1b45e6206df34c0e8ede315bfae0c5effbf16babbb655b77d37846cbad6e3d73393ab5cca7e0ba5c086ddc85fd11d94fc0f2f2c54d043d179b31c2fe3524c9611e6b1d63101fb5912aa6416412507814303a1c4c04e1e24ac9437351bb46c2f64bd613e6a359b8d0c369412afa125666c2f64",
"cfrag": "03428aefe67e03e8f67a125bc918ff9c8c07ff5d42834bb27fec6eb7a31e3437f102f7970be7162a1a0bd4f0a0000a47a15f92b121bd97d522a89b82ba95b8d3f845f3f77f104f3233411cf92ac06193dbd9c0d9b777811fdc9f390b970c190f310f029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c1702a12964bff7d175237bb110c046abd0e01acabc0230128596b6e1e14dc31037e60361676f420729c0d1100d16284e7284ba951991328540feccd42da7f7d734e108022da6c0726594b2d0d069a99813c37ca0c3678b24db738e9519f51008359d0448039eb0759e0b4fbdec3fc293a5284903e3f720bc5435e544d9956a1909c4fe97a335130aeb72ece9797865a1a52caef2a2f5669fb67c8ce04542b4c70550aea8da2c54d043d179b31c2fe3524c9611e6b1d63101fb5912aa6416412507814303a1c4c04e1e24ac9437351bb46c2f64bd613e6a359b8d0c369412afa125666c2f64"
},
{
"kfrag": "762a4ae9fdbb74de327a29d25c577c46521ee44a951c6e33739e5ceb2a340aefd2a93d8cbe37b9149dd26ce59b0b7ffcd9adf1ca822c5b477595ecba1933291503409c76b74f0f415f5b6a8421514c250f71a5c5b6c5b0d89148e03ba2a624a9a503b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f41034f04b1666bc36ac5d3b7ba66420b660d19caf9a995b6cc7cc0aa7c9d0e739f25b1048e754ffd0703e16b453ae8279e5410eb16d2d53683f2d80c30c39918834d70970a09ae17c014fc939979c1e3659b92a40d8688ed77861407316a22d4a8e0b5628c5eec0a2123129ebdb627eae78f8c404f8e129dd407feb2e970b0ba5e39",
"cfrag": "038bbe8c32677553121c7b708c4266e85930ae38541fec43df9b4eb131fcda4b06036ab69b2d77584016302c8391a13bc821811fe8837bd28523ad04081faa6fc498762a4ae9fdbb74de327a29d25c577c46521ee44a951c6e33739e5ceb2a340aef03b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f41"
"kfrag": "846f07cee40b8e76842382c3ff91860deb151f0dde8fd94069eccd36bed52dae4d1999538387c6a65bf1315c645a3147463d100971f59048fee96d6dbffab76602ac30dc810051bd7081378dacf5f9a3cda2049559a2055d7044a13c279d1321cd029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c17035f1801cc965509c5974c73c4d073f0cb23dcdbd595a5e679dfda88a672f007c48ae07466b349cd815da282141a4b77561d86a08c9126541b51825bf1f224b7f1ff62af8def02dcd1035505d68d3fa7612485532a4340ed8b6da1526377d028d5d2ffb34fa41e3ca0cedfa2c13c5c850f0efe7b90347de2aca1ac861b3e51ad90",
"cfrag": "033297024ba5306348cc5bae8222ebd9be691c0a80ef8a499d2e21e514a282d04403f8f9b51c43e28d41abd0ea7f456c6144b8b5a7d52f3a804989960f6d5f4c1e44846f07cee40b8e76842382c3ff91860deb151f0dde8fd94069eccd36bed52dae029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c17025432cb08c56fe7a219e135eb3f7bfffc2824b56c77ddb8425d172fa030ed017403f22028bbd0ddee3a518190a9ad2e656a1b51d46c81e70fe54d7c203ae5cd0a4502ac30dc810051bd7081378dacf5f9a3cda2049559a2055d7044a13c279d1321cd02cf7f9d30039a3dfb39a8f14dd3468bd409a4908f245cdec19e36d76c3b9b01b817ddf591e95693b5e4691cbc5939e9083537048336e979b81891d22f7c3ca0b3ff62af8def02dcd1035505d68d3fa7612485532a4340ed8b6da1526377d028d5d2ffb34fa41e3ca0cedfa2c13c5c850f0efe7b90347de2aca1ac861b3e51ad90"
},
{
"kfrag": "b40778198920434d132c4d3724a7b7422428c9921bd627710c3764a6c54376f6a03be8af10cb0f1c3b74d132dda5feeb4340a9f6213da859c05b6b57249e54e903e9198cc0e86b880251931ab162130f93242164a5b242015195290ba75b5a6bea03b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f4103f27829a4798466ed68c2c53137e4e658e86faebfabf2556837b60b502a1721de3e073a98974686d1b847c27167f118eeea6a27029775800cb1618b393bca9cc35b341b546c8851395b3b68945b73b01fdbe94a9f6c400b22bfb5e3bebeee95887d888c49ccf99553a2941de1cbd3f845c5725d1b6b26017dea5cf161fadb5fda",
"cfrag": "020604cacae76ef0f2a81a582b2c642accc4bc9d29ea9b172211a3d8225cfc4975026ac1a78becd4be2f09b939b3bdac3901bbeec488ab1013965c40565034586824b40778198920434d132c4d3724a7b7422428c9921bd627710c3764a6c54376f603b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f41"
"kfrag": "cfa1e6c88dda69acd16b82230c62b0e4d244192967093c852697eadb3a968bfbe50be9518e07947ab46116ef82587588f16265ad2a8869ff0dd33679fe76c53b037b09f7d2ad9912be527a582c32b241894701f5a4f23b09bcc7d97c3f14be880d029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c170389f298c2ae926e708e04ca683c8412daf649764fae3646db8b0d7dfc2dc07f41478dfdd97cf384d2185291850bbfadb8f8792ece9fc93e144434b2a2918eb85b7a5a7fe7e010987f808fcb9e6c854d0ecb34d03431b13f0198fab53f572b0e2e7f507159dd9ae78a7d738a6759914602fe800a9e321b7137484e32c3f78b0534",
"cfrag": "03e5d1c3e2a6e18e2c84bff336866cbc7ba25540317001f023e3d10d308c328781022fc7fd471ae26228ff3e55a1f10e939cf5eabf4601f72cda5e605890962979c1cfa1e6c88dda69acd16b82230c62b0e4d244192967093c852697eadb3a968bfb029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c1702fb0e61b5d22ae8ce1c781cd52358fa4126631a5bf8a414137aa8b051029bf85d02bdba9b9c354b8c27806202aadc8522bb1f14cc8552b48ec79972245e7ad216ba037b09f7d2ad9912be527a582c32b241894701f5a4f23b09bcc7d97c3f14be880d03cb5bb6a7a4ebdd3dfb6e5d8628bd8eea142e38187f79edf91522f11919c28fe24d99d9b256679dafd0c5c49a2b3b98bf081081a1195acdc5bef4124c759ba1c27a5a7fe7e010987f808fcb9e6c854d0ecb34d03431b13f0198fab53f572b0e2e7f507159dd9ae78a7d738a6759914602fe800a9e321b7137484e32c3f78b0534"
},
{
"kfrag": "bb063b1ae2a2e2c804671a40571b5d9a7746a7b11b98fd1794207daf68e8d408e4ad0acf429b3e97d7d098766cf304fc43454a79d541a8e85cd95ee93b7bfb460242325b9a16de25bca5ce9225091b2d9eec4b98fa627f6c2fec591cfba3561bd303b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f41034c2742c62c69c571623a751dc842998cc47a6d33c7e2d30e099bc10d2675fa8bed049ff1474d604eb97e6c1b997dc506bfcefd6aed3838db23fd08f0cebe176fad3a0c5734d986b506145f0770e6689eb1425eb2817d699be1c993d64b26f2dd59d3acf01c5372adabebaa04336ff03219eadf1fd085a6957bd5e90b83919774",
"cfrag": "022edd320a1560725a60c8116810ac0debf2595bdf274510477181e37e1ce9684c02b56d7468d8a29c5034602dd1960d4a09cc19edf11fd7b90b536a0463f465854bbb063b1ae2a2e2c804671a40571b5d9a7746a7b11b98fd1794207daf68e8d40803b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f41"
"kfrag": "644a9ca35d12fa02acfce67c4c148a7a3f349f05f3ccbe91f05515e16c6e8354da9b537cc1d9798e06a027800bc095a207dd6150aec3f94f71d9a303caf5780e0226328fdd2f804035f671696b4d54776d5eb145c1f731bb9c5af13a2a066baf04029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c1703affbd37c20ce2a84dc0ef8935e0d4281309c898e70e98479fc9d34ece079d834960a70daec268b72ffd403b8a07377adf233e242aff32f63ffeecccd51b8ae2e8629a63165987ec6a6ce3630ccf380f365b880e493bdff130b44c62022ac464bb0059fd4bd06f71fcac83bd0c0d869cd979fc0a6519336d4b8807f8bdb8c09e9",
"cfrag": "03bc92b35ee469a07e2537b3cdcf67f711fda741c80c7412d04cd3efbe9c0f885d02f2e2b5eb391c8d7cabb5e40924609042beecaed21cde17cd7303502599d9ae11644a9ca35d12fa02acfce67c4c148a7a3f349f05f3ccbe91f05515e16c6e8354029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c1703fc0a37748ec9712319336179245fec2dc4250495e5117b76c82c7a2a769be4d60315da4fda16d09d90ff67ff8ffc85191a43617f43e31e5ccfdc954784909633000226328fdd2f804035f671696b4d54776d5eb145c1f731bb9c5af13a2a066baf0403a1984bd77a6eb766d91eae5d18233fe97752ab4dd103cccdbf8bd294592a51c379701c31c31f357be8bb293b1e299beabe7d7cb878d9a8fa5de9d6d12e7f1a138629a63165987ec6a6ce3630ccf380f365b880e493bdff130b44c62022ac464bb0059fd4bd06f71fcac83bd0c0d869cd979fc0a6519336d4b8807f8bdb8c09e9"
},
{
"kfrag": "9a2d97e3bba40307b7c60f6f22c5965f6587206cef4d5d7980ad8d75f0f4ae69de90b3ac071a58a06c4d2d0895db9e71a4f36b86fd078dfce6e436514f70797d03d959ebb3d7ee2fd90f2a390da0d7377f7549877f7720739e7e84e0c488a6d16203b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f410394ba445cfe40a9ebf1bc6a6f9588b704b11b129a2a102e8c5bf892fbb695e2d37d396c1b34f8eed4f348ecb11a29fa2b68c3790ef2ddc169e6fa7dc86e03b1a7fd8faf67773903168ee5f9c2ac60468cd81c7ee389af0f03f3fed356c65e7f182faa22867aa4544554d235f78d28afe7d90fff1cf60184bb1ea947a343c13d07",
"cfrag": "035f87f2fecce4d4734a01d444e3614e2f32be3f9277373f1338ddb0044a4b79ae03a604f360df7cb23097d7b49826088bd3628d82f601f2b4ea9262931c3b4bc5809a2d97e3bba40307b7c60f6f22c5965f6587206cef4d5d7980ad8d75f0f4ae6903b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f41"
"kfrag": "94a4b220fdc66fedb4265cd31567536076de1e30849871f40347fbec9a1926ad01070f7a0dcd779e989396161c3f5ebb4c0ec85eb73dc3266dad490253f1303b02fb8e3d5fc5fc8262801347ce295ddd584e30ba86b2bf7cc1e5007d686c027059029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c170386e37413c2928ef15915392e558d5126b6bd99b6f6abe36a6540fa9ed34a5814da52b649017ac7d983cb8949e1180698cfa52926a65013fd67008c11e6758084bf75dd2269a2a7fcbda7b161ba94684368e8a934867c72cd602dc97dbd2ce1416c74d45cf0f1c571888f4bed802429d9942bd5cac5af9dfcb54f0c68c43be0e3",
"cfrag": "03eb381cc33d44414b4c1396fb2defcb558cda34a6a151905a0baadc899cc221de026ec933bfb218ebe2268c5c515d6be3c851846e8f778c8bc83429f5f04015308494a4b220fdc66fedb4265cd31567536076de1e30849871f40347fbec9a1926ad029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c17037e68de4df577310ffecb5e7756e2c47d075477d105d6cecf777f1391537c19b8020cc6b50471a0f4b27f23172c77c05304e83228c9f1ffe0d37dec260f0b27b18f02fb8e3d5fc5fc8262801347ce295ddd584e30ba86b2bf7cc1e5007d686c0270590282117ed9bb889a0abbcf56b75b59914f08a17bda9396e546a183afedac16fb17298ef9920de9a6d85ed7e9c883fefc4d73f3fbdcde3e75dd3ce02abbbb1e12fcbf75dd2269a2a7fcbda7b161ba94684368e8a934867c72cd602dc97dbd2ce1416c74d45cf0f1c571888f4bed802429d9942bd5cac5af9dfcb54f0c68c43be0e3"
},
{
"kfrag": "3d09cbb50ab9ff970c93a03976efaf5f13aef88fc4e1b8840cebad96d0469605b343d7f3d4297ada1fcc08009260250f29dbb64bfb6dd64c2dd72174be3d87a202f665886dabd4fd94513aa1082a403efcb9722115e7c44f8ce5394799e10c2ca203b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f41037ec97969ef20834c753f460c1c29360ce535cb19e0dd0da3bc9c568157137c3f741dadb514586112bfa22c4aa64c28ba854f7393a04ce77a3c4b731e6eaa41e29f2d240b3adf5a973688c7691e8bde140647f4d2c4d0c06a0d690415a82f18f095fb69a084607734579a590c6d1e477d93716919c67d6627a890fa5a2250109a",
"cfrag": "0321674813fe3ba72c9164b7016299862ce1efdbf57c7eef83bd4d3f6535bc3eae03940fdcd41dfaeb7667a0d2a3e929944ea6a3c2c6d7e9f2fff4265ffb011169b53d09cbb50ab9ff970c93a03976efaf5f13aef88fc4e1b8840cebad96d046960503b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f41"
"kfrag": "c0e69d918527a6a4e4c780c1d18e71ac6bf380a5c2b03eebee6e39d94dfda0d77af3d831a7cfe31b9a3c9439bc6179270e7415925d07d8a437d15149c27dfdf903f7b31324874db68b388bd0c583d2ba5eea7d77d955d7dbf9aed96be4372baff2029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c1703960f432c415cb1198337c835179c7d57f8f604b88d8e0bd75c5093dc7f97952d2b2ea2b3b038a101ee16ac966e8992c79f5fd706c32be51d977ac44ffc43e9fe2e0188e52e4c0867fdb9c077b72d9f147df90ac3d72dc399c6cd3368b2fef2e9df195ff0099c2ebdc1c740761050b94be48555c7c4d01dcd9b7d22f10780210f",
"cfrag": "02357b9861868fd5175dc26fda451aaf8d11c395f07f4f7854026752686ecd3e4c03a7338d0c6fc4ae414290a10f4f6d60a71be774f7553532c544a9de5248468e0dc0e69d918527a6a4e4c780c1d18e71ac6bf380a5c2b03eebee6e39d94dfda0d7029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c1702e0e941cf70e030f65d7a9abcf63170425930d77960c1515f49f2428d1be2042302df32b921f5d6b3dd6d96e1e4ab4e0a0e7a4492d7bbb1113327321e2cad83e47c03f7b31324874db68b388bd0c583d2ba5eea7d77d955d7dbf9aed96be4372baff203eb187837654ed629e64e938662efdc174ff9440523860cb50504faf9c759dab57caa4d7520f002003434554ec6e566e2a1ae736dceb044d4330b395ceae0c87f2e0188e52e4c0867fdb9c077b72d9f147df90ac3d72dc399c6cd3368b2fef2e9df195ff0099c2ebdc1c740761050b94be48555c7c4d01dcd9b7d22f10780210f"
},
{
"kfrag": "71c39f563bdda903d8397370b077ba1348e07cf644eaffdfbca251f63d8e0c8377d0f143019bca10090a07c15ab9d6d71857451443e0e77ca6768b45b93892b802b54fd786330796eebd5df0a7d5dc26422177d5637028aaea293dfa223a72a56203b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f4103aaaf48203b37dc6152c0735493517a31284be4c46b57a21f01359572d1e1e3d1b0fd64fc82efb401f25dab88e48474450b274625c28e16cb51f31259206aba6fe4886083237bdb5f7da67c8e1e2da7fdef57789c919ccceae6b5453eaa22fb6dcb58a2f9f1f20f05d03326031d4817ec52cf3dc9eb37f2d3b014ba315f5b8c16",
"cfrag": "02b37b1fc91e5d99f8249e6c70d19ac9af80cfeab42d2c8b5dbb43b791e5818c480345339e46528e5f7f2d48ab5dd6ba50dc7a44ed7a99a9ef0cee902839076f13a671c39f563bdda903d8397370b077ba1348e07cf644eaffdfbca251f63d8e0c8303b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f41"
"kfrag": "b6e087c707f8ab585b5490af3cacde266763d3bdcd1075cc7b97ff280ddc44e8f405a594c7c619d41a7d3a5a6c4a9decb3c0adcf29cbaec419dc719894a88da8025fa3ed133f204bea48e26af459c22b03cbcf6389cc75fea29598579268b02f61029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c17038ac3c89a5165073c727bcfc91d9b9cb6368d17193eefc027ca271656de1a85469e62be34261feaf68bc327e91113b93d6e4dc48dbb288adab839c550496260378b9bdf534e071fc1f268c602299c14604c0c380b6e88364d552dcd0d296b5fcd5ff07c5edef157edc5365bb32621d31a0509475b872b02e70fb738c19f5200eb",
"cfrag": "03a3baeb8101788fcb1b35c71711bc93a72f5b076dd510c07a2cf1b0b7d8cb32aa03555fb258dfa90b71057c8419d6f63546a477f109a43de517a42d99c29d30597db6e087c707f8ab585b5490af3cacde266763d3bdcd1075cc7b97ff280ddc44e8029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c17024e2b530f571b447d6d922494ed1f4e98a3b03e81ea4ec3e81d441cb28a97710b03d295026073309a1a805eddf1655602d32a1e60ba106820dfa24bb3fb874346cd025fa3ed133f204bea48e26af459c22b03cbcf6389cc75fea29598579268b02f6102ae20a6e66a236b882ad1e0a920d59050fb9bb571af4cb4779175508477546842ab77591f876765676d28093e009824eeb12a67d9772919da96dc64bc033e61768b9bdf534e071fc1f268c602299c14604c0c380b6e88364d552dcd0d296b5fcd5ff07c5edef157edc5365bb32621d31a0509475b872b02e70fb738c19f5200eb"
},
{
"kfrag": "55faf9c9be6d59da90b2c2e9f09d85e3965e00629b31c3854367f86039725ecb5c560659b6dc7d16a5f3202da0489aa02cbbabb65d8e1107c3645ca7e5bf36c3020e06cdf7d03bafc42e77c86d07b76840ffa7db6a5c511f3530d44b34edb69aba03b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f4103f5674cd594e92cace034b8b443a7aae0ae48ed57ca9eeca5ad6e2855334a989c0ea976c30e4f5eb2527b01caa468f150db4a19cae08ba6015df41fc07d4ea6bb33433a543608fd59cacba037daecf6e069f0954ce9a5f1651297c28cf31fdf76b655ed10284f5bb436c93934bb89b2434b7ff9f7bcb414b3e879a5571c88a0b1",
"cfrag": "03a48d0c6578a259efdebdf0b12ab6e1d29b472a520a1f14ecf628eb161a386ce2021ab6cafd3c7778bef9c199911306939ed679e7b4c09fbbd02c897f994417a81f55faf9c9be6d59da90b2c2e9f09d85e3965e00629b31c3854367f86039725ecb03b890c5614684ac49f59bae91f699cf15761d4c994e0561a1dd570d8dc1081f41"
"kfrag": "38872a618b247cc7425dd03aacd50396f289bb353058021c6e3b23cf1e21d61ceb1f5967aa9807da9bdd5da3f581badfa3ae62048f8b858baeb47d6182d73d990232b6fa13c4198a56e1cc5c0b04b46d50711082d42d6227b61b21c47684349a9a029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c170395c0b8a1858e8b623db2f002bc0d916a10113f8a2d17c4a374efa311ae63e8440be7d75c5ed3f499a88062178db1c344d99151aeb2b227a96a65e54c6624ee1f072efdd1911011ae3b30e0530fa8d768a64f72cd9b9b25b84b3085a3306f98f4c19044db37269cacb17abdd1c1a1b479694406cf3824c2d0946c8a9d09800639",
"cfrag": "022694fbf8a1eb257bd941c01a9da99afabc30124b9ca37783ac0de2b20a163e40029a7ccca34c52b6eb8a6ad725b8288b4469f4708a2c83b4384d2a08221d63b5be38872a618b247cc7425dd03aacd50396f289bb353058021c6e3b23cf1e21d61c029a06618df6b941dd9ed0d94ef876fd93ace6b2d3a7ae1de2aba1426c0e843c1703bc9895efb9242603e1bc7880b40bd6147e8b5453e6393114c52f1730d38b05810373655421d8c42cf99ca324733493f12d542c234ba99c9590538ebea682662fce0232b6fa13c4198a56e1cc5c0b04b46d50711082d42d6227b61b21c47684349a9a0271a560c3f4329a2cd18f273ef729c89545190f63ce43430c48a01f937e2e8bdd2305e530800eb059eda71ac31588dbedd86ed3219371594dd25b5e1f77ed66fb072efdd1911011ae3b30e0530fa8d768a64f72cd9b9b25b84b3085a3306f98f4c19044db37269cacb17abdd1c1a1b479694406cf3824c2d0946c8a9d09800639"
}
]
}