From ef43e67550590aacbe9acd664106c11b3c873461 Mon Sep 17 00:00:00 2001 From: Alex Upshaw Date: Fri, 21 Sep 2018 15:35:14 -0700 Subject: [PATCH] Add key generation utility for Concord This commit adds a key generation utility for concord; it can be called from the command line to generate all RSA and threshold signature keys needed by a Concord deployment, which it outputs to keyfiles. A function for reading the keyfiles back in is also included, as is a test of the key generation utility and a README documenting how to use it. Furthermore, this commit makes revisions to simpleTest so that it uses keyfiles of the new format. The key generation utility is implemented in the tools subdirectory. See tools/README.md for more information about this utility. --- CMakeLists.txt | 2 + bftengine/CMakeLists.txt | 4 +- bftengine/tests/simpleTest/CMakeLists.txt | 13 +- bftengine/tests/simpleTest/README.md | 22 +- bftengine/tests/simpleTest/config.cpp | 261 +---- .../simpleTest/scripts/private_replica_0 | 75 +- .../simpleTest/scripts/private_replica_1 | 75 +- .../simpleTest/scripts/private_replica_2 | 75 +- .../simpleTest/scripts/private_replica_3 | 75 +- .../simpleTest/scripts/public_replicas_data | 29 - .../scripts/testReplicasAndClient.sh | 6 + .../threshsign/ThresholdSignaturesTypes.h | 388 +++++++ threshsign/src/CMakeLists.txt | 1 + threshsign/src/ThresholdSignaturesTypes.cpp | 308 ++++++ threshsign/src/bls/relic/BlsNumTypes.cpp | 2 +- tools/CMakeLists.txt | 45 + tools/GenerateConcordKeys.cpp | 363 +++++++ tools/KeyfileIOUtils.cpp | 710 +++++++++++++ tools/KeyfileIOUtils.hpp | 99 ++ tools/README.md | 132 +++ tools/TestGeneratedKeys.cpp | 965 ++++++++++++++++++ tools/testKeyGeneration.sh | 76 ++ 22 files changed, 3416 insertions(+), 310 deletions(-) delete mode 100644 bftengine/tests/simpleTest/scripts/public_replicas_data create mode 100644 threshsign/src/ThresholdSignaturesTypes.cpp create mode 100644 tools/CMakeLists.txt create mode 100644 tools/GenerateConcordKeys.cpp create mode 100644 tools/KeyfileIOUtils.cpp create mode 100644 tools/KeyfileIOUtils.hpp create mode 100644 tools/README.md create mode 100644 tools/TestGeneratedKeys.cpp create mode 100755 tools/testKeyGeneration.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 307facaa15..6ed2bd4eba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,3 +109,5 @@ endif() add_subdirectory(logging) add_subdirectory(threshsign) add_subdirectory(bftengine) +add_subdirectory(tools) +add_subdirectory(bftengine/tests) diff --git a/bftengine/CMakeLists.txt b/bftengine/CMakeLists.txt index 122c787491..f1b1f57444 100644 --- a/bftengine/CMakeLists.txt +++ b/bftengine/CMakeLists.txt @@ -1,3 +1,5 @@ +project (bftengine LANGUAGES CXX) + get_property(LOGGER_INC_DIR GLOBAL PROPERTY LoggerIncludeDir) set(corebft_source_files @@ -89,5 +91,3 @@ target_include_directories(corebft PUBLIC ${LOGGER_INC_DIR}) target_link_libraries(corebft PUBLIC threshsign) target_link_libraries(corebft PUBLIC Threads::Threads) - -add_subdirectory(tests) \ No newline at end of file diff --git a/bftengine/tests/simpleTest/CMakeLists.txt b/bftengine/tests/simpleTest/CMakeLists.txt index 6e249a06ef..a2e0883567 100644 --- a/bftengine/tests/simpleTest/CMakeLists.txt +++ b/bftengine/tests/simpleTest/CMakeLists.txt @@ -1,11 +1,13 @@ set(simpleTest_client_source_files client.cpp config.cpp + ${concord_bft_tools_SOURCE_DIR}/KeyfileIOUtils.cpp ) set(simpleTest_replica_source_files replica.cpp config.cpp + ${concord_bft_tools_SOURCE_DIR}/KeyfileIOUtils.cpp ) add_executable(simpleTest_client @@ -32,9 +34,18 @@ set_target_properties(simpleTest_server PROPERTIES OUTPUT_NAME server) target_link_libraries(simpleTest_client PUBLIC corebft) target_link_libraries(simpleTest_server PUBLIC corebft) +target_include_directories(simpleTest_client + PRIVATE + ${concord_bft_tools_SOURCE_DIR} + ${bftengine_SOURCE_DIR}/include) +target_include_directories(simpleTest_server + PRIVATE + ${concord_bft_tools_SOURCE_DIR} + ${bftengine_SOURCE_DIR}/include) + add_custom_target(copy_simple_test_scripts ALL COMMENT "Copying scripts of simpleTest") add_custom_command(TARGET copy_simple_test_scripts COMMAND ${CMAKE_COMMAND} -E make_directory $/scripts COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/scripts $/scripts) - \ No newline at end of file + diff --git a/bftengine/tests/simpleTest/README.md b/bftengine/tests/simpleTest/README.md index dbbac00775..03a15dbc9a 100644 --- a/bftengine/tests/simpleTest/README.md +++ b/bftengine/tests/simpleTest/README.md @@ -12,7 +12,7 @@ state machine understands two events: The state machine is defined in the `SimpleAppState` class in `replica.cpp`. It exposes only an `execute` method, which is called -every time the replica receives an event. The `main` function simple +every time the replica receives an event. The `main` function simply starts a Concord replica parameterized with this state machine. The test code is defined in `client.cpp`. The client sends a number of @@ -23,17 +23,15 @@ last written value. In the `scripts` directory, you'll find: - * `private_replica_{0,1,2,3}`, which are the private config files - for each replica. The example is for four replicas, with supports - an F=1 environment. See `config.cpp` for documentation of the - format. + * `private_replica_{0,1,2,3}`, which are the key files for each + replica. The example is for four replicas, which supports an F=1 + environment. The keyfile format used is the same as that output by + the `GenerateConcordKeys` tool in the `concord-bft/tools` folder; + see `concord-bft/tools/README.md` for more information on how + these keyfiles are generated and used. - * `public_replicas_data`, which is the public configuration shared - among all nodes. This is how public keys are shared among all - nodes. See `config.cpp` for documentation of the format. - - * `testReplicasAndClient.sh`, which starts all four replicas, and - then runs the client test. + * `testReplicasAndClient.sh`, which generates fresh cryptographic + keys, starts all four replicas, and then runs the client test. * `runReplias.sh`, which just starts all four replicas. @@ -89,4 +87,4 @@ parallel: /home/bfink/builds/concord-bft/debug/bftengine/tests/simpleTest/script parallel: /home/bfink/builds/concord-bft/debug/bftengine/tests/simpleTest/scripts/../server 1 Killing server processes named '/home/bfink/builds/concord-bft/debug/bftengine/tests/simpleTest/scripts/../server' -``` \ No newline at end of file +``` diff --git a/bftengine/tests/simpleTest/config.cpp b/bftengine/tests/simpleTest/config.cpp index 25e425c943..92f959b29b 100644 --- a/bftengine/tests/simpleTest/config.cpp +++ b/bftengine/tests/simpleTest/config.cpp @@ -20,10 +20,13 @@ #include #include #include +#include +#include #include "CommFactory.hpp" #include "ReplicaConfig.hpp" #include "threshsign/ThresholdSignaturesSchemes.h" +#include "KeyfileIOUtils.hpp" using bftEngine::PlainUdpConfig; using bftEngine::PlainTcpConfig; @@ -35,15 +38,7 @@ using std::string; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -// Maximum length of a line in the config file. -#define MAX_ITEM_LENGTH (4096) - -// Stringified max line length, for use in fscanf. -#define MAX_ITEM_LENGTH_STR "4096" - -// Filenames of config files. -const char* nameOfPublicFile = "public_replicas_data"; -const char* namesOfPrivateFiles[] = { +const char* namesOfKeyfiles[] = { "private_replica_0", "private_replica_1", "private_replica_2", @@ -51,15 +46,12 @@ const char* namesOfPrivateFiles[] = { }; // Number of replicas - must be less than or equal to the length of -// namesOfPrivateFiles. +// namesOfKeyfiles. const int numOfReplicas = 4; // Number of client proxies. const int numOfClientProxies = 1; -// Number of failed nodes allowed. numOfReplicas must be at least (3*fVal)+1. -const int fVal = 1; - // Network port of the first replica. Other replicas use ports // basePort+(2*index). const uint16_t basePort = 3710; @@ -67,241 +59,28 @@ const uint16_t basePort = 3710; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -// Read a line from file `f` into buffer `buf`, not exceeding `capacity` -// bytes. Trailing newline is assumed, and removed. -static void readOneLine(FILE *f, int capacity, char * buf) { - fgets(buf, capacity - 1, f); - buf[strlen(buf) - 1] = 0; // strip newline -} - -// Read a line from file `f` and discard it. -static void ignoreOneLine(FILE *f) { - char buf[8192]; - readOneLine(f, 8191, buf); -} - -// Read signer parameters from file `f`, and use them to create a threshold -// signer with index `id`. -// -// Two lines are read from the file: -// * The first is discareded. -// * The second is expected to be the private key in hex. -static IThresholdSigner* createThresholdSigner(FILE* f, - int id, - IThresholdFactory* factory) { - if (id < 1) { - throw std::runtime_error( - "Expected replica's ID to be strictly greater than zero!"); - } - - char secretKey[MAX_ITEM_LENGTH]; - ignoreOneLine(f); - - readOneLine(f, MAX_ITEM_LENGTH, secretKey); - return factory->newSigner(id, secretKey); -} - -// Read verifier parameters from file `f`, and use them to create a threshold -// verifier with index `k`. -// -// 3+`n` lines are read from the file: -// * The first line is expected to be the verifier's public key in hex. -// * The second line is ignored. -// * Each of the next `n` lines is expected to be a threshold key in hex. -// * The final line is ignored. -static IThresholdVerifier * createThresholdVerifier( - FILE * f, int k, int n, IThresholdFactory* factory) { - char publicKey[MAX_ITEM_LENGTH]; - char verifKey[MAX_ITEM_LENGTH]; - - readOneLine(f, MAX_ITEM_LENGTH, publicKey); - - ignoreOneLine(f); - std::vector verifKeys; - verifKeys.push_back(""); // signer 0 does not exist - for (int i = 0; i < n; i++) { - readOneLine(f, MAX_ITEM_LENGTH, verifKey); - verifKeys.push_back(std::string(verifKey)); - } - - // Ignore last comment/empty line - ignoreOneLine(f); - - return factory->newVerifier(k, n, publicKey, verifKeys); -} - -// Initialize the BLS threshold library, and prepare it to create threshold -// signers and verifiers. -// -// Three lines are read from the file. -// * The first is discarded. -// * The second is expected to be the name of a crypto system, either -// "multisig-bls" or "threshold-bls". -// * The third is the name of a curve type, one of "BN-P254", "BN-P256", -// "B12-P381", "BN-P382", "B12-P455", "B24-P477", "KSS-P508", "BN-P638", or -// "B12-P638". -static IThresholdFactory* createThresholdFactory(FILE* f) { - char buf[MAX_ITEM_LENGTH]; - char * curveType = buf; - char cryptosys[MAX_ITEM_LENGTH]; - - ignoreOneLine(f); - readOneLine(f, MAX_ITEM_LENGTH, cryptosys); - readOneLine(f, MAX_ITEM_LENGTH, buf); - - if (strcmp(cryptosys, MULTISIG_BLS_SCHEME) == 0) { - return new BlsThresholdFactory( - BLS::Relic::PublicParametersFactory::getByCurveType(curveType)); - } else if (strcmp(cryptosys, THRESHOLD_BLS_SCHEME) == 0) { - return new BlsThresholdFactory( - BLS::Relic::PublicParametersFactory::getByCurveType(curveType)); - } else { - printf("ERROR: Unsupported cryptosystem: %s\n", cryptosys); - throw std::runtime_error("ERROR: Unsupported cryptosystem"); - } -} - -// Create a replica configuration for the replica with index `replicaId`, using -// data from `publicKeysFile` and `privateKeysFiles`. Returns `true` if the -// files were read and all names matched (see below), or `false` if names did -// not match. -// -// From `publicKeysFile`, first `numOfReplicas`*2 lines are read -// * The first of each pair is the name of a replica. Must be "replica" -// followed by the index of the replica in decimal. For example, "replica0", -// "replica1", ... -// * The second of each pair is the public key of that replica in hex. -// -// After that, two threshold verifier configs are read (see -// createThresholdVerifier for line descriptions). The first verifier is used -// for slow path commit, and the second is used for optimistic path commit. -// -// Next, from `privateKeysFiles`, two lines are read: -// * The first is the index of the replica. This must match `replicaId` in -// decimal. For example "0", "1", ... -// * The second is the private key for the replica. -// -// After that, two threshold signer configs are read (see createThresholdSigner -// for line descriptions). The first signer is used for the slow patch, and the -// second signer is used for the optimistic path. -static bool parseReplicaConfig(uint16_t replicaId, - FILE* publicKeysFile, - FILE* privateKeysFile, - ReplicaConfig* outConfig) { - char tempString[MAX_ITEM_LENGTH]; - - std::set > publicKeysOfReplicas; - - // read from publicKeysFile - - for (int i = 0; i < numOfReplicas; i++) { - fscanf(publicKeysFile, "%" MAX_ITEM_LENGTH_STR "s\n", tempString); - - string name(tempString); - - string expectedName = string("replica") + std::to_string(i); - - if (expectedName != name) return false; - - fscanf(publicKeysFile, "%" MAX_ITEM_LENGTH_STR "s\n", tempString); - - string publicKeyString(tempString); - - publicKeysOfReplicas.insert({i, publicKeyString}); +// Create a replica config for the replica with index `replicaId`. +// inputReplicaKeyfile is used to read the keys for this replica, and default +// values are loaded for non-cryptographic configuration parameters. +void getReplicaConfig(uint16_t replicaId, ReplicaConfig* outConfig) { + + std::string keyfileName = namesOfKeyfiles[replicaId]; + std::ifstream keyfile(keyfileName); + if (!keyfile.is_open()) { + throw std::runtime_error("Unable to read replica keyfile."); } + + bool succ = inputReplicaKeyfile(keyfile, keyfileName, *outConfig); + if (!succ) + throw std::runtime_error("Unable to parse replica keyfile."); - // Read threshold signatures - IThresholdFactory* slowCommitFactory = nullptr; - IThresholdSigner* thresholdSignerForSlowPathCommit = nullptr; - IThresholdVerifier* thresholdVerifierForSlowPathCommit = nullptr; - - IThresholdFactory* optimisticCommitFactory = nullptr; - IThresholdSigner* thresholdSignerForOptimisticCommit = nullptr; - IThresholdVerifier* thresholdVerifierForOptimisticCommit = nullptr; - - slowCommitFactory = createThresholdFactory(publicKeysFile); - thresholdVerifierForSlowPathCommit = - createThresholdVerifier(publicKeysFile, - numOfReplicas - fVal, - numOfReplicas, - slowCommitFactory); - - optimisticCommitFactory = createThresholdFactory(publicKeysFile); - thresholdVerifierForOptimisticCommit = - createThresholdVerifier(publicKeysFile, - numOfReplicas, - numOfReplicas, - optimisticCommitFactory); - - // read from privateKeysFile - - int tempInt = 0; - fscanf(privateKeysFile, "%d\n", &tempInt); - if (tempInt != replicaId) return false; - - fscanf(privateKeysFile, "%" MAX_ITEM_LENGTH_STR "s\n", tempString); - - string sigPrivateKey(tempString); - - thresholdSignerForSlowPathCommit = - createThresholdSigner(privateKeysFile, replicaId+1, slowCommitFactory); - - thresholdSignerForOptimisticCommit = - createThresholdSigner(privateKeysFile, - replicaId+1, - optimisticCommitFactory); - - delete slowCommitFactory; - delete optimisticCommitFactory; - - // set configuration + // set non-cryptographic configuration - outConfig->replicaId = replicaId; - outConfig->fVal = fVal; - outConfig->cVal = 0; outConfig->numOfClientProxies = numOfClientProxies; outConfig->statusReportTimerMillisec = 2000; outConfig->concurrencyLevel = 1; outConfig->autoViewChangeEnabled = false; outConfig->viewChangeTimerMillisec = 60000; - - outConfig->publicKeysOfReplicas = publicKeysOfReplicas; - outConfig->replicaPrivateKey = sigPrivateKey; - - outConfig->thresholdSignerForExecution = nullptr; - outConfig->thresholdVerifierForExecution = nullptr; - - outConfig->thresholdSignerForSlowPathCommit = - thresholdSignerForSlowPathCommit; - outConfig->thresholdVerifierForSlowPathCommit = - thresholdVerifierForSlowPathCommit; - - outConfig->thresholdSignerForCommit = nullptr; - outConfig->thresholdVerifierForCommit = nullptr; - - outConfig->thresholdSignerForOptimisticCommit = - thresholdSignerForOptimisticCommit; - outConfig->thresholdVerifierForOptimisticCommit = - thresholdVerifierForOptimisticCommit; - - return true; -} - -// Create a replica config for the replica with index `replicaId`. This is a -// wrapper around parseReplicaConfig that handles opening the correct files. -void getReplicaConfig(uint16_t replicaId, ReplicaConfig* outConfig) { - FILE* publicKeysFile = fopen(nameOfPublicFile, "r"); - if (!publicKeysFile) - throw std::runtime_error("Unable to read public keys"); - - FILE* privateKeysFile = fopen(namesOfPrivateFiles[replicaId], "r"); - if (!privateKeysFile) - throw std::runtime_error("Unable to read private keys"); - - bool succ = parseReplicaConfig( - replicaId, publicKeysFile, privateKeysFile, outConfig); - if (!succ) - throw std::runtime_error("Unable to parse configuration"); } // Create a UDP communication configuration for the node (replica or client) @@ -338,4 +117,4 @@ PlainTcpConfig getTCPConfig(uint16_t id) { PlainTcpConfig retVal(ip, port, bufLength, nodes, numOfReplicas -1, id); return retVal; -} \ No newline at end of file +} diff --git a/bftengine/tests/simpleTest/scripts/private_replica_0 b/bftengine/tests/simpleTest/scripts/private_replica_0 index 06e3e4d38b..8440e403af 100644 --- a/bftengine/tests/simpleTest/scripts/private_replica_0 +++ b/bftengine/tests/simpleTest/scripts/private_replica_0 @@ -1,6 +1,69 @@ -0 -308204BC020100300D06092A864886F70D0101010500048204A6308204A20201000282010100A1E3C7AA8DAC2334E009BE49A30119F7905CA9477328E8F03517E407D323CF04F7368AB2EE46D9CCAF4FC543AEF929702E8829068A9AD69F004E91868C9D857CC070467A0EED2A22BC2A9EE7543472FE38C13B668B9F6D0781713514F4F494CB4DDD9E71BD50C6CA22AF239BB123A92B5E85C1A85828122E07F9C08D433DB004E92A29028F3DD48635A22112F80D8786A1F9A6C254E0DA0525EFA3C08AB29A18C76E302722BC1E0BFA988711BEA5732E9DF910787C9E29B99BBC02AC77F7F5A6823F180E24C2D0E8EC42A335F20C5E80C27D797A0FEB3A8065022C982CA8B99B7572C3275DBF7D5F3AF90AB173BA2FDF2F2D9C69F1FAD467A9E3EF926E1A2285020111028201001A3024104B9F9C488DA739228003F160848775BC7FCE25AE62F10A88CB911631BE941DF74C311BB3EF2EC9527A6C11FF52D242DF2D02758AA9761F1200288A4CA6A8C01B462DE4EF07D9B7D298EA5DE55C0123F63C3BABFD730E8C59FA72DBD597E3D9A175367A8294AB63E0B7020103403B48BD1D51C6B49F6866AD708636D35C2366ADF4140CD19960842C2EE9D16B91D76FDF0AE3E6381B77FE58BA36B6EBD2E65532C7E30DF1CCBD557E8B51AD323686EBA7597B8FEA1263169B684A06FA9AEC3B048F8338D3825262C64CB263147F1DA210D36198D49FE14A0FC1DB9A8EF4EA2B73255C00BF39AE9379D2E03713FCA72EE9CF3E9598084DB74621A1B90902818100DB7FD1909DA50349DC576D73E5C073D222BA090C857BEB4CA57EAA625467B473BCB589CDF89967041ADCDD5D175A47BF3228B41BC881551AF544F9BBB54B8DD43AA63CA19C813CA69FBAC2440DA0EBCBBEC3D34431417B0ECB91EA27FC6D5CB60F9494DAB7F4E21412E2CFF25109F3663E01D9EAD69FA7662AA28C806CECE34D02818100BCCF7F9BAFA881FE1981B11993334AECF9AEBB98D1E419BABF5CA67F889B9221C46E97AAE21B7819D6CC24D4ECF52B5049487D0C5C66CF54C06F9475E0E2C850B87028C4B3FF1DB26CB9213F501CB11F0931022AF27CF76677456154991C5BA036080A6D904C0B0A209936B6C5462DCED750CF0848C1049B7A783BEC19FFB0190281804D786814EC585B837AF1AE28E7AD560DEE238AB9200D9E574977FFE678249A0ABB12E557C127154CBE2FD5A86298558EC668B809CE4BC3AF2963A36F6D29B99632D142936469D92BBFE78FDBC893260BACBD95DBD5262B6EA2337FD1E09F11A9AB2561B69B475ED9E88C49649512922415E28925B5294A240F0C3196BD08503902818100906270A43B086367F5632D138EAEC0D355859E83EBCC8C256528BB8EB3C242924AEB28AFDA15017D2BC949578806C6C4ECBEF636A1035340CF646278428F4DE35FDD4C5A2F4A9E3D25F6FB4E888E6953F7F84CF3AA5F90030FE9C2E656F7915C658DAD9F13FDEA5309DE934078BD3216A4A734E837A2A92B99E3791DF5C386A902818100AFE19A99B4A2C9A42017EA60947734758A99884B3653276CEEAB3894F5D7A39F9E203AEA3053FE15364B226105E35F31C856DAFA2A69AB72A794798024F8B5F6CDCFECAF2D984020FCF34455221859E09EA408C8D721D95523EE1A09B3F99F6A3B71E63D0528D23ADDBEF6ACA0085CD342E04B1EA0513A31B37439F0E57DCA2A -// 'threshold-bls' private key for threshold 3 out of 4 -3052247136709426809952601292746428082606212115043664080359369503360410402686 -// 'multisig-bls' private key for threshold 4 out of 4 -40537192832482126221972563240276769450015698116174463511830220622025378522 +# Concord-BFT replica keyfile private_replica_0. +# For replica 0 in a 4-replica cluster. + +num_replicas: 4 +f_val: 1 +c_val: 0 +replica_id: 0 + +# RSA non-threshold replica public keys +rsa_public_keys: + - 30820120300D06092A864886F70D01010105000382010D00308201080282010100A2F61615AAE619C54D4BD687A7D4E3D027A7505EA18BF0B82CC04B356BE0974C398B8F15E56099E5CE8B6222F24AC1C5F9B0C5DE3F3035C9759F0F09D0C2068719FE519EA2009E80F8DF4B6E7F03C2E0D6F064FC2E985867FCE66CAC8A9952ABA8056113292445DBC1297A6EE33729239C65D523D8CDFDB38848958940C33C74525E0155D99FF97D4C4D4317D33191763756ED0D3674D8037514572A418A0169151888ACA8EC31B631C04ED158E1B15A396C60D76292FEBBBDD3784D83ECB044ED767696AACDB6323EB1FB60746318AEBB9A5CC6DE339A92E17C2C0CA82B3C85F92DB9CE3DBF8653BDE53F4BF084D8F8C7CA5BEF4E0051FE05BAA8CF6DBC2399020111 + - 30820120300D06092A864886F70D01010105000382010D00308201080282010100B9C99EB540BCA677AB730EE058019D2432B384BF445053A7DC7E975873AEA9F3D5E2A77D80259F7819781C159A3B4FD24F2BCF02D4F4ED05EFDA782460AEB5CAE567228D9AA02B1DAAA1DD788CCC5DD88980B4418946D61BCB6A600302F9F9032469D82C419D1DA958CCA3DC25AA9602CAF85F4B6FC0A5ED0D3415FD47FB1F5775C0F648414319411B31D592454539A2D85ADD5CED0D0E819F66C8F4B63B4F31B57053116F4E4A35EB0D87F1094E9DC46B59FE2BB613B4A2E718DBDF52D1BE5EAD7F95552F8B406CD599A23732627BA4E0BD3C1A97BB14BB6F18785C6DE24E93C065A7372F3E954E5DC57386CE6D8AC815795A5B1BD7754473063AEC7B956409020111 + - 30820120300D06092A864886F70D01010105000382010D00308201080282010100B55EC87F1BB8FE06BAF17EF6C290B60AF008DE4D04D2EFC096B19D0E27E309328637A7BC5A591EF1F4CBDF7F21352BE9B144C1CF57CB56A99AD1E1859B0B0418EAB38F1B44A73C5D584E801FFE82788E22B29ADEEF07D6CA586467B8597F99BC9476D98E791806FD3B4D36568D30F5713183563A4B7FA94D452608F9CC1FB2E2A1E8AFAA9F858D33C28B7059CBA97F5E33EECD7B17DE456B5CE4143F720092C35B78026027221954DBCAAEAD8D82F7BACFF86782EC1182CBDA8E78AD13CE1A0C0323223CF435AEFDE3ABDD33C51294885C0CA3FEC50B64B7E5792032D72EDBA2D0D6071ECE706CA03B4F48690DC58FC977D67C31B60D8B1C59FE1EC054754C8B020111 + - 30820120300D06092A864886F70D01010105000382010D00308201080282010100C21ABAD2260E05E5DCBCCFC462608532EE1F2EC4C0C660E46BEACE4D4A435A45D31859D58B86FB853E28272D76D433FA2A975FC006967C76A8837B405C366D3E3A9DDC807E2DC6E0DB4472916A6149EF2EA65E7E89E77818DFDF4A9F38421F84C2CC507388A9A3B05D2DB3E2C99DFA325A5BB39387129CBEEBB1DA7DE621FFA1E0BB5ACF49562ED0DFBD03FD29A0F2FDE1011C62FD2B572B65F842CA01EBC5E182D4B92B46892F997DEB2169629E228F17BFDD25CCEA07EA5F3ABFB917D2A6C9CE9E026B9BC24EF58C48D3C7907B8EF6E5BA8554A9AF0FCCF7DDCB66DAC24939551D9747D726567336A7A1C7E3F8261F600E0597D80DA107C46E957D5E4DF4B5020111 + +# Execution threshold cryptosystem public configuration. +execution_cryptosystem_type: threshold-bls +execution_cryptosystem_subtype_parameter: BN-P254 +execution_cryptosystem_num_signers: 4 +execution_cryptosystem_threshold: 2 +execution_cryptosystem_public_key: 020d24a4e139d5a7d732b7112801b83b8c66db857af5aa0a6964f7d86f9fe2e9d91505dc5d67eb28e1df123363ce1b116eed9f410639bcc96b24da654ad8fe979f +execution_cryptosystem_verification_keys: + - 0212e1aa988094ee9c2263dd98048cb06d48bd818bbbf1205ffa6339658738d0112269849ea1ac55fe0f4986dc81fcfc80eed11152e3027669094b571ead277bbf + - 02042c10e830d8adbb92c464be5e8e043c982eed82cb45ca4b460f9d82aa183f18054d2580702c7a8475e0735bf228da3d15df3280691e854fc88e49fcee43c465 + - 0310f9a22eb94e068e7948f7a0ad64ed8371cb07b75ae52c74e3587cc690d9d7ee15160cc695f452ff71250eb05621c75996ac8580b967ec0588d26758a375a1ea + - 0302dda9f185850009b08a2f22cb637a15c9a2da677a11302267035e704179f4d70bda229a4fb6ae9af30ee8e82f608931657d501392905787b5ebe6597173e27d + +# Slow path commit threshold cryptosystem public configuration. +slow_commit_cryptosystem_type: threshold-bls +slow_commit_cryptosystem_subtype_parameter: BN-P254 +slow_commit_cryptosystem_num_signers: 4 +slow_commit_cryptosystem_threshold: 3 +slow_commit_cryptosystem_public_key: 02058ed8ae8b55cc3b674f8c05940554c32d35203c4d6fa0c7e54e91287e2f559105b3c0048be1bf32143825b1e96ce734d7cd8e39b28893ecfed01868fa37dbb4 +slow_commit_cryptosystem_verification_keys: + - 02093a80ed694ac9ee5096f37900762638be765f0d4517569761c1146509bb12671f5b1f30c1c4f987bc36216b4f69bed4ac1b54c7f094b9f01c4c8a538cc45ce8 + - 03242eff0e8a8639cc840d4438bec151de2e6840949d16dc006b0862cfd9bef2c3003a1783a4d8a1f2c2f195f5ec733e0e23a00b5da1d5eb5705b201b652bc23d9 + - 02204af450f399b20f3cc8285a3513fc0c39518f33e3f827eab68b16ac97be56aa085777893ed29d37a60fd77c69abdbfd05a3f6d51c9b25d3a9f33f4afbcdc061 + - 031bb32eada4d3f2e6fd6b63b5ad84af83babb1e4d569e6ab2ecdb0bb26bd07dba251cfd58721d0bb369044c470a5cea721006740eda5d909e850c259a09f10583 + +# Commit threshold cryptosystem public configuration. +commit_cryptosystem_type: threshold-bls +commit_cryptosystem_subtype_parameter: BN-P254 +commit_cryptosystem_num_signers: 4 +commit_cryptosystem_threshold: 4 +commit_cryptosystem_public_key: 031c28db8b612135328f04e2a31b85f65bc33bf4e1fb32d7df48939173a2d745c20f793682b23578eb4975d22a7af3b7bd61916e66f0dcbbcaefa118ad5fd7bd5d +commit_cryptosystem_verification_keys: + - 020de71ba1cd8c4a683e9d783013b92add014452826b3a4fc054e25dc651ee1d300df27b81a605cfb35dbf1ab9cbd7ce2a6e1778fa3a7c30766387eb5984ba5270 + - 03214a84285abf66a34c32dba5896ff4edc4c6f17a8333c39ac404fe0494c30f21191a5c5f509f3fd8e70c0630a0f6f33443b4ed8893fb3842fc12f3f8ff8c0d7f + - 031923249ea9ed334dffdc6569240d90ce57a194279135816bf43eba08c7fff455183e29aa1607a11a78ffad4b107f24548a01453f49cd5e9fcbd8dbf9f114f045 + - 0220d2253a629acc970521c2569170fdbe7f9ec9ed3a30405dd5d017ef056e785f12422f7cac5069e7d101eb017e8a98555d697356ebcccdad4c4f1bee4a4476f8 + +# Optimistic fast path commit threshold cryptosystem public configuration. +optimistic_commit_cryptosystem_type: multisig-bls +optimistic_commit_cryptosystem_subtype_parameter: BN-P254 +optimistic_commit_cryptosystem_num_signers: 4 +optimistic_commit_cryptosystem_threshold: 4 +optimistic_commit_cryptosystem_public_key: 0214fbcbb456f0bccd68a3ee42dd28255bea4c0b3aeb5abf820a3ae1d14405251e19bad72b6fb2c0fbceae2cfa7ab33e320d36b68bcbbcc51282b7486f43160a12 +optimistic_commit_cryptosystem_verification_keys: + - 020322fb834b84cc171f0da4c9bd1d9de18a141bfcd5817b82a59823571831cc2a1a02ce331ebfe01b51f7b001137ec9e28eca27a99f5dcec164b26aa07006f795 + - 020fb53bc712704671bc1ae6a19b729093d352fc1add47e9804733ef5dcf1849b0164a6e6a1fc3bf07aa5adf7f355525d8cd8f4d8f0b0c9723fd2bc800fdb715be + - 031b92e9dbf44ae5e87593e5ca6983fcca579ff22f28ea7e3dfd6ea8c98f19717609438156c91eac41ff2126274b0dcdfee0c1145754594ca3c7ec4ba4b2d6949e + - 02047f862a912d3c979c17a40284df584216361b8b3e95a36a6424e6c9dbfa326f08b3e556260d723591fe14e41bfae702197f721734dcb674a6f7a53aabc52a6c + +# Private keys for this replica +rsa_private_key: 308204BB020100300D06092A864886F70D0101010500048204A5308204A10201000282010100A2F61615AAE619C54D4BD687A7D4E3D027A7505EA18BF0B82CC04B356BE0974C398B8F15E56099E5CE8B6222F24AC1C5F9B0C5DE3F3035C9759F0F09D0C2068719FE519EA2009E80F8DF4B6E7F03C2E0D6F064FC2E985867FCE66CAC8A9952ABA8056113292445DBC1297A6EE33729239C65D523D8CDFDB38848958940C33C74525E0155D99FF97D4C4D4317D33191763756ED0D3674D8037514572A418A0169151888ACA8EC31B631C04ED158E1B15A396C60D76292FEBBBDD3784D83ECB044ED767696AACDB6323EB1FB60746318AEBB9A5CC6DE339A92E17C2C0CA82B3C85F92DB9CE3DBF8653BDE53F4BF084D8F8C7CA5BEF4E0051FE05BAA8CF6DBC2399020111028201000CC801BB6CC6C0C42E3824E7809D3F0B4E6779C125C4B381E5646A4A76E4704236B59CCA806BF7FDF214F8A35E4C2346BE400F84E1D195C986B7245115648D0F9DA583E448F0FD5F72E4563ADCC9144DDEA9715508AC937B9B5D5DDB562A249A03238F24A3DAB0255067A535DF9FEF25EE261AC18E7E96686F14C06F2837783127A66512C762CBBCA3998D1049EC27CD0A59D6FEA6663A26F53D603E309F88B4CCA5F65B0DD224529157BDA47BB47FEDB4CDC6A4F3CAC018B220E92160B279BCC47395ED2A28AEFA505BA47C2AF75CCD109AEFA03539F7BAE755721756E3E91963D716C580B917B3946E2DB6DF3A49002D4C694E9A1D096461D24F3B15AF462102818100D49FEA8906064167D7D199A25C499FBE35992972A0EE46B1931301DF2668F91C538F0B690D46CCA8D86F37048E247CAD207034551A78B9A0FE2CEBDEE8ABAC6FA87E8239FAC5116D7C4ED84487A560BD7D5945132297E51B70E77BB9FA540402FF5FC6AB75CABA0BBC1B1742ACF5D0915C1E2D724292B510C8773405D165E12B02818100C4348E1D656E12704E95E2E5C864F641BDC44E6BCBEF2BE12B32CA322F2EF94B9045783AAB6E15F09C3265DBA17FD59657BC87CB23C133DFE082F0050A5D73AE7C363CCCD681EDCD41D2B1ECC8EBD8BAAA89A87914F89EE86B1341A919FD5C7F40D790CC9EBCDE165D4D612DA567E5A52A1DEFD2DE7B652D5E0A029847DB844B0281807090E593D6034FCD905FE7EC8B36094694D89D78EBC970B85CEBF1EE9BDD38968697060A7070C6B3BDE08689F0E623E32F4A760EEFE58F735963137602B53D2C0DE89F4BDF1D0939F684182447D00609F7112491A8E700D24AD4E726393B89A73BE7692D98B69EBAEB1D66AAD409AAA74EE2CCC405207DF9D38A66D5E7540DCB028180229FDCD802D7306E2BFC55379BD594DE6CC84A1305DEE9A034CCBA451762A476BF1B5173C3E6401B66DBB79F3A9E16A20F7B9F7E337C7290EB6266977A4CBA0FBB9119C9CB80572438CAD41ABA0B8099696396337C2BDFCEA97BDE6922B43D7FDE44289C947BAEB8A70DA7BCC2D619777FE72A52637F2FF8F27A3CB17617ADEF028181008C2D4CE4A6A30D3734B88C682B245BD2FEC21A43D96E5DFBB3039270EC0610CF6EE50869CF28F272B6CEEF32510247D5337112CED3CB91DB2646425AA8E7AC558DE5240570AD000CB5944A198FCC4ED3020A31110BB0D55B894EAEAE14623827CB6FC65FE4CFF8D699538F6B514591E6E414380EC9A3F606A3084D59CD31F5C3 +execution_cryptosystem_private_key: 4681477801847123361755406387245152534550480451118126810777244852088086838231 +slow_commit_cryptosystem_private_key: 5713946288136062254062075275438026344483994821978045988384345788085926825955 +commit_cryptosystem_private_key: 6798518601337957613964853113267953965674312235544877846438744457040151693440 +optimistic_commit_cryptosystem_private_key: 9536283277718764239334725784840732393108097010967748970007452155896211818841 diff --git a/bftengine/tests/simpleTest/scripts/private_replica_1 b/bftengine/tests/simpleTest/scripts/private_replica_1 index 39006e9241..851b760486 100644 --- a/bftengine/tests/simpleTest/scripts/private_replica_1 +++ b/bftengine/tests/simpleTest/scripts/private_replica_1 @@ -1,6 +1,69 @@ -1 -308204BD020100300D06092A864886F70D0101010500048204A7308204A30201000282010100E4F34453CA6026B2E185E6FBBF85040333CB9558C73A95F7F44837536482AB82871CB4C4EC0FDD58143D662B656763E66B3B50B628CA700546E81C71BEED0B54FAAF1F43541AB7C5787FE21D180342B805A7E9B5076D84ACC30AC36C88B42C08A76DCFFBB484AA568969CABA993A73C3656FE50CEF1438D40E9AB2063FA8A2C41D57EDCFFA343788BBDB6D8E5C6BA879A6B9938CB5F1FFC861CC257AEDA55BD3F8F0086913F07AC3E19E30B42EFE7122B7B2AD27AD4BDA54A96C5F392B7A671573713180780B53F4B9F2C312837252BB624D694CE6F40C50C018E7B5F2D9C138F6838B6FAE2DA482D857423CEDF963B47ED00F25C96B7E721BEF29CDA8C3ECF70201110282010006BBDC5CD13F1032700B77BC1C389E3C5458CFAFC99FD73BFFA7C56455C79BA1F4EA418D523CB3AFC45C28A6EC64EC5999BDFAD82E604E96BE521EF449615328257D9F09827941A3ECF4B3D3ADE1FA6ED2FD68C18F46FC5F6F25F6B05E5FA6F13219D1694912F5F37C831C8D0481B81C55CE95CBACADC56FA6139BD301DF5014C5720E8822D45D17516DF309539A1E9B896ECD882501591C59F67F69AA1B18B5DE417973BA8391569711654FE91A8BDF50A38B23D289887D17B7E444BA2246D46940CFE2E9A50472E62AE92246BB1D4620C0FA3DA562046D2B31C9E4B98A571808F5995C15561E4F9F4576EB0836B230C58082AB09B070710EE5A1D39DC20C6D02818100F2032CE8E3D97DC6C3D3644224FE326DE43E7DBFB5A35C4B3F252A718242E84D74E75025B1978E66E47E482144889428934E71F93A225A5C21B6D94B1373FA9D10F65C152ADA3B4ECCDF1A0A8046BCB482085902BA7AB3C0C0B068024AD2CEB54E4D295590B7906A8F4BD0E76AC06ADD6C0A0CA8743387C742B0317F2DC033C302818100F22ED2D276265CA9276DC20F1CF5656381C3C9B81620CDB92FEA0F00D3C92B5EFF5696E49CDF9EDCECD073F5F4EF49516EABC06C7CE55F5B614934CD5F79044267DF3948454681635B60B27A9E51B2B686A3D41A3574C21042CBAF5303A76152779803DF48060D8521D1A61E6BF54E5CD7B4A7C60BC907A6DEBF7A33873E12BD02818100E3C6C0DB30CCB29CF48AB8B6B967B6FE03FE9478327BA228B3E6BE88F311CB9431CAA5C91F9DB333A9E043E313535E444E67F2CC72F327DE3DD944FB5D9A5548886F65B991BE55EFCFE109734B8DDEC801E9BD2FBE919A1ED378DA5C82A84A140D75CC8CC47087EBD2293D160A1E82B24790FCDAC7B8075220A5D43B765A8B11028181008036E815115F9A77AB7657ADA5EB53CB44B2F25266115DDA82C7351E8E3D53324AF19B2DBC766329AA8C79A0547EAE5849A638B1E7C4BA0333811BF4419A6BAAAF762D627F073570D6060422CC495E9CDDDE431CEF1FB2089BD53EB37A67ABFE7B8CB6C1807BACCE02D867010BFA56A99F5FA41D8DC4C7D0D04740B1DE2FEBCD02818100990339249E5E84C3DB026A09AB2EBDE893966B8D0044BD3F780F8A55E2078351ECBB549D30563BCDE94A96EBE9B0A21F6C53F56C7D58D11730D2C4D388F8E9D0BD4629FD66564C817799F057A21EA1E74B8973722E8CF1C0A2276307A06C898306AB7024107BB77E4BE26F2917ACEF7F4A6E76248F8B5395D6C94E9157FBD971 -// 'threshold-bls' private key for threshold 3 out of 4 -16504933221992010945433502773619442332155359654607428242883970447703165633187 -// 'multisig-bls' private key for threshold 4 out of 4 -8748230532740125108137913559477203628453848807982855170372454681341076283660 +# Concord-BFT replica keyfile private_replica_1. +# For replica 1 in a 4-replica cluster. + +num_replicas: 4 +f_val: 1 +c_val: 0 +replica_id: 1 + +# RSA non-threshold replica public keys +rsa_public_keys: + - 30820120300D06092A864886F70D01010105000382010D00308201080282010100A2F61615AAE619C54D4BD687A7D4E3D027A7505EA18BF0B82CC04B356BE0974C398B8F15E56099E5CE8B6222F24AC1C5F9B0C5DE3F3035C9759F0F09D0C2068719FE519EA2009E80F8DF4B6E7F03C2E0D6F064FC2E985867FCE66CAC8A9952ABA8056113292445DBC1297A6EE33729239C65D523D8CDFDB38848958940C33C74525E0155D99FF97D4C4D4317D33191763756ED0D3674D8037514572A418A0169151888ACA8EC31B631C04ED158E1B15A396C60D76292FEBBBDD3784D83ECB044ED767696AACDB6323EB1FB60746318AEBB9A5CC6DE339A92E17C2C0CA82B3C85F92DB9CE3DBF8653BDE53F4BF084D8F8C7CA5BEF4E0051FE05BAA8CF6DBC2399020111 + - 30820120300D06092A864886F70D01010105000382010D00308201080282010100B9C99EB540BCA677AB730EE058019D2432B384BF445053A7DC7E975873AEA9F3D5E2A77D80259F7819781C159A3B4FD24F2BCF02D4F4ED05EFDA782460AEB5CAE567228D9AA02B1DAAA1DD788CCC5DD88980B4418946D61BCB6A600302F9F9032469D82C419D1DA958CCA3DC25AA9602CAF85F4B6FC0A5ED0D3415FD47FB1F5775C0F648414319411B31D592454539A2D85ADD5CED0D0E819F66C8F4B63B4F31B57053116F4E4A35EB0D87F1094E9DC46B59FE2BB613B4A2E718DBDF52D1BE5EAD7F95552F8B406CD599A23732627BA4E0BD3C1A97BB14BB6F18785C6DE24E93C065A7372F3E954E5DC57386CE6D8AC815795A5B1BD7754473063AEC7B956409020111 + - 30820120300D06092A864886F70D01010105000382010D00308201080282010100B55EC87F1BB8FE06BAF17EF6C290B60AF008DE4D04D2EFC096B19D0E27E309328637A7BC5A591EF1F4CBDF7F21352BE9B144C1CF57CB56A99AD1E1859B0B0418EAB38F1B44A73C5D584E801FFE82788E22B29ADEEF07D6CA586467B8597F99BC9476D98E791806FD3B4D36568D30F5713183563A4B7FA94D452608F9CC1FB2E2A1E8AFAA9F858D33C28B7059CBA97F5E33EECD7B17DE456B5CE4143F720092C35B78026027221954DBCAAEAD8D82F7BACFF86782EC1182CBDA8E78AD13CE1A0C0323223CF435AEFDE3ABDD33C51294885C0CA3FEC50B64B7E5792032D72EDBA2D0D6071ECE706CA03B4F48690DC58FC977D67C31B60D8B1C59FE1EC054754C8B020111 + - 30820120300D06092A864886F70D01010105000382010D00308201080282010100C21ABAD2260E05E5DCBCCFC462608532EE1F2EC4C0C660E46BEACE4D4A435A45D31859D58B86FB853E28272D76D433FA2A975FC006967C76A8837B405C366D3E3A9DDC807E2DC6E0DB4472916A6149EF2EA65E7E89E77818DFDF4A9F38421F84C2CC507388A9A3B05D2DB3E2C99DFA325A5BB39387129CBEEBB1DA7DE621FFA1E0BB5ACF49562ED0DFBD03FD29A0F2FDE1011C62FD2B572B65F842CA01EBC5E182D4B92B46892F997DEB2169629E228F17BFDD25CCEA07EA5F3ABFB917D2A6C9CE9E026B9BC24EF58C48D3C7907B8EF6E5BA8554A9AF0FCCF7DDCB66DAC24939551D9747D726567336A7A1C7E3F8261F600E0597D80DA107C46E957D5E4DF4B5020111 + +# Execution threshold cryptosystem public configuration. +execution_cryptosystem_type: threshold-bls +execution_cryptosystem_subtype_parameter: BN-P254 +execution_cryptosystem_num_signers: 4 +execution_cryptosystem_threshold: 2 +execution_cryptosystem_public_key: 020d24a4e139d5a7d732b7112801b83b8c66db857af5aa0a6964f7d86f9fe2e9d91505dc5d67eb28e1df123363ce1b116eed9f410639bcc96b24da654ad8fe979f +execution_cryptosystem_verification_keys: + - 0212e1aa988094ee9c2263dd98048cb06d48bd818bbbf1205ffa6339658738d0112269849ea1ac55fe0f4986dc81fcfc80eed11152e3027669094b571ead277bbf + - 02042c10e830d8adbb92c464be5e8e043c982eed82cb45ca4b460f9d82aa183f18054d2580702c7a8475e0735bf228da3d15df3280691e854fc88e49fcee43c465 + - 0310f9a22eb94e068e7948f7a0ad64ed8371cb07b75ae52c74e3587cc690d9d7ee15160cc695f452ff71250eb05621c75996ac8580b967ec0588d26758a375a1ea + - 0302dda9f185850009b08a2f22cb637a15c9a2da677a11302267035e704179f4d70bda229a4fb6ae9af30ee8e82f608931657d501392905787b5ebe6597173e27d + +# Slow path commit threshold cryptosystem public configuration. +slow_commit_cryptosystem_type: threshold-bls +slow_commit_cryptosystem_subtype_parameter: BN-P254 +slow_commit_cryptosystem_num_signers: 4 +slow_commit_cryptosystem_threshold: 3 +slow_commit_cryptosystem_public_key: 02058ed8ae8b55cc3b674f8c05940554c32d35203c4d6fa0c7e54e91287e2f559105b3c0048be1bf32143825b1e96ce734d7cd8e39b28893ecfed01868fa37dbb4 +slow_commit_cryptosystem_verification_keys: + - 02093a80ed694ac9ee5096f37900762638be765f0d4517569761c1146509bb12671f5b1f30c1c4f987bc36216b4f69bed4ac1b54c7f094b9f01c4c8a538cc45ce8 + - 03242eff0e8a8639cc840d4438bec151de2e6840949d16dc006b0862cfd9bef2c3003a1783a4d8a1f2c2f195f5ec733e0e23a00b5da1d5eb5705b201b652bc23d9 + - 02204af450f399b20f3cc8285a3513fc0c39518f33e3f827eab68b16ac97be56aa085777893ed29d37a60fd77c69abdbfd05a3f6d51c9b25d3a9f33f4afbcdc061 + - 031bb32eada4d3f2e6fd6b63b5ad84af83babb1e4d569e6ab2ecdb0bb26bd07dba251cfd58721d0bb369044c470a5cea721006740eda5d909e850c259a09f10583 + +# Commit threshold cryptosystem public configuration. +commit_cryptosystem_type: threshold-bls +commit_cryptosystem_subtype_parameter: BN-P254 +commit_cryptosystem_num_signers: 4 +commit_cryptosystem_threshold: 4 +commit_cryptosystem_public_key: 031c28db8b612135328f04e2a31b85f65bc33bf4e1fb32d7df48939173a2d745c20f793682b23578eb4975d22a7af3b7bd61916e66f0dcbbcaefa118ad5fd7bd5d +commit_cryptosystem_verification_keys: + - 020de71ba1cd8c4a683e9d783013b92add014452826b3a4fc054e25dc651ee1d300df27b81a605cfb35dbf1ab9cbd7ce2a6e1778fa3a7c30766387eb5984ba5270 + - 03214a84285abf66a34c32dba5896ff4edc4c6f17a8333c39ac404fe0494c30f21191a5c5f509f3fd8e70c0630a0f6f33443b4ed8893fb3842fc12f3f8ff8c0d7f + - 031923249ea9ed334dffdc6569240d90ce57a194279135816bf43eba08c7fff455183e29aa1607a11a78ffad4b107f24548a01453f49cd5e9fcbd8dbf9f114f045 + - 0220d2253a629acc970521c2569170fdbe7f9ec9ed3a30405dd5d017ef056e785f12422f7cac5069e7d101eb017e8a98555d697356ebcccdad4c4f1bee4a4476f8 + +# Optimistic fast path commit threshold cryptosystem public configuration. +optimistic_commit_cryptosystem_type: multisig-bls +optimistic_commit_cryptosystem_subtype_parameter: BN-P254 +optimistic_commit_cryptosystem_num_signers: 4 +optimistic_commit_cryptosystem_threshold: 4 +optimistic_commit_cryptosystem_public_key: 0214fbcbb456f0bccd68a3ee42dd28255bea4c0b3aeb5abf820a3ae1d14405251e19bad72b6fb2c0fbceae2cfa7ab33e320d36b68bcbbcc51282b7486f43160a12 +optimistic_commit_cryptosystem_verification_keys: + - 020322fb834b84cc171f0da4c9bd1d9de18a141bfcd5817b82a59823571831cc2a1a02ce331ebfe01b51f7b001137ec9e28eca27a99f5dcec164b26aa07006f795 + - 020fb53bc712704671bc1ae6a19b729093d352fc1add47e9804733ef5dcf1849b0164a6e6a1fc3bf07aa5adf7f355525d8cd8f4d8f0b0c9723fd2bc800fdb715be + - 031b92e9dbf44ae5e87593e5ca6983fcca579ff22f28ea7e3dfd6ea8c98f19717609438156c91eac41ff2126274b0dcdfee0c1145754594ca3c7ec4ba4b2d6949e + - 02047f862a912d3c979c17a40284df584216361b8b3e95a36a6424e6c9dbfa326f08b3e556260d723591fe14e41bfae702197f721734dcb674a6f7a53aabc52a6c + +# Private keys for this replica +rsa_private_key: 308204BA020100300D06092A864886F70D0101010500048204A4308204A00201000282010100B9C99EB540BCA677AB730EE058019D2432B384BF445053A7DC7E975873AEA9F3D5E2A77D80259F7819781C159A3B4FD24F2BCF02D4F4ED05EFDA782460AEB5CAE567228D9AA02B1DAAA1DD788CCC5DD88980B4418946D61BCB6A600302F9F9032469D82C419D1DA958CCA3DC25AA9602CAF85F4B6FC0A5ED0D3415FD47FB1F5775C0F648414319411B31D592454539A2D85ADD5CED0D0E819F66C8F4B63B4F31B57053116F4E4A35EB0D87F1094E9DC46B59FE2BB613B4A2E718DBDF52D1BE5EAD7F95552F8B406CD599A23732627BA4E0BD3C1A97BB14BB6F18785C6DE24E93C065A7372F3E954E5DC57386CE6D8AC815795A5B1BD7754473063AEC7B9564090201110282010008324E87FF1761B274BD8BF34F2D3F673E78DC71D99A21CEEF5FF016B9CF3C342B518763A789307279981F5B4E5570B2B0AB583110ECB01A9D67C18922620F8CB74C1459121DA78C9A59F6F27EAEA9C98D98806C4D95F2DB9444B1698B6CE91A7DD77E3E301239C7789F9DD13DE5A4BC5BC73161721B529D481CA69DFF693252D7955B724A1BAF25BA3C97DB29494D4E13AB2D1760507240DC1B82ABCA7BE3054FE892F584B99950902F31D70D7DA26DDC3B498863C2A7F49DF97F96FAE138DED4805BFC3DBEED2B92C90096DA48D2735483C75E4AD966341A72D4BD8112B97EF888B3ABB3196432AE1EDD0EFA4B354EE1456940FCA5198899E56E560DD89C7D02818100D170CEA6859B980AE2A56A1EAC17A668EA7F0B8EBC051BA3D63CA5CFD8EF78C90BAB48DF45ECEE56EE537990242B1C2031D46BAF8DB4C6BCC5BB32CE577AA7FD547589304DD8E5BB5B007204B2628DF32D5D5BA3D607ED1B82C30401AAC28B70E89559E90AA4FDEBD2782555155CB1F345B9DC84156921136D6F2B230DCFA26D02818100E316B9832BDEA9DF10844EB69C0565A5855E7E66FF3DD51FA1653BEEEFA911F0412D5C75139D1E12388C4F565E03CA94B99B0FBDFDCD643D79F107B2C4BB62A688573C7A14CAB02B2622782C818D4B7B8D0A3972CBC8C5AD94D548E8AACCABE4D66064C4F3AF62E5CB3C66338FBD75D8DD9A2C15FD2566C36546A02ADE97E68D0281807B334C61F43D687EDFAC98C6BF9570F26BD24308AAD5D406058D163E0723743A06DD39ECBFB88C3322C7B0EB6091D44F2C5ED5EECBD3C032CEAA5A1F0648269504815FC20FACC35F2678BB8A4AD08FBC38CD8133329B402E4CEB2F8882908E426AB234E36FAC59214EA106E6C14595DA6540275CC14CE647A9C8EC32BCD47DA90281806ADD8479F686E68716D4D9BF587B02A83EC30E4E963B371DF1990D25257CBD25C45194EBCCFEA4BD47C98EBF3B4D1409C0C170D1E0D9201CEE1712AE7AB288C6D6BFA3FD36F5F88CC6A6CF2400BAF658425F2A17E76D8A3391554F7C8C9C8D2064E2114D9FDA106C2367B79FCB2BFB38E0C105AFFEA8305BF36C879BB40B3F5102818004F815D801C868F08E71B595E7B050E2539EC78F5673EC165D49699A942BBD8DA3C0D6EDB27C448EF62E65BDD46EC247663D410D20995B05C7BB8823C464846329F74370C1B821CB2ABA4E51DB83869EC8E5455A1D41F15BB67CB65AFE8C2883D08974B1EEA99282CD3B1DDFBE213523032B8E44E7C649E6D14348A6169055E4 +execution_cryptosystem_private_key: 14991831654610688606890052632997236039711231583608467688338524740439307485857 +slow_commit_cryptosystem_private_key: 12808602575807384160464102567671972960286707046483574707369229571091479303781 +commit_cryptosystem_private_key: 2542944741026621257838986975981418110477519106405321844033100892640963583616 +optimistic_commit_cryptosystem_private_key: 1898929273882552010740990889013359392802440236614290035997754166259466767419 diff --git a/bftengine/tests/simpleTest/scripts/private_replica_2 b/bftengine/tests/simpleTest/scripts/private_replica_2 index dfee03264d..ff5c977b3f 100644 --- a/bftengine/tests/simpleTest/scripts/private_replica_2 +++ b/bftengine/tests/simpleTest/scripts/private_replica_2 @@ -1,6 +1,69 @@ -2 -308204BB020100300D06092A864886F70D0101010500048204A5308204A102010002820101009B93D9A4D3326036680108CEEDE528E0D68A32AC5B591AF15B212931FAE4FCDD8BF26722961159E905D2B7626FF08627FD9F5B24E0303911BBD58A5C50D69CFEB3703DF585D12B89E711E0661F6D0AD49A9172C52C42E07D3D88FCC240A003E9C70E0CEB436FE8F5677CF63BDB620772385F703C04EE348EC4D5515A359F11B21E1CEE60049B5A38E9D5B63FEBB21DD4D56D67150F5E5F920487794700B76391741D392E521DE01BF7A160D96B7A5521F16430584EEFEF3CBF3528CD574CAF37516076576477A9A58EAF760931C600C5C437A470FFE440CB1F8E22C46D92BFEE19F9A6BA2F3DD55BCCC3132AA0219A4C5E880A8CDDAF05D2D05ACD849DEC1B990201110282010014975546C1997DACD90F321B63403659FE46FF2D667170BE0FD372A0F7CB7BD2073A6F8857A06A047D01893670B2A8581DCD8FD3F07EDA6076FA615F0AB2FE30C4ECF92442A6FA77E61CB80D8428C8F67DDE8B6CEB81526AEDCA99EC888DA62A3C3A54888CB0B1A802672096FB2753CF1E0CA1AD973DA512E55877F19627E0757C47147FFBCAED7EACE0D2A48DA6FE26D281D2F42A9680C87B8E26D395F5360EBF17F8E4CB385B21CE51634020872FF0E27CC907BCBB583BBC1749292FBF1B0F157F0BA45A56F0D421BA20AEF07FB9261F41A067D72887B63A48E82B9E879E176D1D53760B801B5B62B8C86FDAA0FF2184A89CF4184629283CAF19A24458C31502818100D113C7D5B7053D55243D7C1E6F2E916209E011C5D3D4C935686C15323C161BB9AC4E985DE35576871A95C59389342DAD8188E56B7049CC5B6F7F262F19D4365139282CAF55427960E98C0193AFF5F372175D431C5DCA6178A30CBCA5E4A3E16BD60068251CA538D3D021E9C37E41DFE90622664D97DA507335CDD55E6DFAC8B502818100BE7E52C350EE36EDC7D91F0D4E407DF82346A9A8A46DC955685B2247E5D65A13078B4848A83B0E5C8D4F580C08F367E6A42C787985906BC8A62284837F62C8E5E794D5400F4EF83AC2C199F668B5B2DE4EEA88EEBA3CFA636ECC530DDB27179860E2C7FCBBB43F9CA0F4228BCA74A4828A881ED21CA629132561FD950F19C9D5028181009FE1F32AF55E5C13EE895EEA18C941FFAD32E06A1A758ACE7D075B80C489607EED2D0B1A9EC8E22B145469E94ACD8C57812C73340A92C9731906E0F6D784298967F18B952314B72BFDE388BC3B439C0BF3BFC9E883F51D5C407326D9365F33E90D0F5EB2F7C9A3ED44CEA3B39CC8F68504B0E4D1EC97E32AECE8B23926ECF3D502818059A4DBA73524CE8E03B1780642F12C38891231B8C5D94FAFB8A35B6D20DD57907C054F31401BCA85E825569C40728B3F5C5129A29934E76D7B5B89A74B014F7B3FCD91878EBBC01BA6F1B1DD5E739F77ACAA9ACAB1FE93F28E7E4533B26CBFCF3CA6F4B32B27A576E254C4F67D64112E5F4F1D900D7B5E9F991F0DEBCADEF591028180488C596A10E45CC3945D688942FA41FE92E2CC09A9853F325B64167CAB1F54CA8DEAA6AE4A2757BA2603A8FD8A03BD760E40121C8AAEE76BD690FA5252A4051F16ABE3E0B55F82766C4DD7BC4AF182269DE490D5B606B59A4BDF5C8CF2526F0569BBC830145E23E6AEAC3EABA74B744BD2FB5120A5DBD098DEB00EE540867449 -// 'threshold-bls' private key for threshold 3 out of 4 -6510632974842924712235661145704412318904958942478900952106410999261410134527 -// 'multisig-bls' private key for threshold 4 out of 4 -13854519404447903207969572812584393279285272324041832302268901917686786456768 +# Concord-BFT replica keyfile private_replica_2. +# For replica 2 in a 4-replica cluster. + +num_replicas: 4 +f_val: 1 +c_val: 0 +replica_id: 2 + +# RSA non-threshold replica public keys +rsa_public_keys: + - 30820120300D06092A864886F70D01010105000382010D00308201080282010100A2F61615AAE619C54D4BD687A7D4E3D027A7505EA18BF0B82CC04B356BE0974C398B8F15E56099E5CE8B6222F24AC1C5F9B0C5DE3F3035C9759F0F09D0C2068719FE519EA2009E80F8DF4B6E7F03C2E0D6F064FC2E985867FCE66CAC8A9952ABA8056113292445DBC1297A6EE33729239C65D523D8CDFDB38848958940C33C74525E0155D99FF97D4C4D4317D33191763756ED0D3674D8037514572A418A0169151888ACA8EC31B631C04ED158E1B15A396C60D76292FEBBBDD3784D83ECB044ED767696AACDB6323EB1FB60746318AEBB9A5CC6DE339A92E17C2C0CA82B3C85F92DB9CE3DBF8653BDE53F4BF084D8F8C7CA5BEF4E0051FE05BAA8CF6DBC2399020111 + - 30820120300D06092A864886F70D01010105000382010D00308201080282010100B9C99EB540BCA677AB730EE058019D2432B384BF445053A7DC7E975873AEA9F3D5E2A77D80259F7819781C159A3B4FD24F2BCF02D4F4ED05EFDA782460AEB5CAE567228D9AA02B1DAAA1DD788CCC5DD88980B4418946D61BCB6A600302F9F9032469D82C419D1DA958CCA3DC25AA9602CAF85F4B6FC0A5ED0D3415FD47FB1F5775C0F648414319411B31D592454539A2D85ADD5CED0D0E819F66C8F4B63B4F31B57053116F4E4A35EB0D87F1094E9DC46B59FE2BB613B4A2E718DBDF52D1BE5EAD7F95552F8B406CD599A23732627BA4E0BD3C1A97BB14BB6F18785C6DE24E93C065A7372F3E954E5DC57386CE6D8AC815795A5B1BD7754473063AEC7B956409020111 + - 30820120300D06092A864886F70D01010105000382010D00308201080282010100B55EC87F1BB8FE06BAF17EF6C290B60AF008DE4D04D2EFC096B19D0E27E309328637A7BC5A591EF1F4CBDF7F21352BE9B144C1CF57CB56A99AD1E1859B0B0418EAB38F1B44A73C5D584E801FFE82788E22B29ADEEF07D6CA586467B8597F99BC9476D98E791806FD3B4D36568D30F5713183563A4B7FA94D452608F9CC1FB2E2A1E8AFAA9F858D33C28B7059CBA97F5E33EECD7B17DE456B5CE4143F720092C35B78026027221954DBCAAEAD8D82F7BACFF86782EC1182CBDA8E78AD13CE1A0C0323223CF435AEFDE3ABDD33C51294885C0CA3FEC50B64B7E5792032D72EDBA2D0D6071ECE706CA03B4F48690DC58FC977D67C31B60D8B1C59FE1EC054754C8B020111 + - 30820120300D06092A864886F70D01010105000382010D00308201080282010100C21ABAD2260E05E5DCBCCFC462608532EE1F2EC4C0C660E46BEACE4D4A435A45D31859D58B86FB853E28272D76D433FA2A975FC006967C76A8837B405C366D3E3A9DDC807E2DC6E0DB4472916A6149EF2EA65E7E89E77818DFDF4A9F38421F84C2CC507388A9A3B05D2DB3E2C99DFA325A5BB39387129CBEEBB1DA7DE621FFA1E0BB5ACF49562ED0DFBD03FD29A0F2FDE1011C62FD2B572B65F842CA01EBC5E182D4B92B46892F997DEB2169629E228F17BFDD25CCEA07EA5F3ABFB917D2A6C9CE9E026B9BC24EF58C48D3C7907B8EF6E5BA8554A9AF0FCCF7DDCB66DAC24939551D9747D726567336A7A1C7E3F8261F600E0597D80DA107C46E957D5E4DF4B5020111 + +# Execution threshold cryptosystem public configuration. +execution_cryptosystem_type: threshold-bls +execution_cryptosystem_subtype_parameter: BN-P254 +execution_cryptosystem_num_signers: 4 +execution_cryptosystem_threshold: 2 +execution_cryptosystem_public_key: 020d24a4e139d5a7d732b7112801b83b8c66db857af5aa0a6964f7d86f9fe2e9d91505dc5d67eb28e1df123363ce1b116eed9f410639bcc96b24da654ad8fe979f +execution_cryptosystem_verification_keys: + - 0212e1aa988094ee9c2263dd98048cb06d48bd818bbbf1205ffa6339658738d0112269849ea1ac55fe0f4986dc81fcfc80eed11152e3027669094b571ead277bbf + - 02042c10e830d8adbb92c464be5e8e043c982eed82cb45ca4b460f9d82aa183f18054d2580702c7a8475e0735bf228da3d15df3280691e854fc88e49fcee43c465 + - 0310f9a22eb94e068e7948f7a0ad64ed8371cb07b75ae52c74e3587cc690d9d7ee15160cc695f452ff71250eb05621c75996ac8580b967ec0588d26758a375a1ea + - 0302dda9f185850009b08a2f22cb637a15c9a2da677a11302267035e704179f4d70bda229a4fb6ae9af30ee8e82f608931657d501392905787b5ebe6597173e27d + +# Slow path commit threshold cryptosystem public configuration. +slow_commit_cryptosystem_type: threshold-bls +slow_commit_cryptosystem_subtype_parameter: BN-P254 +slow_commit_cryptosystem_num_signers: 4 +slow_commit_cryptosystem_threshold: 3 +slow_commit_cryptosystem_public_key: 02058ed8ae8b55cc3b674f8c05940554c32d35203c4d6fa0c7e54e91287e2f559105b3c0048be1bf32143825b1e96ce734d7cd8e39b28893ecfed01868fa37dbb4 +slow_commit_cryptosystem_verification_keys: + - 02093a80ed694ac9ee5096f37900762638be765f0d4517569761c1146509bb12671f5b1f30c1c4f987bc36216b4f69bed4ac1b54c7f094b9f01c4c8a538cc45ce8 + - 03242eff0e8a8639cc840d4438bec151de2e6840949d16dc006b0862cfd9bef2c3003a1783a4d8a1f2c2f195f5ec733e0e23a00b5da1d5eb5705b201b652bc23d9 + - 02204af450f399b20f3cc8285a3513fc0c39518f33e3f827eab68b16ac97be56aa085777893ed29d37a60fd77c69abdbfd05a3f6d51c9b25d3a9f33f4afbcdc061 + - 031bb32eada4d3f2e6fd6b63b5ad84af83babb1e4d569e6ab2ecdb0bb26bd07dba251cfd58721d0bb369044c470a5cea721006740eda5d909e850c259a09f10583 + +# Commit threshold cryptosystem public configuration. +commit_cryptosystem_type: threshold-bls +commit_cryptosystem_subtype_parameter: BN-P254 +commit_cryptosystem_num_signers: 4 +commit_cryptosystem_threshold: 4 +commit_cryptosystem_public_key: 031c28db8b612135328f04e2a31b85f65bc33bf4e1fb32d7df48939173a2d745c20f793682b23578eb4975d22a7af3b7bd61916e66f0dcbbcaefa118ad5fd7bd5d +commit_cryptosystem_verification_keys: + - 020de71ba1cd8c4a683e9d783013b92add014452826b3a4fc054e25dc651ee1d300df27b81a605cfb35dbf1ab9cbd7ce2a6e1778fa3a7c30766387eb5984ba5270 + - 03214a84285abf66a34c32dba5896ff4edc4c6f17a8333c39ac404fe0494c30f21191a5c5f509f3fd8e70c0630a0f6f33443b4ed8893fb3842fc12f3f8ff8c0d7f + - 031923249ea9ed334dffdc6569240d90ce57a194279135816bf43eba08c7fff455183e29aa1607a11a78ffad4b107f24548a01453f49cd5e9fcbd8dbf9f114f045 + - 0220d2253a629acc970521c2569170fdbe7f9ec9ed3a30405dd5d017ef056e785f12422f7cac5069e7d101eb017e8a98555d697356ebcccdad4c4f1bee4a4476f8 + +# Optimistic fast path commit threshold cryptosystem public configuration. +optimistic_commit_cryptosystem_type: multisig-bls +optimistic_commit_cryptosystem_subtype_parameter: BN-P254 +optimistic_commit_cryptosystem_num_signers: 4 +optimistic_commit_cryptosystem_threshold: 4 +optimistic_commit_cryptosystem_public_key: 0214fbcbb456f0bccd68a3ee42dd28255bea4c0b3aeb5abf820a3ae1d14405251e19bad72b6fb2c0fbceae2cfa7ab33e320d36b68bcbbcc51282b7486f43160a12 +optimistic_commit_cryptosystem_verification_keys: + - 020322fb834b84cc171f0da4c9bd1d9de18a141bfcd5817b82a59823571831cc2a1a02ce331ebfe01b51f7b001137ec9e28eca27a99f5dcec164b26aa07006f795 + - 020fb53bc712704671bc1ae6a19b729093d352fc1add47e9804733ef5dcf1849b0164a6e6a1fc3bf07aa5adf7f355525d8cd8f4d8f0b0c9723fd2bc800fdb715be + - 031b92e9dbf44ae5e87593e5ca6983fcca579ff22f28ea7e3dfd6ea8c98f19717609438156c91eac41ff2126274b0dcdfee0c1145754594ca3c7ec4ba4b2d6949e + - 02047f862a912d3c979c17a40284df584216361b8b3e95a36a6424e6c9dbfa326f08b3e556260d723591fe14e41bfae702197f721734dcb674a6f7a53aabc52a6c + +# Private keys for this replica +rsa_private_key: 308204BC020100300D06092A864886F70D0101010500048204A6308204A20201000282010100B55EC87F1BB8FE06BAF17EF6C290B60AF008DE4D04D2EFC096B19D0E27E309328637A7BC5A591EF1F4CBDF7F21352BE9B144C1CF57CB56A99AD1E1859B0B0418EAB38F1B44A73C5D584E801FFE82788E22B29ADEEF07D6CA586467B8597F99BC9476D98E791806FD3B4D36568D30F5713183563A4B7FA94D452608F9CC1FB2E2A1E8AFAA9F858D33C28B7059CBA97F5E33EECD7B17DE456B5CE4143F720092C35B78026027221954DBCAAEAD8D82F7BACFF86782EC1182CBDA8E78AD13CE1A0C0323223CF435AEFDE3ABDD33C51294885C0CA3FEC50B64B7E5792032D72EDBA2D0D6071ECE706CA03B4F48690DC58FC977D67C31B60D8B1C59FE1EC054754C8B020111028201005559C7C358570E2148EA1DA14C8055AACB4F77ABC608E94B92357715B86AD726D5BFD676C11AE162CD8D1DE17909F68C172F6A43749BEC8C0C9F00B758052F1AC8CCF80CD50367B374D9A5B4B40129AC4C9048E1616D19C8A21121C02A1DEDFE63FBB1AC75387BC2764273EC7EADA0ADBCF282EE41A57CD9117B4F849C4B270071E30F780477C435574AD2208CC91F3752EFB8FFCB4A52AE575C0AC21FD1633DE8EC01B5F7FA0C8DAE5CD8C943CF998828A02D86911DFAD14CFEEC187C5F65155677FC1C6C1C24C76CF59871E697917F676D436559028093543C85DD77682471CB8B00611F394EB31019362D2B98508350EA5C1575225957BBDEADED6DB0D7F102818100E6367210E6535D7A93CCCD0B27240732518A6621D63E8587AA04CC56110EAA097CDC3B76C1176241F7755239F40F70B7D16A810134428541FC51A0B08E918EB26BC2DF903D5B343C31261CE0D085BD5E8B9BB1FD31EE5C425E743AEDF8B3BAF093FDD39B8E76EF46ABEEE590AFF422534AA24CDBE4DD3F4BB929EF62C948677B02818100C9AFBCBAAFB3AEC7D53FA4C9795A15D65226FE39B1A1D031393BB10CDD54F5D64FA64346B7175C65D1D00FC7E95A60C1A83985C3C36F488D1A9F22487CF1D48C3FA14AF0511EAC99EAFBDC60EA8AC1FB14A8C2CA35F7B73C740448CE40BDD3406C50D2B4DD9FB61D0D2ACFB8612DC25F21422BA838474DF6319AFDC502151A3102818100876B52280F03DCA2750F0F33BCABC7FF7B425A32058E306DEB8A5A14828118BA49727D54EA0DC153FAF9B7E5DADBE7F3A85CC45B0FAEA8BD673F133AAE37811DA8CCFBFA7E71E27DC28EE3CF89B8150A703D77C21D5F0917FB536DF5651E6DF6EDA45E5B80FAAADE4704FF8249626E8B59142D360E27CAE13FBE50947666D375028180472EF750F2B7E355968EEEDDB25C07B50DEFA5054DC0A3D523423E7D02D2B11E7676EA916DCC027E4A0D32BF0710D6DAF0144D5426DBFB7D18746673EFDCE19AE947FC54D1561ECCE986118B9E12DB0D5295EA657C758BF73801831B9E611D62081C869A301A40467D1E2B32042E449A0BBD00597D4657C04DBE3B72B570DC1102818100B5130AB112580F43B252AD881425679EAA78D37C925664E4218EDCDEEAE1EF976AC084DA60A8B27E2CC2E604166B5E2DE2BCC7573EAE9EC0820AEF3DE5BC24A485A62826EA66D99F29FB5773A34236BC54EA5579FAFEC8FEA62311B51C83ACAF12E6B60BF677E7E4DCE03B9ED9A76DE74784157416C51F8D9ACB1274B9670DD6 +execution_cryptosystem_private_key: 8504076776358421567083894736517585635112403112694055816871425764624957917534 +slow_commit_cryptosystem_private_key: 8741252438524156776027803973937400511687985424963596749532357738237931171959 +commit_cryptosystem_private_key: 8802427667512181050444223619266739265908410210191712114555705994338146024288 +optimistic_commit_cryptosystem_private_key: 9236185114513455157724050468710908007724321945838330740309448661407027883097 diff --git a/bftengine/tests/simpleTest/scripts/private_replica_3 b/bftengine/tests/simpleTest/scripts/private_replica_3 index c596293060..3de3b12bb3 100644 --- a/bftengine/tests/simpleTest/scripts/private_replica_3 +++ b/bftengine/tests/simpleTest/scripts/private_replica_3 @@ -1,6 +1,69 @@ -3 -308204BB020100300D06092A864886F70D0101010500048204A5308204A10201000282010100D622DFBC52C8B90FD7852D035E606ACA63AC94B5837B138B8FE6035CC5AB08A84E71BB9D2FD3E33EBDFAE2A709E2E8E501DE20295C3BD95684F59FDC6731E2735A4E72F3DFC532499E0C1A95DF036C3E2A4F69C8F07B0AAAD074F3CCE5A52988CCE80F4494FD9942BFBC87FC3ADE5229514C6AE03449EC69BC92B67AF4FCD431E2036893EEC139BD01144C90B6CD0B52EF7F1779B634C07E80EDC1682ED1F0FC60A91248A1FFAAED3ECA96EC3B464C19C208447784FA499F5D2403A4831C641631A9D355988B4E3512FF0C7603A4DB944ABCC310CB25B8B425682403900294352D814405D2C5088DE9061A29BD89CC1E7808406741216DBAA3E0B6A1A35D862502011102820100023FD4191AAF48EF7E7FC913EF3E52DEA150DF2453AAB45F95692387F751EE57D17F0B1D1466CC1154D1B1B5628625F1320953294EF3B89A2FA6136D5722680696FFBF981305D60A7436FBFA0B7C457084BF388192A9173CF434DBD696D96615560D31A3ADAA7650D5E9C758297E086477B60BE102B354C4E0193478AFBFF778F9AFB153A9C2FB8B941527EDB7F572FAC43587A3A35F9CE20148FBCC6293E85BFBAB9E91753502C3034105619BB0169233B07C400A325C666594FFA61E38CDC7BFCC2A294214C5F9BD9A81382F8145BBCB45AEFA429C65F639609136BF91381F708E6F86029D42C897A69C5634E5E8B0E76B53A0DE6D6FE5E94C0685355B38E902818100F42061331C19E6DC8FE0162C3D5678D21ED424D19870211A5E8622B0498DD4C7B31166984478CFB1F91597630DB3F121F3E2B1CC21C65B20020862D3250B1AC24E7E48A3FA4C3A52FFD1D8FD1321DB171A8E430D71F813D94122B87530528E581E548BCFDED5AEC73B051FDE875985A995B320E553140990A60354CA78BA3DCD02818100E08D15DDB1582E2BC622F6CA76FC9D3FD98FB500F636482541A9FB833CA9B3997CF8B3FF2DD03AB60FED65A34816C2FFC8842ADACBACC537FAE628A48757F63EF6724359D81F0E35F751F29412D6AB73FF116E25C70486E3F45C37FF227BF3C59A34D8C694A750C7E2720A3C571757DED3386C7C03C16110D597C1E7531D51B902818100BAAF596351B9744E4FE7987C2EE7C5CDDB56EEFAA1BF285F7575A20E565D667A97FE3F6561898FC4551082D346B6C7745116C432B06A81EB4CD93C8358900567693364B9A14959C6FFDCB4FDC35620029BD6334684544B69E683F677BB8A6CD9F91379F9500CD0F2B4A990D75871A2729FA71927D61E61AAD94DD76DA79D7A8D02818076E147CFB83DBE172CA9193E02C1F8E5914C148809E0808C31D276184D4AC87E6F567D68FA22F1E7EA50811A35393A0EF1AF61FB5CC4E0E166B6158447A709E5190F50D5362E8F0D82EF261228174BB5E16394AA9689ED0F4521C34AD60562F0247654A55DC1FD96FF698CF2C4B20157D93BFD3298938DBD9E414889865AD0E9028180551D128BF9B79293FF7CC84FD8A5B5891230F4493D80DFDC72F29E5CBC27520376986956A8FC06C2A0CD58508758ADEE39E4A4067119906FF27A37B3A36D8909E795707201B52FCD63E298B55D0C7829E6272D2F5EA3CDB2A9F5694CB28424DE8BA7ACA58890E1454E4934531D6CECD5DF540EAFC4E2998BEC0A670E3D8CDA4A -// 'threshold-bls' private key for threshold 3 out of 4 -6665563857293832680240684693464805862374169185467587706083448886366284338604 -// 'multisig-bls' private key for threshold 4 out of 4 -7914109900936730178632254672027980865147291337009856530438436937919632364927 +# Concord-BFT replica keyfile private_replica_3. +# For replica 3 in a 4-replica cluster. + +num_replicas: 4 +f_val: 1 +c_val: 0 +replica_id: 3 + +# RSA non-threshold replica public keys +rsa_public_keys: + - 30820120300D06092A864886F70D01010105000382010D00308201080282010100A2F61615AAE619C54D4BD687A7D4E3D027A7505EA18BF0B82CC04B356BE0974C398B8F15E56099E5CE8B6222F24AC1C5F9B0C5DE3F3035C9759F0F09D0C2068719FE519EA2009E80F8DF4B6E7F03C2E0D6F064FC2E985867FCE66CAC8A9952ABA8056113292445DBC1297A6EE33729239C65D523D8CDFDB38848958940C33C74525E0155D99FF97D4C4D4317D33191763756ED0D3674D8037514572A418A0169151888ACA8EC31B631C04ED158E1B15A396C60D76292FEBBBDD3784D83ECB044ED767696AACDB6323EB1FB60746318AEBB9A5CC6DE339A92E17C2C0CA82B3C85F92DB9CE3DBF8653BDE53F4BF084D8F8C7CA5BEF4E0051FE05BAA8CF6DBC2399020111 + - 30820120300D06092A864886F70D01010105000382010D00308201080282010100B9C99EB540BCA677AB730EE058019D2432B384BF445053A7DC7E975873AEA9F3D5E2A77D80259F7819781C159A3B4FD24F2BCF02D4F4ED05EFDA782460AEB5CAE567228D9AA02B1DAAA1DD788CCC5DD88980B4418946D61BCB6A600302F9F9032469D82C419D1DA958CCA3DC25AA9602CAF85F4B6FC0A5ED0D3415FD47FB1F5775C0F648414319411B31D592454539A2D85ADD5CED0D0E819F66C8F4B63B4F31B57053116F4E4A35EB0D87F1094E9DC46B59FE2BB613B4A2E718DBDF52D1BE5EAD7F95552F8B406CD599A23732627BA4E0BD3C1A97BB14BB6F18785C6DE24E93C065A7372F3E954E5DC57386CE6D8AC815795A5B1BD7754473063AEC7B956409020111 + - 30820120300D06092A864886F70D01010105000382010D00308201080282010100B55EC87F1BB8FE06BAF17EF6C290B60AF008DE4D04D2EFC096B19D0E27E309328637A7BC5A591EF1F4CBDF7F21352BE9B144C1CF57CB56A99AD1E1859B0B0418EAB38F1B44A73C5D584E801FFE82788E22B29ADEEF07D6CA586467B8597F99BC9476D98E791806FD3B4D36568D30F5713183563A4B7FA94D452608F9CC1FB2E2A1E8AFAA9F858D33C28B7059CBA97F5E33EECD7B17DE456B5CE4143F720092C35B78026027221954DBCAAEAD8D82F7BACFF86782EC1182CBDA8E78AD13CE1A0C0323223CF435AEFDE3ABDD33C51294885C0CA3FEC50B64B7E5792032D72EDBA2D0D6071ECE706CA03B4F48690DC58FC977D67C31B60D8B1C59FE1EC054754C8B020111 + - 30820120300D06092A864886F70D01010105000382010D00308201080282010100C21ABAD2260E05E5DCBCCFC462608532EE1F2EC4C0C660E46BEACE4D4A435A45D31859D58B86FB853E28272D76D433FA2A975FC006967C76A8837B405C366D3E3A9DDC807E2DC6E0DB4472916A6149EF2EA65E7E89E77818DFDF4A9F38421F84C2CC507388A9A3B05D2DB3E2C99DFA325A5BB39387129CBEEBB1DA7DE621FFA1E0BB5ACF49562ED0DFBD03FD29A0F2FDE1011C62FD2B572B65F842CA01EBC5E182D4B92B46892F997DEB2169629E228F17BFDD25CCEA07EA5F3ABFB917D2A6C9CE9E026B9BC24EF58C48D3C7907B8EF6E5BA8554A9AF0FCCF7DDCB66DAC24939551D9747D726567336A7A1C7E3F8261F600E0597D80DA107C46E957D5E4DF4B5020111 + +# Execution threshold cryptosystem public configuration. +execution_cryptosystem_type: threshold-bls +execution_cryptosystem_subtype_parameter: BN-P254 +execution_cryptosystem_num_signers: 4 +execution_cryptosystem_threshold: 2 +execution_cryptosystem_public_key: 020d24a4e139d5a7d732b7112801b83b8c66db857af5aa0a6964f7d86f9fe2e9d91505dc5d67eb28e1df123363ce1b116eed9f410639bcc96b24da654ad8fe979f +execution_cryptosystem_verification_keys: + - 0212e1aa988094ee9c2263dd98048cb06d48bd818bbbf1205ffa6339658738d0112269849ea1ac55fe0f4986dc81fcfc80eed11152e3027669094b571ead277bbf + - 02042c10e830d8adbb92c464be5e8e043c982eed82cb45ca4b460f9d82aa183f18054d2580702c7a8475e0735bf228da3d15df3280691e854fc88e49fcee43c465 + - 0310f9a22eb94e068e7948f7a0ad64ed8371cb07b75ae52c74e3587cc690d9d7ee15160cc695f452ff71250eb05621c75996ac8580b967ec0588d26758a375a1ea + - 0302dda9f185850009b08a2f22cb637a15c9a2da677a11302267035e704179f4d70bda229a4fb6ae9af30ee8e82f608931657d501392905787b5ebe6597173e27d + +# Slow path commit threshold cryptosystem public configuration. +slow_commit_cryptosystem_type: threshold-bls +slow_commit_cryptosystem_subtype_parameter: BN-P254 +slow_commit_cryptosystem_num_signers: 4 +slow_commit_cryptosystem_threshold: 3 +slow_commit_cryptosystem_public_key: 02058ed8ae8b55cc3b674f8c05940554c32d35203c4d6fa0c7e54e91287e2f559105b3c0048be1bf32143825b1e96ce734d7cd8e39b28893ecfed01868fa37dbb4 +slow_commit_cryptosystem_verification_keys: + - 02093a80ed694ac9ee5096f37900762638be765f0d4517569761c1146509bb12671f5b1f30c1c4f987bc36216b4f69bed4ac1b54c7f094b9f01c4c8a538cc45ce8 + - 03242eff0e8a8639cc840d4438bec151de2e6840949d16dc006b0862cfd9bef2c3003a1783a4d8a1f2c2f195f5ec733e0e23a00b5da1d5eb5705b201b652bc23d9 + - 02204af450f399b20f3cc8285a3513fc0c39518f33e3f827eab68b16ac97be56aa085777893ed29d37a60fd77c69abdbfd05a3f6d51c9b25d3a9f33f4afbcdc061 + - 031bb32eada4d3f2e6fd6b63b5ad84af83babb1e4d569e6ab2ecdb0bb26bd07dba251cfd58721d0bb369044c470a5cea721006740eda5d909e850c259a09f10583 + +# Commit threshold cryptosystem public configuration. +commit_cryptosystem_type: threshold-bls +commit_cryptosystem_subtype_parameter: BN-P254 +commit_cryptosystem_num_signers: 4 +commit_cryptosystem_threshold: 4 +commit_cryptosystem_public_key: 031c28db8b612135328f04e2a31b85f65bc33bf4e1fb32d7df48939173a2d745c20f793682b23578eb4975d22a7af3b7bd61916e66f0dcbbcaefa118ad5fd7bd5d +commit_cryptosystem_verification_keys: + - 020de71ba1cd8c4a683e9d783013b92add014452826b3a4fc054e25dc651ee1d300df27b81a605cfb35dbf1ab9cbd7ce2a6e1778fa3a7c30766387eb5984ba5270 + - 03214a84285abf66a34c32dba5896ff4edc4c6f17a8333c39ac404fe0494c30f21191a5c5f509f3fd8e70c0630a0f6f33443b4ed8893fb3842fc12f3f8ff8c0d7f + - 031923249ea9ed334dffdc6569240d90ce57a194279135816bf43eba08c7fff455183e29aa1607a11a78ffad4b107f24548a01453f49cd5e9fcbd8dbf9f114f045 + - 0220d2253a629acc970521c2569170fdbe7f9ec9ed3a30405dd5d017ef056e785f12422f7cac5069e7d101eb017e8a98555d697356ebcccdad4c4f1bee4a4476f8 + +# Optimistic fast path commit threshold cryptosystem public configuration. +optimistic_commit_cryptosystem_type: multisig-bls +optimistic_commit_cryptosystem_subtype_parameter: BN-P254 +optimistic_commit_cryptosystem_num_signers: 4 +optimistic_commit_cryptosystem_threshold: 4 +optimistic_commit_cryptosystem_public_key: 0214fbcbb456f0bccd68a3ee42dd28255bea4c0b3aeb5abf820a3ae1d14405251e19bad72b6fb2c0fbceae2cfa7ab33e320d36b68bcbbcc51282b7486f43160a12 +optimistic_commit_cryptosystem_verification_keys: + - 020322fb834b84cc171f0da4c9bd1d9de18a141bfcd5817b82a59823571831cc2a1a02ce331ebfe01b51f7b001137ec9e28eca27a99f5dcec164b26aa07006f795 + - 020fb53bc712704671bc1ae6a19b729093d352fc1add47e9804733ef5dcf1849b0164a6e6a1fc3bf07aa5adf7f355525d8cd8f4d8f0b0c9723fd2bc800fdb715be + - 031b92e9dbf44ae5e87593e5ca6983fcca579ff22f28ea7e3dfd6ea8c98f19717609438156c91eac41ff2126274b0dcdfee0c1145754594ca3c7ec4ba4b2d6949e + - 02047f862a912d3c979c17a40284df584216361b8b3e95a36a6424e6c9dbfa326f08b3e556260d723591fe14e41bfae702197f721734dcb674a6f7a53aabc52a6c + +# Private keys for this replica +rsa_private_key: 308204BB020100300D06092A864886F70D0101010500048204A5308204A10201000282010100C21ABAD2260E05E5DCBCCFC462608532EE1F2EC4C0C660E46BEACE4D4A435A45D31859D58B86FB853E28272D76D433FA2A975FC006967C76A8837B405C366D3E3A9DDC807E2DC6E0DB4472916A6149EF2EA65E7E89E77818DFDF4A9F38421F84C2CC507388A9A3B05D2DB3E2C99DFA325A5BB39387129CBEEBB1DA7DE621FFA1E0BB5ACF49562ED0DFBD03FD29A0F2FDE1011C62FD2B572B65F842CA01EBC5E182D4B92B46892F997DEB2169629E228F17BFDD25CCEA07EA5F3ABFB917D2A6C9CE9E026B9BC24EF58C48D3C7907B8EF6E5BA8554A9AF0FCCF7DDCB66DAC24939551D9747D726567336A7A1C7E3F8261F600E0597D80DA107C46E957D5E4DF4B5020111028201000DB394B77E2B2791BB408722F1DCA603985687D1A73527F8079E20A2114A065F481FD6272AFA782785E4B778AB05F199302ED38F0F861ADB330C4AF57BF7CB79D9F912939C7BB3AF7EE9B9C8017C5386579F51F6DC8ED54706C477B6E8DD83BB10C320C8E88471F45AE81EC4B6E3FF97217BEE8EEE6DBCC22EC1429F79A80C0547A8D53FF47069C598EEC02DB8C2E47EE9BAEA07255D37C1AB5711C75D721309D38D18BAF5912A2CBA57671D03F1AF44A6161C856581F4A5692114EE0273EA572502A0D172F21E3AB658FD3F086930ACB893E241DA50686B37BB10C9D4C5B543B9D59BD9BE578C68D5E0E57C543767A6FAD007E7AA57F2BEF9A7639B8018B5D902818100D00F4C5B957EF8769206280B22F6CDE4D225BA434ED7AABC53686A4E72D6642679EE3A4F8799B45EFC49552CDA096C25AEAB367C0754442401041A2BD7BF0AEF18D64844F9E0FA0AA82430A3D5FCAA35523B119BAC0A790844B695A06C5388DAE7D617DF173A6C8D4C38624E0C84759D0C59C13274E7C912F32BE1615DF55E5B02818100EED44169ACF40695AC808EBFA28BD56875036EBA7255C1376C93B1F3389AA95A7E97A0832811A5C0DC7642217B5F83723830BD47FCE4B9F46237526172A9795D7ECD293A1AD0A8AB2237F4D16E02088807506E6968DC24D5C84D1D45D2D338744F4AB4DC0CBE4F6E147D371883B81EC4C7DBD468CB47E90E007F5BABBEFA862F02818100C3D229BF9BC2CBBAE3C98F198A51B2B93E41A03F59437384124427D15D0603E7FA49A04AD9FA132C38BD7D5763CCA20559199CB0F7D6D6B8796D45CEE92C4686ADF6DA9B458872DCDA7C6A039C3918AAA7BF1FA192DCAE25E6517DC429B808558EE79DFF24EBB175ED623E67934F7DC0FC90B5D522BC088A4E476AB5FE141C910281807063E28C15278AA0C9A5E8D2A6D8646D643DD9C126BEF1837E639F090B941375E1384B8903CC11C42B82F1F1A3783DDB65BC954F0D98CFFA8892811ECC8BFCE0B4244FA2DF7140508892CD8FBB4C4040037124E64F76A7EC22062BE49F7274EB709BA0678D86BBF7912BDDB12EED3BA7E594A031509A4F8E1E5A0D05870C7B6102818016BD198C7F5F203FA9415DFB02BFD716BBE98100F22D39F5B51F448E7F72D95F40BF23C5D1A098EE410E1032AAFE9D7734641377313B7637F1B72611FBF9536491D867D78CBA6A326029A342E57F81067F532A04547A0EE80077256AA9204DCA30F996421D080D79FB51624B2D564A03A81C72BF7BE82E07D4AD9606F95205AC +execution_cryptosystem_private_key: 2016321898106154527277736840037935230513574641779643945404326788810608349211 +slow_commit_cryptosystem_private_key: 10310004607302212385693983636466042908447409560822864863902109153690852646438 +commit_cryptosystem_private_key: 7228901245157859809737939329292776858548795529405492628015780027277517492253 +optimistic_commit_cryptosystem_private_key: 8692344236695863968964493903404119728571157078229370243313593471357142613619 diff --git a/bftengine/tests/simpleTest/scripts/public_replicas_data b/bftengine/tests/simpleTest/scripts/public_replicas_data deleted file mode 100644 index e1bc64dd29..0000000000 --- a/bftengine/tests/simpleTest/scripts/public_replicas_data +++ /dev/null @@ -1,29 +0,0 @@ -replica0 -30820120300D06092A864886F70D01010105000382010D00308201080282010100A1E3C7AA8DAC2334E009BE49A30119F7905CA9477328E8F03517E407D323CF04F7368AB2EE46D9CCAF4FC543AEF929702E8829068A9AD69F004E91868C9D857CC070467A0EED2A22BC2A9EE7543472FE38C13B668B9F6D0781713514F4F494CB4DDD9E71BD50C6CA22AF239BB123A92B5E85C1A85828122E07F9C08D433DB004E92A29028F3DD48635A22112F80D8786A1F9A6C254E0DA0525EFA3C08AB29A18C76E302722BC1E0BFA988711BEA5732E9DF910787C9E29B99BBC02AC77F7F5A6823F180E24C2D0E8EC42A335F20C5E80C27D797A0FEB3A8065022C982CA8B99B7572C3275DBF7D5F3AF90AB173BA2FDF2F2D9C69F1FAD467A9E3EF926E1A2285020111 -replica1 -30820120300D06092A864886F70D01010105000382010D00308201080282010100E4F34453CA6026B2E185E6FBBF85040333CB9558C73A95F7F44837536482AB82871CB4C4EC0FDD58143D662B656763E66B3B50B628CA700546E81C71BEED0B54FAAF1F43541AB7C5787FE21D180342B805A7E9B5076D84ACC30AC36C88B42C08A76DCFFBB484AA568969CABA993A73C3656FE50CEF1438D40E9AB2063FA8A2C41D57EDCFFA343788BBDB6D8E5C6BA879A6B9938CB5F1FFC861CC257AEDA55BD3F8F0086913F07AC3E19E30B42EFE7122B7B2AD27AD4BDA54A96C5F392B7A671573713180780B53F4B9F2C312837252BB624D694CE6F40C50C018E7B5F2D9C138F6838B6FAE2DA482D857423CEDF963B47ED00F25C96B7E721BEF29CDA8C3ECF7020111 -replica2 -30820120300D06092A864886F70D01010105000382010D003082010802820101009B93D9A4D3326036680108CEEDE528E0D68A32AC5B591AF15B212931FAE4FCDD8BF26722961159E905D2B7626FF08627FD9F5B24E0303911BBD58A5C50D69CFEB3703DF585D12B89E711E0661F6D0AD49A9172C52C42E07D3D88FCC240A003E9C70E0CEB436FE8F5677CF63BDB620772385F703C04EE348EC4D5515A359F11B21E1CEE60049B5A38E9D5B63FEBB21DD4D56D67150F5E5F920487794700B76391741D392E521DE01BF7A160D96B7A5521F16430584EEFEF3CBF3528CD574CAF37516076576477A9A58EAF760931C600C5C437A470FFE440CB1F8E22C46D92BFEE19F9A6BA2F3DD55BCCC3132AA0219A4C5E880A8CDDAF05D2D05ACD849DEC1B99020111 -replica3 -30820120300D06092A864886F70D01010105000382010D00308201080282010100D622DFBC52C8B90FD7852D035E606ACA63AC94B5837B138B8FE6035CC5AB08A84E71BB9D2FD3E33EBDFAE2A709E2E8E501DE20295C3BD95684F59FDC6731E2735A4E72F3DFC532499E0C1A95DF036C3E2A4F69C8F07B0AAAD074F3CCE5A52988CCE80F4494FD9942BFBC87FC3ADE5229514C6AE03449EC69BC92B67AF4FCD431E2036893EEC139BD01144C90B6CD0B52EF7F1779B634C07E80EDC1682ED1F0FC60A91248A1FFAAED3ECA96EC3B464C19C208447784FA499F5D2403A4831C641631A9D355988B4E3512FF0C7603A4DB944ABCC310CB25B8B425682403900294352D814405D2C5088DE9061A29BD89CC1E7808406741216DBAA3E0B6A1A35D8625020111 - -// public parameters for threshold 3 out of 4 -threshold-bls -BN-P254 -022322f320746179249bd56f0d625cfc9712e6783f3d5e718c2b65a2f885152c9f1bdceade423c1a51fba1c3a88eda52b231a873ee5b62b25983a67f983928dd47 -// share verification keys -0316e371abbe9e44ffde112b6ffefcfd5d533b8373b8d71c7ffdecf9cf1db451371164435603bc328f503cfa4c91f30ee320d1bf90e4a8abb1cabce21bb0d7fd70 -030f688d30c4a6787e0b4a29d6b49764fe7da4a7b326529009266176e8f644f0e811f82d495a7dc4ae8b4178f6b122d66e8e4ecb499b4def474900337982876a06 -0306896dc4f05a1e34e37e7b7c9076c7899ce27bf4ad007d4d4438de1f490b348d24e2f480170b7f7ccbd03711db72a2badb7cdc2a3f8562fa1e3b8bb359bb4146 -032448d19114e4aaaaeec6ec9dcb20188a184703dbbe46938bb383e1a54e477f380e5bd8d7747ab74115c15f10bd89a142e5d6fe1d5e01193e120a9ef93ef45fb6 - -// public parameters for threshold 4 out of 4 -multisig-bls -BN-P254 -0210c9d8d707c0f5992702e7d9aa75fab3b14395d1a87051e4fe7a037902091784203e129d9eae5a13c96e9557b7328dd1da52edbcd8fddc6dc5b1b1c784527695 -// share verification keys -021d8926525118f27374ae38e91cf63ea3477dbb05f7de18cd0790cf004d104af01bdd2b85b9d822b56ba9e4dd9ab98eb862048f1fd86dd52f4f13157ff58c5298 -021115ac59597a41a35e3db881305d2b72a08a47d86f878448d3b12ad538038fa2186315ab2c08a63fb6821bbaad1834b592afd03418719616c16a41a4e3b17b8f -031cc6834d224e0a738da3595498b8fb44cadbaab21f01cb409cc662ec9958ae3f1a383302ffd6f740ddf26ac1149a0b5ea95f17023d597f600f6c8bf4eb9460d5 -0206b08822db0626df994ea0817fbd077be66fb89f72f95db5c9265c150bb77155161e73898a1cc6aed165b643eb6632a0bf7366d09f24c8dad6b796e0cd1e9cc5 - diff --git a/bftengine/tests/simpleTest/scripts/testReplicasAndClient.sh b/bftengine/tests/simpleTest/scripts/testReplicasAndClient.sh index c6899b749a..ff442be397 100755 --- a/bftengine/tests/simpleTest/scripts/testReplicasAndClient.sh +++ b/bftengine/tests/simpleTest/scripts/testReplicasAndClient.sh @@ -3,6 +3,12 @@ set -e scriptdir=$(cd $(dirname $0); pwd -P) +echo "Generating new keys..." + +rm -f private_replica_* + +../../../../tools/GenerateConcordKeys -n 4 -f 1 -o private_replica_ + parallel --halt now,fail=1 -j0 ::: \ "$scriptdir/../server 0" \ "$scriptdir/../server 1" \ diff --git a/threshsign/include/threshsign/ThresholdSignaturesTypes.h b/threshsign/include/threshsign/ThresholdSignaturesTypes.h index 031095dfc6..28b114d8df 100644 --- a/threshsign/include/threshsign/ThresholdSignaturesTypes.h +++ b/threshsign/include/threshsign/ThresholdSignaturesTypes.h @@ -13,6 +13,9 @@ #pragma once +#include +#include + /** * The current implementation sends the share ID (i.e., the signer ID) with the share signature. * Here we define its data type so that we can easily support an arbitray number of signers. @@ -27,3 +30,388 @@ typedef ShareID NumSharesType; #define MULTISIG_BLS_SCHEME "multisig-bls" #define THRESHOLD_BLS_SCHEME "threshold-bls" + +class IThresholdFactory; +class IThresholdSigner; +class IThresholdVerifier; + +/** + * Exception thrown when attempting to create or use a cryptosystem with invalid + * parameters. This may include an unsupported or unrecognized cryptosystem type + * or subtype parameter, subtype parameters inapplicable to the given type + * selection, invalid numbers of signers or thresholds, or threshold/number of + * signers not supported by the selected type of cryptosystem. + */ +class InvalidCryptosystemException: public std::exception { +public: + + /** + * Constructor for InvalidCryptosystemException. + * + * @param what Description of why this exception is being thrown. + */ + explicit InvalidCryptosystemException(const std::string& what): + msg(what) {}; + + /** + * Accessor for the description this exception was constructed with. + * + * @return The description this exception was constructed with. + */ + virtual const char* what() const noexcept override { + return msg.c_str(); + } +private: + std::string msg; +}; + +/** + * Exception thrown when attempting to make an access or use of a cryptosystem + * that requires state which has not yet been initialized. This type of + * exception exists because the Cryptosystem class is designed with either + * generating fresh keys or loading existing ones in mind. + */ +class UninitializedCryptosystemException: public std::exception { +public: + + /** + * Constructor for UninitializedCryptosystemException. + * + * @param what Description of why this exception is being thrown. + */ + explicit UninitializedCryptosystemException(const std::string& what): + msg(what) {}; + + /** + * Accessor for the description this exception was constructed with. + * + * @return The description this exception was constructed with. + */ + virtual const char* what() const noexcept override { + return msg.c_str(); + } +private: + std::string msg; +}; + +/** + * A class for representing threshold cryptosystems of different types, + * numbers of signers, and threshold levels. + */ +class Cryptosystem { +private: + std::string type; + std::string subtype; + + uint16_t numSigners; + uint16_t threshold; + + // If only one signer's private key is known and stored in this cryptosystem, + // this field records that signer's ID; otherwise (if no or all private keys + // are known to this cryptosystem), this field stores Cryptosystem::NID to + // represent it is inapplicable. + uint16_t signerID; + + // Note that 0 is not a valid signer ID because signer IDs are 1-indexed. + static const uint16_t NID = 0; + + std::string publicKey; + std::vector verificationKeys; + std::vector privateKeys; + + // Internally used helper functions. + IThresholdFactory* createThresholdFactory(); + +public: + + /** + * Constructor for the Cryptosystem class. + * + * @param sysType The type of threshold cryptosystem to create. A list + * of currently supported types can be obtained with the + * static getAvailableCryptosystemTypes function of + * Cryptosystem. + * @param sysSubtype Subtype of threshold cryptosystem to create. The + * meaning of this parameter is dependent on the type of + * cryptosystem selected with sysType. For example, if + * sysType specifies a type of elliptic curve + * cryptography, then sysSubtype should specify an + * elliptic curve type. + * @param sysNumSigners The total number of signers in this threshold + * cryptosystem. + * @param sysThreshold The threshold for this threshold cryptosystem, that + * is, the number of signatures needed from different + * individual signers to produce a complete signature + * under this cryptosystem. + * + * @throws InvalidCryptosystemException If sysType is unrecognized or + * unsupported, if sysSubtype is + * invalid, unrecognized, or unsupported + * for the type of cryptosystem + * specified by sysType, if sysThreshold + * is greater than sysNumSigners, or if + * constraints on sysNumSigners and/or + * sysThreshold specific to the type + * and/or subtype of cryptosystem + * selected are not met. + */ + Cryptosystem(const std::string& sysType, + const std::string& sysSubtype, + uint16_t sysNumSigners, + uint16_t sysThreshold); + + /** + * Destructor for Cryptosystem. + */ + virtual ~Cryptosystem() {} + + // Functions for checking how a cryptosystem is configured. + + /** + * Get the type of this cryptosystem. + * + * @return A string representing the type of this cryptosystem. + */ + const std::string& getType() const { return type;} + + /** + * Get the type-dependent subtype of this crytposystem. + * + * @return A string representing the subtype of this cryptosystem. + */ + const std::string& getSubtype() const { return subtype;} + + /** + * Get the number of signers in this cryptosystem. + * + * @return The number of signers in this cryptosystem. + */ + uint16_t getNumSigners() const { return numSigners;} + + /** + * Get the threshold for this threshold cryptosystem. + * + * @return The threshold for this cryptosystem. + */ + uint16_t getThreshold() const { return threshold;} + + /** + * Pseudorandomly generate a complete set of keys for this cryptosystem and + * store them in this Cryptosystem object. Note that this function may take a + * while to run depending on the cryptosystem type and number of signers, as + * it performs pseudorandom key generation, which is computationally + * expensive. Any existing keys loaded in this cryptosystem will be + * overwritten. + */ + void generateNewPseudorandomKeys(); + + /** + * Get the public key for this threshold cryptosystem, represented as a + * string. The format of the string is cryptosystem type-dependent. + * + * @return The public key for this threshold cryptosystem. + * + * @throws UninitializedCryptosystemException If this cryptosystem does not + * currently have a public key + * because keys for it have not + * been either generated or + * loaded. + */ + std::string getSystemPublicKey() const; + + /** + * Get a list of verification keys for this threshold cryptosystem, + * represented as strings. Their format is cryptosystem type-dependent. + * + * @return A vector containing the verification keys, in order of which signer + * they correspond to. To comply with the convention of 1-indexing + * signer IDs, verification keys will begin at index 1 of the vector. + * The contents of index 0 of the vector is left undefined. + * + * @throws UninitializedCryptosystemException If this cryptosystem does not + * currently have verification + * keys because keys for it have + * not been either generated or + * loaded. + */ + std::vector getSystemVerificationKeys() const; + + /** + * Get a list of private keys for this threshold cryptosystem, represented as + * strings. Their format is cryptosystem type-dependent. + * + * @return A vector containing the private keys, in order of which signer they + * correspond to. To comply with the convention of 1-indexing signer + * IDs, the private keys will begin at index 1 of the vector. The + * contents of index 0 are left undefined. + * + * @throws UninitializedCryptosystemException If this cryptosystem does not + * currently have private keys + * because keys for it have not + * been generated and private keys + * have not been loaded. + */ + std::vector getSystemPrivateKeys() const; + + /** + * Get the private key for a specific signer in this threshold cryptosystem, + * represented as a string of cryptosystem type-dependent format. + * + * @param signerIndex The index for the signer to get the private key for; + * signers are indexed from [1, numSigners]. + * + * @return The private key for the specified signer. + * + * @throws UninitializedCryptosystemException If this cryptosystem does not + * currently have the private key + * for the specified replica + * because it has not been + * generated or loaded. + * @throws std::out_of_range If signerIndex > numSigners or + * signerIndex < 1. + */ + std::string getPrivateKey(uint16_t signerIndex) const; + + /** + * Load an existing set of keys to this cryptosystem. If this cryptosystem is + * currently holding a set of keys, they will be overwritten. + * + * @param publicKey Public key to load for this cryptosystem, + * represented as a string. + * @param verificationKeys List of verification keys to load for this + * cryptosystem, represented as strings, in order of + * signer they correspond to. To comply with the + * convention of 1-indexing signer IDs, the + * verification keys should beginat index 1 of the + * vector. The content at index 0 of the vector will + * not be used by this function. + * + * @throws InvalidCryptosystemException If the set of keys given is not valid + * for this cryptosystem. + */ + void loadKeys(const std::string& publicKey, + const std::vector& verificationKeys); + + /** + * Load the private key for a specific signer using this cryptosystem. Any + * existing private keys will be overwritten. + * + * @param signerIndex The signer ID for the signer to which this private key + * belongs, which should be in the range + * [1, numSigners]. + * @param key The private key to load belonging to this signer. + * + * @throws InvalidCryptosystemException If the given private key is invalid. + * @throws std::out_of_range If signerID is not in the range + * [1, numReplicas]. + */ + void loadPrivateKey(uint16_t signerIndex, + const std::string& key); + + /** + * Create a threshod verifier for this cryptosystem. + * + * @return A pointer to a newly created IThresholdVerifier object for this + * cryptosystem. + * + * @throws UninitializedCryptosystemException If this cryptosystem does not + * have the required public and + * verification keys loaded to + * create a verifier. + */ + IThresholdVerifier* createThresholdVerifier(); + + /** + * Create a threshold signer with the private key loaded for this system. + * This function requires that a single private key (the one belonging to the + * signer of interest) is currently loaded to this cryptosystem. + * + * @return A pointer to a newly created IThresholdSigner object with the + * private key loaded to this cryptosystem. + * + * @throws UninitializedCryptosystemException If this cryptosystem does not + * have a private key loaded, or if + * it has all private keys loaded. + */ + IThresholdSigner* createThresholdSigner(); + + /** + * Check whether a given string represents a valid public key under this + * cryptosystem. + * + * @param key The string to check the validity of as a public key. + * + * @return True if this string represents a valid public key under this + * cryptosystem, false otherwise. + */ + bool isValidPublicKey(const std::string& key) const; + + /** + * Check whether a given string represents a valid verification key under this + * cryptosystem. + * + * @param key The string to check the validity of as a verification key. + * + * @return True if this string represents a valid verification key under this + * cryptosystem, false otherwise. + */ + bool isValidVerificationKey(const std::string& key) const; + + /** + * Check whether a given string represents a valid private key under this + * cryptosystem. + * + * @param key The string to check the validity of as a private key. + * + * @return True if this string represents a valid private key under this + * cryptosystem, false otherwise. + */ + bool isValidPrivateKey(const std::string& key) const; + +/** + * Check whether a given selection of cryptosystem type and subtype is + * recognized and supported. + * + * @param type The type of cryptosystem to check. + * @param subtype A type-dependent subtype selection to check. + * + * @return True if this combination of type and subtype is recognized and + * supported, false otherwise. + */ + static bool isValidCryptosystemSelection(const std::string& type, + const std::string& subtype); + + /** + * Check whether a given selection of cryptosystem type and subtype is + * recognized and whether it supports the given number of signers and + * threshold. + * + * @param type The type of cryptosystem to check. + * @param subtype A type-dependent subtype selection to check. + * @param numSigners A number of signers to check support for under the given + * cryptosystem type and subtype. + * @param threshold A threshold to check support for under the given + * cryptosystem type, subtype and number of signers. + * + * @return True if this combination of type and subtype is recognized and + * supported, and it supports the given combination of number of + * signers and threshold, false otherwise. + */ + static bool isValidCryptosystemSelection(const std::string& type, + const std::string& subtype, + uint16_t numSigners, + uint16_t threshold); + + /** + * Get a list of supported cryptosystem types and descriptions of what + * type-specific parameters they require. + * + * @param ret A vector to which to append this functions output, as pairs of + * strings. The first string in each pair is the name for a + * supported cryptosystem type, and the second string is a + * description of what the type-specific subtype parameter + * specifies for that cryptosytem type. + */ + static void getAvailableCryptosystemTypes( + std::vector>& ret); +}; diff --git a/threshsign/src/CMakeLists.txt b/threshsign/src/CMakeLists.txt index 213ea077a8..9104ac13c0 100644 --- a/threshsign/src/CMakeLists.txt +++ b/threshsign/src/CMakeLists.txt @@ -7,6 +7,7 @@ set(common_source_files ISecretKey.cpp IThresholdVerifier.cpp VectorOfShares.cpp + ThresholdSignaturesTypes.cpp ) add_library(common OBJECT ${common_source_files}) diff --git a/threshsign/src/ThresholdSignaturesTypes.cpp b/threshsign/src/ThresholdSignaturesTypes.cpp new file mode 100644 index 0000000000..c593c3f932 --- /dev/null +++ b/threshsign/src/ThresholdSignaturesTypes.cpp @@ -0,0 +1,308 @@ +// Concord +// +// Copyright (c) 2018 VMware, Inc. All Rights Reserved. +// +// This product is licensed to you under the Apache 2.0 license (the "License"). +// You may not use this product except in compliance with the Apache 2.0 License. +// +// This product may include a number of subcomponents with separate copyright +// notices and license terms. Your use of these subcomponents is subject to the +// terms and conditions of the subcomponent's license, as noted in the +// LICENSE file. + +#include + +#include "threshsign/ThresholdSignaturesTypes.h" +#include "threshsign/IThresholdSigner.h" +#include "threshsign/IThresholdVerifier.h" +#include "threshsign/bls/relic/BlsThresholdFactory.h" +#include "threshsign/bls/relic/PublicParametersFactory.h" + +Cryptosystem::Cryptosystem(const std::string& sysType, + const std::string& sysSubtype, + uint16_t sysNumSigners, + uint16_t sysThreshold) { + if (!isValidCryptosystemSelection(sysType, sysSubtype, sysNumSigners, + sysThreshold)) { + throw InvalidCryptosystemException("Invalid cryptosystem selection:" + " primary type: " + sysType + ", subtype: " + sysSubtype + ", with " + + std::to_string(sysNumSigners) + " signers and threshold of " + + std::to_string(sysThreshold) + "."); + } + type = sysType; + subtype = sysSubtype; + numSigners = sysNumSigners; + threshold = sysThreshold; + signerID = NID; +} + +// Helper function to generateNewPseudorandomKeys. +IThresholdFactory* Cryptosystem::createThresholdFactory() { + if (type == MULTISIG_BLS_SCHEME) { + return new BLS::Relic::BlsThresholdFactory( + BLS::Relic::PublicParametersFactory::getByCurveType(subtype.c_str())); + } else if (type == THRESHOLD_BLS_SCHEME) { + return new BLS::Relic::BlsThresholdFactory( + BLS::Relic::PublicParametersFactory::getByCurveType(subtype.c_str())); + } else { + // This should never occur because Cryptosystem validates its parameters + // in its constructor. + throw InvalidCryptosystemException("Using cryptosystem of unsupported" + " type: " + type + "."); + } +} + +void Cryptosystem::generateNewPseudorandomKeys() { + std::unique_ptr factory(createThresholdFactory()); + std::vector signers; + IThresholdVerifier* verifier; + + std::tie(signers, verifier) + = factory->newRandomSigners(threshold, numSigners); + + publicKey = verifier->getPublicKey().toString(); + + verificationKeys.clear(); + verificationKeys.push_back(""); // Account for 1-indexing of signer IDs. + for (uint16_t i = 1; i <= numSigners; ++i) { + verificationKeys.push_back(verifier->getShareVerificationKey( + static_cast(i)).toString()); + } + + privateKeys.clear(); + privateKeys.push_back(""); // Account for 1-indexing of signer IDs. + for (uint16_t i = 1; i <= numSigners; ++i) { + privateKeys.push_back(signers[i]->getShareSecretKey().toString()); + } + + for (auto signer: signers) { + delete signer; + } + + signerID = NID; + + delete verifier; +} + +std::string Cryptosystem::getSystemPublicKey() const { + if (publicKey.length() < 1) { + throw UninitializedCryptosystemException("A public key has not been" + " generated or loaded for this cryptosystem."); + } + return publicKey; +} + +std::vector Cryptosystem::getSystemVerificationKeys() const { + std::vector output; + if (verificationKeys.size() != (numSigners + 1)) { + throw UninitializedCryptosystemException("Verification keys have not been" + " generated or loaded for this cryptosystem."); + } + // This should create a new copy of verificationKeys since we are returning by + // value. + return verificationKeys; +} + +std::vector Cryptosystem::getSystemPrivateKeys() const { + std::vector output; + if (privateKeys.size() != (numSigners + 1)) { + throw UninitializedCryptosystemException("Private keys have not been" + " generated or loaded for this cryptosystem."); + } + // This should create a new copy of privateKeys since we are returning by + // value. + return privateKeys; +} + +std::string Cryptosystem::getPrivateKey(uint16_t signerIndex) const { + if ((signerIndex < 1) || (signerIndex > numSigners)) { + throw std::out_of_range("Signer index for requested private key out of" + " range."); + } + + if (privateKeys.size() == (numSigners + 1)) { + return privateKeys[signerIndex]; + } else if ((privateKeys.size() == 1) && (signerID == signerIndex)) { + return privateKeys.front(); + } + + throw UninitializedCryptosystemException("Private keys have not been" + " generated or loaded for this cryptosystem."); +} + +void Cryptosystem::loadKeys(const std::string& publicKey, + const std::vector& verificationKeys) { + if (!isValidPublicKey(publicKey)) { + throw InvalidCryptosystemException("\"" + publicKey + "\" is not a valid" + " public key for this cryptosystem (type " + type + " and subtype " + + subtype + ")."); + } + if (verificationKeys.size() != (numSigners + 1)) { + throw InvalidCryptosystemException("Incorrect number of verification keys" + " provided: " + std::to_string(verificationKeys.size()) + " (expected " + + std::to_string(numSigners + 1) + ")."); + } + for (size_t i = 1; i <= numSigners; ++i) { + if (!isValidVerificationKey(verificationKeys[i])) { + throw InvalidCryptosystemException("\"" + verificationKeys[i] + "\" is" + " not a valid verification key for this cryptosystem (type " + type + + " and subtype " + subtype + ")."); + } + } + + this->verificationKeys.clear(); + this->privateKeys.clear(); + this->publicKey = publicKey; + + signerID = NID; + + // This should make a copy of the verificationKeys vector we received as a + // parameter since this.verificationKeys is stored by value. + this->verificationKeys = verificationKeys; +} + +void Cryptosystem::loadPrivateKey(uint16_t signerIndex, + const std::string& key) { + if ((signerIndex < 1) & (signerIndex > numSigners)) { + throw std::out_of_range("Signer index for provided private key out of" + " range."); + } + if (!isValidPrivateKey(key)) { + throw InvalidCryptosystemException("\"" + key + "\" is not a valid private" + " key for this cryptosystem (type " + type + " and subtype " + subtype + + ")."); + } + + signerID = signerIndex; + privateKeys.clear(); + privateKeys.push_back(key); +} + +IThresholdVerifier* Cryptosystem::createThresholdVerifier() { + if (publicKey.length() < 1) { + throw UninitializedCryptosystemException("Attempting to create a threshold" + " verifier for a cryptosystem with no public key loaded."); + } + if (verificationKeys.size() != (numSigners + 1)) { + throw UninitializedCryptosystemException("Attempting to create a threshold" + " verifier for a cryptosystem without verification keys loaded."); + } + + IThresholdFactory* factory = createThresholdFactory(); + + IThresholdVerifier* verifier + = factory->newVerifier(threshold, numSigners, publicKey.c_str(), + verificationKeys); + + delete factory; + return verifier; +} + +IThresholdSigner* Cryptosystem::createThresholdSigner() { + if (privateKeys.size() != 1) { + if (privateKeys.size() < 1) { + throw UninitializedCryptosystemException("Attempting to create a" + " threshold signer for a cryptosystem with no private keys loaded."); + } else { + throw UninitializedCryptosystemException("Attempting to create a" + " threshold signer for a cryptosystem with more than one private key" + " loaded without selecting a signer."); + } + } + + IThresholdFactory* factory = createThresholdFactory(); + + // Note we add 1 to the signer ID because IThresholdSigner seems to use a + // convention in which signer IDs are 1-indexed. + IThresholdSigner* signer + = factory->newSigner(signerID, privateKeys.front().c_str()); + + delete factory; + return signer; +} + +static const size_t expectedPublicKeyLength = 130; +static const size_t expectedVerificationKeyLength = 130; + +bool Cryptosystem::isValidPublicKey(const std::string& key) const { + return (key.length() == expectedPublicKeyLength) + && (std::regex_match(key, std::regex("[0-9A-Fa-f]+"))); +} + +bool Cryptosystem::isValidVerificationKey(const std::string& key) const { + return (key.length() == expectedVerificationKeyLength) + && (std::regex_match(key, std::regex("[0-9A-Fa-f]+"))); +} + +bool Cryptosystem::isValidPrivateKey(const std::string& key) const { + + // We currently do not validate the length of the private key's string + // representation because the length of its serialization varies slightly. + + return std::regex_match(key, std::regex("[0-9A-Fa-f]+")); +} + +bool Cryptosystem::isValidCryptosystemSelection(const std::string& type, + const std::string& subtype) { + + if (type == MULTISIG_BLS_SCHEME) { + try { + BLS::Relic::BlsThresholdFactory factory( + BLS::Relic::PublicParametersFactory::getByCurveType( + subtype.c_str())); + return true; + } catch (std::exception e) { + return false; + } + } else if (type == THRESHOLD_BLS_SCHEME) { + try { + BLS::Relic::BlsThresholdFactory factory( + BLS::Relic::PublicParametersFactory::getByCurveType( + subtype.c_str())); + return true; + } catch (std::exception e) { + return false; + } + } else { + return false; + } +} + +bool Cryptosystem::isValidCryptosystemSelection(const std::string& type, + const std::string& subtype, + uint16_t numSigners, + uint16_t threshold) { + + // Automatically return false if numSigners and threshold are inherently + // invalid. Note we have chosen to disallow 0 as either numSigners or + // threshold, as such Cryptosystems would not be useful, but supporting them + // could introduce additional corner cases to the Cryptosystem class or code + // using it. + if ((numSigners < 1) + || (threshold < 1) + || (threshold > numSigners)) { + return false; + } + + // Note MULTISIG_BLS scheme is not a true threshold scheme and is only + // allowable if the threshold equals the number of signers. + if ((type == MULTISIG_BLS_SCHEME) && (threshold != numSigners)) { + return false; + } else { + return isValidCryptosystemSelection(type, subtype); + } +} + +void Cryptosystem::getAvailableCryptosystemTypes( + std::vector>& ret) { + + std::pair p; + + p.first = MULTISIG_BLS_SCHEME; + p.second = "an elliptical curve type, for example, BN-P254"; + ret.push_back(p); + + p.first = THRESHOLD_BLS_SCHEME; + p.second = "an elliptical curve type, for example, BN-P254"; + ret.push_back(p); +} diff --git a/threshsign/src/bls/relic/BlsNumTypes.cpp b/threshsign/src/bls/relic/BlsNumTypes.cpp index 87f066ccd6..f7459dffef 100644 --- a/threshsign/src/bls/relic/BlsNumTypes.cpp +++ b/threshsign/src/bls/relic/BlsNumTypes.cpp @@ -73,7 +73,7 @@ std::string BNT::toString(int base) const { AutoCharBuf buf(size); //bn_write_str(reinterpret_cast(buf.getBuf()), size, n, base); bn_write_str(buf.getBuf(), size, n, base); - std::string str(buf, static_cast(size)); + std::string str(buf); return str; } diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt new file mode 100644 index 0000000000..f780d224f9 --- /dev/null +++ b/tools/CMakeLists.txt @@ -0,0 +1,45 @@ +project(concord_bft_tools LANGUAGES CXX) + +add_executable(GenerateConcordKeys + GenerateConcordKeys.cpp + KeyfileIOUtils.hpp + KeyfileIOUtils.cpp) +target_include_directories(GenerateConcordKeys + PRIVATE + ${threshsign_SOURCE_DIR}/src + ${threshsign_SOURCE_DIR}/lib + ${threshsign_SOURCE_DIR}/include + ${bftengine_SOURCE_DIR}/src + ${bftengine_SOURCE_DIR}/include) +target_link_libraries(GenerateConcordKeys + PUBLIC + threshsign) +link_with_relic_library(GenerateConcordKeys) +set_target_properties(GenerateConcordKeys + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY + .) + +add_executable(TestGeneratedKeys + TestGeneratedKeys.cpp + KeyfileIOUtils.hpp + KeyfileIOUtils.cpp) +target_include_directories(TestGeneratedKeys + PRIVATE + ${threshsign_SOURCE_DIR}/src + ${threshsign_SOURCE_DIR}/lib + ${threshsign_SOURCE_DIR}/include + ${bftengine_SOURCE_DIR}/src + ${bftengine_SOURCE_DIR}/include) +target_link_libraries(TestGeneratedKeys + PUBLIC + threshsign + corebft) +link_with_relic_library(TestGeneratedKeys) +set_target_properties(TestGeneratedKeys + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY + .) + +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/testKeyGeneration.sh + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) diff --git a/tools/GenerateConcordKeys.cpp b/tools/GenerateConcordKeys.cpp new file mode 100644 index 0000000000..9dfa3ebf40 --- /dev/null +++ b/tools/GenerateConcordKeys.cpp @@ -0,0 +1,363 @@ +// Concord +// +// Copyright (c) 2018 VMware, Inc. All Rights Reserved. +// +// This product is licensed to you under the Apache 2.0 license (the "License"). +// You may not use this product except in compliance with the Apache 2.0 +// License. +// +// This product may include a number of subcomponents with separate copyright +// notices and license terms. Your use of these subcomponents is subject to the +// terms and conditions of the subcomponent's license, as noted in the LICENSE +// file. + +#include +#include +#include + +#include + +#include "threshsign/ThresholdSignaturesTypes.h" +#include "KeyfileIOUtils.hpp" + +// Helper functions and static state to this executable's main function. + +static bool containsHelpOption(int argc, char** argv) { + for (int i = 1; i < argc; ++i) { + if (std::string(argv[i]) == "--help") { + return true; + } + } + return false; +} + +static CryptoPP::RandomPool sGlobalRandGen; +const unsigned int rsaKeyLength = 2048; + +static std::pair generateRsaKey() { + + // Uses CryptoPP implementation of RSA key generation. + + std::pair keyPair; + + CryptoPP::RSAES>::Decryptor + priv(sGlobalRandGen, rsaKeyLength); + CryptoPP::HexEncoder privEncoder(new CryptoPP::StringSink(keyPair.first)); + priv.DEREncode(privEncoder); + privEncoder.MessageEnd(); + + CryptoPP::RSAES>::Encryptor pub(priv); + CryptoPP::HexEncoder pubEncoder(new CryptoPP::StringSink(keyPair.second)); + pub.DEREncode(pubEncoder); + pubEncoder.MessageEnd(); + + return keyPair; +} + +static bool parseUInt16(uint16_t& output, + const std::string& str, + uint16_t min, + uint16_t max, + const std::string& name) { + long long unverifiedNum; + std::string errorMessage = "Invalid value given for " + name + ": " + str + + " (expected integer in range [" + std::to_string(min) + ", " + + std::to_string(max) + "], inclusive.\n"; + + try { + unverifiedNum = std::stoll(str); + } catch (std::invalid_argument e) { + std::cout << errorMessage; + return false; + } catch (std::out_of_range e) { + std::cout << errorMessage; + return false; + } + + if ((unverifiedNum < (long long)min) || (unverifiedNum > (long long)max)) { + std::cout << errorMessage; + return false; + } else { + output = (uint16_t)unverifiedNum; + return true; + } +} + +/** + * Main function for the GenerateConcordKeys executable. Pseudorandomly + * generates a new set of keys for a Concord deployment with given F and C + * values and writes them to an output file. The output is formatted using + * constructs from a subset of YAML to make it both human and machine readable. + * The output includes an RSA key pair for each of the replicas for general + * communication and non-threshold cryptographic purposes and the complete key + * set for the four threshold cryptosystems used by Concord. All + * per-replica keys are given in lists in which the order corresponds to the + * replicas' order. + * + * @param argc The number of command line arguments to this main function, + * including the command this executable was launched with. + * @param argv Command line arguments to this function, with the first being the + * command this executable was launched with as is conventional. A + * description of expected and supported command line parameters is + * available by runnign the utility with the "--help" option. + * + * @return 0; currently this utility will output an error message to the command + * line if it exits unsuccessfully due to invalid command-line + * parameters, but it will not return an exit code indicating an error. + */ +int main(int argc, char** argv) { + + std::string usageMessage = "Usage:\n" + "GenerateConcordKeys -n TOTAL_NUMBER_OF_REPLICAS \\\n" + " -f NUMBER_OF_FAULTY_REPLICAS_TO_TOLERATE -o OUTPUT_FILE_PREFIX\n" + "The generated keys will be output to a number of files, one per replica." + " The\nfiles will each be named OUTPUT_FILE_PREFIX, where is a" + " sequential ID for\nthe replica to which the file corresponds in the" + " range [0,\nTOTAL_NUMBER_OF_REPLICAS]. Each file contains all public" + " keys for the cluster,\nbut only the private keys for the replica with" + " the corresponding ID.\n" + "Optionally, you may also choose what types of cryptosystems to use:\n" + " --execution_cryptosys SYSTEM_TYPE PARAMETER\n" + " --slow_commit_cryptosys SYSTEM_TYPE PARAMETER\n" + " --commit_cryptosys SYSTEM_TYPE PARAMETER\n" + " --opptimistic_commit_cryptosys SYSTEM_TYPE PARAMETER\n" + "Currently, the following cryptosystem types are supported\n" + "(and take the following as parameters):\n"; + + std::vector> cryptosystemTypes; + Cryptosystem::getAvailableCryptosystemTypes(cryptosystemTypes); + for (size_t i = 0; i < cryptosystemTypes.size(); ++i) { + usageMessage += " " + cryptosystemTypes[i].first + " (" + + cryptosystemTypes[i].second + ")\n"; + } + + usageMessage += "If any of these cryptosystem selections are not made" + " explictly, a default will\nbe selected.\n\nSpecial options:\n --help :" + " display this usage message and exit.\n"; + + // Display the usage message and exit if no arguments were given, or if --help + // was given anywhere. + if ((argc <= 1) || (containsHelpOption(argc, argv))) { + std::cout << usageMessage; + return 0; + } + + uint16_t f; + uint16_t n; + + // Note we have declared this stream locally to main and by value, and that, + // if the output file is successfully opened, we are relying on ofstream's + // destructor being called implicitly when main returns and this goes out of + // scope to close the stream. + std::string outputPrefix; + + bool hasF = false; + bool hasN = false; + bool hasOutput = false; + + std::string execType = "threshold-bls"; + std::string execParam = "BN-P254"; + std::string slowType = "threshold-bls"; + std::string slowParam = "BN-P254"; + std::string commitType = "threshold-bls"; + std::string commitParam = "BN-P254"; + std::string optType = "multisig-bls"; + std::string optParam = "BN-P254"; + + // Read input from the command line. + // Note we ignore argv[0] because that just contains the command that was used + // to launch this executable by convention. + for (int i = 1; i < argc; ++i) { + std::string option(argv[i]); + + if (option == "-f") { + if (i >= argc - 1) { + std::cout << "Expected an argument to -f.\n"; + return -1; + } + std::string arg = argv[i + 1]; + if (parseUInt16(f, arg, 1, UINT16_MAX, "-f")) { + hasF = true; + } else { + return -1; + } + ++i; + + } else if (option == "-n") { + if (i >= argc - 1) { + std::cout << "Expected an argument to -n.\n"; + return -1; + } + std::string arg = argv[i + 1]; + + // Note we do not enforce a minimum value for n here; since we require + // n > 3f and f > 0, lower bounds for n will be handled when we + // enforce the n > 3f constraint below. + if (parseUInt16(n, arg, 0, UINT16_MAX, "-n")) { + hasN = true; + } else { + return -1; + } + ++i; + + } else if (option == "-o") { + if (i >= argc - 1) { + std::cout << "Expected an argument to -o.\n"; + return -1; + } + outputPrefix = argv[i + 1]; + hasOutput = true; + ++i; + + } else if (option == "--execution_cryptosys") { + if (i >= argc - 2) { + std::cout << "Expected 2 arguments to --execution_cryptosys.\n"; + return -1; + } + execType = argv[i + 1]; + execParam = argv[i + 2]; + i += 2; + + } else if (option == "--slow_commit_cryptosys") { + if (i >= argc - 2) { + std::cout << "Expected 2 arguments to --slow_commit_cryptosys.\n"; + return -1; + } + slowType = argv[i + 1]; + slowParam = argv[i + 2]; + i += 2; + + } else if (option == "--commit_cryptosys") { + if (i >= argc - 2) { + std::cout << "Expected 2 arguments to --execution_cryptosys.\n"; + return -1; + } + commitType = argv[i + 1]; + commitParam = argv[i + 2]; + i += 2; + + } else if (option == "--optimistic_commit_cryptosys") { + if (i >= argc - 2) { + std::cout << "Expected 2 arguments to --execution_cryptosys.\n"; + return -1; + } + optType = argv[i + 1]; + optParam = argv[i + 2]; + i += 2; + + } else { + std::cout << "Unrecognized command line argument: " << option << "\n"; + return -1; + } + } + + // Check that required parameters were actually given. + if (!hasF) { + std::cout << "No value given for required -f parameter.\n"; + return -1; + } + if (!hasN) { + std::cout << "No value given for required -n parameter.\n"; + return -1; + } + if (!hasOutput) { + std::cout << "No value given for required -o parameter.\n"; + return -1; + } + + // Verify constraints between F and N and compute C. + + // Note we check that N >= 3F + 1 using uint32_ts even though F and N are + // uint16_ts just in case 3F + 1 overflows a uint16_t. + uint32_t minN = 3 * (uint32_t)f + 1; + if ((uint32_t)n < minN) { + std::cout << "Due to the design of Byzantine fault tolerance, number of" + " replicas (-n) must be\ngreater than or equal to (3 * F + 1), where F" + " is the maximum number of faulty\nreplicas (-f).\n"; + return -1; + } + + // We require N - 3F - 1 to be even so C can be an integer. + if (((n - (3 * f) - 1) % 2) != 0) { + std::cout << "For technical reasons stemming from our current" + " implementation of Byzantine\nfault tolerant consensus, we currently" + " require that (N - 3F - 1) be even, where\nN is the total number of" + " replicas (-n) and F is the maximum number of faulty\nreplicas (-f).\n"; + return -1; + } + + uint16_t c = (n - (3 * f) - 1) / 2; + + uint16_t execThresh = f + 1; + uint16_t slowThresh = f * 2 + c + 1; + uint16_t commitThresh = f * 3 + c + 1; + uint16_t optThresh = n; + + // Verify cryptosystem selections. + if (!Cryptosystem::isValidCryptosystemSelection(execType, execParam, + n, execThresh)) { + std::cout << "Invalid selection of cryptosystem for execution cryptosystem" + " (with threshold " << execThresh << " out of " << n << "): " + << execType << " " << execParam << ".\n"; + return -1; + } + if (!Cryptosystem::isValidCryptosystemSelection(slowType, slowParam, + n, slowThresh)) { + std::cout << "Invalid selection of cryptosystem for slow path commit" + " cryptosystem (with threshold " << slowThresh << " out of " + << n << "): " << slowType << " " << slowParam << ".\n"; + return -1; + } + if (!Cryptosystem::isValidCryptosystemSelection(commitType, commitParam, + n, commitThresh)) { + std::cout << "Invalid selection of cryptosystem for commit cryptosystem" + " (with threshold " << commitThresh << " out of " << n << "): " + << commitType << " " << commitParam << ".\n"; + return -1; + } + if (!Cryptosystem::isValidCryptosystemSelection(optType, optParam, + n, optThresh)) { + std::cout << "Invalid selection of cryptosystem for optimistic fast path" + " commit cryptosystem (with threshold " << optThresh << " out of " + << n << "): " << optType << " " << optParam << ".\n"; + return -1; + } + + // Validate that all output files are valid before possibly wasting a + // significant ammount of time generating keys that cannot be output. + std::vector outputFiles; + for (uint16_t i = 0; i < n; ++i) { + outputFiles.push_back(std::ofstream(outputPrefix + std::to_string(i))); + if (!outputFiles.back().is_open()) { + std::cout << "Could not open output file " << outputPrefix << i << ".\n"; + return -1; + } + } + + std::vector> rsaKeys; + for (uint16_t i = 0; i < n; ++i) { + rsaKeys.push_back(generateRsaKey()); + } + + Cryptosystem execSys(execType, execParam, n, execThresh); + Cryptosystem slowSys(slowType, slowParam, n, slowThresh); + Cryptosystem commitSys(commitType, commitParam, n, commitThresh); + Cryptosystem optSys(optType, optParam, n, optThresh); + + execSys.generateNewPseudorandomKeys(); + slowSys.generateNewPseudorandomKeys(); + commitSys.generateNewPseudorandomKeys(); + optSys.generateNewPseudorandomKeys(); + + // Output the generated keys. + + for (uint16_t i = 0; i < n; ++i) { + if (!outputReplicaKeyfile(i, n, f, c, outputFiles[i], + outputPrefix + std::to_string(i), rsaKeys, execSys, slowSys, + commitSys, optSys)) { + return -1; + } + } + + return 0; +} diff --git a/tools/KeyfileIOUtils.cpp b/tools/KeyfileIOUtils.cpp new file mode 100644 index 0000000000..f59d848e53 --- /dev/null +++ b/tools/KeyfileIOUtils.cpp @@ -0,0 +1,710 @@ +// Concord +// +// Copyright (c) 2018 VMware, Inc. All Rights Reserved. +// +// This product is licensed to you under the Apache 2.0 license (the "License"). +// You may not use this product except in compliance with the Apache 2.0 +// License. +// +// This product may include a number of subcomponents with separate copyright +// notices and license terms. Your use of these subcomponents is subject to the +// terms and conditions of the subcomponent's license, as noted in the LICENSE +// file. + +#include +#include +#include +#include +#include + +#include "KeyfileIOUtils.hpp" + +// Helper function to outputReplicaKeyfile. +static void serializeCryptosystemPublicConfiguration(std::ostream& output, + const Cryptosystem& system, + const std::string& sysName, + const std::string& prefix) + { + + uint16_t numReplicas = system.getNumSigners(); + + output << "\n# " << sysName << " threshold cryptosystem public" + " configuration.\n"; + output << prefix << "_cryptosystem_type: " << system.getType() << "\n"; + output << prefix << "_cryptosystem_subtype_parameter: " + << system.getSubtype() << "\n"; + output << prefix << "_cryptosystem_num_signers: " << numReplicas << "\n"; + output << prefix << "_cryptosystem_threshold: " << system.getThreshold() + << "\n"; + output << prefix << "_cryptosystem_public_key: " + << system.getSystemPublicKey() << "\n"; + + std::vector verificationKeys + = system.getSystemVerificationKeys(); + + output << prefix << "_cryptosystem_verification_keys:\n"; + for (uint16_t i = 1; i <= numReplicas; ++i) { + output << " - " << verificationKeys[i] << "\n"; + } +} + +bool outputReplicaKeyfile(uint16_t replicaID, + uint16_t numReplicas, + uint16_t f, + uint16_t c, + std::ostream& output, + const std::string& outputFilename, + const std::vector>& rsaKeys, + const Cryptosystem& execSys, + const Cryptosystem& slowSys, + const Cryptosystem& commitSys, + const Cryptosystem& optSys) { + + if ((3 * f + 2 * c + 1) != numReplicas) { + std::cout << "F, C, and number of replicas do not agree for requested" + " output.\n"; + return false; + } + + output << "# Concord-BFT replica keyfile " << outputFilename << ".\n"; + output << "# For replica " << replicaID << " in a " << numReplicas + << "-replica cluster.\n\n"; + output << "num_replicas: " << numReplicas << "\n"; + output << "f_val: " << f << "\n"; + output << "c_val: " << c << "\n"; + output << "replica_id: " << replicaID << "\n\n"; + + output << "# RSA non-threshold replica public keys\n"; + output << "rsa_public_keys:\n"; + for (uint16_t i = 0; i < numReplicas; ++i) { + output << " - " << rsaKeys[i].second << "\n"; + } + + serializeCryptosystemPublicConfiguration(output, execSys, "Execution", + "execution"); + serializeCryptosystemPublicConfiguration(output, slowSys, "Slow path commit", + "slow_commit"); + serializeCryptosystemPublicConfiguration(output, commitSys, "Commit", + "commit"); + serializeCryptosystemPublicConfiguration(output, optSys, + "Optimistic fast path commit", "optimistic_commit"); + + output << "\n# Private keys for this replica\n"; + + output << "rsa_private_key: " << rsaKeys[replicaID].first << "\n"; + output << "execution_cryptosystem_private_key: " + << execSys.getPrivateKey(replicaID + 1) << "\n"; + output << "slow_commit_cryptosystem_private_key: " + << slowSys.getPrivateKey(replicaID + 1) << "\n"; + output << "commit_cryptosystem_private_key: " + << commitSys.getPrivateKey(replicaID + 1) << "\n"; + output << "optimistic_commit_cryptosystem_private_key: " + << optSys.getPrivateKey(replicaID + 1) << "\n"; + + return true; +} + +// Helper functions to inputReplicaKeyfile + +// Trims any whitespace off of both ends of a string. +static std::string trim(const std::string& str) { + + std::string ret = str; + size_t trim = ret.find_first_not_of(" \t"); + if (trim != std::string::npos) { + ret = ret.substr(trim, ret.length() - trim); + } + trim = ret.find_last_not_of(" \t"); + if (trim != std::string::npos) { + ret = ret.substr(0, trim + 1); + } + return ret; +} + +// Handles inputing unsigned 16-bit integers from the identifier->value map +// created while parsing the keyfile. This function validates that the desired +// integer is in the map, is a valid integer and not some other string value, +// and is within range. +static bool parseUint16(uint16_t& output, + const std::string& identifier, + std::unordered_map& map, + const std::string& filename, + const std::unordered_map& + lineNumbers, + uint16_t min, + uint16_t max) { + + if (map.count(identifier) < 1) { + if (lineNumbers.count(identifier) < 1) { + std::cout << filename << ": Missing assignment for required parameter: " + << identifier << ".\n"; + } else { + std::cout << filename << ": line " << lineNumbers.at(identifier) + << ": expected integer value for " << identifier << ", found list.\n"; + } + return false; + } + + std::string strVal = map[identifier]; + long long unvalidatedVal; + + std::string errorMessage = filename + ": line " + + std::to_string(lineNumbers.at(identifier)) + ": Invalid value given for " + + identifier + ": " + strVal + " ( expected integer in range [" + + std::to_string(min) + ", " + std::to_string(max) + "], inclusive.\n"; + + try { + unvalidatedVal = std::stoll(strVal); + } catch (std::invalid_argument e) { + std::cout << errorMessage; + return false; + } catch (std::out_of_range e) { + std::cout << errorMessage; + return false; + } + + if ((unvalidatedVal < (long long)min) || (unvalidatedVal > (long long)max)) { + std::cout << errorMessage; + return false; + } + + map.erase(identifier); + output = (uint16_t)unvalidatedVal; + return true; +} + +// Simple validators for RSA keys to ensure they at least conform to the +// expected format. +const size_t rsaPublicKeyHexadecimalLength = 584; + +static bool validateRSAPublicKey (const std::string& key) { + return (key.length() == rsaPublicKeyHexadecimalLength) + && (std::regex_match(key, std::regex("[0-9A-Fa-f]+"))); +} + +static bool validateRSAPrivateKey (const std::string& key) { + + // Note we do not verify the length of RSA private keys because their length + // actually seems to vary a little in the output; it hovers around 2430 + // characters but often does not exactly match that number. + + return std::regex_match(key, std::regex("[0-9A-Fa-f]+")); +} + +// Checks that there are entries for all identifiers given in entries in the +// variable map produced by parsing the keyfile, and prints errors if there +// are not. +static bool expectEntries(const std::vector& entries, + const std::unordered_map + map, + const std::string& filename, + const std::unordered_map + lineNumbers) { + for (auto entry: entries) { + if (map.count(entry) < 1) { + if (lineNumbers.count(entry) < 1) { + std::cout << filename << ": Missing assignment for required parameter: " + << entry << ".\n"; + } else { + std::cout << filename << ": line " << lineNumbers.at(entry) + << ": expected string value for " << entry << ", found list.\n"; + } + return false; + } + } + return true; +} + +// Handles reading all the public configuration for each of the four +// cryptosystems we expect to read in. +static bool deserializeCryptosystemPublicConfiguration( + std::unique_ptr& cryptosystem, + const std::string& name, + const std::string& prefix, + std::unordered_map& valueAssignments, + std::unordered_map>& listAssignments, + const std::string& filename, + const std::unordered_map& identifierLines, + const std::unordered_map>& listEntryLines, + uint16_t numReplicas) { + std::string typeVar = prefix + "_cryptosystem_type"; + std::string subtypeVar = prefix + "_cryptosystem_subtype_parameter"; + std::string numSignersVar = prefix + "_cryptosystem_num_signers"; + std::string threshVar = prefix + "_cryptosystem_threshold"; + std::string pubKeyVar = prefix + "_cryptosystem_public_key"; + std::string verifKeyVar = prefix + "_cryptosystem_verification_keys"; + + uint16_t numSigners, threshold; + + if (!parseUint16(numSigners, numSignersVar, valueAssignments, filename, + identifierLines, 1, UINT16_MAX)) { + return false; + } + if (!parseUint16(threshold, threshVar, valueAssignments, filename, + identifierLines, 1, UINT16_MAX)) { + return false; + } + + if (numSigners != numReplicas) { + std::cout << filename << ": line " << identifierLines.at(numSignersVar) + << ": Unexpected number of signers; it is expected the number of signers" + " for each cryptosystem will be equal to num_replicas.\n"; + return false; + } + + if (!expectEntries({typeVar, subtypeVar, pubKeyVar}, valueAssignments, + filename, identifierLines)) { + return false; + } + + std::string type = valueAssignments[typeVar]; + valueAssignments.erase(typeVar); + std::string subtype = valueAssignments[subtypeVar]; + valueAssignments.erase(subtypeVar); + + if (!Cryptosystem::isValidCryptosystemSelection(type, subtype, numSigners, + threshold)) { + std::cout << filename << ": line " << identifierLines.at(typeVar) << ":" + " Invalid configuration for " << name << " cryptosystem (type " << type + << ", subtype " << subtype << ", threshold of " << threshold << " out of " + << numSigners << ").\n"; + return false; + } + cryptosystem.reset(new Cryptosystem(type, subtype, numSigners, threshold)); + + std::string publicKey = valueAssignments[pubKeyVar]; + valueAssignments.erase(pubKeyVar); + + if (!cryptosystem->isValidPublicKey(publicKey)) { + std::cout << filename << ": line " << identifierLines.at(pubKeyVar) << ":" + " Invalid public key for selected type of cryptosystem.\n"; + return false; + } + + if (listAssignments.count(verifKeyVar) < 1) { + if (identifierLines.count(verifKeyVar) < 1) { + std::cout << filename << ": Missing assignment for required parameter: " + << verifKeyVar << ".\n"; + } else { + std::cout << filename << ": line " << identifierLines.at(verifKeyVar) + << ": expected list for " << verifKeyVar << ", found single value.\n"; + } + return false; + } + + std::vector verificationKeys + = std::move(listAssignments[verifKeyVar]); + listAssignments.erase(verifKeyVar); + + // Account for convention of 1-indexing threshold signer IDs. + verificationKeys.insert(verificationKeys.begin(), ""); + + if (verificationKeys.size() != (numSigners + 1)) { + std::cout << filename << ": line " << identifierLines.at(verifKeyVar) + << ": Unexpected number of verification keys for " << name + << " cryptosystem; it is expected that the number of verification keys" + " is equal to " << numSignersVar << ".\n"; + return false; + } + for (size_t i = 1; i <= numSigners; ++i) { + if (!cryptosystem->isValidVerificationKey(verificationKeys[i])) { + std::cout << filename << ": line " << listEntryLines.at(verifKeyVar).at(i) + << ": Invalid verification key for this cryptosystem.\n"; + return false; + } + } + + cryptosystem->loadKeys(publicKey, verificationKeys); + return true; +} + +// Generate a generic message to report any unrecognized or invalid syntax. +// Attempts to include a brief description of what syntaxes are valid. +static std::string getBadSyntaxMessage(const std::string& filename, + size_t lineNumber) { + return filename + ": line " + std::to_string(lineNumber) + + ": Unrecognized syntax.\nRecognized syntaxes are:\n" + " IDENTIFIER: VALUE\nand\n" + " IDENTIFIER:\n - LIST_ENTRY\n - LIST_ENTRY\n ...\n"; +} + +// Parse the input keyfile from text into a more convenient in-memory +// representations of maps from identifiers to their values. Also creates some +// records of what line numbers everything it parses come from for use in +// giving error messages referencing specific lines. +bool parseReplicaKeyfile( + std::istream& input, + const std::string& filename, + std::unordered_map& valueAssignments, + std::unordered_map>& listAssignments, + std::unordered_map& identifierLines, + std::unordered_map>& listEntryLines) { + + std::vector* currentList = nullptr; + std::vector* currentListLines = nullptr; + + size_t lineNumber = 1; + + while (input.peek() != EOF) { + std::string line; + std::getline(input, line); + + // Ignore comments. + size_t commentStart = line.find_first_of("#"); + if (commentStart != std::string::npos) { + line = line.substr(0, commentStart); + } + + line = trim(line); + + // Ignore this line if it contains only whitespace and/or comments. + if (line.length() < 1) { + ++lineNumber; + continue; + } + + // Note the key file format currently permits 3 types of non-empty lines: + // assignments of values to an identifier, assignments of lists to an + // identifier, and list entries. + + // Multiple :s are never expected in one line, so we will reject lines like + // this here so that we do not have to handle them in both assignment cases. + if (line.find_first_of(":") != line.find_last_of(":")) { + std::cout << getBadSyntaxMessage(filename, lineNumber); + return false; + } + + // Case of a list entry. Format: + // - LIST_ENTRY + if ((line.length() > 2) && (line[0] == '-') && (line[1] == ' ')) { + + std::string value = trim(line.substr(2, line.length() - 2)); + if (value.find_first_of(" \t") != std::string::npos) { + std::cout << filename << ": line " << lineNumber << ": Whitespace is" + " not allowed in identifiers or values.\n"; + return false; + } + + // Note we do not to check whether the value is missing completely because + // we know this line, beginning with "- ", had a length of 3 before + // trimming. + + // We will check that there is not a colon in the value because the use of + // those is reserved to indicate assignments. + if (value.find_first_of(":") != std::string::npos) { + std::cout << filename << ": line " << lineNumber << ": Invalid list" + " entry: contains \":\".\n"; + return false; + } + + if (!currentList) { + std::cout << filename << ": line " << lineNumber << ": Unexpected list" + " entry (not following a declaration of a list or another list" + " entry).\n"; + return false; + } + + currentList->push_back(value); + currentListLines->push_back(lineNumber); + + // Case of assignment of a list to an identifier. Format: + // IDENTIFIER: + } else if ((line.length() > 1) && (line[line.length() - 1] == ':')) { + + std::string identifier = trim(line.substr(0, line.length() - 1)); + if (identifier.find_first_of(" \t") != std::string::npos) { + std::cout << filename << ": line " << lineNumber << ": Whitespace is" + " not allowed in identifiers or values.\n"; + return false; + } + + // Note that we do not have to check whether the identifier is not missing + // completely because we know the line was at least 2 characters long and + // ended in the colon after trimming. + + if (identifierLines.count(identifier) > 0) { + std::cout << filename << ": line " << lineNumber << ": Attempting to" + " make a new assignment to an identifier that is already in use" + " (previous assignment on line " << identifierLines[identifier] + << ").\n"; + return false; + } + + listAssignments[identifier] = std::vector(); + listEntryLines[identifier] = std::vector(); + + currentList = &(listAssignments[identifier]); + currentListLines = &(listEntryLines[identifier]); + + identifierLines[identifier] = lineNumber; + + // Case of assignment of a value to an identifier. Format: + // IDENTIFIER: VALUE + } else if ((line.length() >= 3) + && (line.find_first_of(":") != std::string::npos)) { + + size_t colonLoc = line.find_first_of(":"); + std::string identifier = trim(line.substr(0, colonLoc)); + std::string value = trim(line.substr(colonLoc + 1, + line.length() - (colonLoc + 1))); + + if ((identifier.find_first_of(" \t") != std::string::npos) + || (value.find_first_of(" \t") != std::string::npos)) { + std::cout << filename << ": line " << lineNumber << ": Whitespace is" + " not allowed in identifiers or values.\n"; + std::cout << "\"" << identifier << "\"\n\"" << value << "\"\n"; + return false; + } + + if (identifier.length() < 1) { + std::cout << filename << ": line " << lineNumber << ": Expected" + " identifier before assignment.\n"; + return false; + } + + // Note we do not need to check that the value is non-empty because any + // case that would yield that would have triggered the above case for + // assignment of a list to an identifier. + + if (identifierLines.count(identifier) > 0) { + std::cout << filename << ": line " << lineNumber << ": Attempting to" + " make a new assignment to an identifier that is already in use" + " (previous assignment on line " << identifierLines[identifier] + << ").\n"; + return false; + } + + currentList = nullptr; + currentListLines = nullptr; + + valueAssignments[identifier] = value; + identifierLines[identifier] = lineNumber; + + // If none of the above cases were true, then whatever this line is is not + // of a supported format. + } else { + std::cout << getBadSyntaxMessage(filename, lineNumber); + return false; + } + + ++lineNumber; + } + + return true; +} + +bool inputReplicaKeyfile(std::istream& input, + const std::string& filename, + bftEngine::ReplicaConfig& config) { + + std::unordered_map valueAssignments; + std::unordered_map> listAssignments; + std::unordered_map identifierLines; + std::unordered_map> listEntryLines; + + if (!parseReplicaKeyfile(input, filename, valueAssignments, listAssignments, + identifierLines, listEntryLines)) { + return false; + } + + uint16_t numReplicas, f, c, replicaID; + + if (!parseUint16(numReplicas, "num_replicas", valueAssignments, filename, + identifierLines, 1, UINT16_MAX)) { + return false; + } + if (!parseUint16(f, "f_val", valueAssignments, filename, identifierLines, 1, + UINT16_MAX)) { + return false; + } + if (!parseUint16(c, "c_val", valueAssignments, filename, identifierLines, 0, + UINT16_MAX)) { + return false; + } + if (!parseUint16(replicaID, "replica_id", valueAssignments, filename, + identifierLines, 0, UINT16_MAX)) { + return false; + } + + // Note we validate the number of replicas using 32-bit integers in case + // (3 * f + 2 * c + 1) overflows a 16-bit integer. + uint32_t predictedNumReplicas = 3 * (uint32_t)f + 2 * (uint32_t)c + 1; + if (predictedNumReplicas != (uint32_t)numReplicas) { + std::cout << filename << ": line " << identifierLines["num_replicas"] + << ": num_replicas must be equal to (3 * f_val + 2 * c_val + 1).\n"; + return false; + } + if (replicaID >= numReplicas) { + std::cout << filename << ": line " << identifierLines["replica_id"] + << ": invalid replica_id; replica IDs must be in the range [0," + " num_replicas], inclusive.\n"; + } + + // Load RSA public keys + if (listAssignments.count("rsa_public_keys") < 1) { + if (identifierLines.count("rsa_public_keys") < 1) { + std::cout << filename << ": Missing assignment for required parameter:" + " rsa_public_keys.\n"; + } else { + std::cout << filename << ": line " << identifierLines["rsa_public_keys"] + << ": expected list for rsa_public_keys, found single value.\n"; + } + return false; + } + + std::vector rsaPublicKeys + = std::move(listAssignments["rsa_public_keys"]); + listAssignments.erase("rsa_public_keys"); + + if (rsaPublicKeys.size() != numReplicas) { + std::cout << filename << ": line " << identifierLines["rsa_public_keys"] + << ": incorrect number of public RSA keys given; the number of RSA keys" + " must match num_replicas.\n"; + return false; + } + for (size_t i = 0; i < numReplicas; ++i) { + if (!validateRSAPublicKey(rsaPublicKeys[i])) { + std::cout << filename << ": line " + << listEntryLines["rsa_public_keys"][i] + << ": Invalid RSA public key.\n"; + return false; + } + } + + // Load cryptosystem public configurations. + // Note we reference the Cryptosystems here via unique_ptrs rahter than + // declaring them by value because we need to declare them here before they + // are constructed by a helper function, which cannot be done if they are + // declared by value because they have no default (0-parameter) constructor. + std::unique_ptr execSys; + std::unique_ptr slowSys; + std::unique_ptr commitSys; + std::unique_ptr optSys; + + if (!deserializeCryptosystemPublicConfiguration(execSys, "execution", + "execution", valueAssignments, listAssignments, filename, + identifierLines, listEntryLines, numReplicas)) { + return false; + } + if (!deserializeCryptosystemPublicConfiguration(slowSys, "slow path commit", + "slow_commit", valueAssignments, listAssignments, filename, + identifierLines, listEntryLines, numReplicas)) { + return false; + } + if (!deserializeCryptosystemPublicConfiguration(commitSys, "commit", "commit", + valueAssignments, listAssignments, filename, identifierLines, + listEntryLines, numReplicas)) { + return false; + } + if (!deserializeCryptosystemPublicConfiguration(optSys, + "optimistic fast path commit", "optimistic_commit", valueAssignments, + listAssignments, filename, identifierLines, listEntryLines, + numReplicas)) { + return false; + } + + // Load private keys for this replica. + if (!expectEntries({"rsa_private_key", "execution_cryptosystem_private_key", + "slow_commit_cryptosystem_private_key", + "commit_cryptosystem_private_key", + "optimistic_commit_cryptosystem_private_key"}, valueAssignments, + filename, identifierLines)) { + return false; + } + + std::string rsaPrivateKey = valueAssignments["rsa_private_key"]; + valueAssignments.erase("rsa_private_key"); + + if (!validateRSAPrivateKey(rsaPrivateKey)) { + std::cout << filename << ": line " << identifierLines["rsa_private_key"] + << ": Invalid RSA private key.\n"; + return false; + } + + std::string execPrivateKey + = valueAssignments["execution_cryptosystem_private_key"]; + std::string slowPrivateKey + = valueAssignments["slow_commit_cryptosystem_private_key"]; + std::string commitPrivateKey + = valueAssignments["commit_cryptosystem_private_key"]; + std::string optPrivateKey + = valueAssignments["optimistic_commit_cryptosystem_private_key"]; + + valueAssignments.erase("execution_cryptosystem_private_key"); + valueAssignments.erase("slow_commit_cryptosystem_private_key"); + valueAssignments.erase("commit_cryptosystem_private_key"); + valueAssignments.erase("optimistic_commit_cryptosystem_private_key"); + + if (!execSys->isValidPrivateKey(execPrivateKey)) { + std::cout << filename << ": line " + << identifierLines["execution_cryptosystem_private_key"] + << ": Invalid private key for selected cryptosystem.\n"; + return false; + } + if (!slowSys->isValidPrivateKey(slowPrivateKey)) { + std::cout << filename << ": line " + << identifierLines["slow_commit_cryptosystem_private_key"] + << ": Invalid private key for selected cryptosystem.\n"; + return false; + } + if (!commitSys->isValidPrivateKey(commitPrivateKey)) { + std::cout << filename << ": line " + << identifierLines["commit_cryptosystem_private_key"] + << ": Invalid private key for selected cryptosystem.\n"; + return false; + } + if (!optSys->isValidPrivateKey(optPrivateKey)) { + std::cout << filename << ": line " + << identifierLines["optimistic_commit_cryptosystem_private_key"] + << ": Invalid private key for selected cryptosystem.\n"; + return false; + } + + execSys->loadPrivateKey(replicaID + 1, execPrivateKey); + slowSys->loadPrivateKey(replicaID + 1, slowPrivateKey); + commitSys->loadPrivateKey(replicaID + 1, commitPrivateKey); + optSys->loadPrivateKey(replicaID + 1, optPrivateKey); + + // Verify that there were not any unexpected parameters specified in the + // keyfile. + if ((valueAssignments.size() > 0) || (listAssignments.size() > 0)) { + for (auto assignment: valueAssignments) { + std::cout << filename << ": line " << identifierLines[assignment.first] + << ": Unrecognized parameter: " << assignment.first << ".\n"; + } + for (auto assignment: listAssignments) { + std::cout << filename << ": line " << identifierLines[assignment.first] + << ": Unrecognized parameter: " << assignment.first << ".\n"; + } + return false; + } + + // Copy all the information loaded into the replica configuration struct. + // Note we do not begin copying the information until we know it has been + // loaded successfully, so the configuration struct will not be left in a + // partially loaded state. + config.fVal = f; + config.cVal = c; + config.replicaId = replicaID; + config.publicKeysOfReplicas.clear(); + for (uint16_t i = 0; i < numReplicas; ++i) { + config.publicKeysOfReplicas.insert(std::pair(i, + rsaPublicKeys[i])); + } + config.replicaPrivateKey = rsaPrivateKey; + + config.thresholdSignerForExecution = execSys->createThresholdSigner(); + config.thresholdSignerForSlowPathCommit = slowSys->createThresholdSigner(); + config.thresholdSignerForCommit = commitSys->createThresholdSigner(); + config.thresholdSignerForOptimisticCommit = optSys->createThresholdSigner(); + + config.thresholdVerifierForExecution = execSys->createThresholdVerifier(); + config.thresholdVerifierForSlowPathCommit + = slowSys->createThresholdVerifier(); + config.thresholdVerifierForCommit = commitSys->createThresholdVerifier(); + config.thresholdVerifierForOptimisticCommit + = optSys->createThresholdVerifier(); + + return true; +} diff --git a/tools/KeyfileIOUtils.hpp b/tools/KeyfileIOUtils.hpp new file mode 100644 index 0000000000..9e1c62f044 --- /dev/null +++ b/tools/KeyfileIOUtils.hpp @@ -0,0 +1,99 @@ +// Concord +// +// Copyright (c) 2018 VMware, Inc. All Rights Reserved. +// +// This product is licensed to you under the Apache 2.0 license (the "License"). +// You may not use this product except in compliance with the Apache 2.0 +// License. +// +// This product may include a number of subcomponents with separate copyright +// notices and license terms. Your use of these subcomponents is subject to the +// terms and conditions of the subcomponent's license, as noted in the LICENSE +// file. + +#include + +#include "bftengine/ReplicaConfig.hpp" +#include "threshsign/ThresholdSignaturesTypes.h" + +/** + * Output the required generated keys for a given replica to a file. The replica + * can then read the keys back to fill out its bftEngine::ReplicaConfig& using + * inputReplicaKeyFile below. + * + * @param replicaID The replica ID for the replica to which this keyfile + * will correspond. Note replica IDs should be in the + * range [0, numReplicas - 1]. + * @param numReplicas The total number of replicas in the deployment this + * replica will be in. Note numReplicas must be equal to + * (3 * f + 2 * c + 1). + * @param f The F parameter to SBFT for this deployment (the number + * of byzantine faulty replicas to tolerate before safety + * and/or correctness may be lost). + * @param c C parameter to the SBFT algorithm for this deployment + * (the number of slow, crashed, or unresponsive replicas + * that can be tolerated before falling back on the slow + * path for commit consensus). + * @param output Output stream to which to write this keyfile. + * @param outputFilename Filename to which output corresponds; this may be used + * in giving more descriptive error messages. + * @param rsaKeys RSA keys generated for this deployment. It is expected + * that there is one pair of keys per replica, each + * represented as a pair of strings in rsaKeys, ordered by + * replicaID. The private key should be the first string + * in each pair and the public key the second. + * @param execSys Cryptosystem for consensus on execution results in this + * deployment, with all keys already generated. + * @param slowSys Cryptosystem for consensus on transaction commit order + * in the slow path for this deployment, with all keys + * already generated. + * @param commitSys Cryptosystem for consensus on transaction commit order + * in the general path for this deployment, with all keys + * already generated. + * @param optSys Cryptosystem for consensus on transaction commit order + * in the optimistic fast path for this deployment, with + * all keys already generated. + * + * @return True if the keyfile was successfully output, false otherwise. Reasons * this function could fail to successfully output the keyfile may + * include I/O issues or disagreement of numReplicas with f and c. + */ +bool outputReplicaKeyfile(uint16_t replicaID, + uint16_t numReplicas, + uint16_t f, + uint16_t c, + std::ostream& output, + const std::string& outputFilename, + const std::vector>& rsaKeys, + const Cryptosystem& execSys, + const Cryptosystem& slowSys, + const Cryptosystem& commitSys, + const Cryptosystem& optSys); + +/** + * Read in a keyfile for the current replica that was output with + * outputReplicaKeyfile above and initialize the relevant fields of a + * bftEninge::ReplicaConfig with the information read. If successful, this + * function will set the following fileds of the ReplicaConfig: fVAl, CVal, + * replicaId, publicKeysOfReplicas, replicaPrivateKey, + * thresholdSignerForExecution, thresholdVerifierForExecution, + * thresholdSignerForSlowPathCommit, thresholdVerifierForSlowPathCommit, + * thresholdSignerForCommit, thresholdVerifierForCommit, + * thresholdSignerForOptimisticCommit, and thresholdVerifierForOptimisticCommit. + * Other fields of the ReplicaConfig will not be modified by this function. This + * function will not modify the ReplicaConfig at all if it is unsuccesfull; it + * will instead print an error message and return false. + * + * @param input Input source for the keyfile to be read from. + * @param inputFilename The filename to which input corresponds. This may be + * used in giving more specific error messages. + * @param config A bftEngine::ReplicaConfig to output the cryptographic + * configuration read to. + * + * @return True if the keyfile is successfully read and the read information + * output to config, and false otherwise. Reasons for failure may + * include I/O issues or invalid formatting or contents of the keyfile. + */ +bool inputReplicaKeyfile(std::istream& input, + const std::string& inputFilename, + bftEngine::ReplicaConfig& config); diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 0000000000..1865006fa0 --- /dev/null +++ b/tools/README.md @@ -0,0 +1,132 @@ +# Concord-BFT Tools # + +This subdirectory has been created for tools for use with Concord-BFT. Currently, the following tool(s) are availalbe in this directory: +- GenerateConcordKeys: A tool for generating all the keys required by the replicas in a Concord cluster of given dimensions. + +## GenerateConcordKeys ## + +GenerateConcordKeys is a command line utility for generating the keys required by Concord cluster. It takes the dimensions of the deployment as command line parameters and outputs a keyfile for each replica. A function for reading the keyfiles back in when launching the replicas is also provided. + +### Generating Keys ### + +First, if you have not done so already, build Concord-BFT. See the build instructions in the top level `README.md` for Concord-BFT for instructions on installing Concord-BFT's required dependencies and building Concord-BFT. CMake has been set up so that GenerateConcordKeys will be automatically built along with the rest of Concord-BFT. Its executable will appear in the `tools` subdirectory of your Concord-BFT build. + +Once you have built GenerateConcordKeys, switch to the `tools` subdirectory of your Concord-BFT build. If your build was successfull, there should be a binary for `GenerateConcordKeys`. Run it with: + +`./GenerateConcordKeys -n -f -o ` + +Here, `NUM_REPLICAS` should be the total number of replicas in this Concord cluster, `MAX_FAULTY` should be the maximum number of Byzantine-faulty replicas the cluster must tolerate before safety is lost, and `OUTPUT_PREFIX` should be a prefix for the output keyfiles. Due to the constraints of the SBFT algorithm for Byzantine fault tolerance, `NUM_REPLICAS` must be greater than `3 * MAX_FAULTY`. If the parameters are accepted and key generation is successful, `NUM_REPLICAS` keyfiles will be generated and output, each with a filename of the format `OUTPUT_PREFIX`, where `OUTPUT_PREFIX` is as specified in the command line parameters and `` is a sequential ID for the replica to which each keyfile corresponds in the range `[0, NUM_REPLICAS - 1]`, inclusive. + +`GenerateConcordKeys` may take a while to run, depending on the cluster size, as key generation for public key and threshold cryptosystems is computationally expensive. + +`./GenerateConcordKeys --help` can be run for a summary of command line parameters expected and options availalbe for `GenerateConcordKeys`, including any optional parameters `GenerateConcordKeys` supports, such as cryptosystem type selection. + +### Using Generated Keys ### + +The keyfiles output by `GenerateConcordKeys` should be distributed to the places where the replicas they correspond to will be run. In a production environment, for example, each replica should be run on a different machine, ideally with each machine in a different failure domain, and the keyfile for each replica should be distributed to the machine that will run that replica. + +To load the keyfiles once they have been distributed to the replicas, a function, specifically `inputReplicaKeyfile`, declared in `tools/KeyfileIOUtils.hpp`, has been provided for reading in replica keyfiles from the on-disk format output by `GenerateConcordKeys` to a `bftEngine::ReplicaConfig` struct, which is the in-memory representation used by Concord-BFT when constructing bftEngine::Replica objects. + +`inputReplicaKeyfile` takes a `std::istream` to read the keyfile from and a `bftEngine::ReplicaConfig` reference to write the keys read to. Note that `inputReplicaKeyfile` does not initialize the entire `bftEngine::ReplicaConfig`; it initializes only the cryptographic fields and those immediately related to them, such as `fVal` and `cVal`. Fields such as `statusReportTimerMillisec`, which are not related to the cryptographic configuration, are untouched by `inputReplicaKeyfile`. `inputReplicaKeyfile` returns a `bool` indicating whether it succeeded or failed; the entire `bftEngine::Replicaconfig` should be untouched in the event of a failure. The primary reason `inputReplicaKeyfile` might fail is a malformatted or otherwise invalid keyfile. Please see the comments on the declaration of `inputReplicaKeyfile` in `tools/KeyfileIOUtils.hpp` for more details about `inputReplicaKeyfile`, such as exactly which `bftEngine::ReplicaConfig` fields it sets if it is successful. + +### Keyfile Format ### + +The keyfiles `GenerateConcordKeys` produces and that can be read with `inputReplicaKeyfile` are of a simple format that is intended to be easily readable by both humans and software. + +#### Keyfile Structure and Syntax #### + +The data in a keyfile of this format is structured as an associative array, that is, a mapping of values to keys. Two fundamental types of values are supported: strings and ordered lists of strings. The strings in either of these types of values may be re-interpreted as other things (for example, integers) depending on what the keys are. The keys must also be strings. Whitespace and the characters `':'` and `'#'` are explicitly disallowed from both keys and values. + +This format is insensitive to the order that these value-to-key assignments are made in. Having more than one assignment to the same key is explicitly disallowed, even if the same value is assigned both times. Additionally, keyfiles of this format may contain comments. + +Comments are started with a `'#'` character and continue until the end of the line they started on; comments are to be completely ignored when parsing a keyfile; blank lines, indentation, and trailing space are also to be completely ignored. Furthermore, anywhere that a space is allowed or required, any ammount of non-newline whitespace is permitted. + +The syntax for assigning a string value to a key is: + +`KEY: VALUE` + +where `KEY` is the key and `VALUE` is the value. The key, `:`, and value must all be on the same line, in that order, and only one such assignment is allowed per line. + +The syntax for assigning a list of strings to a key is: + +``` +KEY: + - VALUE_1 + - VALUE_2 + - VALUE_3 +``` + +where `KEY` is the key and (`VALUE_1`, `VALUE_2`, `VALUE_3`) are the entries in the list of strings. The key (with the `:`) and each list entry (with its preceding `-`, separated from the list entry's value itself by a space (or any ammount of non-newline whitespace)) must be on separate lines. Lists of any positive integer length are allowed syntactically. + +The parser expects to see assignments for a specific set of keys, and it also has specific expectations about what types of values can be legally assigned to what keys. The parser will reject keyfiles if they are missing any assignments it expects to find or if any of the values assigned are illegal. The parser will also reject files containing assignments to any keys that it does not recognize. + +#### Expected Contents of the Keyfiles #### + +The current set of keys the parser expects values assigned to will be grouped into four broad categories for the purpose of this discussion: fundamental parameters, a list of public RSA keys, threshold cryptosystem public configurations, and private keys for the replica to which this keyfile belongs. Parameters in the first three categories should have consistent values among every replica's keyfile; however, the private keys should differ between replicas. + +##### Fundamental Parameters ##### + +There are four fundamental parameters expected: + +Parameter | Expected Value | Description +--- | --- | --- +`num_replicas` | positive integer | Total number of replicas for this Concord-BFT cluster. The total number of replicas must be equal to `3 * f_val + 2 * c_val + 1`. +`f_val` | positive integer | F parameter to the SBFT algorithm, that is, the maximum number of byzantine-faulty replicas that can be lost before safety is lost. +`c_val` | non-negative integer | C parameter to the SBFT algorithm, that is, the maximum number of slow, crashed, or otherwise unresponsive replicas that can be tolerated before Concord must fall back to the slow path for committing transactions. +`replica_id` | non-negative integer | Replica ID for the replica to which this keyfile belongs; replica IDs must be in the range [0, `num_replicas` - 1], inclusive, and no two replicas should have the same ID. + +##### List of Public RSA Keys ##### + +A list of public RSA keys is expected under the identifier `rsa_public_keys`: + +Parameter | Expected Value | Description +--- | --- | --- +`rsa_public_keys` | list of RSA keys in hexadecimal | A public RSA key for each replica for non-threshold cryptographic purposes. The keys should be in hexadecimal, and there should be as many keys as there are replicas. The keys should be given in ascending order of ID of the replica they belong to. + +##### Threshold Cryptosystem Public Configuration ##### + +A set of parameters is expected for each threshold cryptosystem used by Concord-BFT (of which there are currently four). Although configuration of each cryptosystem is expected to vary, the type and purposes of their parameters given in the keyfile is consistent. The parameters for each of the cryptosystems are differentiated from each other with a prefix that specifies which cryptosystem the parameter specifies. The prefixes are: + +Prefix | Cryptosystem Purpose +--- | --- +`execution` | Consensus on results of executing the transactions in a block. +`slow_commit` | Consensus on what transactions to commit in what order in a block, in the slow-path case where more than `c_val` replicas are slow, crashed, or otherwise unresponsive. +`commit` | Consensus on what transactions to commit in what order in a block in the general case. +`optimisitic_commit` | Consensus on what transactions to commit in what order in a block, in the optimistic fast-path case where all replicas are currently responsive. + +For each cryptosystem, a set of six public configuration parameters is expected, which should each begin with that cryptosystem's prefix: + +Parameter | Expected Value | Description +--- | --- | --- +`_cryptosystem_type` | string | Names a cryptosystem type for this cryptosystem; note that a summary of available cryptosystem types is included in `GenerateConcordKeys`'s help text. +`_cryptosystem_subtype_parameter` | string | A type-specific parameter specifying a subtype for this cryptosystem. For example, this is generally an elliptic curve type if an elliptic curve cryptosystem was selected. +`_cryptosystem_num_signers` | positive integer | Number of signers in this cryptosystem; it is expected that this value will be equal to `num_replicas`. +`_cryptosystem_threshold` | positive integrer | Threshold for this cryptosystem, that is, the number of unique signers that are required to produce a complete threshold signature under this cryptosystem. +`_cryptosystem_public_key` | cryptographic key of type-dependent format | The public key for this threshold cryptosystem. +`` | list of cryptographic key of type-dependent format | A verification key for each signer under this cryptosystem. The verification keys can be used to verify a specific signer's signature share during the collection of signatures for a complete threshold signture. The keys should be ordered by signer ID of the signer to which they correspond. + +##### Replica Private Keys ##### + +For each threshold cryptosystem, a private key is expected for the replica to which the keyfile belongs. Similarly to the threshold cryptosystem public configuration, the private keys' identifiers use a prefix to identify which cryptosystem they correspond to: + +Parameter | Expected Value | Description +--- | --- | --- +`_cryptosystem_private_key` | cryptographic key of a type-dependent format | The private key for the replica identified by `replica_id` under the threshold cryptosystem named by `PREFIX`. + +Furthermore, a private RSA key is expected for the replica: + +Parameter | Expected Value | Description +--- | --- | --- +`rsa_private_key` | RSA private key represented in hexadecimal | RSA private key for the replica identified by `replica_id`. + +### Testing Key Generation ### + +A utility for testing the validity of a complete set of keyfiles is provided, which can be used to test and verify the output of `GenerateConcordKeys` and could also be used to verify that a set of keyfiles is still valid after making post-generation manual or automatic adustments to them. The test is `TestGeneratedKeys`, and a binary for it should be included in the same directory (`tools`) as `GenerateConcordKeys` in a complete build of Concord-BFT. The test can be run with the following command: + +`TestGeneratedKeys -n -o ` + +where `NUM_REPLICAS` and `OUTPUT_PREFIX` are the same as those that were used when `GenerateConcordKeys` was run; that is, `TestGeneratedKeys` expects to find `NUM_REPLICAS` keyfiles to test with names of the format `OUTPUT_PREFIX`, where `i` is an index in the range `[0, NUM_REPLICAS - 1]`, inclusive, indicating which replica each keyfile belongs to. + +The last line of `TestGeneratedKeys`'s output (to the terminal) will include `SUCCESS` if the keyfiles passed the test or `FAILURE` if they did not; furthermore, `TestGeneratedKeys` will have a zero return code for passing results and a non-zero return code for failing results. + +A bash shell script, specifically `testKeyGeneration.sh`, is also available in the same directory as `GenerateConcordKeys` and `TestGeneratedKeys` to test that key generation and keyfile parsing are working correctly. `testKeyGeneration.sh` automatically runs `GenerateConcordKeys` and then tests its output with `TestGeneratedKeys` for several different sizes of Concord clusters. By default, the largest test that `testKeyGeneration.sh` offers is not run because the large test may take a while to run. In order to run `testKeyGeneration.sh` including this optional large test, run `testKeyGeneration.sh` with the `--run_large_test` option. diff --git a/tools/TestGeneratedKeys.cpp b/tools/TestGeneratedKeys.cpp new file mode 100644 index 0000000000..4c2321e130 --- /dev/null +++ b/tools/TestGeneratedKeys.cpp @@ -0,0 +1,965 @@ +// Concord +// +// Copyright (c) 2018 VMware, Inc. All Rights Reserved. +// +// This product is licensed to you under the Apache 2.0 license (the "License"). +// You may not use this product except in compliance with the Apache 2.0 +// License. +// +// This product may include a number of subcomponents with separate copyright +// notices and license terms. Your use of these subcomponents is subject to the +// terms and conditions of the subcomponent's license, as noted in the LICENSE +// file. + +#include +#include +#include +#include + +#include "bftengine/Crypto.hpp" +#include "threshsign/ThresholdSignaturesTypes.h" +#include "KeyfileIOUtils.hpp" + +// How often to output status when testing cryptosystems, measured as an +// interval measured in tested signaturs. +static const size_t kTestProgressReportingInterval = 128; + +// Hash(es) to test for each signer combination that will be validated. +static const std::string kHashesToTest[1] = { + "986699702ad64879360bbaccf7df4b2255a777f85a57c699c895992ea6fff2ac3c5e386c634f" + "9f9588be531154368468d8f454e82bee8d780ea13f7466f90a30ae0627fab054798ab217dfd6" + "2a988ca5875b555df5392b07664dcf4e947034f66e0ec51a9e469d78badf9c9c357d6ea14bcf" + "cd86d5f23e7f19ed11f9c18c859a9600320700d23e6a935fbf58c2310aeba2faaac00a7075de" + "02e6fd1cc94448daa7ead2aa6b4750b571211b01af392e8f100c0cd8011709690c2ef44847a6" + "47f60cfd8dd0005cd39fb599f9f8ad5be5a939c542707fc3d7c55c1b4e8dcde5ab02b9c9f421" + "2ae2d9bad10bf6299e2e02979e2c6ecc4d9989986d01ef58da511f671e983fe16169895534c3" + "ead052e9fd0d3b2963e64601362cc441c0e3a5c5a892edb3dab2b8db54c8d2025e4e9ba2aef1" + "ba2054751c7473d47fac4ccc407752fcbb30596c1815e806b3a88860e5e0d1f340556b55fb19" + "4b3b9761108bc14c33b4f957d5c3cbb74f7f7531dfbd37e14e773d453ea51209d485d1623df9" + "13875038247edb228b7b34075ee93d970f73e768fc2982c33e091a1a29fd2c29760b46aa1a63" + "d26992682b906b96f98dc5140babeb98dbccadceaf8f5e31b6f0906c773b6426df866dae32a2" + "1d88c54ee130f6f60761bc49a5b0864ac8f89bd464e5e2c8e8e8938570a47933d83e934d6b39" + "6e45479128168ce36f61880e93038a7895b1fb4303b50a59b21f92c721ca7ebdafcd96b9f23e" + "d6b0e276417034a564061c3d8c055afd9afbf6d933b41504c9fa39fe7c100ad538ea41be536c" + "b1e4e7eee0644c4d02beb00ff2be77ed84e17e65105c25a5caf74aca6c4204df6cacf07fa914" + "3260767dd8f6c8b794b16cf22cf2353da51840e0d20348b48907c44da481298dfa3f45b55d08" + "69acd530f82d06542970d15753ae1806a4229341b7af785175998944d5b575b00196fa01ed10" + "f4ffef06912a1b5964eb0604c8633929e7e056bdeb814cd0a719149c164a464bbc855e38f9aa" + "7bd19505dd85e487a55fff1bfc579c12f3816e87776273c6e3e72222c6a61132fac441e3af3b" + "db465f44dac867c66c2e83d925cdc976ebac4569945532ffbed26693ec61ad54b2897097dd67" + "88e6d5da2390a2cf0842783779e39478a91b06c32911fdd3466562a4cef2ff490bba670e20fe" + "6122a4d936c703e9cf6f5847c4d4e202074326ad953b37d97264c9b7d36ba26413d14ca38108" + "f4ceabe84b52768653168c54ff4d25c05c99c653e3cd606b87d5dbae249f57dc406969a5fcf0" + "eb3b1a893c5111853bed1cc60fe074a55aa51a975cc3217594ff1479036a05d01c01b2f610b4" + "e4adbc629e06dc636b65872072cdf084ee5a7e0a63afe42931025d4e5ed60d069cfa71d91bc7" + "451a8a2109529181fd150fc055ad42ce5c30c9512cd64ee3789f8c0d0069501be65f1950" +}; + +// Helper functions to main acting as sub-components of the test. + +// validateFundamentalFields and validateConfigStructIntegrity are sanity checks +// for the partially-filled-out ReplicaConfig structs read from the keyfiles to +// validate they are in order before attempting tests of the actual +// cryptographic keys. + +static bool validateFundamentalFields( + const std::vector& configs) { + uint16_t numReplicas = configs.size(); + uint16_t fVal = configs.front().fVal; + uint16_t cVal = configs.front().cVal; + + // Note we validate agreement of numReplicas, fVal, and cVal with 32-bit + // integers in case 3F + 2C + 1 overflows a 16-bit integer. + uint32_t expectedNumReplicas = 3 * (uint32_t)fVal + 2 * (uint32_t)cVal + 1; + + // Note that check fVal >= 1 before enforcing agreement of fVal and cVal with + // numReplicas to give precedence to complaining about invalid F over + // disagreement with numReplicas. + if ((fVal >= 1) && (expectedNumReplicas != (uint32_t)numReplicas)) { + std::cout << "TestGeneratedKeys: FAILURE: fVal (" << fVal << ") and cVal (" + << cVal << ") (according to key file 0) do not agree with the number" + " of replicas (" << numReplicas << "). It is required that numReplicas =" + " (3 * fVal + 2 * cVal + 1).\n"; + return false; + } + + for (uint16_t i = 0; i < numReplicas; ++i) { + const bftEngine::ReplicaConfig& config = configs[i]; + if (config.replicaId != i) { + std::cout << "TestGeneratedKeys: FAILURE: Key file " << i + << " specifies a replica ID disagreeing with its filename.\n"; + return false; + } + if (config.fVal < 1) { + std::cout << "TestGeneratedKeys: FAILURE: Replica " << i << " has an" + " invalid F value: " << config.fVal << ".\n."; + return false; + } + if (config.fVal != fVal) { + std::cout << "TestGeneratedKeys: FAILURE: Replica " << i << " has an F" + " value inconsistent with replica(s) 0 through " << (i - 1) << ".\n"; + return false; + } + if (config.cVal != cVal) { + std::cout << "TestGeneratedKeys: FAILURE: Replica " << i << " has a C" + " value inconsistent with replica(s) 0 through " << (i - 1) << ".\n"; + return false; + } + } + + return true; +} + +static bool validateConfigStructIntegrity( + const std::vector& configs) { + uint16_t numReplicas = configs.size(); + + for (uint16_t i = 0; i < numReplicas; ++i) { + const bftEngine::ReplicaConfig& config = configs[i]; + if (config.publicKeysOfReplicas.size() != numReplicas) { + std::cout << "TestGeneratedKeys: FAILURE: Size of the set of public keys" + " of replicas in replica " << i << "'s key file does not match the" + " number of replicas.\n"; + return false; + } + + std::set foundIDs; + for (auto entry: config.publicKeysOfReplicas) { + uint16_t id = entry.first; + if (id >= numReplicas) { + std::cout << "TestGeneratedKeys: FAILURE: Entry with invalid replica" + " ID (" << id << ") in set of public keys of replicas for replica " + << i <<".\n"; + return false; + } + if (foundIDs.count(id) > 0) { + std::cout << "TestGeneratedKeys: FAILURE: Set of public keys of" + " replicas for replica " << i << " contains duplicate entries for" + " replica " << id << ".\n"; + return false; + } + foundIDs.insert(id); + } + + if (!config.thresholdSignerForExecution) { + std::cout << "TestGeneratedKeys: FAILURE: No threshold signer for" + " execution for replica " << i << ".\n"; + return false; + } + if (!config.thresholdVerifierForExecution) { + std::cout << "TestGeneratedKeys: FAILURE: No threshold verifier for" + " execution for replica " << i << ".\n"; + return false; + } + if (!config.thresholdSignerForSlowPathCommit) { + std::cout << "TestGeneratedKeys: FAILURE: No threshold signer for slow" + " path commit for replica " << i << ".\n"; + return false; + } + if (!config.thresholdVerifierForSlowPathCommit) { + std::cout << "TestGeneratedKeys: FAILURE: No threshold verifier for slow" + " path commit for replica " << i << ".\n"; + return false; + } + if (!config.thresholdSignerForCommit) { + std::cout << "TestGeneratedKeys: FAILURE: No threshold signer for commit" + " for replica " << i << ".\n"; + return false; + } + if (!config.thresholdVerifierForCommit) { + std::cout << "TestGeneratedKeys: FAILURE: No threshold verifier for" + " commit for replica " << i << ".\n"; + return false; + } + if (!config.thresholdSignerForOptimisticCommit) { + std::cout << "TestGeneratedKeys: FAILURE: No threshold signer for" + " optimistic commit for replica " << i << ".\n"; + return false; + } + if (!config.thresholdVerifierForOptimisticCommit) { + std::cout << "TestGeneratedKeys: FAILURE: No threshold verifier for" + " optimistic commit for replica " << i << ".\n"; + return false; + } + } + + return true; +} + +// Helper function to test RSA keys to test the compatibility of a single key +// pair. +static bool testRSAKeyPair(const std::string& privateKey, + const std::string& publicKey, + uint16_t replicaID) { + + // The signer and verifier are stored with unique pointers rather than by + // value so that they can be constructed in try/catch statements without + // limiting their scope to those statements; declaring them by value is not + // possible in this case becuause they lack paramter-less default + // constructors. + std::unique_ptr signer; + std::unique_ptr verifier; + + std::string invalidPrivateKey = "TestGeneratedKeys: FAILURE: Invalid RSA" + " private key for replica " + std::to_string(replicaID) + ".\n"; + std::string invalidPublicKey = "TestGeneratedKeys: FAILURE: Invalid RSA" + " public key for replica " + std::to_string(replicaID) + ".\n"; + + try { + signer.reset(new bftEngine::impl::RSASigner(privateKey.c_str())); + } catch (std::exception e) { + std::cout << invalidPrivateKey; + return false; + } + try { + verifier.reset(new bftEngine::impl::RSAVerifier(publicKey.c_str())); + } catch (std::exception e) { + std::cout << invalidPublicKey; + return false; + } + + for (auto iter = std::begin(kHashesToTest); iter != std::end(kHashesToTest); + ++iter) { + const std::string& hash = *iter; + + size_t signatureLength; + try { + signatureLength = signer->signatureLength(); + } catch (std::exception e) { + std::cout << invalidPrivateKey; + return false; + } + size_t returnedSignatureLength; + char* signatureBuf = new char[signatureLength]; + + try { + if (!signer->sign(hash.c_str(), hash.length(), signatureBuf, + signatureLength, returnedSignatureLength)) { + std::cout << "TestGeneratedKeys: FAILURE: Failed to sign data with" + " replica " << replicaID << "'s RSA private key.\n"; + delete[] signatureBuf; + return false; + } + } catch (std::exception e) { + std::cout << invalidPrivateKey; + delete[] signatureBuf; + return false; + } + + try { + if (!verifier->verify(hash.c_str(), hash.length(), signatureBuf, + returnedSignatureLength)) { + std::cout << "TestGeneratedKeys: FAILURE: A signature with replica " + << replicaID << "'s RSA private key could not be verified with" + " replica " << replicaID << "'s RSA public key.\n"; + delete[] signatureBuf; + return false; + } + } catch (std::exception e) { + std::cout << invalidPublicKey; + delete[] signatureBuf; + return false; + } + + delete[] signatureBuf; + } + + return true; +} + +// Test that the RSA key pairs given in the keyfiles work, that the keyfiles +// agree on what the public keys are, and that there are no duplicates. +static bool testRSAKeys(const std::vector& configs) { + uint16_t numReplicas = configs.size(); + + std::cout << "Testing " << numReplicas << " RSA key pairs...\n"; + std::unordered_map expectedPublicKeys; + std::unordered_set rsaPublicKeysSeen; + + // Test that a signature produced with each replica's private key can be + // verified with that replica's public key. + for (uint16_t i = 0; i < numReplicas; ++i) { + std::string privateKey = configs[i].replicaPrivateKey; + std::string publicKey; + + for (auto publicKeyEntry: configs[i].publicKeysOfReplicas) { + if (publicKeyEntry.first == i) { + publicKey = publicKeyEntry.second; + } + } + + if(!testRSAKeyPair(privateKey, publicKey, i)) { + return false; + } + + if (rsaPublicKeysSeen.count(publicKey) > 0) { + uint16_t existingKeyholder; + for (auto publicKeyEntry: expectedPublicKeys) { + if (publicKeyEntry.second == publicKey) { + existingKeyholder = publicKeyEntry.first; + } + } + std::cout << "TestGeneratedKeys: FAILURE: Replicas " << existingKeyholder + << " and " << i << " share the same RSA public key.\n"; + return false; + } + expectedPublicKeys[i] = publicKey; + + if (((i + 1) % kTestProgressReportingInterval) == 0) { + std::cout << "Tested " << (i + 1) << " out of " << numReplicas + << " RSA key pairs...\n"; + } + } + + std::cout << "Verifying that all replicas agree on RSA public keys...\n"; + + // Verify that all replicas' keyfiles agree on the RSA public keys. + for (uint16_t i = 0; i < numReplicas; ++i) { + for (auto publicKeyEntry: configs[i].publicKeysOfReplicas) { + if (publicKeyEntry.second != expectedPublicKeys[publicKeyEntry.first]) { + std::cout << "TestGeneratedKeys: FAILURE: Replica " << i << " has an" + " incorrect RSA public key for replica " << publicKeyEntry.first + << ".\n"; + return false; + } + } + } + + std::cout << "All RSA key tests were successful.\n"; + + return true; +} + +// Testing the threshold cryptosystem keys is not as straightforward as testing +// the RSA keys because each signature may have multiple signers. Testing all +// possible signer combinations, or even only all signer combinations that we +// expect to produce a complete valid threshold signature, is not feasible +// (unless the number of signers is rather small), as the number of possible +// signer combinations grows combinatorially with the number of signers; this +// can get even worth if we consider testing whether signer order makes a +// difference. +// +// For this case, which is intended specifically as a test of the keyset +// generated by GenerateConcordKeys, we deliberately choose to limit ourselves +// to testing that GenerateConcordKeys generates a valid keyset under our +// threshold cryptography implementations in the threshsign directory; we do NOT +// thoroughly test the correctness of the implementations in threshsign here. +// +// To this end, we try to test that the thresholds for the generated +// cryptosystems are correct and to cover all keys in the systems with the test. + +// Function for selecting what combinations of signers to test for a given +// number of signers and threshold; note the isolation of this functions makes +// it less difficult to reconfigure what tests we want to do on each thresold +// cryptosystem. +static std::vector> + getThresholdSignerCombinationsToTest(uint16_t numSigners, + uint16_t threshold) { + std::vector> signerCombinations; + std::vector signers; + + // Try signer sets of sizes 1, threshold - 1, and threshold to validate that + // threshold is as expected and working correctly for this cryptosystem. + std::vector signerNumsToTest; + signerNumsToTest.push_back(1); + if ((threshold - 1) > signerNumsToTest.back()) { + signerNumsToTest.push_back(threshold - 1); + } + if (threshold > signerNumsToTest.back()) { + signerNumsToTest.push_back(threshold); + } + + for (auto numSignersToTest: signerNumsToTest) { + for (uint16_t i = 0; i < numSignersToTest; ++i) { + signers.push_back(i); + } + signerCombinations.push_back(std::move(signers)); + } + + // Ensure that every private/verification key pair is tested. Since the + // threshold is less than the number of signers, we achieve this by testing + // consecutive (by signer index) bocks of keys of size threshold until we have + // tested all keys. To handle that the number of signers may not be divisible + // by the threshold, we wrap around the final block to the front again if it + // goes past the end of the keys. + + // We use a 32 bit integer to keep track of how many signers we have tested so + // far, even though the signers are indexed with 16 bit integers, because + // signersTested will likely exceed the number of signers during the last + // block, at which point we will continue selecting as many signers as we need + // by wraping it back around to the front with modulus; we cannot immediately + // set signersTested itself to itself mod numSigners once it exceeds the + // number of signers because whether it has yet exceeded the number of signers + // is used as the condition to determine whether we have covered all the keys + // or whether we need to add more threshold-sized blocks of them. + uint32_t signersTested = 0; + + while (signersTested < (uint32_t)numSigners) { + for (uint16_t i = 0; i < threshold; ++i) { + signers.push_back((uint16_t)(signersTested % (uint32_t)numSigners)); + ++signersTested; + } + signerCombinations.push_back(std::move(signers)); + } + + return signerCombinations; +} + +// Helper function to testThresholdSignature used to release accumulators, which +// is done through the verifier that created the accumulator, which we do not +// trust not to throw an exception during the release process because we do not +// trust that the keys we constructed it with were valid. +static bool releaseAccumulator(IThresholdVerifier* verifier, + IThresholdAccumulator* accumulator) { + if (accumulator) { + try { + verifier->release(accumulator); + } catch (std::exception e) { + return false; + } + } + return true; +} + +// Helper function to testThresholdCryptosystem for testing a single signature. +// +// Note we cannot accept signers and verifier as const because +// IThresholdSigner.signData and IThresholdVerifier.release are not marked as +// const, even though threshold signers and verifiers are theoretically +// reusable. +static bool testThresholdSignature(const std::string& cryptosystemName, + std::vector signers, + IThresholdVerifier* verifier, + const std::vector& signersToTest, + uint16_t numSigners, + uint16_t threshold) { + + std::string invalidPublicConfig = "TestGeneratedKeys: FAILURE: Invalid public" + " and verification keyset for " + cryptosystemName + " threshold" + " cryptosystem.\n"; + std::string invalidKeyset = "TestGeneratedKeys: FAILURE: Invalid keyset for" + " the " + cryptosystemName + " threshold cryptosystem.\n"; + + uint16_t participatingSigners = signersToTest.size(); + + for (auto hash: kHashesToTest) { + int hashLength = hash.length(); + + IThresholdAccumulator* accumulator; + + try { + accumulator = verifier->newAccumulator(true); + + // It is necessary to try to catch an exception from newAccumulator and + // then construct an accumulator with verification disabled (and make sure + // we do not attempt to use verification below if we had to do this) + // because some implementations of IThresholdAccumulator have the behavior + // of failing to support verification and throwing an exception when + // attempting to construct them with verification. At the time thiw code + // was written, IThresholdVerifier did not include a means of checking + // whether the accumulators an implementation of it creates support + // verification other than handling the exception that occurs if they do + // not. + } catch (std::exception e) { + try { + accumulator = verifier->newAccumulator(false); + } catch (std::exception e) { + std::cout << invalidPublicConfig; + releaseAccumulator(verifier, accumulator); + return false; + } + } + + bool verificationEnabled; + try { + verificationEnabled = accumulator->hasShareVerificationEnabled(); + } catch (std::exception e) { + std::cout << invalidPublicConfig; + releaseAccumulator(verifier, accumulator); + return false; + } + + if (verificationEnabled) { + try { + accumulator->setExpectedDigest(reinterpret_cast( + hash.c_str()), hashLength); + } catch (std::exception e) { + std::cout << invalidPublicConfig; + releaseAccumulator(verifier, accumulator); + return false; + } + } + + int accumulatorSize; + if (verificationEnabled) { + try { + accumulatorSize = accumulator->getNumValidShares(); + } catch (std::exception e) { + std::cout << invalidPublicConfig; + releaseAccumulator(verifier, accumulator); + return false; + } + if (accumulatorSize != 0) { + std::cout << "TestGeneratedKeys: FAILURE: Newly created signature" + " accumulator for " << cryptosystemName << " threshold cryptosystem" + " reports already having valid signatures.\n"; + releaseAccumulator(verifier, accumulator); + return false; + } + } + + for (auto signerID: signersToTest) { + IThresholdSigner* signer = signers[signerID]; + std::string invalidPrivateKey = "TestGeneratedKeys: FAILURE: Invalid" + " private key for signer " + std::to_string(signerID) + " under the " + + cryptosystemName + " threshold cryptosystem.\n"; + int sigShareLen; + try { + sigShareLen = signer->requiredLengthForSignedData(); + } catch (std::exception e) { + std::cout << invalidPrivateKey; + releaseAccumulator(verifier, accumulator); + return false; + } + char* sigShareBuf = new char[sigShareLen]; + try { + signer->signData(hash.c_str(), hashLength, sigShareBuf, sigShareLen); + } catch (std::exception e) { + std::cout << invalidPrivateKey; + releaseAccumulator(verifier, accumulator); + delete[] sigShareBuf; + return false; + } + int addRes; + try { + addRes = accumulator->add(sigShareBuf, sigShareLen); + } catch (std::exception e) { + std::cout << invalidKeyset; + releaseAccumulator(verifier, accumulator); + delete[] sigShareBuf; + return false; + } + delete[] sigShareBuf; + + if (verificationEnabled) { + + // Note we do not necessarily expect the accumulator to accept the + // signature if it already has enough signatures to satisfy the + // threshold, as extra signatures are not actually helpful to it for + // producing the composite signature it was created to produce. + if (((accumulatorSize + 1) <= threshold) + && (addRes != (accumulatorSize + 1))) { + std::cout << "TestGeneratedKeys: FAILURE: Signature accumulator" + " could not validate replica " << signerID << "'s signature for " + << cryptosystemName << " threshold cryptosystem.\n"; + releaseAccumulator(verifier, accumulator); + return false; + } else { + accumulatorSize = addRes; + } + } + } + + int signatureLength; + try { + signatureLength = verifier->requiredLengthForSignedData(); + } catch (std::exception e) { + std::cout << invalidPublicConfig; + releaseAccumulator(verifier, accumulator); + return false; + } + char* sigBuf = new char[signatureLength]; + try { + accumulator->getFullSignedData(sigBuf, signatureLength); + } catch (std::exception e) { + std::cout << invalidKeyset; + releaseAccumulator(verifier, accumulator); + delete[] sigBuf; + return false; + } + + bool signatureAccepted; + try { + signatureAccepted = verifier->verify(hash.c_str(), hashLength, + sigBuf, signatureLength); + } catch (std::exception e) { + std::cout << invalidKeyset; + releaseAccumulator(verifier, accumulator); + delete[] sigBuf; + return false; + } + + delete[] sigBuf; + if (!releaseAccumulator(verifier, accumulator)) { + std::cout << invalidKeyset; + return false; + } + + if (signatureAccepted != (participatingSigners >= threshold)) { + std::cout << "TestGeneratedKeys: FAILURE: Threshold signer with " + << participatingSigners << " signatures unexpectedly " + << (signatureAccepted ? "accepted" : "rejected") << " under the " + << cryptosystemName << " threshold cryptosystem, which has threshold " + << threshold << " out of " << numSigners << ".\n"; + return false; + } + } + + return true; +} + +// Run all tests we want to do on each threshold cryptosystem on a given +// threshold cryptosystem. +static bool testThresholdCryptosystem( + const std::string& name, + const std::vector& signers, + const std::vector& verifiers, + uint16_t numSigners, + uint16_t threshold) { + std::cout << "Testing " << name << " threshold cryptosystem.\n"; + + size_t testsCompleted = 0; + + IThresholdVerifier* referenceVerifier = verifiers.front(); + std::vector> signerCombinationsToTest + = getThresholdSignerCombinationsToTest(numSigners, threshold); + size_t totalTests = signerCombinationsToTest.size(); + + // Test that the threshold cryptosystem functions as expected. + for (auto signerCombination: signerCombinationsToTest) { + if (!testThresholdSignature(name, signers, referenceVerifier, + signerCombination, numSigners, threshold)) { + return false; + } + ++testsCompleted; + if ((testsCompleted % kTestProgressReportingInterval) == 0) { + std::cout << "Tested " << testsCompleted << " out of " << totalTests + << " signer combinations to test on the " << name << " threshold" + " cryptosystem.\n"; + } + } + + // Verify that all replicas' keyfiles agree on the public and verification + // keys for this cryptosystem. + for (uint16_t i = 0; i < numSigners; ++i) { + IThresholdVerifier* verifier = verifiers[i]; + if (verifier->getPublicKey().toString() + != referenceVerifier->getPublicKey().toString()) { + std::cout << "TestGeneratedKeys: FAILURE: Replica " << i << "'s key file" + " has the wrong public key for the " << name << " threshold" + " cryptosystem.\n"; + return false; + } + for (uint16_t j = 0; j < numSigners; ++j) { + if (verifier->getShareVerificationKey(j).toString() + != referenceVerifier->getShareVerificationKey(j).toString()) { + std::cout << "TestGeneratedKeys: FAILURE: Replica " << i << "'s key" + " file has the wrong share verification key for replica " << j + << " under the " << name << " threshold cryptosystem.\n"; + return false; + } + } + } + + // Verify that each replica's private key is unique. + std::unordered_set privKeys; + for (uint16_t i = 0; i < numSigners; ++i) { + std::string key = signers[i]->getShareSecretKey().toString(); + if (privKeys.count(key) > 0) { + uint16_t existingKeyHolder; + for (uint16_t j = 0; j < i; ++j) { + if (signers[j]->getShareSecretKey().toString() == key) { + existingKeyHolder = j; + } + } + std::cout << "TestGeneratedKeys: FAILURE: Replica " << i << " shares a" + " private key with replica " << existingKeyHolder << " under the " + << name << " threshold cryptosystem.\n"; + return false; + } + } + + std::cout << "The " << name << " threshold cryptosystem tested" + " successfully.\n"; + return true; +} + +// Tests all threshold cryptosystems given in the keyfiles by calling +// testThresholdCryptosystem for each of them. +static bool testThresholdKeys(const std::vector& + configs) { + uint16_t numReplicas = configs.size(); + + // Compute thresholds. + uint16_t f = configs.front().fVal; + uint16_t c = configs.front().cVal; + uint16_t execThresh = f + 1; + uint16_t slowThresh = f * 2 + c + 1; + uint16_t commitThresh = f * 3 + c + 1; + uint16_t optThresh = f * 3 + c * 2 + 1; + + std::cout << "Testing threshold cryptographic keys...\n"; + + std::vector signers; + std::vector verifiers; + + for (uint16_t i = 0; i < numReplicas; ++i) { + signers.push_back(configs[i].thresholdSignerForExecution); + verifiers.push_back(configs[i].thresholdVerifierForExecution); + } + if (!testThresholdCryptosystem("execution", signers, verifiers, numReplicas, + execThresh)) { + return false; + } + + signers.clear(); + verifiers.clear(); + for (uint16_t i = 0; i < numReplicas; ++i) { + signers.push_back(configs[i].thresholdSignerForSlowPathCommit); + verifiers.push_back(configs[i].thresholdVerifierForSlowPathCommit); + } + if (!testThresholdCryptosystem("slow path commit", signers, verifiers, + numReplicas, slowThresh)) { + return false; + } + + signers.clear(); + verifiers.clear(); + for (uint16_t i = 0; i < numReplicas; ++i) { + signers.push_back(configs[i].thresholdSignerForCommit); + verifiers.push_back(configs[i].thresholdVerifierForCommit); + } + if (!testThresholdCryptosystem("commit", signers, verifiers, numReplicas, + commitThresh)) { + return false; + } + + signers.clear(); + verifiers.clear(); + for (uint16_t i = 0; i < numReplicas; ++i) { + signers.push_back(configs[i].thresholdSignerForOptimisticCommit); + verifiers.push_back(configs[i].thresholdVerifierForOptimisticCommit); + } + if (!testThresholdCryptosystem("optimistic fast path commit", signers, + verifiers, numReplicas, optThresh)) { + return false; + } + + std::cout << "All threshold cryptography tests were successful.\n"; + + return true; +} + +// Function to simplify the process of freeing the dynamically allocated memory +// referenced by each ReplicaConfig struct, which the main function below may +// need to do in one of several places because it may return early in the event +// of a failure. +static void freeConfigs(const std::vector& configs) { + for (auto config: configs) { + if (config.thresholdSignerForExecution) { + delete config.thresholdSignerForExecution; + } + if (config.thresholdVerifierForExecution) { + delete config.thresholdVerifierForExecution; + } + if (config.thresholdSignerForSlowPathCommit) { + delete config.thresholdSignerForSlowPathCommit; + } + if (config.thresholdVerifierForSlowPathCommit) { + delete config.thresholdVerifierForSlowPathCommit; + } + if (config.thresholdSignerForCommit) { + delete config.thresholdSignerForCommit; + } + if (config.thresholdVerifierForCommit) { + delete config.thresholdVerifierForCommit; + } + if (config.thresholdSignerForOptimisticCommit) { + delete config.thresholdSignerForOptimisticCommit; + } + if (config.thresholdVerifierForOptimisticCommit) { + delete config.thresholdVerifierForOptimisticCommit; + } + } +} + +// Helper function for determining whether --help was given. +static bool containsHelpOption(int argc, char** argv) { + for (int i = 1; i < argc; ++i) { + if (std::string(argv[i]) == "--help") { + return true; + } + } + return false; +} + +/** + * Main function for the TestGeneratedKeys executable. TestGeneratedKeys is + * intended as a test for the correctness of GenerateConcordKeys, although it + * can also validate a set of keyfiles that have been manually created or + * modified as long as they comply with the output keyfile naming convention + * that GenerateConcordKeys uses. + * + * @param argc The number of arguments to this executable, including the name by + * which this executable was launched as the first by convention. + * @param argv Command line arguments to this executable, including the name by + * which it was launched as the first argument per convention. This + * executable can be run with the --help option for usage + * information on what command line arguments are expected. + * + * @return 0 if the testing is launched and completed successfully; -1 if the + * tests could not be launched (for example, because of issue with the + * command line parameters or missing input files) or if the input key + * files fail the tests. + */ +int main(int argc, char** argv) { + std::string usageMessage = + "Usage:\n" + " TestGeneratedKeys -n TOTAL_NUMBER_OF_REPLICAS -o KEYFILE_PREFIX.\n" + "TestGeneratedKeys is intended to test the output of the\n" + "GenerateConcordKeys utility; TestGeneratedKeys expects that\n" + "GenerateConcordKeys has already been run and produced keyfiles for it to\n" + "test. TOTAL_NUMBER_OF_REPLICAS should specify how many replicas there\n" + "are in the deployment that TestGeneratedKeys has generated keys for, and\n" + "KEYFILE_PREFIX should be the prefix passed to GenerateConcordKeys via\n" + "its -o option that all. TestGeneratedKeys expects to find\n" + "TOTAL_NUMBER_OF_REPLICAS keyfiles each named KEYFILE_PREFIX, where\n" + " is an integer in the range [0, TOTAL_NUMBRER_OF_REPLICAS - 1],\n" + "inclusive.\n\n" + "TestGeneratedKeys can be run with no options or with the --help option\n" + "to view this usage text.\n"; + + // Output the usage message if no arguments were given. Note that argc should + // equal 1 in that case, as the first argument is the command used to run this + // executable by convention. + if ((argc <= 1) || (containsHelpOption(argc, argv))) { + std::cout << usageMessage; + return 0; + } + + uint16_t numReplicas; + std::string outputPrefix; + + bool hasNumReplicas; + bool hasOutputPrefix; + + // Read input from the command line. + // Note we ignore argv[0] because it contains the command that was used to run + // this executable by convention. + for (int i = 1; i < argc; ++i) { + std::string option(argv[i]); + + if (option == "-n") { + if (i >= argc - 1) { + std::cout << "Expected an argument to -n.\n"; + return -1; + } + std::string arg = argv[i + 1]; + long long unvalidatedNumReplicas; + + std::string errorMessage = "Invalid value for -n; -n must be a positive" + " integer not exceeding " + std::to_string(UINT16_MAX) + ".\n"; + + try { + unvalidatedNumReplicas = std::stoll(arg); + } catch (std::invalid_argument e) { + std::cout << errorMessage; + return -1; + } catch (std::out_of_range e) { + std::cout << errorMessage; + return -1; + } + if ((unvalidatedNumReplicas < 1) + || (unvalidatedNumReplicas > UINT16_MAX)) { + std::cout << errorMessage; + return -1; + } else { + numReplicas = (uint16_t)unvalidatedNumReplicas; + hasNumReplicas = true; + } + ++i; + + } else if (option == "-o") { + if (i >= argc - 1) { + std::cout << "Expected an argument to -o.\n"; + return -1; + } + outputPrefix = argv[i + 1]; + hasOutputPrefix = true; + ++i; + + } else { + std::cout << "Unrecognized command line option: " << option << ".\n"; + return -1; + } + } + + if (!hasNumReplicas) { + std::cout << "No value given for required -n parameter.\n"; + return -1; + } + if (!hasOutputPrefix) { + std::cout << "No value given for required -o parameter.\n"; + return -1; + } + + std::cout << "TestGeneratedKeys launched.\n"; + std::cout << "Testing keyfiles for a " << numReplicas << "-replica Concord" + " deployment...\n"; + + std::vector configs(numReplicas); + + // Verify that all keyfiles exist before possibly wasting a significant + // ammount of time parsing an incomplete set of files. + std::vector inputFiles; + for (uint16_t i = 0; i < numReplicas; ++i) { + std::string filename = outputPrefix + std::to_string(i); + inputFiles.push_back(std::ifstream(filename)); + if (!inputFiles.back().is_open()) { + std::cout << "TestGeneratedKeys: FAILURE: Could not open keyfile " + << filename << ".\n"; + return -1; + } + } + + for (uint16_t i = 0; i < numReplicas; ++i) { + std::string filename = outputPrefix + std::to_string(i); + if (!inputReplicaKeyfile(inputFiles[i], filename, configs[i])) { + std::cout << "TestGeneratedKeys: FAILURE: Failed to input keyfile " + << filename << "; this keyfile is invalid.\n"; + freeConfigs(configs); + return -1; + } else { + std::cout << "Succesfully input keyfile " << filename << ".\n"; + } + } + + std::cout << "All keyfiles were input successfully.\n"; + + std::cout << "Verifying sanity of the cryptographic configuratigurations read" + " from the keyfiles...\n"; + if (!validateFundamentalFields(configs)) { + freeConfigs(configs); + return -1; + } + if (!validateConfigStructIntegrity(configs)) { + freeConfigs(configs); + return -1; + } + std::cout << "Cryptographic configurations read appear to be sane.\n"; + std::cout << "Testing key functionality and agreement...\n"; + if (!testRSAKeys(configs)) { + freeConfigs(configs); + return -1; + } + if (!testThresholdKeys(configs)) { + freeConfigs(configs); + return -1; + } + std::cout << "Done testing all keys.\n"; + std::cout << "TestGeneratedKeys: SUCCESS.\n"; + + freeConfigs(configs); + + return 0; +} diff --git a/tools/testKeyGeneration.sh b/tools/testKeyGeneration.sh new file mode 100755 index 0000000000..c2965140d6 --- /dev/null +++ b/tools/testKeyGeneration.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +# Test GenerateConcordKeys using TestGeneratedKeys for several different +# dimensions of Concord clusters. + +# Only run the large test if it was explicitly requested, since it may take a +# while to run. + +run_large_test=false + +for i in "$@" +do + if [ "$i" = "--run_large_test" ]; then + run_large_test=true + else + echo "testKeyGeneration: Unrecognized Argument: $i" + exit -1 + fi +done + +echo "testKeyGeneration: Testing GenerateConcordKeys for several different" \ + " cluster sizes..." + +rm test_keyfile_* +echo "Generating keys for a 4-replica cluster..." +./GenerateConcordKeys -f 1 -n 4 -o test_keyfile_ +echo "Done. Testing the keys..." +if ! ./TestGeneratedKeys -n 4 -o test_keyfile_; then + echo "testKeyGeneration: FAILURE" + exit -1 +fi + +rm test_keyfile_* +echo "Generating keys for a 6-replica cluster..." +./GenerateConcordKeys -f 1 -n 6 -o test_keyfile_ +echo "Done. Testing the keys..." + +if ! ./TestGeneratedKeys -n 6 -o test_keyfile_; then + echo "testKeyGeneration: FAILURE" + exit -1 +fi + +rm test_keyfile_* +echo "Generating keys for a 61-replica cluster. This won't be instantaneous..." +./GenerateConcordKeys -f 20 -n 61 -o test_keyfile_ +echo "Done. Testing the keys..." + +if ! ./TestGeneratedKeys -n 61 -o test_keyfile_; then + echo "testKeyGeneration: FAILURE" + exit -1 +fi + +rm test_keyfile_* +echo "Generating keys for a 67-replica cluster. This won't be instantaneous..." +./GenerateConcordKeys -f 20 -n 67 -o test_keyfile_ +echo "Done. Testing the keys..." + +if ! ./TestGeneratedKeys -n 67 -o test_keyfile_; then + echo "testKeyGeneration: FAILURE" + exit -1 +fi + +if [ "$run_large_test" = true ]; then + rm test_keyfile_* + echo "Generating keys for a 931-replica cluster. This may take a while..." + ./GenerateConcordKeys -f 300 -n 931 -o test_keyfile_ + echo "Done. Testing the keys..." + + if ! ./TestGeneratedKeys -n 931 -o test_keyfile_; then + echo "testKeyGeneration: FAILURE" + exit -1 + fi +fi + +echo "testKeyGeneration: SUCCESS: All tests were successful." +exit 0