Skip to content

Commit 76841bf

Browse files
mzk-vctashcherbakov
authored andcommitted
Support of state proofs in client (#394)
* bls signatures charm-based implementation * bls infrustructure and hierarchy * sign one msg * implement bls_key_registry; support seed for BLS keys * fix tests * expect all data in str * bls-bft implementation * bls-bft implementation * fix tests * call BLS validate COMMIT in replica * add BLS_KEY to Node txn * add init_bls_keys script * fix init script * support calculation of multi-sig; add gc * rename test_send_txns_no_bls to test_send_txns_partial_bls to make it match file name and purpose * fix conditions and getting of public key by node name in BlsBftPlenum * modify tests to avoid 3pc batching * make replica add bls signature to COMMIT message * change signature of calculate_multi_sig to let it return optional str * add test_send_txns_full_bls test * make replica register own commit in bls registry * move docstrings from BlsBftPlenum to BlsBft * add base class for BLS validation errors * raise exception if validation of bls signature for commit failed * add validate_multi_sig method to BlsBft * make BlsBftPlenum raise exceptions in validation methods and do not store commits * comment raising of exception if there is no signature since it is allowed as of now * update test_validate_pre_prepare_incorrect_multi_sig * in replica handle exceptions from bls * update tests in test_bls_bft.py to make them test multisig using prepares instead of commits * move signatures from commit to prepares as it is described in design doc * remove debug logging and unused import * make replica add latest multi-sig to preprepare * create BlsMultiSignatureField validator and test for it * remove redundant test case for BlsMultiSignature message * update test of validation of commit and prepare preprepare messages * use BlsMultiSignatureField instead of BlsMultiSignature in preprepare * use multi-sig as a tuple instead of a dict * propagate primaries multisig to other nodes * return bls signature back to commit * add log for saving multi sig * use multisig for domain ledger only * fix tests in test_primary_selector * fix test for commit message * fix name of test_send_txns_full_bls test * add signarue for current batch to preprepare * refactor verification methods of BlsBftPlenum * update test of PrePrepare message * Add key value bls store * Save on master instance only * check if multisig is none before handling it * add missing empty line * pass bls store to domain request handler * add bls_Store to TestNode * fix broken import of PREPARE * add constants for state proof fields * exclude state proof from checking of rreply equality * Integrate indy_crypto lib * fix excluding of state_proof fromr replies * Add indy-crypto factory * New indy-crypto api * Final indy_crypto doc * add correct root hash to multi singature in preprepare * create class for multi signature * use MultiSignature in bls_bft * add todo about updating BlsMultiSignature message * add checks of multi sig fields * init bls keys in tests * send BLS sigs in COMMITs only * use MultiSignature in BlsStore * add as_dict and define __eq__ in MultiSignature * use MultiSignature in BlsBftPlenum * Add new dep python3-indy-crypto to install req * blskey support * remove redundant args * update signatures, remove validation of prepare, use MultiSignature * Make generator type str * remove sig from (pre)prepare, add state to commit * Add blsfactoryindycrypto; add dedicated seed for bls * support 48-bit seed * disable charm-based tests * re-factored bls_bft move all bls-related logic from replica to bls_bft * re-factored bls_bft move all bls-related logic from replica to bls_bft * use pool_state for multi-sig * fixes * fixed tests * Edit docker file to install indy-crypto (#384) * Edit docker file to install indy-crypto (#384) * pass pool_state to bls_bft * fix static validation errors * fix static validation errors * fix static validation errors * fix static validation errors * fix static validation errors * add txn time to nym * Bls storage (#387) * Edit docker file to install indy-crypto * Change libindy-crypto source to sovrin repo instead of wget it * remove bls multisig message test * use pool_state_root; get rid of charm-code * use correct pool_state_root for multi-sig * update tests * fix tests * support getting a value for a specified root * create bls keys in initLocalKeys * return bls key in initLocalKeys * update usages of initLocalKeys * generate bls keys not only for local nodes * fix static code validation errors * get BLS keys for the given pool root state * extend tests * add checking of proof in hasConsensus * add base implementation of take_one_proved * add use_bls param to initNodeKeysForBothStacks * continue implementation of state proof in cli * use bls_bft for checking multi sig in client * add tests for BLS sig consensus * enable BLS for domain ledger only * fix tests to include BLS keys into NODE txn for new nodes * rename request param to reply * use one method for making both key and value * use list instead of tuple when creating PrePrepare to have correct equal * more bls_bft tests; improve logging * change arg list of BlsFactoryIndyCrypto in create_bls_bft * fix usage of initLocalKeys gen_steward_key * fix code review findings * refactor hasConsensus * add docs * use bls crypto for checking multisignature * fix signature of getReply * exclude state proof from quorum check * build and install python3-indy-crypto with libindy-crypto dependency (needs to be re-factored) * load bls keys in Client * move here make_proof from indy-node * fix quorum condition * comment out early init of bls_node_public_keys * create special class for multi sig verification * fix json serializer * fix verification of state proof in client * make test node and client add proof for some reqs * add test for state proofs on client * use 'buy' instead of 'hello' for state proof checks * remove unused imports * fix indentation * remove unused method * fcreate base64 serializer * user serializers instead of direct usage of base* * remove unused exit line * check that number of participants in multisig >= f * fix quorumed; check number of participants * create mostCommonElementWithFreq * update logic of take_one_quorumed * merge mostCommonElementWithFreq nad mostCommonElement * update signature of mostCommonElement * fix formatting if objSearchReplace signature * use None instead of set() as default arg val * use bls quorum instead of reply quorum for participants * change log level to warning for replies * use named serializers in make_proof * fix formatting * introduce lazy_field decorator * create bls_key_register_pool_manager_ledger * rake ledger instead of pool_manager in BlsKeyRegisterPoolManagerLedger * rename BlsKeyRegisterPoolmanagerLedger to BlsKeyRegisterPoolLedger * use BlsKeyRegisterPoolLedgerin client * fix proof validation on client * make IndyCryptoMultiSigVerifier get GroupParams instead of Generator * create MultiSignatureVerifier abstract class * support MultiSignatureVerifier in crypto factory * create verifier using factory in client * create utility method for creation of full root hash * use utility method create_full_root_hash * fix active waiting when there is no messages * add check_sufficient_replies_received util method it uses client's hasConsensus * fix logging of request id in client * make client check if multi signature empty * use check_sufficient_replies_received in tests * use check_sufficient_replies_received in waitForSufficientRepliesForRequests * remove fVal param from sendReqsToNodesAndVerifySuffReplies * tmp warkaround: remove state proof from catchup reply * update buy in sendRepliesToClients * remove debug loop * transform generator to list * make take_one_proved return result instead of reply * in client use create_default_bls_crypto_factory * change instId to 0 to fix test
1 parent abdb4d7 commit 76841bf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+643
-273
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import base64
2+
from common.serializers.mapping_serializer import MappingSerializer
3+
4+
5+
class Base64Serializer(MappingSerializer):
6+
def serialize(self, data, fields=None, toBytes=False):
7+
return base64.b64encode(data)
8+
9+
def deserialize(self, data, fields=None):
10+
return base64.b64decode(data)

common/serializers/serialization.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from typing import Mapping
22

33
from common.serializers.base58_serializer import Base58Serializer
4+
from common.serializers.base64_serializer import Base64Serializer
45
from common.serializers.json_serializer import JsonSerializer
56
from common.serializers.msgpack_serializer import MsgPackSerializer
67
from common.serializers.signing_serializer import SigningSerializer
@@ -13,6 +14,7 @@
1314
client_req_rep_store_serializer = JsonSerializer()
1415
multi_sig_store_serializer = JsonSerializer()
1516
state_roots_serializer = Base58Serializer()
17+
proof_nodes_serializer = Base64Serializer()
1618

1719

1820
def serialize_msg_for_signing(msg: Mapping, topLevelKeysToIgnore=None):

crypto/bls/bls_factory.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,19 @@
44
from crypto.bls.bls_crypto import BlsCrypto, BlsGroupParamsLoader
55
from crypto.bls.bls_key_manager import BlsKeyManager
66
from crypto.bls.bls_key_register import BlsKeyRegister
7+
from crypto.bls.bls_multi_signature_verifier import MultiSignatureVerifier
78
from plenum.bls.bls_store import BlsStore
89

910

1011
class BlsFactoryCrypto(metaclass=ABCMeta):
12+
1113
def generate_bls_keys(self, seed=None) -> str:
1214
return self._get_bls_crypto_class().generate_keys(
1315
self._load_group_params(),
1416
seed)
1517

1618
def generate_and_store_bls_keys(self, seed=None) -> str:
17-
bls_key_manager = self._create_key_manager(
18-
self._load_group_params())
19+
bls_key_manager = self._create_key_manager(self._load_group_params())
1920

2021
sk, pk = self.generate_bls_keys(seed)
2122
stored_sk, stored_pk = bls_key_manager.save_keys(sk, pk)
@@ -28,6 +29,14 @@ def create_bls_crypto_from_saved_keys(self) -> BlsCrypto:
2829
sk, pk = bls_key_manager.load_keys()
2930
return self._create_bls_crypto(sk, pk, group_params)
3031

32+
def create_multi_signature_verifier(self) -> MultiSignatureVerifier:
33+
group_params = self._load_group_params()
34+
return self._create_multi_signature_verifier(group_params)
35+
36+
@abstractmethod
37+
def _create_multi_signature_verifier(self, group_params) -> MultiSignatureVerifier:
38+
pass
39+
3140
def _load_group_params(self):
3241
return self._create_group_params_loader().load_group_params()
3342

@@ -58,6 +67,9 @@ def create_bls_bft(self, is_master) -> BlsBft:
5867
bls_key_register = self._create_bls_key_register()
5968
return self._create_bls_bft(bls_crypto, bls_key_register, is_master)
6069

70+
def create_multi_signature_verifier(self) -> MultiSignatureVerifier:
71+
return self._bls_factory_crypto.create_multi_signature_verifier()
72+
6173
@abstractmethod
6274
def create_bls_store(self) -> BlsStore:
6375
pass
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from abc import ABCMeta
2+
from typing import Sequence
3+
4+
5+
class MultiSignatureVerifier(metaclass=ABCMeta):
6+
"""
7+
Abstract multi signature verifier, to be used in
8+
places where full bls support is not required.
9+
"""
10+
11+
def verify(self, signature: str, message: str, pks: Sequence[str]) -> bool:
12+
"""
13+
Verify multi signature
14+
"""
15+
pass

crypto/bls/indy_crypto/bls_crypto_indy_crypto.py

Lines changed: 58 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
from crypto.bls.bls_crypto import BlsCrypto, GroupParams, BlsGroupParamsLoader
55
from indy_crypto.bls import BlsEntity, Generator, VerKey, SignKey, Bls, Signature, MultiSignature
66

7+
from crypto.bls.bls_multi_signature_verifier import MultiSignatureVerifier
8+
79

810
class BlsGroupParamsLoaderIndyCrypto(BlsGroupParamsLoader):
911
def load_group_params(self) -> GroupParams:
@@ -12,40 +14,22 @@ def load_group_params(self) -> GroupParams:
1214
return GroupParams(group_name, g)
1315

1416

15-
class BlsCryptoIndyCrypto(BlsCrypto):
16-
SEED_LEN = 48
17-
18-
def __init__(self, sk: str, pk: str, params: GroupParams):
19-
super().__init__(sk, pk, params)
20-
self._generator = BlsCryptoIndyCrypto._bls_from_str(params.g, Generator)
21-
self._sk_bls = BlsCryptoIndyCrypto._bls_from_str(sk, SignKey)
22-
self._pk_bls = BlsCryptoIndyCrypto._bls_from_str(pk, VerKey)
23-
17+
class IndyCryptoBlsUtils:
2418
@staticmethod
25-
def _bls_to_str(v: BlsEntity) -> str:
19+
def bls_to_str(v: BlsEntity) -> str:
2620
return base58.b58encode(v.as_bytes())
2721

2822
@staticmethod
29-
def _bls_from_str(v: str, cls) -> BlsEntity:
23+
def bls_from_str(v: str, cls) -> BlsEntity:
3024
bts = base58.b58decode(v)
3125
return cls.from_bytes(bts)
3226

3327
@staticmethod
34-
def _msg_to_bls_bytes(msg: str) -> bytes:
28+
def msg_to_bls_bytes(msg: str) -> bytes:
3529
return msg.encode()
3630

3731
@staticmethod
38-
def generate_keys(params: GroupParams, seed=None) -> (str, str):
39-
seed = BlsCryptoIndyCrypto._prepare_seed(seed)
40-
gen = BlsCryptoIndyCrypto._bls_from_str(params.g, Generator)
41-
sk = SignKey.new(seed)
42-
vk = VerKey.new(gen, sk)
43-
sk_str = BlsCryptoIndyCrypto._bls_to_str(sk)
44-
vk_str = BlsCryptoIndyCrypto._bls_to_str(vk)
45-
return sk_str, vk_str
46-
47-
@staticmethod
48-
def _prepare_seed(seed):
32+
def prepare_seed(seed):
4933
seed_bytes = None
5034
if isinstance(seed, str):
5135
seed_bytes = seed.encode()
@@ -60,25 +44,63 @@ def _prepare_seed(seed):
6044

6145
return seed_bytes
6246

47+
48+
class IndyCryptoMultiSigVerifier(MultiSignatureVerifier):
49+
50+
def __init__(self, params: GroupParams):
51+
self._generator = \
52+
IndyCryptoBlsUtils\
53+
.bls_from_str(params.g, Generator) # type: Generator
54+
55+
def verify(self, signature: str, message: str, pks: Sequence[str]) -> bool:
56+
epks = [IndyCryptoBlsUtils.bls_from_str(p, VerKey) for p in pks]
57+
multi_signature = \
58+
IndyCryptoBlsUtils\
59+
.bls_from_str(signature, MultiSignature) # type: MultiSignature
60+
message_bytes = IndyCryptoBlsUtils.msg_to_bls_bytes(message)
61+
return Bls.verify_multi_sig(multi_sig=multi_signature,
62+
message=message_bytes,
63+
ver_keys=epks,
64+
gen=self._generator)
65+
66+
67+
class BlsCryptoIndyCrypto(BlsCrypto):
68+
SEED_LEN = 48
69+
70+
def __init__(self, sk: str, pk: str, params: GroupParams):
71+
super().__init__(sk, pk, params)
72+
self._sk_bls = IndyCryptoBlsUtils.bls_from_str(sk, SignKey)
73+
self._pk_bls = IndyCryptoBlsUtils.bls_from_str(pk, VerKey)
74+
self._generator = \
75+
IndyCryptoBlsUtils\
76+
.bls_from_str(params.g, Generator) # type: Generator
77+
self._multi_sig_verifier = IndyCryptoMultiSigVerifier(params)
78+
79+
@staticmethod
80+
def generate_keys(params: GroupParams, seed=None) -> (str, str):
81+
seed = IndyCryptoBlsUtils.prepare_seed(seed)
82+
gen = IndyCryptoBlsUtils.bls_from_str(params.g, Generator)
83+
sk = SignKey.new(seed)
84+
vk = VerKey.new(gen, sk)
85+
sk_str = IndyCryptoBlsUtils.bls_to_str(sk)
86+
vk_str = IndyCryptoBlsUtils.bls_to_str(vk)
87+
return sk_str, vk_str
88+
6389
def sign(self, message: str) -> str:
64-
bts = BlsCryptoIndyCrypto._msg_to_bls_bytes(message)
90+
bts = IndyCryptoBlsUtils.msg_to_bls_bytes(message)
6591
sign = Bls.sign(bts, self._sk_bls)
66-
return BlsCryptoIndyCrypto._bls_to_str(sign)
92+
return IndyCryptoBlsUtils.bls_to_str(sign)
6793

6894
def create_multi_sig(self, signatures: Sequence[str]) -> str:
69-
sigs = [BlsCryptoIndyCrypto._bls_from_str(s, Signature) for s in signatures]
95+
sigs = [IndyCryptoBlsUtils.bls_from_str(s, Signature) for s in signatures]
7096
bts = MultiSignature.new(sigs)
71-
return BlsCryptoIndyCrypto._bls_to_str(bts)
97+
return IndyCryptoBlsUtils.bls_to_str(bts)
7298

7399
def verify_sig(self, signature: str, message: str, pk: str) -> bool:
74-
return Bls.verify(BlsCryptoIndyCrypto._bls_from_str(signature, Signature),
75-
BlsCryptoIndyCrypto._msg_to_bls_bytes(message),
76-
BlsCryptoIndyCrypto._bls_from_str(pk, VerKey),
100+
return Bls.verify(IndyCryptoBlsUtils.bls_from_str(signature, Signature),
101+
IndyCryptoBlsUtils.msg_to_bls_bytes(message),
102+
IndyCryptoBlsUtils.bls_from_str(pk, VerKey),
77103
self._generator)
78104

79-
def verify_multi_sig(self, signature: str, message: str, pks: Sequence[str]) -> bool:
80-
epks = [BlsCryptoIndyCrypto._bls_from_str(p, VerKey) for p in pks]
81-
return Bls.verify_multi_sig(BlsCryptoIndyCrypto._bls_from_str(signature, MultiSignature),
82-
BlsCryptoIndyCrypto._msg_to_bls_bytes(message),
83-
epks,
84-
self._generator)
105+
def verify_multi_sig(self, signature: str, message: str, pks: Sequence[str]):
106+
return self._multi_sig_verifier.verify(signature, message, pks)

plenum/bls/bls_bft_factory.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from crypto.bls.bls_bft import BlsBft
33
from crypto.bls.bls_factory import BlsFactoryBft, BlsFactoryCrypto
44
from crypto.bls.bls_key_register import BlsKeyRegister
5+
from crypto.bls.bls_multi_signature_verifier import MultiSignatureVerifier
56
from plenum.bls.bls_bft_plenum import BlsBftPlenum
67
from plenum.bls.bls_crypto_factory import create_default_bls_crypto_factory
78
from plenum.bls.bls_key_register_pool_manager import BlsKeyRegisterPoolManager

plenum/bls/bls_bft_plenum.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from crypto.bls.bls_crypto import BlsCrypto
55
from crypto.bls.bls_key_register import BlsKeyRegister
66
from crypto.bls.bls_multi_signature import MultiSignature
7+
from plenum.bls.bls_bft_utils import create_full_root_hash
78
from plenum.bls.bls_store import BlsStore
89
from plenum.common.constants import DOMAIN_LEDGER_ID, BLS_PREFIX
910
from plenum.common.exceptions import SuspiciousNode
@@ -155,7 +156,7 @@ def gc(self, key_3PC):
155156
# ----MULT_SIG----
156157

157158
def _create_multi_sig_value(self, state_root_hash, pool_state_root_hash):
158-
return state_root_hash + pool_state_root_hash
159+
return create_full_root_hash(state_root_hash, pool_state_root_hash)
159160

160161
def _validate_signature(self, sender, bls_sig, state_root_hash):
161162
sender_node = self.get_node_name(sender)

plenum/bls/bls_bft_utils.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
3+
def create_full_root_hash(root_hash, pool_root_hash):
4+
"""
5+
Utility method for creating full root hash that then can be signed
6+
by multi signature
7+
"""
8+
return root_hash + pool_root_hash

plenum/bls/bls_crypto_factory.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from crypto.bls.bls_crypto import BlsGroupParamsLoader
22
from crypto.bls.bls_factory import BlsFactoryCrypto
33
from crypto.bls.bls_key_manager import BlsKeyManager
4-
from crypto.bls.indy_crypto.bls_crypto_indy_crypto import BlsCryptoIndyCrypto, BlsGroupParamsLoaderIndyCrypto
4+
from crypto.bls.indy_crypto.bls_crypto_indy_crypto import BlsCryptoIndyCrypto, \
5+
BlsGroupParamsLoaderIndyCrypto, IndyCryptoMultiSigVerifier
56
from plenum.bls.bls_key_manager_file import BlsKeyManagerFile
67

78

@@ -30,6 +31,9 @@ def __init__(self, basedir=None, node_name=None):
3031
self._basedir = basedir
3132
self._node_name = node_name
3233

34+
def _create_multi_signature_verifier(self, group_params):
35+
return IndyCryptoMultiSigVerifier(group_params)
36+
3337
def _create_group_params_loader(self) -> BlsGroupParamsLoader:
3438
return BlsGroupParamsLoaderIndyCrypto()
3539

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from crypto.bls.bls_key_register import BlsKeyRegister
2+
from plenum.common.constants import BLS_KEY, TXN_TYPE, NODE, ALIAS, DATA
3+
4+
5+
class BlsKeyRegisterPoolLedger(BlsKeyRegister):
6+
"""
7+
Ledger-based implementation of BlsKeyRegister
8+
"""
9+
10+
def __init__(self, ledger):
11+
self._ledger = ledger
12+
self._current_bls_keys = None # {node_name : BLS key}
13+
# Not supported methods
14+
15+
def get_pool_root_hash_committed(self):
16+
raise NotImplementedError()
17+
18+
def get_key_by_name(self, node_name, pool_state_root_hash=None):
19+
if self._current_bls_keys is None:
20+
self._current_bls_keys = self._load_keys_for_root()
21+
return self._current_bls_keys.get(node_name)
22+
23+
def _load_keys_for_root(self):
24+
keys = {}
25+
for _, txn in self._ledger.getAllTxn():
26+
if txn[TXN_TYPE] == NODE:
27+
data = txn[DATA]
28+
alias = data[ALIAS]
29+
blskey = data.get(BLS_KEY)
30+
keys[alias] = blskey
31+
return keys

0 commit comments

Comments
 (0)