From 2779865500830fd31fdce61a0a38b340eac395d3 Mon Sep 17 00:00:00 2001 From: Sidnei Teixeira Date: Mon, 22 Jun 2026 18:37:19 +0100 Subject: [PATCH 1/3] IS-1475 move ECDH key setting to generateDKGPoly call; add batched writes to levelDB --- LevelDB.cpp | 37 ++++++++ LevelDB.h | 9 ++ SGXWalletServer.cpp | 197 ++++++++++++++++++++++++++++++++++++++--- SGXWalletServer.hpp | 17 +++- TestUtils.cpp | 13 +-- WalletDBKeys.h | 5 ++ abstractstubserver.h | 19 +++- sgxwallet_common.h | 8 ++ spec.json | 16 +++- stubclient.h | 17 +++- testw.cpp | 73 +++++++++++---- zmq_src/ReqMessage.cpp | 16 +++- zmq_src/ReqMessage.h | 8 ++ zmq_src/ZMQClient.cpp | 16 +++- zmq_src/ZMQClient.h | 5 +- zmq_src/ZMQMessage.cpp | 4 + zmq_src/ZMQMessage.h | 3 + 17 files changed, 417 insertions(+), 46 deletions(-) diff --git a/LevelDB.cpp b/LevelDB.cpp index 4c9f8901..0b85b376 100644 --- a/LevelDB.cpp +++ b/LevelDB.cpp @@ -28,6 +28,7 @@ #include #include "leveldb/db.h" +#include "leveldb/write_batch.h" #include #include "LevelDB.h" @@ -96,6 +97,42 @@ void LevelDB::writeRawString(std::string_view _key, const string &_value) { throwExceptionOnError(status); } +void LevelDB::writeBatch(const vector> &puts, + const vector &deletes, + bool requireNewPutKeys) { + lock_guard lock(mutex); + + // make sure no keys with same names existed before + if (requireNewPutKeys) { + for (const auto &it : puts) { + if (readString(it.first) != nullptr) { + throw SGXException(KEY_NAME_ALREADY_EXISTS, + string(__FUNCTION__) + ":Name already exists" + + it.first); + } + } + } + + leveldb::WriteBatch batch; + Json::FastWriter fastWriter; + + for (const auto &it : puts) { + Json::Value writerData; + writerData["value"] = it.second; + writerData["timestamp"] = std::to_string(std::time(nullptr)); + std::string output = fastWriter.write(writerData); + + batch.Put(Slice(it.first), Slice(output)); + } + + for (const auto &key : deletes) { + batch.Delete(Slice(key)); + } + + auto status = db->Write(writeOptions, &batch); + throwExceptionOnError(status); +} + void LevelDB::deleteDHDKGKey(std::string_view _key) { string full_key = string(WalletDBKeys::DKG_DH_KEY_PREFIX) + string(_key); diff --git a/LevelDB.h b/LevelDB.h index 6ffe190c..91547da7 100644 --- a/LevelDB.h +++ b/LevelDB.h @@ -90,6 +90,15 @@ class LevelDB { */ void writeRawString(std::string_view key1, const string &value1); + /** + * @brief Atomically writes and deletes keys in a single LevelDB batch. + * Values in puts are wrapped in the standard JSON envelope with timestamp. + * If requireNewPutKeys is true, all put keys must not already exist. + */ + void writeBatch(const vector> &puts, + const vector &deletes, + bool requireNewPutKeys = false); + void writeDataUnique(std::string_view Name, const string &value); void deleteDHDKGKey(std::string_view _key); diff --git a/SGXWalletServer.cpp b/SGXWalletServer.cpp index c7afa71d..ba5cf7c0 100644 --- a/SGXWalletServer.cpp +++ b/SGXWalletServer.cpp @@ -43,6 +43,7 @@ #include "SGXException.h" #include "TECrypto.h" #include "WalletDBKeys.h" +#include #include "SGXWalletServer.h" #include "SGXWalletServer.hpp" @@ -536,7 +537,8 @@ Json::Value SGXWalletServer::generateDKGPolyImpl(const string &_polyName, } Json::Value SGXWalletServer::generateDKGPolyV3Impl( - const string &_polyName, const string &_previousBLSPrivateKeyName, int _t) { + const string &_polyName, const string &_previousBLSPrivateKeyName, int _t, + int _n, const Json::Value &_publicKeys) { COUNT_STATISTICS spdlog::info("Entering {}", __FUNCTION__); INIT_RESULT(result) @@ -561,12 +563,69 @@ Json::Value SGXWalletServer::generateDKGPolyV3Impl( string(__FUNCTION__) + ":Invalid gen dkg param t "); } + if (!check_n_t(_t, _n)) { + throw SGXException(GENERATE_DKGV3_POLY_INVALID_PARAMS, + string(__FUNCTION__) + ":Invalid gen dkg params n/t"); + } + + if (!_publicKeys.isArray() || (int)_publicKeys.size() != _n) { + throw SGXException(GENERATE_DKGV3_POLY_INVALID_PUBKEY_COUNT, + string(__FUNCTION__) + + ":publicKeys size must equal n"); + } + + vector pubKeyStrs; + pubKeyStrs.reserve(_n); + for (int i = 0; i < _n; i++) { + if (!checkHex(_publicKeys[i].asString(), 64)) { + throw SGXException(GENERATE_DKGV3_POLY_INVALID_PUBKEY_HEX, + string(__FUNCTION__) + + ":Invalid public key at index " + + to_string(i)); + } + pubKeyStrs.push_back(_publicKeys[i].asString()); + } + std::shared_ptr encryptedBLSKey = readFromDb(_previousBLSPrivateKeyName); CHECK_STATE(encryptedBLSKey); encrPolyHex = genDkgPolyV3(_t, *encryptedBLSKey); - writeDataToDB(_polyName, encrPolyHex); + + // Build and persist binding metadata + string joinedKeys; + for (const auto &k : pubKeyStrs) { + joinedKeys += k; + joinedKeys += ","; + } + if (!joinedKeys.empty()) joinedKeys.pop_back(); + string recipientsHash = cryptlite::sha256::hash_hex(joinedKeys); + + Json::Value meta; + meta["version"] = 1; + meta["polyName"] = _polyName; + meta["t"] = _t; + meta["n"] = _n; + for (int i = 0; i < _n; i++) { + meta["publicKeys"][i] = pubKeyStrs[i]; + } + meta["recipientsHash"] = recipientsHash; + meta["previousBLSPrivateKeyName"] = _previousBLSPrivateKeyName; + meta["createdAt"] = + (Json::Int64)chrono::duration_cast( + chrono::system_clock::now().time_since_epoch()) + .count(); + + Json::FastWriter writer; + string metaKey = + string(WalletDBKeys::DKG_META_V1_PREFIX) + _polyName; + + vector> puts; + puts.emplace_back(_polyName, encrPolyHex); + puts.emplace_back(metaKey, writer.write(meta)); + + // Poly and metadata must be persisted atomically to avoid fail-open paths. + LevelDB::getLevelDb()->writeBatch(puts, {}, true); } HANDLE_SGX_EXCEPTION(result) @@ -876,16 +935,24 @@ Json::Value SGXWalletServer::complaintResponseImpl(const string &_polyName, } } + vector keysToDelete; + keysToDelete.reserve(static_cast(_n) * 2 + 3); + for (int i = 0; i < _n; i++) { string name = _polyName + "_" + to_string(i) + ":"; - LevelDB::getLevelDb()->deleteDHDKGKey(name); + keysToDelete.push_back(string(WalletDBKeys::DKG_DH_KEY_PREFIX) + name); string shareG2_name = "shareG2_" + _polyName + "_" + to_string(i) + ":"; - LevelDB::getLevelDb()->deleteKey(shareG2_name); + keysToDelete.push_back(shareG2_name); } - LevelDB::getLevelDb()->deleteKey(_polyName); + keysToDelete.push_back(_polyName); string encryptedSecretShareName = "encryptedSecretShare:" + _polyName; - LevelDB::getLevelDb()->deleteKey(encryptedSecretShareName); + keysToDelete.push_back(encryptedSecretShareName); + + string metaKey = string(WalletDBKeys::DKG_META_V1_PREFIX) + _polyName; + keysToDelete.push_back(metaKey); + + LevelDB::getLevelDb()->writeBatch({}, keysToDelete, false); } HANDLE_SGX_EXCEPTION(result) @@ -988,6 +1055,41 @@ Json::Value SGXWalletServer::getSecretShareV2Impl(const string &_polyName, ":Invalid DKG parameters: n or t "); } + // If V3 binding metadata exists for this poly, enforce exact match - + // Enforce same security guarantees as new getSecretShareV3Impl + string metaKey = string(WalletDBKeys::DKG_META_V1_PREFIX) + _polyName; + shared_ptr metaStr = checkDataFromDb(metaKey); + // If exists, then poly was created as V3 - need same security guarantees + if (metaStr != nullptr) { + Json::Value meta; + Json::Reader reader; + if (!reader.parse(*metaStr, meta)) { + throw SGXException(INVALID_DKG_GETSS_V2_POLY_NAME, + string(__FUNCTION__) + + ":Failed to parse DKG metadata"); + } + if (meta["t"].asInt() != _t || meta["n"].asInt() != _n) { + throw SGXException(INVALID_DKG_GETSS_V2_META_PARAMS_MISMATCH, + string(__FUNCTION__) + + ":t/n mismatch with bound metadata"); + } + const Json::Value &boundKeys = meta["publicKeys"]; + if (boundKeys.size() != _pubKeys.size()) { + throw SGXException(INVALID_DKG_GETSS_V2_META_PUBKEYS_MISMATCH, + string(__FUNCTION__) + + ":publicKeys count mismatch with bound metadata"); + } + for (Json::ArrayIndex i = 0; i < boundKeys.size(); i++) { + if (boundKeys[i].asString() != _pubKeys[i].asString()) { + throw SGXException( + INVALID_DKG_GETSS_V2_META_PUBKEYS_MISMATCH, + string(__FUNCTION__) + + ":publicKey mismatch with bound metadata at index " + + to_string(i)); + } + } + } + shared_ptr encrPoly = readFromDb(_polyName); vector pubKeysStrs; @@ -1016,6 +1118,63 @@ Json::Value SGXWalletServer::getSecretShareV2Impl(const string &_polyName, RETURN_SUCCESS(result) } +Json::Value SGXWalletServer::getSecretShareV3Impl(const string &_polyName) { + COUNT_STATISTICS + spdlog::info("Entering {}", __FUNCTION__); + INIT_RESULT(result); + result["secretShare"] = ""; + + try { + if (!checkName(_polyName, "POLY")) { + throw SGXException(INVALID_DKG_GETSS_V3_POLY_NAME, + string(__FUNCTION__) + ":Invalid polynomial name"); + } + + string metaKey = string(WalletDBKeys::DKG_META_V1_PREFIX) + _polyName; + shared_ptr metaStr = checkDataFromDb(metaKey); + if (metaStr == nullptr) { + throw SGXException(INVALID_DKG_GETSS_V3_NO_METADATA, + string(__FUNCTION__) + + ":No V3 binding metadata found for poly: " + + _polyName); + } + + Json::Value meta; + Json::Reader reader; + if (!reader.parse(*metaStr, meta)) { + throw SGXException(INVALID_DKG_GETSS_V3_NO_METADATA, + string(__FUNCTION__) + + ":Failed to parse DKG metadata for: " + _polyName); + } + + int t = meta["t"].asInt(); + int n = meta["n"].asInt(); + const Json::Value &boundKeys = meta["publicKeys"]; + + vector pubKeyStrs; + pubKeyStrs.reserve(n); + for (int i = 0; i < n; i++) { + pubKeyStrs.push_back(boundKeys[i].asString()); + } + + shared_ptr encrPoly = readFromDb(_polyName); + + string secret_share_name = "encryptedSecretShare:" + _polyName; + shared_ptr encryptedSecretShare = checkDataFromDb(secret_share_name); + + if (encryptedSecretShare != nullptr) { + result["secretShare"] = *encryptedSecretShare.get(); + } else { + string s = + getSecretSharesV2(_polyName, encrPoly->c_str(), pubKeyStrs, t, n); + result["secretShare"] = s; + } + } + HANDLE_SGX_EXCEPTION(result) + + RETURN_SUCCESS(result) +} + Json::Value SGXWalletServer::dkgVerificationV2Impl(const string &_publicShares, const string &_ethKeyName, const string &_secretShare, @@ -1261,16 +1420,24 @@ Json::Value SGXWalletServer::createBLSPrivateKeyV3Impl( // Delete SGX data related to the DKG process only if polyName was passed if (hasCleanupPolyName) { + vector keysToDelete; + keysToDelete.reserve(static_cast(_n) * 2 + 3); + for (int i = 0; i < _n; i++) { string name = _polyName + "_" + to_string(i) + ":"; - LevelDB::getLevelDb()->deleteDHDKGKey(name); + keysToDelete.push_back(string(WalletDBKeys::DKG_DH_KEY_PREFIX) + name); string shareG2_name = "shareG2_" + _polyName + "_" + to_string(i) + ":"; - LevelDB::getLevelDb()->deleteKey(shareG2_name); + keysToDelete.push_back(shareG2_name); } - LevelDB::getLevelDb()->deleteKey(_polyName); + keysToDelete.push_back(_polyName); string encryptedSecretShareName = "encryptedSecretShare:" + _polyName; - LevelDB::getLevelDb()->deleteKey(encryptedSecretShareName); + keysToDelete.push_back(encryptedSecretShareName); + + string metaKey = string(WalletDBKeys::DKG_META_V1_PREFIX) + _polyName; + keysToDelete.push_back(metaKey); + + LevelDB::getLevelDb()->writeBatch({}, keysToDelete, false); } } HANDLE_SGX_EXCEPTION(result) @@ -1471,8 +1638,10 @@ Json::Value SGXWalletServer::generateDKGPoly(const string &_polyName, int _t) { } Json::Value SGXWalletServer::generateDKGPolyV3( - const string &_polyName, const string &_previousBLSPrivateKeyName, int _t) { - return generateDKGPolyV3Impl(_polyName, _previousBLSPrivateKeyName, _t); + const string &_polyName, const string &_previousBLSPrivateKeyName, int _t, + int _n, const Json::Value &_publicKeys) { + return generateDKGPolyV3Impl(_polyName, _previousBLSPrivateKeyName, _t, _n, + _publicKeys); } Json::Value SGXWalletServer::getVerificationVector(const string &_polynomeName, @@ -1570,6 +1739,10 @@ Json::Value SGXWalletServer::getSecretShareV2(const string &_polyName, return getSecretShareV2Impl(_polyName, _publicKeys, t, n); } +Json::Value SGXWalletServer::getSecretShareV3(const string &_polyName) { + return getSecretShareV3Impl(_polyName); +} + Json::Value SGXWalletServer::dkgVerificationV2(const string &_publicShares, const string ðKeyName, const string &SecretShare, int t, diff --git a/SGXWalletServer.hpp b/SGXWalletServer.hpp index 890390aa..4c5a2eae 100644 --- a/SGXWalletServer.hpp +++ b/SGXWalletServer.hpp @@ -122,10 +122,13 @@ class SGXWalletServer : public AbstractStubServer { /** * Generates a DKG polynomial using '_previousBLSPrivateKeyName' BLS key * as the polynomial's free coefficient. + * Requires ECDH keys of all recipients to tie them to this polynomial + * for later usage (sharing encrypted secret contribution shares) */ virtual Json::Value generateDKGPolyV3(const string &_polyName, - const string &_previousBLSPrivateKeyName, int _t); + const string &_previousBLSPrivateKeyName, int _t, int _n, + const Json::Value &_publicKeys); virtual Json::Value getVerificationVector(const string &_polynomeName, int _t); @@ -169,6 +172,13 @@ class SGXWalletServer : public AbstractStubServer { const Json::Value &_publicKeys, int t, int n); + /** + * @brief Retrieves secret share contributions for the given polynomial name, + * using the ECDH public keys set on 'generateDKGPolyV3'. + * This call differs from 'getSecretShareV2' by not allowing caller passed ECDH keys. + */ + virtual Json::Value getSecretShareV3(const string &_polyName); + virtual Json::Value dkgVerificationV2(const string &_publicShares, const string ðKeyName, const string &SecretShare, int t, int n, @@ -223,7 +233,8 @@ class SGXWalletServer : public AbstractStubServer { static Json::Value generateDKGPolyV3Impl(const string &_polyName, - const string &_previousBLSPrivateKeyName, int _t); + const string &_previousBLSPrivateKeyName, int _t, + int _n, const Json::Value &_publicKeys); static Json::Value getVerificationVectorImpl(const string &_polyName, int _t); @@ -264,6 +275,8 @@ class SGXWalletServer : public AbstractStubServer { const Json::Value &_pubKeys, int _t, int _n); + static Json::Value getSecretShareV3Impl(const string &_polyName); + static Json::Value dkgVerificationV2Impl(const string &_publicShares, const string &_ethKeyName, const string &_secretShare, int _t, diff --git a/TestUtils.cpp b/TestUtils.cpp index b66ac95e..b469111c 100644 --- a/TestUtils.cpp +++ b/TestUtils.cpp @@ -386,7 +386,8 @@ RotationDkgData runDKGV3ForRotation(StubClient &c, TestUtils::makeDKGPolyName(schainID, contributor, dkgID); // use previous' DKG BLS private key name Json::Value response = c.generateDKGPolyV3( - data.polyNames[contributor], v2Data.blsKeyNames[contributor], t); + data.polyNames[contributor], v2Data.blsKeyNames[contributor], t, n, + data.publicEcdsaKeys); CHECK_STATE(response["status"] == 0); // get verification vectors @@ -399,8 +400,7 @@ RotationDkgData runDKGV3ForRotation(StubClient &c, } for (int contributor = 0; contributor < n; ++contributor) { - secretShares[contributor] = c.getSecretShareV2(data.polyNames[contributor], - data.publicEcdsaKeys, t, n); + secretShares[contributor] = c.getSecretShareV3(data.polyNames[contributor]); CHECK_STATE(secretShares[contributor]["status"] == 0); } @@ -520,7 +520,8 @@ runDKGV3ForRotationWithNewNodes(StubClient &c, const RotationDkgData &v2Data, schainID, static_cast(oldDealerIndex), dkgID); Json::Value response = c.generateDKGPolyV3(dealerPolyNames[oldDealerIndex], - v2Data.blsKeyNames.at(oldDealerIndex), t); + v2Data.blsKeyNames.at(oldDealerIndex), t, newN, + data.publicEcdsaKeys); CHECK_STATE(response["status"] == 0); // get verification vectors @@ -532,8 +533,8 @@ runDKGV3ForRotationWithNewNodes(StubClient &c, const RotationDkgData &v2Data, // get secret contributions from this dealer - using 'newN' number of points // one for each new node - dealerSecretShares[oldDealerIndex] = c.getSecretShareV2( - dealerPolyNames[oldDealerIndex], data.publicEcdsaKeys, t, newN); + dealerSecretShares[oldDealerIndex] = + c.getSecretShareV3(dealerPolyNames[oldDealerIndex]); CHECK_STATE(dealerSecretShares[oldDealerIndex]["status"] == 0); } diff --git a/WalletDBKeys.h b/WalletDBKeys.h index f229c206..98d79dbd 100644 --- a/WalletDBKeys.h +++ b/WalletDBKeys.h @@ -35,6 +35,11 @@ static constexpr const std::string_view BLS_KEY_PREFIX = "BLS_KEY:"; static constexpr const std::string_view POLY_KEY_PREFIX = "POLY:"; static constexpr const std::string_view DKG_DH_KEY_PREFIX = "DKG_DH_KEY_"; +// Plaintext metadata for V3 recipient-bound polynomials. +// Stores t, n, ordered recipient public ECDH keys, and their deterministic hash. +// Not encrypted at rest — contains only public key material. +static constexpr const std::string_view DKG_META_V1_PREFIX = "DKG_META_V1:"; + static constexpr const std::string_view SEK_ENCRYPTED_PAYLOAD_KEY_PREFIXES[] = { ECDSA_KEY_PREFIX, TEMP_ECDSA_KEY_PREFIX, BLS_KEY_PREFIX, POLY_KEY_PREFIX, DKG_DH_KEY_PREFIX}; diff --git a/abstractstubserver.h b/abstractstubserver.h index dc28f1a5..3dca4380 100644 --- a/abstractstubserver.h +++ b/abstractstubserver.h @@ -79,7 +79,8 @@ class AbstractStubServer : public jsonrpc::AbstractServer { jsonrpc::Procedure( "generateDKGPolyV3", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_OBJECT, "polyName", jsonrpc::JSON_STRING, "previousBLSPrivateKeyName", - jsonrpc::JSON_STRING, "t", jsonrpc::JSON_INTEGER, NULL), + jsonrpc::JSON_STRING, "t", jsonrpc::JSON_INTEGER, "n", + jsonrpc::JSON_INTEGER, "publicKeys", jsonrpc::JSON_ARRAY, NULL), &AbstractStubServer::generateDKGPolyV3I); this->bindAndAddMethod(jsonrpc::Procedure("getVerificationVector", jsonrpc::PARAMS_BY_NAME, @@ -156,6 +157,11 @@ class AbstractStubServer : public jsonrpc::AbstractServer { "polyName", jsonrpc::JSON_STRING, "publicKeys", jsonrpc::JSON_ARRAY, "n", jsonrpc::JSON_INTEGER, "t", jsonrpc::JSON_INTEGER, NULL), &AbstractStubServer::getSecretShareV2I); + this->bindAndAddMethod( + jsonrpc::Procedure("getSecretShareV3", jsonrpc::PARAMS_BY_NAME, + jsonrpc::JSON_OBJECT, "polyName", + jsonrpc::JSON_STRING, NULL), + &AbstractStubServer::getSecretShareV3I); this->bindAndAddMethod( jsonrpc::Procedure( "dkgVerificationV2", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_OBJECT, @@ -241,7 +247,8 @@ class AbstractStubServer : public jsonrpc::AbstractServer { Json::Value &response) { response = this->generateDKGPolyV3( request["polyName"].asString(), - request["previousBLSPrivateKeyName"].asString(), request["t"].asInt()); + request["previousBLSPrivateKeyName"].asString(), request["t"].asInt(), + request["n"].asInt(), request["publicKeys"]); } inline virtual void getVerificationVectorI(const Json::Value &request, Json::Value &response) { @@ -315,6 +322,10 @@ class AbstractStubServer : public jsonrpc::AbstractServer { request["polyName"].asString(), request["publicKeys"], request["t"].asInt(), request["n"].asInt()); } + inline virtual void getSecretShareV3I(const Json::Value &request, + Json::Value &response) { + response = this->getSecretShareV3(request["polyName"].asString()); + } inline virtual void dkgVerificationV2I(const Json::Value &request, Json::Value &response) { response = this->dkgVerificationV2( @@ -372,7 +383,8 @@ class AbstractStubServer : public jsonrpc::AbstractServer { virtual Json::Value generateDKGPoly(const std::string &polyName, int t) = 0; virtual Json::Value generateDKGPolyV3(const std::string &polyName, - const std::string &previousBLSPrivateKeyName, int t) = 0; + const std::string &previousBLSPrivateKeyName, int t, int n, + const Json::Value &publicKeys) = 0; virtual Json::Value getVerificationVector(const std::string &polyName, int t) = 0; virtual Json::Value getSecretShare(const std::string &polyName, @@ -402,6 +414,7 @@ class AbstractStubServer : public jsonrpc::AbstractServer { virtual Json::Value getSecretShareV2(const std::string &polyName, const Json::Value &publicKeys, int t, int n) = 0; + virtual Json::Value getSecretShareV3(const std::string &polyName) = 0; virtual Json::Value dkgVerificationV2(const std::string &publicShares, const std::string ðKeyName, const std::string &SecretShare, int t, diff --git a/sgxwallet_common.h b/sgxwallet_common.h index 52472178..4066372c 100644 --- a/sgxwallet_common.h +++ b/sgxwallet_common.h @@ -206,6 +206,14 @@ extern bool autoconfirm; #define INVALID_GEN_DKGV3_POLY_NAME -124 #define INVALID_GEN_DKGV3_POLY_PREV_BLS_KEY_NAME -125 #define GENERATE_DKGV3_POLY_INVALID_PARAMS -126 +#define GENERATE_DKGV3_POLY_INVALID_PUBKEY_COUNT -127 +#define GENERATE_DKGV3_POLY_INVALID_PUBKEY_HEX -128 + +#define INVALID_DKG_GETSS_V3_POLY_NAME -129 +#define INVALID_DKG_GETSS_V3_NO_METADATA -130 + +#define INVALID_DKG_GETSS_V2_META_PUBKEYS_MISMATCH -131 +#define INVALID_DKG_GETSS_V2_META_PARAMS_MISMATCH -132 #define SGX_ENCLAVE_ERROR -666 diff --git a/spec.json b/spec.json index 93b4f8c5..17d24f06 100644 --- a/spec.json +++ b/spec.json @@ -96,7 +96,9 @@ "params": { "polyName": "POLY:SCHAIN_ID :NODE_ID :DKG_ID", "previousBLSPrivateKeyName": "BLS_KEY:SCHAIN_ID :NODE_ID :DKG_ID", - "t": 3 + "t": 3, + "n": 4, + "publicKeys": ["hex_pubkey_0", "hex_pubkey_1"] }, "returns": { "status": 0, @@ -148,6 +150,18 @@ } }, + { + "name": "getSecretShareV3", + "params": { + "polyName": "POLY:SCHAIN_ID :NODE_ID :DKG_ID: " + }, + "returns": { + "status": 0, + "errorMessage": "12345", + "secretShare": "123" + } + }, + { "name": "dkgVerification", "params": { diff --git a/stubclient.h b/stubclient.h index ae6df0e5..5fdae5fc 100644 --- a/stubclient.h +++ b/stubclient.h @@ -113,11 +113,14 @@ class StubClient : public jsonrpc::Client { Json::Value generateDKGPolyV3(const std::string &polyName, const std::string &previousBLSPrivateKeyName, - int t) { + int t, int n, + const Json::Value &publicKeys) { Json::Value p; p["polyName"] = polyName; p["previousBLSPrivateKeyName"] = previousBLSPrivateKeyName; p["t"] = t; + p["n"] = n; + p["publicKeys"] = publicKeys; Json::Value result = this->CallMethod("generateDKGPolyV3", p); if (result.isObject()) return result; @@ -172,6 +175,18 @@ class StubClient : public jsonrpc::Client { result.toStyledString()); } + Json::Value getSecretShareV3(const std::string &polyName) { + Json::Value p; + p["polyName"] = polyName; + Json::Value result = this->CallMethod("getSecretShareV3", p); + if (result.isObject()) + return result; + else + throw jsonrpc::JsonRpcException( + jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, + result.toStyledString()); + } + Json::Value dkgVerification(const std::string &publicShares, const std::string ðKeyName, const std::string &SecretShare, int t, int n, diff --git a/testw.cpp b/testw.cpp index 7f54ee86..a1a8c5f2 100644 --- a/testw.cpp +++ b/testw.cpp @@ -1256,9 +1256,14 @@ TEST_CASE_METHOD(TestFixtureDKGV3Api, Json::Value previousBlsKey = c.generateBLSPrivateKey(previousBlsKeyName); REQUIRE(previousBlsKey["status"].asInt() == 0); + Json::Value dkgV3PublicKeys(Json::arrayValue); + dkgV3PublicKeys.append(SAMPLE_DKG_PUB_KEY_1); + dkgV3PublicKeys.append(SAMPLE_DKG_PUB_KEY_2); + const string polyName = TestUtils::makeDKGPolyName(schainID, 0, dkgV3ID); - Json::Value genPoly = - c.generateDKGPolyV3(polyName, previousBlsKeyName, DKG_V3_API_T); + Json::Value genPoly = c.generateDKGPolyV3(polyName, previousBlsKeyName, + DKG_V3_API_T, DKG_V3_API_N, + dkgV3PublicKeys); REQUIRE(genPoly["status"].asInt() == 0); Json::Value verificationVector = @@ -1268,16 +1273,30 @@ TEST_CASE_METHOD(TestFixtureDKGV3Api, DKG_V3_API_T) .empty()); - Json::Value genPolyWrongName = - c.generateDKGPolyV3("poly", previousBlsKeyName, DKG_V3_API_T); + Json::Value v3SecretShares = c.getSecretShareV3(polyName); + REQUIRE(v3SecretShares["status"].asInt() == 0); + + Json::Value wrongPublicKeys(Json::arrayValue); + wrongPublicKeys.append(SAMPLE_DKG_PUB_KEY_1); + wrongPublicKeys.append( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + Json::Value mismatchedV2Share = + c.getSecretShareV2(polyName, wrongPublicKeys, DKG_V3_API_T, DKG_V3_API_N); + REQUIRE(mismatchedV2Share["status"].asInt() != 0); + + Json::Value genPolyWrongName = c.generateDKGPolyV3( + "poly", previousBlsKeyName, DKG_V3_API_T, DKG_V3_API_N, + dkgV3PublicKeys); REQUIRE(genPolyWrongName["status"].asInt() != 0); Json::Value genPolyWrongPreviousBls = c.generateDKGPolyV3( - TestUtils::makeDKGPolyName(schainID, 1, dkgV3ID), "bls", DKG_V3_API_T); + TestUtils::makeDKGPolyName(schainID, 1, dkgV3ID), "bls", DKG_V3_API_T, + DKG_V3_API_N, dkgV3PublicKeys); REQUIRE(genPolyWrongPreviousBls["status"].asInt() != 0); Json::Value genPolyWrongT = c.generateDKGPolyV3( - TestUtils::makeDKGPolyName(schainID, 2, dkgV3ID), previousBlsKeyName, 33); + TestUtils::makeDKGPolyName(schainID, 2, dkgV3ID), previousBlsKeyName, 33, + DKG_V3_API_N, dkgV3PublicKeys); REQUIRE(genPolyWrongT["status"].asInt() != 0); } @@ -1309,8 +1328,9 @@ TEST_CASE_METHOD(TestFixtureDKGV3Api, "DKG V3 JSONRPC API creates BLS key", REQUIRE(previousBlsKey["status"].asInt() == 0); polyNames[i] = TestUtils::makeDKGPolyName(schainID, i, dkgV3ID); - Json::Value genPoly = - c.generateDKGPolyV3(polyNames[i], previousBlsKeyNames[i], DKG_V3_API_T); + Json::Value genPoly = c.generateDKGPolyV3( + polyNames[i], previousBlsKeyNames[i], DKG_V3_API_T, DKG_V3_API_N, + publicEcdsaKeys); REQUIRE(genPoly["status"].asInt() == 0); Json::Value verificationVector = @@ -1321,8 +1341,7 @@ TEST_CASE_METHOD(TestFixtureDKGV3Api, "DKG V3 JSONRPC API creates BLS key", } for (int contributor = 0; contributor < DKG_V3_API_N; ++contributor) { - Json::Value secretShares = c.getSecretShareV2( - polyNames[contributor], publicEcdsaKeys, DKG_V3_API_T, DKG_V3_API_N); + Json::Value secretShares = c.getSecretShareV3(polyNames[contributor]); REQUIRE(secretShares["status"].asInt() == 0); dealerSecretShares[contributor] = secretShares["secretShare"].asString(); REQUIRE(dealerSecretShares[contributor].length() == @@ -1412,9 +1431,14 @@ TEST_CASE_METHOD(TestFixtureDKGV3Api, "DKG V3 ZMQ API generates DKG polynomial", TestUtils::makeBLSKeyName(schainID, 0, dkgV2ID); REQUIRE(client->generateBLSPrivateKey(previousBlsKeyName)); + Json::Value dkgV3PublicKeys(Json::arrayValue); + dkgV3PublicKeys.append(SAMPLE_DKG_PUB_KEY_1); + dkgV3PublicKeys.append(SAMPLE_DKG_PUB_KEY_2); + const string polyName = TestUtils::makeDKGPolyName(schainID, 0, dkgV3ID); - REQUIRE( - client->generateDKGPolyV3(polyName, previousBlsKeyName, DKG_V3_API_T)); + REQUIRE(client->generateDKGPolyV3(polyName, previousBlsKeyName, + DKG_V3_API_T, DKG_V3_API_N, + dkgV3PublicKeys)); Json::Value verificationVector = client->getVerificationVector(polyName, DKG_V3_API_T); @@ -1422,12 +1446,24 @@ TEST_CASE_METHOD(TestFixtureDKGV3Api, "DKG V3 ZMQ API generates DKG polynomial", DKG_V3_API_T) .empty()); - REQUIRE(!client->generateDKGPolyV3("poly", previousBlsKeyName, DKG_V3_API_T)); + REQUIRE_NOTHROW(client->getSecretShareV3(polyName)); + + Json::Value wrongPublicKeys(Json::arrayValue); + wrongPublicKeys.append(SAMPLE_DKG_PUB_KEY_1); + wrongPublicKeys.append( + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + REQUIRE_THROWS(client->getSecretShare(polyName, wrongPublicKeys, DKG_V3_API_T, + DKG_V3_API_N)); + + REQUIRE(!client->generateDKGPolyV3("poly", previousBlsKeyName, + DKG_V3_API_T, DKG_V3_API_N, + dkgV3PublicKeys)); REQUIRE_THROWS(client->generateDKGPolyV3( - TestUtils::makeDKGPolyName(schainID, 1, dkgV3ID), "bls", DKG_V3_API_T)); + TestUtils::makeDKGPolyName(schainID, 1, dkgV3ID), "bls", DKG_V3_API_T, + DKG_V3_API_N, dkgV3PublicKeys)); REQUIRE(!client->generateDKGPolyV3( TestUtils::makeDKGPolyName(schainID, 2, dkgV3ID), previousBlsKeyName, - 33)); + 33, DKG_V3_API_N, dkgV3PublicKeys)); } TEST_CASE_METHOD(TestFixtureDKGV3Api, "DKG V3 ZMQ API creates BLS key", @@ -1460,7 +1496,8 @@ TEST_CASE_METHOD(TestFixtureDKGV3Api, "DKG V3 ZMQ API creates BLS key", // generate poly using previous DKG key polyNames[i] = TestUtils::makeDKGPolyName(schainID, i, dkgV3ID); REQUIRE(client->generateDKGPolyV3(polyNames[i], previousBlsKeyNames[i], - DKG_V3_API_T)); + DKG_V3_API_T, DKG_V3_API_N, + publicEcdsaKeys)); Json::Value verificationVector = client->getVerificationVector(polyNames[i], DKG_V3_API_T); @@ -1469,8 +1506,8 @@ TEST_CASE_METHOD(TestFixtureDKGV3Api, "DKG V3 ZMQ API creates BLS key", } for (int contributor = 0; contributor < DKG_V3_API_N; ++contributor) { - dealerSecretShares[contributor] = client->getSecretShare( - polyNames[contributor], publicEcdsaKeys, DKG_V3_API_T, DKG_V3_API_N); + dealerSecretShares[contributor] = + client->getSecretShareV3(polyNames[contributor]); REQUIRE(dealerSecretShares[contributor].length() == static_cast(DKG_V3_API_N) * TestUtils::DKG_ENCRYPTED_SECRET_CONTRIBUTION_HEX_LEN); diff --git a/zmq_src/ReqMessage.cpp b/zmq_src/ReqMessage.cpp index a037b3ab..8cfdc741 100644 --- a/zmq_src/ReqMessage.cpp +++ b/zmq_src/ReqMessage.cpp @@ -136,6 +136,8 @@ Json::Value generateDKGPolyReqMessage::process() { Json::Value generateDKGPolyV3ReqMessage::process() { auto polyName = getStringRapid("polyName"); auto t = getInt64Rapid("t"); + auto n = getInt64Rapid("n"); + auto publicKeys = getJsonValueRapid("publicKeys"); auto previousBLSPrivateKeyName = getStringRapid("previousBLSPrivateKeyName"); if (checkKeyOwnership && !isKeyByOwner(previousBLSPrivateKeyName, getStringRapid("cert"))) { @@ -144,7 +146,7 @@ Json::Value generateDKGPolyV3ReqMessage::process() { throw std::invalid_argument("Only owner of the key can access it"); } auto result = SGXWalletServer::generateDKGPolyV3Impl( - polyName, previousBLSPrivateKeyName, t); + polyName, previousBLSPrivateKeyName, t, n, publicKeys); if (checkKeyOwnership && result["status"] == 0) { auto cert = getStringRapid("cert"); spdlog::info("Cert {} creates key {}", cert, polyName); @@ -182,6 +184,18 @@ Json::Value getSecretShareReqMessage::process() { return result; } +Json::Value getSecretShareV3ReqMessage::process() { + auto polyName = getStringRapid("polyName"); + if (checkKeyOwnership && !isKeyByOwner(polyName, getStringRapid("cert"))) { + spdlog::error("Cert {} try to access key {} which does not belong to it", + getStringRapid("cert"), polyName); + throw std::invalid_argument("Only owner of the key can access it"); + } + auto result = SGXWalletServer::getSecretShareV3Impl(polyName); + result["type"] = ZMQMessage::GET_SECRET_SHARE_RSP; + return result; +} + Json::Value dkgVerificationReqMessage::process() { auto ethKeyName = getStringRapid("ethKeyName"); auto t = getInt64Rapid("t"); diff --git a/zmq_src/ReqMessage.h b/zmq_src/ReqMessage.h index e0f7e1f4..51c7935d 100644 --- a/zmq_src/ReqMessage.h +++ b/zmq_src/ReqMessage.h @@ -102,6 +102,14 @@ class getSecretShareReqMessage : public ZMQMessage { virtual Json::Value process(); }; +class getSecretShareV3ReqMessage : public ZMQMessage { +public: + getSecretShareV3ReqMessage(shared_ptr &_d) + : ZMQMessage(_d){}; + + virtual Json::Value process(); +}; + class dkgVerificationReqMessage : public ZMQMessage { public: dkgVerificationReqMessage(shared_ptr &_d) diff --git a/zmq_src/ZMQClient.cpp b/zmq_src/ZMQClient.cpp index 899f962b..b8e588e1 100644 --- a/zmq_src/ZMQClient.cpp +++ b/zmq_src/ZMQClient.cpp @@ -369,12 +369,15 @@ bool ZMQClient::generateDKGPoly(const string &polyName, int t) { bool ZMQClient::generateDKGPolyV3(const string &polyName, const string &previousBLSPrivateKeyName, - int t) { + int t, int n, + const Json::Value &publicKeys) { Json::Value p; p["type"] = ZMQMessage::GENERATE_DKG_POLY_V3_REQ; p["polyName"] = polyName; p["previousBLSPrivateKeyName"] = previousBLSPrivateKeyName; p["t"] = t; + p["n"] = n; + p["publicKeys"] = publicKeys; auto result = dynamic_pointer_cast(doRequestReply(p)); CHECK_STATE(result); @@ -408,6 +411,17 @@ string ZMQClient::getSecretShare(const string &polyName, return result->getSecretShare(); } +string ZMQClient::getSecretShareV3(const string &polyName) { + Json::Value p; + p["type"] = ZMQMessage::GET_SECRET_SHARE_V3_REQ; + p["polyName"] = polyName; + auto result = + dynamic_pointer_cast(doRequestReply(p)); + CHECK_STATE(result); + CHECK_STATE(result->getStatus() == 0); + return result->getSecretShare(); +} + bool ZMQClient::dkgVerification(const string &publicShares, const string ðKeyName, const string &secretShare, int t, int n, diff --git a/zmq_src/ZMQClient.h b/zmq_src/ZMQClient.h index 5c90f43c..80e8d06a 100644 --- a/zmq_src/ZMQClient.h +++ b/zmq_src/ZMQClient.h @@ -106,13 +106,16 @@ class ZMQClient { bool generateDKGPoly(const string &polyName, int t); bool generateDKGPolyV3(const string &polyName, - const string &previousBLSPrivateKeyName, int t); + const string &previousBLSPrivateKeyName, int t, + int n, const Json::Value &publicKeys); Json::Value getVerificationVector(const string &polyName, int t); string getSecretShare(const string &polyName, const Json::Value &pubKeys, int t, int n); + string getSecretShareV3(const string &polyName); + bool dkgVerification(const string &publicShares, const string ðKeyName, const string &secretShare, int t, int n, int idx); diff --git a/zmq_src/ZMQMessage.cpp b/zmq_src/ZMQMessage.cpp index 35726108..ddf4a236 100644 --- a/zmq_src/ZMQMessage.cpp +++ b/zmq_src/ZMQMessage.cpp @@ -216,6 +216,9 @@ ZMQMessage::buildRequest(string &_type, shared_ptr _d, case ENUM_GET_SECRET_SHARE_REQ: ret = make_shared(_d); break; + case ENUM_GET_SECRET_SHARE_V3_REQ: + ret = make_shared(_d); + break; case ENUM_DKG_VERIFY_REQ: ret = make_shared(_d); break; @@ -393,6 +396,7 @@ const std::map ZMQMessage::requests{ {GENERATE_DKG_POLY_V3_REQ, ENUM_GENERATE_DKG_POLY_V3_REQ}, {GET_VV_REQ, ENUM_GET_VV_REQ}, {GET_SECRET_SHARE_REQ, ENUM_GET_SECRET_SHARE_REQ}, + {GET_SECRET_SHARE_V3_REQ, ENUM_GET_SECRET_SHARE_V3_REQ}, {DKG_VERIFY_REQ, ENUM_DKG_VERIFY_REQ}, {CREATE_BLS_PRIVATE_REQ, ENUM_CREATE_BLS_PRIVATE_REQ}, {CREATE_BLS_PRIVATE_V3_REQ, ENUM_CREATE_BLS_PRIVATE_V3_REQ}, diff --git a/zmq_src/ZMQMessage.h b/zmq_src/ZMQMessage.h index e2b2d23b..3cf84ec2 100644 --- a/zmq_src/ZMQMessage.h +++ b/zmq_src/ZMQMessage.h @@ -90,6 +90,8 @@ class ZMQMessage { static constexpr const char *GET_VV_REQ = "getVerificationVectorReq"; static constexpr const char *GET_VV_RSP = "getVerificationVectorRsp"; static constexpr const char *GET_SECRET_SHARE_REQ = "getSecretShareReq"; + static constexpr const char *GET_SECRET_SHARE_V3_REQ = + "getSecretShareV3Req"; static constexpr const char *GET_SECRET_SHARE_RSP = "getSecretShareRsp"; static constexpr const char *DKG_VERIFY_REQ = "dkgVerificationReq"; static constexpr const char *DKG_VERIFY_RSP = "dkgVerificationRsp"; @@ -140,6 +142,7 @@ class ZMQMessage { ENUM_GENERATE_DKG_POLY_V3_REQ, ENUM_GET_VV_REQ, ENUM_GET_SECRET_SHARE_REQ, + ENUM_GET_SECRET_SHARE_V3_REQ, ENUM_DKG_VERIFY_REQ, ENUM_CREATE_BLS_PRIVATE_REQ, ENUM_CREATE_BLS_PRIVATE_V3_REQ, From d82f105e5c5a7a590d52198236dc6e0778ab18f0 Mon Sep 17 00:00:00 2001 From: Sidnei Teixeira Date: Mon, 22 Jun 2026 19:04:29 +0100 Subject: [PATCH 2/3] IS-1475 code format --- LevelDB.cpp | 10 ++--- SGXWalletServer.cpp | 44 ++++++++++----------- SGXWalletServer.hpp | 5 ++- TestUtils.cpp | 15 ++++---- WalletDBKeys.h | 4 +- abstractstubserver.h | 10 ++--- stubclient.h | 3 +- testw.cpp | 89 ++++++++++++++++++++++--------------------- zmq_src/ZMQClient.cpp | 3 +- zmq_src/ZMQClient.h | 4 +- zmq_src/ZMQMessage.h | 3 +- 11 files changed, 95 insertions(+), 95 deletions(-) diff --git a/LevelDB.cpp b/LevelDB.cpp index 0b85b376..2ea35555 100644 --- a/LevelDB.cpp +++ b/LevelDB.cpp @@ -98,17 +98,17 @@ void LevelDB::writeRawString(std::string_view _key, const string &_value) { } void LevelDB::writeBatch(const vector> &puts, - const vector &deletes, - bool requireNewPutKeys) { + const vector &deletes, + bool requireNewPutKeys) { lock_guard lock(mutex); // make sure no keys with same names existed before if (requireNewPutKeys) { for (const auto &it : puts) { if (readString(it.first) != nullptr) { - throw SGXException(KEY_NAME_ALREADY_EXISTS, - string(__FUNCTION__) + ":Name already exists" + - it.first); + throw SGXException(KEY_NAME_ALREADY_EXISTS, string(__FUNCTION__) + + ":Name already exists" + + it.first); } } } diff --git a/SGXWalletServer.cpp b/SGXWalletServer.cpp index ba5cf7c0..a7e9be39 100644 --- a/SGXWalletServer.cpp +++ b/SGXWalletServer.cpp @@ -580,8 +580,7 @@ Json::Value SGXWalletServer::generateDKGPolyV3Impl( if (!checkHex(_publicKeys[i].asString(), 64)) { throw SGXException(GENERATE_DKGV3_POLY_INVALID_PUBKEY_HEX, string(__FUNCTION__) + - ":Invalid public key at index " + - to_string(i)); + ":Invalid public key at index " + to_string(i)); } pubKeyStrs.push_back(_publicKeys[i].asString()); } @@ -598,7 +597,8 @@ Json::Value SGXWalletServer::generateDKGPolyV3Impl( joinedKeys += k; joinedKeys += ","; } - if (!joinedKeys.empty()) joinedKeys.pop_back(); + if (!joinedKeys.empty()) + joinedKeys.pop_back(); string recipientsHash = cryptlite::sha256::hash_hex(joinedKeys); Json::Value meta; @@ -611,21 +611,19 @@ Json::Value SGXWalletServer::generateDKGPolyV3Impl( } meta["recipientsHash"] = recipientsHash; meta["previousBLSPrivateKeyName"] = _previousBLSPrivateKeyName; - meta["createdAt"] = - (Json::Int64)chrono::duration_cast( - chrono::system_clock::now().time_since_epoch()) - .count(); + meta["createdAt"] = (Json::Int64)chrono::duration_cast( + chrono::system_clock::now().time_since_epoch()) + .count(); Json::FastWriter writer; - string metaKey = - string(WalletDBKeys::DKG_META_V1_PREFIX) + _polyName; + string metaKey = string(WalletDBKeys::DKG_META_V1_PREFIX) + _polyName; - vector> puts; - puts.emplace_back(_polyName, encrPolyHex); - puts.emplace_back(metaKey, writer.write(meta)); + vector> puts; + puts.emplace_back(_polyName, encrPolyHex); + puts.emplace_back(metaKey, writer.write(meta)); - // Poly and metadata must be persisted atomically to avoid fail-open paths. - LevelDB::getLevelDb()->writeBatch(puts, {}, true); + // Poly and metadata must be persisted atomically to avoid fail-open paths. + LevelDB::getLevelDb()->writeBatch(puts, {}, true); } HANDLE_SGX_EXCEPTION(result) @@ -1075,9 +1073,10 @@ Json::Value SGXWalletServer::getSecretShareV2Impl(const string &_polyName, } const Json::Value &boundKeys = meta["publicKeys"]; if (boundKeys.size() != _pubKeys.size()) { - throw SGXException(INVALID_DKG_GETSS_V2_META_PUBKEYS_MISMATCH, - string(__FUNCTION__) + - ":publicKeys count mismatch with bound metadata"); + throw SGXException( + INVALID_DKG_GETSS_V2_META_PUBKEYS_MISMATCH, + string(__FUNCTION__) + + ":publicKeys count mismatch with bound metadata"); } for (Json::ArrayIndex i = 0; i < boundKeys.size(); i++) { if (boundKeys[i].asString() != _pubKeys[i].asString()) { @@ -1133,10 +1132,10 @@ Json::Value SGXWalletServer::getSecretShareV3Impl(const string &_polyName) { string metaKey = string(WalletDBKeys::DKG_META_V1_PREFIX) + _polyName; shared_ptr metaStr = checkDataFromDb(metaKey); if (metaStr == nullptr) { - throw SGXException(INVALID_DKG_GETSS_V3_NO_METADATA, - string(__FUNCTION__) + - ":No V3 binding metadata found for poly: " + - _polyName); + throw SGXException( + INVALID_DKG_GETSS_V3_NO_METADATA, + string(__FUNCTION__) + + ":No V3 binding metadata found for poly: " + _polyName); } Json::Value meta; @@ -1160,7 +1159,8 @@ Json::Value SGXWalletServer::getSecretShareV3Impl(const string &_polyName) { shared_ptr encrPoly = readFromDb(_polyName); string secret_share_name = "encryptedSecretShare:" + _polyName; - shared_ptr encryptedSecretShare = checkDataFromDb(secret_share_name); + shared_ptr encryptedSecretShare = + checkDataFromDb(secret_share_name); if (encryptedSecretShare != nullptr) { result["secretShare"] = *encryptedSecretShare.get(); diff --git a/SGXWalletServer.hpp b/SGXWalletServer.hpp index 4c5a2eae..5dc071b3 100644 --- a/SGXWalletServer.hpp +++ b/SGXWalletServer.hpp @@ -175,8 +175,9 @@ class SGXWalletServer : public AbstractStubServer { /** * @brief Retrieves secret share contributions for the given polynomial name, * using the ECDH public keys set on 'generateDKGPolyV3'. - * This call differs from 'getSecretShareV2' by not allowing caller passed ECDH keys. - */ + * This call differs from 'getSecretShareV2' by not allowing caller passed + * ECDH keys. + */ virtual Json::Value getSecretShareV3(const string &_polyName); virtual Json::Value dkgVerificationV2(const string &_publicShares, diff --git a/TestUtils.cpp b/TestUtils.cpp index b469111c..9b90e94a 100644 --- a/TestUtils.cpp +++ b/TestUtils.cpp @@ -385,9 +385,9 @@ RotationDkgData runDKGV3ForRotation(StubClient &c, data.polyNames[contributor] = TestUtils::makeDKGPolyName(schainID, contributor, dkgID); // use previous' DKG BLS private key name - Json::Value response = c.generateDKGPolyV3( - data.polyNames[contributor], v2Data.blsKeyNames[contributor], t, n, - data.publicEcdsaKeys); + Json::Value response = c.generateDKGPolyV3(data.polyNames[contributor], + v2Data.blsKeyNames[contributor], + t, n, data.publicEcdsaKeys); CHECK_STATE(response["status"] == 0); // get verification vectors @@ -518,10 +518,9 @@ runDKGV3ForRotationWithNewNodes(StubClient &c, const RotationDkgData &v2Data, // generate new polynomial for each dealer dealerPolyNames[oldDealerIndex] = TestUtils::makeDKGPolyName( schainID, static_cast(oldDealerIndex), dkgID); - Json::Value response = - c.generateDKGPolyV3(dealerPolyNames[oldDealerIndex], - v2Data.blsKeyNames.at(oldDealerIndex), t, newN, - data.publicEcdsaKeys); + Json::Value response = c.generateDKGPolyV3( + dealerPolyNames[oldDealerIndex], v2Data.blsKeyNames.at(oldDealerIndex), + t, newN, data.publicEcdsaKeys); CHECK_STATE(response["status"] == 0); // get verification vectors @@ -534,7 +533,7 @@ runDKGV3ForRotationWithNewNodes(StubClient &c, const RotationDkgData &v2Data, // get secret contributions from this dealer - using 'newN' number of points // one for each new node dealerSecretShares[oldDealerIndex] = - c.getSecretShareV3(dealerPolyNames[oldDealerIndex]); + c.getSecretShareV3(dealerPolyNames[oldDealerIndex]); CHECK_STATE(dealerSecretShares[oldDealerIndex]["status"] == 0); } diff --git a/WalletDBKeys.h b/WalletDBKeys.h index 98d79dbd..b21a1546 100644 --- a/WalletDBKeys.h +++ b/WalletDBKeys.h @@ -36,8 +36,8 @@ static constexpr const std::string_view POLY_KEY_PREFIX = "POLY:"; static constexpr const std::string_view DKG_DH_KEY_PREFIX = "DKG_DH_KEY_"; // Plaintext metadata for V3 recipient-bound polynomials. -// Stores t, n, ordered recipient public ECDH keys, and their deterministic hash. -// Not encrypted at rest — contains only public key material. +// Stores t, n, ordered recipient public ECDH keys, and their deterministic +// hash. Not encrypted at rest — contains only public key material. static constexpr const std::string_view DKG_META_V1_PREFIX = "DKG_META_V1:"; static constexpr const std::string_view SEK_ENCRYPTED_PAYLOAD_KEY_PREFIXES[] = { diff --git a/abstractstubserver.h b/abstractstubserver.h index 3dca4380..7835d2ec 100644 --- a/abstractstubserver.h +++ b/abstractstubserver.h @@ -157,11 +157,11 @@ class AbstractStubServer : public jsonrpc::AbstractServer { "polyName", jsonrpc::JSON_STRING, "publicKeys", jsonrpc::JSON_ARRAY, "n", jsonrpc::JSON_INTEGER, "t", jsonrpc::JSON_INTEGER, NULL), &AbstractStubServer::getSecretShareV2I); - this->bindAndAddMethod( - jsonrpc::Procedure("getSecretShareV3", jsonrpc::PARAMS_BY_NAME, - jsonrpc::JSON_OBJECT, "polyName", - jsonrpc::JSON_STRING, NULL), - &AbstractStubServer::getSecretShareV3I); + this->bindAndAddMethod(jsonrpc::Procedure("getSecretShareV3", + jsonrpc::PARAMS_BY_NAME, + jsonrpc::JSON_OBJECT, "polyName", + jsonrpc::JSON_STRING, NULL), + &AbstractStubServer::getSecretShareV3I); this->bindAndAddMethod( jsonrpc::Procedure( "dkgVerificationV2", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_OBJECT, diff --git a/stubclient.h b/stubclient.h index 5fdae5fc..6fd920f1 100644 --- a/stubclient.h +++ b/stubclient.h @@ -113,8 +113,7 @@ class StubClient : public jsonrpc::Client { Json::Value generateDKGPolyV3(const std::string &polyName, const std::string &previousBLSPrivateKeyName, - int t, int n, - const Json::Value &publicKeys) { + int t, int n, const Json::Value &publicKeys) { Json::Value p; p["polyName"] = polyName; p["previousBLSPrivateKeyName"] = previousBLSPrivateKeyName; diff --git a/testw.cpp b/testw.cpp index a1a8c5f2..d6c6d706 100644 --- a/testw.cpp +++ b/testw.cpp @@ -1256,14 +1256,14 @@ TEST_CASE_METHOD(TestFixtureDKGV3Api, Json::Value previousBlsKey = c.generateBLSPrivateKey(previousBlsKeyName); REQUIRE(previousBlsKey["status"].asInt() == 0); - Json::Value dkgV3PublicKeys(Json::arrayValue); - dkgV3PublicKeys.append(SAMPLE_DKG_PUB_KEY_1); - dkgV3PublicKeys.append(SAMPLE_DKG_PUB_KEY_2); + Json::Value dkgV3PublicKeys(Json::arrayValue); + dkgV3PublicKeys.append(SAMPLE_DKG_PUB_KEY_1); + dkgV3PublicKeys.append(SAMPLE_DKG_PUB_KEY_2); const string polyName = TestUtils::makeDKGPolyName(schainID, 0, dkgV3ID); - Json::Value genPoly = c.generateDKGPolyV3(polyName, previousBlsKeyName, - DKG_V3_API_T, DKG_V3_API_N, - dkgV3PublicKeys); + Json::Value genPoly = + c.generateDKGPolyV3(polyName, previousBlsKeyName, DKG_V3_API_T, + DKG_V3_API_N, dkgV3PublicKeys); REQUIRE(genPoly["status"].asInt() == 0); Json::Value verificationVector = @@ -1273,25 +1273,24 @@ TEST_CASE_METHOD(TestFixtureDKGV3Api, DKG_V3_API_T) .empty()); - Json::Value v3SecretShares = c.getSecretShareV3(polyName); - REQUIRE(v3SecretShares["status"].asInt() == 0); + Json::Value v3SecretShares = c.getSecretShareV3(polyName); + REQUIRE(v3SecretShares["status"].asInt() == 0); - Json::Value wrongPublicKeys(Json::arrayValue); - wrongPublicKeys.append(SAMPLE_DKG_PUB_KEY_1); - wrongPublicKeys.append( + Json::Value wrongPublicKeys(Json::arrayValue); + wrongPublicKeys.append(SAMPLE_DKG_PUB_KEY_1); + wrongPublicKeys.append( "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - Json::Value mismatchedV2Share = + Json::Value mismatchedV2Share = c.getSecretShareV2(polyName, wrongPublicKeys, DKG_V3_API_T, DKG_V3_API_N); - REQUIRE(mismatchedV2Share["status"].asInt() != 0); + REQUIRE(mismatchedV2Share["status"].asInt() != 0); - Json::Value genPolyWrongName = c.generateDKGPolyV3( - "poly", previousBlsKeyName, DKG_V3_API_T, DKG_V3_API_N, - dkgV3PublicKeys); + Json::Value genPolyWrongName = c.generateDKGPolyV3( + "poly", previousBlsKeyName, DKG_V3_API_T, DKG_V3_API_N, dkgV3PublicKeys); REQUIRE(genPolyWrongName["status"].asInt() != 0); - Json::Value genPolyWrongPreviousBls = c.generateDKGPolyV3( - TestUtils::makeDKGPolyName(schainID, 1, dkgV3ID), "bls", DKG_V3_API_T, - DKG_V3_API_N, dkgV3PublicKeys); + Json::Value genPolyWrongPreviousBls = + c.generateDKGPolyV3(TestUtils::makeDKGPolyName(schainID, 1, dkgV3ID), + "bls", DKG_V3_API_T, DKG_V3_API_N, dkgV3PublicKeys); REQUIRE(genPolyWrongPreviousBls["status"].asInt() != 0); Json::Value genPolyWrongT = c.generateDKGPolyV3( @@ -1328,9 +1327,12 @@ TEST_CASE_METHOD(TestFixtureDKGV3Api, "DKG V3 JSONRPC API creates BLS key", REQUIRE(previousBlsKey["status"].asInt() == 0); polyNames[i] = TestUtils::makeDKGPolyName(schainID, i, dkgV3ID); - Json::Value genPoly = c.generateDKGPolyV3( - polyNames[i], previousBlsKeyNames[i], DKG_V3_API_T, DKG_V3_API_N, - publicEcdsaKeys); + } + + for (int i = 0; i < DKG_V3_API_N; ++i) { + Json::Value genPoly = + c.generateDKGPolyV3(polyNames[i], previousBlsKeyNames[i], DKG_V3_API_T, + DKG_V3_API_N, publicEcdsaKeys); REQUIRE(genPoly["status"].asInt() == 0); Json::Value verificationVector = @@ -1431,14 +1433,13 @@ TEST_CASE_METHOD(TestFixtureDKGV3Api, "DKG V3 ZMQ API generates DKG polynomial", TestUtils::makeBLSKeyName(schainID, 0, dkgV2ID); REQUIRE(client->generateBLSPrivateKey(previousBlsKeyName)); - Json::Value dkgV3PublicKeys(Json::arrayValue); - dkgV3PublicKeys.append(SAMPLE_DKG_PUB_KEY_1); - dkgV3PublicKeys.append(SAMPLE_DKG_PUB_KEY_2); + Json::Value dkgV3PublicKeys(Json::arrayValue); + dkgV3PublicKeys.append(SAMPLE_DKG_PUB_KEY_1); + dkgV3PublicKeys.append(SAMPLE_DKG_PUB_KEY_2); const string polyName = TestUtils::makeDKGPolyName(schainID, 0, dkgV3ID); - REQUIRE(client->generateDKGPolyV3(polyName, previousBlsKeyName, - DKG_V3_API_T, DKG_V3_API_N, - dkgV3PublicKeys)); + REQUIRE(client->generateDKGPolyV3(polyName, previousBlsKeyName, DKG_V3_API_T, + DKG_V3_API_N, dkgV3PublicKeys)); Json::Value verificationVector = client->getVerificationVector(polyName, DKG_V3_API_T); @@ -1446,24 +1447,23 @@ TEST_CASE_METHOD(TestFixtureDKGV3Api, "DKG V3 ZMQ API generates DKG polynomial", DKG_V3_API_T) .empty()); - REQUIRE_NOTHROW(client->getSecretShareV3(polyName)); + REQUIRE_NOTHROW(client->getSecretShareV3(polyName)); - Json::Value wrongPublicKeys(Json::arrayValue); - wrongPublicKeys.append(SAMPLE_DKG_PUB_KEY_1); - wrongPublicKeys.append( + Json::Value wrongPublicKeys(Json::arrayValue); + wrongPublicKeys.append(SAMPLE_DKG_PUB_KEY_1); + wrongPublicKeys.append( "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - REQUIRE_THROWS(client->getSecretShare(polyName, wrongPublicKeys, DKG_V3_API_T, - DKG_V3_API_N)); + REQUIRE_THROWS(client->getSecretShare(polyName, wrongPublicKeys, DKG_V3_API_T, + DKG_V3_API_N)); - REQUIRE(!client->generateDKGPolyV3("poly", previousBlsKeyName, - DKG_V3_API_T, DKG_V3_API_N, - dkgV3PublicKeys)); + REQUIRE(!client->generateDKGPolyV3("poly", previousBlsKeyName, DKG_V3_API_T, + DKG_V3_API_N, dkgV3PublicKeys)); REQUIRE_THROWS(client->generateDKGPolyV3( TestUtils::makeDKGPolyName(schainID, 1, dkgV3ID), "bls", DKG_V3_API_T, DKG_V3_API_N, dkgV3PublicKeys)); REQUIRE(!client->generateDKGPolyV3( - TestUtils::makeDKGPolyName(schainID, 2, dkgV3ID), previousBlsKeyName, - 33, DKG_V3_API_N, dkgV3PublicKeys)); + TestUtils::makeDKGPolyName(schainID, 2, dkgV3ID), previousBlsKeyName, 33, + DKG_V3_API_N, dkgV3PublicKeys)); } TEST_CASE_METHOD(TestFixtureDKGV3Api, "DKG V3 ZMQ API creates BLS key", @@ -1483,18 +1483,21 @@ TEST_CASE_METHOD(TestFixtureDKGV3Api, "DKG V3 ZMQ API creates BLS key", vector publicShares(DKG_V3_API_N); vector dealerSecretShares(DKG_V3_API_N); - // generate some BLSkeys and polys to simulate DKG process + // Generate all recipient keys and previous BLS keys first. for (int i = 0; i < DKG_V3_API_N; ++i) { auto ecdsaKey = client->generateECDSAKey(); publicEcdsaKeys.append(ecdsaKey.first); ecdsaKeyNames[i] = ecdsaKey.second; - // generate some BLS key (simulate previous DKG keys) + // Generate previous DKG key material. previousBlsKeyNames[i] = TestUtils::makeBLSKeyName(schainID, i, dkgV2ID); REQUIRE(client->generateBLSPrivateKey(previousBlsKeyNames[i])); - // generate poly using previous DKG key polyNames[i] = TestUtils::makeDKGPolyName(schainID, i, dkgV3ID); + } + + // Generate polys only after the full recipient set is available. + for (int i = 0; i < DKG_V3_API_N; ++i) { REQUIRE(client->generateDKGPolyV3(polyNames[i], previousBlsKeyNames[i], DKG_V3_API_T, DKG_V3_API_N, publicEcdsaKeys)); @@ -1507,7 +1510,7 @@ TEST_CASE_METHOD(TestFixtureDKGV3Api, "DKG V3 ZMQ API creates BLS key", for (int contributor = 0; contributor < DKG_V3_API_N; ++contributor) { dealerSecretShares[contributor] = - client->getSecretShareV3(polyNames[contributor]); + client->getSecretShareV3(polyNames[contributor]); REQUIRE(dealerSecretShares[contributor].length() == static_cast(DKG_V3_API_N) * TestUtils::DKG_ENCRYPTED_SECRET_CONTRIBUTION_HEX_LEN); diff --git a/zmq_src/ZMQClient.cpp b/zmq_src/ZMQClient.cpp index b8e588e1..89a3e27a 100644 --- a/zmq_src/ZMQClient.cpp +++ b/zmq_src/ZMQClient.cpp @@ -369,8 +369,7 @@ bool ZMQClient::generateDKGPoly(const string &polyName, int t) { bool ZMQClient::generateDKGPolyV3(const string &polyName, const string &previousBLSPrivateKeyName, - int t, int n, - const Json::Value &publicKeys) { + int t, int n, const Json::Value &publicKeys) { Json::Value p; p["type"] = ZMQMessage::GENERATE_DKG_POLY_V3_REQ; p["polyName"] = polyName; diff --git a/zmq_src/ZMQClient.h b/zmq_src/ZMQClient.h index 80e8d06a..ab916a15 100644 --- a/zmq_src/ZMQClient.h +++ b/zmq_src/ZMQClient.h @@ -106,8 +106,8 @@ class ZMQClient { bool generateDKGPoly(const string &polyName, int t); bool generateDKGPolyV3(const string &polyName, - const string &previousBLSPrivateKeyName, int t, - int n, const Json::Value &publicKeys); + const string &previousBLSPrivateKeyName, int t, int n, + const Json::Value &publicKeys); Json::Value getVerificationVector(const string &polyName, int t); diff --git a/zmq_src/ZMQMessage.h b/zmq_src/ZMQMessage.h index 3cf84ec2..74c87572 100644 --- a/zmq_src/ZMQMessage.h +++ b/zmq_src/ZMQMessage.h @@ -90,8 +90,7 @@ class ZMQMessage { static constexpr const char *GET_VV_REQ = "getVerificationVectorReq"; static constexpr const char *GET_VV_RSP = "getVerificationVectorRsp"; static constexpr const char *GET_SECRET_SHARE_REQ = "getSecretShareReq"; - static constexpr const char *GET_SECRET_SHARE_V3_REQ = - "getSecretShareV3Req"; + static constexpr const char *GET_SECRET_SHARE_V3_REQ = "getSecretShareV3Req"; static constexpr const char *GET_SECRET_SHARE_RSP = "getSecretShareRsp"; static constexpr const char *DKG_VERIFY_REQ = "dkgVerificationReq"; static constexpr const char *DKG_VERIFY_RSP = "dkgVerificationRsp"; From f3cf2d0f312277dcc6504433eb106f650d2eac4e Mon Sep 17 00:00:00 2001 From: Sidnei Teixeira Date: Mon, 22 Jun 2026 19:27:56 +0100 Subject: [PATCH 3/3] IS-1475 fix gh comments; format --- LevelDB.cpp | 6 +++--- SGXWalletServer.cpp | 43 ++++++++++++++++++++++++++++++++++++++++--- sgxwallet_common.h | 2 ++ spec.json | 9 +++++++-- 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/LevelDB.cpp b/LevelDB.cpp index 2ea35555..5cee7bdd 100644 --- a/LevelDB.cpp +++ b/LevelDB.cpp @@ -106,9 +106,9 @@ void LevelDB::writeBatch(const vector> &puts, if (requireNewPutKeys) { for (const auto &it : puts) { if (readString(it.first) != nullptr) { - throw SGXException(KEY_NAME_ALREADY_EXISTS, string(__FUNCTION__) + - ":Name already exists" + - it.first); + throw SGXException(KEY_NAME_ALREADY_EXISTS, + string(__FUNCTION__) + + ":Name already exists: " + it.first); } } } diff --git a/SGXWalletServer.cpp b/SGXWalletServer.cpp index a7e9be39..a9347ac0 100644 --- a/SGXWalletServer.cpp +++ b/SGXWalletServer.cpp @@ -577,7 +577,8 @@ Json::Value SGXWalletServer::generateDKGPolyV3Impl( vector pubKeyStrs; pubKeyStrs.reserve(_n); for (int i = 0; i < _n; i++) { - if (!checkHex(_publicKeys[i].asString(), 64)) { + if (!checkHex(_publicKeys[i].asString(), + DKG_ECDSA_PUBLIC_KEY_NUM_BYTES)) { throw SGXException(GENERATE_DKGV3_POLY_INVALID_PUBKEY_HEX, string(__FUNCTION__) + ":Invalid public key at index " + to_string(i)); @@ -690,7 +691,7 @@ Json::Value SGXWalletServer::getSecretShareImpl(const string &_polyName, vector pubKeysStrs; for (int i = 0; i < _n; i++) { - if (!checkHex(_pubKeys[i].asString(), 64)) { + if (!checkHex(_pubKeys[i].asString(), DKG_ECDSA_PUBLIC_KEY_NUM_BYTES)) { throw SGXException(INVALID_DKG_GETSS_KEY_HEX, string(__FUNCTION__) + ":Invalid public key"); } @@ -1093,7 +1094,7 @@ Json::Value SGXWalletServer::getSecretShareV2Impl(const string &_polyName, vector pubKeysStrs; for (int i = 0; i < _n; i++) { - if (!checkHex(_pubKeys[i].asString(), 64)) { + if (!checkHex(_pubKeys[i].asString(), DKG_ECDSA_PUBLIC_KEY_NUM_BYTES)) { throw SGXException(INVALID_DKG_GETSS_V2_PUBKEY_HEX, string(__FUNCTION__) + ":Invalid public key"); } @@ -1146,13 +1147,49 @@ Json::Value SGXWalletServer::getSecretShareV3Impl(const string &_polyName) { ":Failed to parse DKG metadata for: " + _polyName); } + if (!meta.isObject() || !meta.isMember("t") || !meta["t"].isInt() || + !meta.isMember("n") || !meta["n"].isInt()) { + throw SGXException( + INVALID_DKG_GETSS_V3_NO_METADATA, + string(__FUNCTION__) + + ":Invalid DKG metadata structure for: " + _polyName); + } + int t = meta["t"].asInt(); int n = meta["n"].asInt(); + + if (!check_n_t(t, n)) { + throw SGXException( + INVALID_DKG_GETSS_V3_NO_METADATA, + string(__FUNCTION__) + + ":Invalid DKG metadata params n/t for: " + _polyName); + } + + if (!meta.isMember("publicKeys") || !meta["publicKeys"].isArray()) { + throw SGXException( + INVALID_DKG_GETSS_V3_NO_METADATA, + string(__FUNCTION__) + + ":Missing metadata publicKeys array for: " + _polyName); + } + const Json::Value &boundKeys = meta["publicKeys"]; + if ((int)boundKeys.size() != n) { + throw SGXException( + INVALID_DKG_GETSS_V3_NO_METADATA, + string(__FUNCTION__) + + ":Metadata publicKeys size mismatch for: " + _polyName); + } vector pubKeyStrs; pubKeyStrs.reserve(n); for (int i = 0; i < n; i++) { + if (!boundKeys[i].isString() || + !checkHex(boundKeys[i].asString(), DKG_ECDSA_PUBLIC_KEY_NUM_BYTES)) { + throw SGXException(INVALID_DKG_GETSS_V3_NO_METADATA, + string(__FUNCTION__) + + ":Invalid metadata public key at index " + + to_string(i)); + } pubKeyStrs.push_back(boundKeys[i].asString()); } diff --git a/sgxwallet_common.h b/sgxwallet_common.h index 4066372c..be83ffe7 100644 --- a/sgxwallet_common.h +++ b/sgxwallet_common.h @@ -75,6 +75,8 @@ extern bool autoconfirm; #define ECDSA_SKEY_BASE 16 #define ECDSA_ENCR_LEN 93 #define ECDSA_BIN_LEN 33 +// Uncompressed ECDSA public key without prefix: X(32 bytes) || Y(32 bytes) +#define DKG_ECDSA_PUBLIC_KEY_NUM_BYTES 64 #define PLAINTEXT_KEY_TOO_LONG -2 #define UNPADDED_KEY -3 diff --git a/spec.json b/spec.json index 17d24f06..80bb5cd2 100644 --- a/spec.json +++ b/spec.json @@ -98,7 +98,12 @@ "previousBLSPrivateKeyName": "BLS_KEY:SCHAIN_ID :NODE_ID :DKG_ID", "t": 3, "n": 4, - "publicKeys": ["hex_pubkey_0", "hex_pubkey_1"] + "publicKeys": [ + "hex_pubkey_0", + "hex_pubkey_1", + "hex_pubkey_2", + "hex_pubkey_3" + ] }, "returns": { "status": 0, @@ -153,7 +158,7 @@ { "name": "getSecretShareV3", "params": { - "polyName": "POLY:SCHAIN_ID :NODE_ID :DKG_ID: " + "polyName": "POLY:SCHAIN_ID :NODE_ID :DKG_ID" }, "returns": { "status": 0,