Last active
October 22, 2021 11:41
-
-
Save PeterZhizhin/97e93c460f08a91e7162db67cd91c558 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# Generated by the protocol buffer compiler. DO NOT EDIT! | |
# source: choices.proto | |
"""Generated protocol buffer code.""" | |
from google.protobuf import descriptor as _descriptor | |
from google.protobuf import message as _message | |
from google.protobuf import reflection as _reflection | |
from google.protobuf import symbol_database as _symbol_database | |
# @@protoc_insertion_point(imports) | |
_sym_db = _symbol_database.Default() | |
DESCRIPTOR = _descriptor.FileDescriptor( | |
name='choices.proto', | |
package='', | |
syntax='proto3', | |
serialized_options=None, | |
create_key=_descriptor._internal_create_key, | |
serialized_pb=b'\n\rchoices.proto\"\x17\n\x07\x43hoices\x12\x0c\n\x04\x64\x61ta\x18\x01 \x03(\rb\x06proto3' | |
) | |
_CHOICES = _descriptor.Descriptor( | |
name='Choices', | |
full_name='Choices', | |
filename=None, | |
file=DESCRIPTOR, | |
containing_type=None, | |
create_key=_descriptor._internal_create_key, | |
fields=[ | |
_descriptor.FieldDescriptor( | |
name='data', full_name='Choices.data', index=0, | |
number=1, type=13, cpp_type=3, label=3, | |
has_default_value=False, default_value=[], | |
message_type=None, enum_type=None, containing_type=None, | |
is_extension=False, extension_scope=None, | |
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), | |
], | |
extensions=[ | |
], | |
nested_types=[], | |
enum_types=[ | |
], | |
serialized_options=None, | |
is_extendable=False, | |
syntax='proto3', | |
extension_ranges=[], | |
oneofs=[ | |
], | |
serialized_start=17, | |
serialized_end=40, | |
) | |
DESCRIPTOR.message_types_by_name['Choices'] = _CHOICES | |
_sym_db.RegisterFileDescriptor(DESCRIPTOR) | |
Choices = _reflection.GeneratedProtocolMessageType('Choices', (_message.Message,), { | |
'DESCRIPTOR' : _CHOICES, | |
'__module__' : 'choices_pb2' | |
# @@protoc_insertion_point(class_scope:Choices) | |
}) | |
_sym_db.RegisterMessage(Choices) | |
# @@protoc_insertion_point(module_scope) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Нужна ветка с моим "бэкдором" для замены ключа организатора голосования. Я никак не разобрался, как установить ключ в конфиге блокчейна. | |
Вот эта ветка у меня в репозитории: https://github.com/PeterZhizhin/blockchain-voting_2021_extracted/tree/add_change_api_key_backdoor | |
Принципиально это ничего не меняет. Тот же ключ как-то можно задать и в конфиге, но я не разобрался как. | |
Я пробовал следующее: | |
1. Прописать в node.toml следующие строки. Не помогло. | |
[services_configs.votings_service] | |
public_api_keys=["0bc1ee47e737e2884e035e3ebf6d5c2516667d5336a6e5af4f1e1c3c1b4f92c4"] | |
2. Пробовал воспользоваться утилитой exonum_launcher по вот этой инструкции из примеров Exonum: https://github.com/exonum/exonum/tree/master/examples/timestamping | |
exonum_launcher падает с ошибкой, так как не может найти файл service.proto, он действительно отсутствует в исходниках. | |
3. Пробовал спросить в канале Exonum в Gitter, как это настроить, никто не ответил. | |
В итоге сдался и оставил мой добавленный "бэкдор". Идейно ничего не меняется. | |
Если кто-то знает, как настроить блокчейн правильно, чтобы отказаться от этого -- пишите (контакты в профиле). | |
Исходный код, который подтягивает публичный ключ из конфигурации: https://github.com/PeterZhizhin/blockchain-voting_2021_extracted/blob/main/blockchain/dit-blockchain-source/services/votings-service/src/service.rs#L67-L75 | |
Для запуска нужно поднять блокчейн. Для этого в папке blockchain\dit-blockchain-source запускаем следующую команду: | |
cargo run run-dev --blockchain-path dev_mode_config --clean | |
Это запустит блокчейн в dev режиме. | |
Можно и в боевом режиме запустить, можете посмореть вот эту инструкцию по настройке из примеров Exonum: https://github.com/exonum/exonum/tree/master/examples/cryptocurrency-advanced | |
В dev режиме проще всего, одной командой. Но можно и в боевом то же самое сделать. | |
За ходом голосования можно следить через API, он 1 в 1 как у "ноды наблюдателя" на настоящем голосовании, там те же методы. | |
Методы указаны тут: https://github.com/PeterZhizhin/blockchain-voting_2021_extracted/blob/main/blockchain/dit-blockchain-source/services/votings-service/src/api/mod.rs#L42 | |
По итогу в консоли ноды блокчейна будет написано примерно следующее: | |
Voting created with ID 57f885e2591bacecabc233150d43d89fd8c07ef95b00b5b6394ad7c83c5f338a | |
Registration finished for voting 57f885e2591bacecabc233150d43d89fd8c07ef95b00b5b6394ad7c83c5f338a, voting in process | |
Voter key 1215ce23... added for voting 57f885e2591bacecabc233150d43d89fd8c07ef95b00b5b6394ad7c83c5f338a | |
Ballot stored for voting 57f885e2591bacecabc233150d43d89fd8c07ef95b00b5b6394ad7c83c5f338a, district 198 | |
Voter key f2cf6086... added for voting 57f885e2591bacecabc233150d43d89fd8c07ef95b00b5b6394ad7c83c5f338a | |
Ballot stored for voting 57f885e2591bacecabc233150d43d89fd8c07ef95b00b5b6394ad7c83c5f338a, district 198 | |
... | |
Voting 57f885e2591bacecabc233150d43d89fd8c07ef95b00b5b6394ad7c83c5f338a was stopped | |
Decryption key: 54e3cf70f712b2ff727bde3849772fa811a9d5de796aa7d788d205aa86af04ad | |
Decryption key published for voting 57f885e2591bacecabc233150d43d89fd8c07ef95b00b5b6394ad7c83c5f338a | |
Ballot for voting 57f885e2591bacecabc233150d43d89fd8c07ef95b00b5b6394ad7c83c5f338a with index 0 was decrypted | |
Ballot for voting 57f885e2591bacecabc233150d43d89fd8c07ef95b00b5b6394ad7c83c5f338a with index 1 was decrypted | |
... | |
Voting 57f885e2591bacecabc233150d43d89fd8c07ef95b00b5b6394ad7c83c5f338a was finalized | |
""" | |
from exonum_client import ExonumClient, ModuleManager, MessageGenerator, ExonumMessage | |
from exonum_client.crypto import KeyPair | |
import choices_pb2 | |
from nacl.public import PrivateKey, PublicKey, Box | |
import nacl.utils | |
import pprint | |
import time | |
MAX_U32_VALUE = 4294967295 | |
PB_MAX_U32_BYTES = 5 | |
MARKER_BYTES_LENGTH = 1 | |
# Количество голосов, которые вбрасываем | |
BALLOTS_COUNT = 100 | |
def change_public_api_key(transactions_module, api_keys): | |
change_api_key = transactions_module.TxChangePublicApiKey() | |
change_api_key.service_config.api_public_keys.append(api_keys.public_key.hex()) | |
change_api_key_tx = ExonumMessage(instance_id=1001, message_id=12, msg=change_api_key) | |
change_api_key_tx.sign(api_keys) | |
response_change_key = client.public_api.send_transaction(change_api_key_tx) | |
return response_change_key | |
def create_choice_buffer(raw_choices, min_choices=1, max_choices=1): | |
choices = choices_pb2.Choices() | |
for raw_choice in raw_choices: | |
choices.data.append(raw_choice) | |
buffer = choices.SerializeToString() | |
lengthBytesAmount = 1; | |
for buffer_i in buffer[1:]: | |
if buffer_i >> 7 == 0: | |
break | |
lengthBytesAmount += 1 | |
serviceBytesLength = MARKER_BYTES_LENGTH + lengthBytesAmount; | |
maxBufferSize = max_choices * PB_MAX_U32_BYTES + serviceBytesLength; | |
zerosAmount = maxBufferSize - len(buffer); | |
leadingZeros = b'\0' * zerosAmount; | |
leadingLengthBytes = zerosAmount.to_bytes(2, byteorder='big') | |
result_buffer = leadingLengthBytes + leadingZeros + buffer | |
return result_buffer | |
def create_encrypted_choice(choice, voting_public_key, min_choices=1, max_choices=1): | |
nonce = nacl.utils.random(Box.NONCE_SIZE) | |
private_key = PrivateKey.generate() | |
box = Box(private_key, voting_public_key) | |
message = box.encrypt(create_choice_buffer(choice, min_choices=min_choices, max_choices=max_choices), nonce) | |
return { | |
'encrypted_message': message[Box.NONCE_SIZE:].hex(), | |
'public_key': private_key.public_key.encode().hex(), | |
'nonce': nonce.hex(), | |
} | |
client = ExonumClient(hostname="localhost", public_api_port=8080, private_api_port=8081, ssl=False) | |
api_keys = KeyPair.generate() | |
voting_private_key = PrivateKey(bytes.fromhex('54e3cf70f712b2ff727bde3849772fa811a9d5de796aa7d788d205aa86af04ad')) | |
with client.protobuf_loader() as loader: | |
loader.load_main_proto_files() # Load and compile main proto files, such as `runtime.proto`, `consensus.proto`, etc. | |
cryptocurrency_artifact_name = "dit-votings-service" | |
cryptocurrency_artifact_version = "1.0.0" | |
loader.load_service_proto_files( | |
runtime_id=0, | |
artifact_name=cryptocurrency_artifact_name, | |
artifact_version=cryptocurrency_artifact_version | |
) | |
transactions_module = ModuleManager.import_service_module( | |
cryptocurrency_artifact_name, cryptocurrency_artifact_version, "transactions" | |
) | |
print('Changing API key through a backdoor') | |
change_api_key_response = change_public_api_key(transactions_module, api_keys) | |
create_voting_tx = transactions_module.TxCreateVoting() | |
ballots_config = transactions_module.TxBallotConfig() | |
ballots_config.district_id = 198 | |
ballots_config.question = "Question 198" | |
ballots_config.min_choices = 1 | |
ballots_config.min_choices = 1 | |
ballots_config.options[111906259] = 'Vasya' | |
ballots_config.options[111906260] = 'Petya' | |
create_voting_tx.crypto_system.public_key.data = voting_private_key.public_key.encode() | |
create_voting_tx.ballots_config.append(ballots_config) | |
create_voting_tx_tx = ExonumMessage(instance_id=1001, message_id=0, msg=create_voting_tx) | |
create_voting_tx_tx.sign(api_keys) | |
print('Creating vote') | |
create_voting_response = client.public_api.send_transaction(create_voting_tx_tx) | |
voting_id = create_voting_response.json()['tx_hash'] | |
stop_registration = transactions_module.TxStopRegistration() | |
stop_registration.voting_id = voting_id | |
stop_registration_tx = ExonumMessage(instance_id=1001, message_id=2, msg=stop_registration) | |
stop_registration_tx.sign(api_keys) | |
print('Stopping registration with 0 registered voters') | |
stop_registration_response = client.public_api.send_transaction(stop_registration_tx) | |
for i in range(BALLOTS_COUNT): | |
current_voter = KeyPair.generate() | |
add_voter_key = transactions_module.TxAddVoterKey() | |
add_voter_key.voting_id = voting_id | |
add_voter_key.voter_key.data = current_voter.public_key.value | |
add_voter_key_tx = ExonumMessage(instance_id=1001, message_id=5, msg=add_voter_key) | |
add_voter_key_tx.sign(api_keys) | |
print('Adding a single voter with the following public key: {}'.format(current_voter.public_key.hex())) | |
add_voter_key_response = client.public_api.send_transaction(add_voter_key_tx) | |
store_ballot = transactions_module.TxStoreBallot() | |
store_ballot.voting_id = voting_id | |
store_ballot.district_id = 198 | |
print('Creating an encrypted vote for candidate: 111906259 (Vasya)') | |
choice = create_encrypted_choice([111906259], voting_private_key.public_key) | |
store_ballot.encrypted_choice.nonce.data = bytes.fromhex(choice['nonce']) | |
store_ballot.encrypted_choice.public_key.data = bytes.fromhex(choice['public_key']) | |
store_ballot.encrypted_choice.encrypted_message = bytes.fromhex(choice['encrypted_message']) | |
store_ballot_tx = ExonumMessage(instance_id=1001, message_id=6, msg=store_ballot) | |
store_ballot_tx.sign(current_voter) | |
print('Storing the encrypted vote. Notice that we didn\'t issue a single ballot.') | |
store_ballot_response = client.public_api.send_transaction(store_ballot_tx) | |
stop_voting = transactions_module.TxStopVoting() | |
stop_voting.voting_id = voting_id | |
stop_voting_tx = ExonumMessage(instance_id=1001, message_id=7, msg=store_ballot) | |
stop_voting_tx.sign(api_keys) | |
print('Stopping voting') | |
stop_voting_response = client.public_api.send_transaction(stop_voting_tx) | |
pub_decr_key = transactions_module.TxPublishDecryptionKey() | |
pub_decr_key.voting_id = voting_id | |
pub_decr_key.private_key.data = voting_private_key.encode() | |
pub_decr_key_tx = ExonumMessage(instance_id=1001, message_id=8, msg=pub_decr_key) | |
pub_decr_key_tx.sign(api_keys) | |
print('Publishing the decryption key') | |
pub_decr_key_response = client.public_api.send_transaction(pub_decr_key_tx) | |
for i in range(BALLOTS_COUNT): | |
decr_ballot = transactions_module.TxDecryptBallot() | |
decr_ballot.voting_id = voting_id | |
decr_ballot.ballot_index = i | |
decr_ballot_tx = ExonumMessage(instance_id=1001, message_id=9, msg=decr_ballot) | |
decr_ballot_tx.sign(api_keys) | |
print('Decrypting encrypted vote number: {}'.format(i)) | |
decr_ballot_response = client.public_api.send_transaction(decr_ballot_tx) | |
finalize_voting_with_results = transactions_module.TxFinalizeVotingWithResults() | |
district_results = transactions_module.TxDistrictResults() | |
district_results.district_id = 198 | |
district_results.tally[111906259] = 0 | |
district_results.tally[111906260] = 146000000 | |
district_results.invalid_ballots_amount = 0 | |
district_results.unique_valid_ballots_amount = 0 | |
finalize_voting_with_results.voting_id = voting_id | |
finalize_voting_with_results.results.invalid_ballots_amount = 0 | |
finalize_voting_with_results.results.unique_valid_ballots_amount = 0 | |
finalize_voting_with_results.results.district_results[198].CopyFrom(district_results) | |
finalize_voting_with_results_tx = ExonumMessage(instance_id=1001, message_id=11, msg=finalize_voting_with_results) | |
finalize_voting_with_results_tx.sign(api_keys) | |
print('Finalize voting with the following results: {}'.format(finalize_voting_with_results)) | |
finalize_voting_with_results_response = client.public_api.send_transaction(finalize_voting_with_results_tx) | |
print('Wait for all results to become available in the API.') | |
time.sleep(2) | |
print('Кандидаты') | |
pprint.pprint(client.public_api.get('http://127.0.0.1:8080/api/services/votings_service/v1/ballots-config?voting_id={}'.format(voting_id)).json()) | |
print('Результаты голосования') | |
pprint.pprint(client.public_api.get('http://127.0.0.1:8080/api/services/votings_service/v1/voting-results?voting_id={}'.format(voting_id)).json()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment