diff options
Diffstat (limited to 'src/signer/noscrypt_signer.cpp')
-rw-r--r-- | src/signer/noscrypt_signer.cpp | 121 |
1 files changed, 100 insertions, 21 deletions
diff --git a/src/signer/noscrypt_signer.cpp b/src/signer/noscrypt_signer.cpp index 26f8e54..c56070c 100644 --- a/src/signer/noscrypt_signer.cpp +++ b/src/signer/noscrypt_signer.cpp @@ -13,26 +13,22 @@ class NoscryptSigner : public INostrConnectSigner public: NoscryptSigner(shared_ptr<plog::IAppender> appender) { - // Set up the logger. plog::init(plog::debug, appender.get()); - // Set up the noscrypt library. - this->context = make_shared<NCContext>(); - auto contextStructSize = NCGetContextStructSize(); - unique_ptr<uint8_t[]> randomEntropy(new uint8_t[contextStructSize]); - - random_device device; - mt19937 seed(device()); - uniform_int_distribution<int> distribution(1, NC_CONTEXT_ENTROPY_SIZE); - generate_n(randomEntropy.get(), NC_CONTEXT_ENTROPY_SIZE, [&]() { return distribution(seed); }); + this->noscryptContext = this->initNoscryptContext(); + if (this->noscryptContext == nullptr) + { + return; + } - NCResult result = NCInitContext(context.get(), randomEntropy.get()); - this->handleNoscryptInitResult(result); + const auto [privateKey, publicKey] = this->createLocalKeypair(); + this->localPrivateKey = privateKey; + this->localPublicKey = publicKey; }; ~NoscryptSigner() { - NCDestroyContext(context.get()); + NCDestroyContext(this->noscryptContext.get()); }; void receiveConnection(string connectionToken) override @@ -55,36 +51,119 @@ public: }; private: - shared_ptr<NCContext> context; + shared_ptr<NCContext> noscryptContext; + + string localPrivateKey; + string localPublicKey; + + /** + * @brief Initializes the noscrypt library context into the class's `context` property. + * @returns `true` if successful, `false` otherwise. + */ + shared_ptr<NCContext> initNoscryptContext() + { + shared_ptr<NCContext> context(new NCContext); + auto contextStructSize = NCGetContextStructSize(); + unique_ptr<uint8_t> randomEntropy(new uint8_t[contextStructSize]); + + random_device rd; + mt19937 gen(rd()); + uniform_int_distribution<> dist(0, contextStructSize); + generate_n(randomEntropy.get(), contextStructSize, [&]() { return dist(gen); }); + + NCResult result = NCInitContext(context.get(), randomEntropy.get()); + this->logNoscryptResult(result); + + if (result != NC_SUCCESS) + { + return nullptr; + } + + return context; + }; - void handleNoscryptInitResult(NCResult result) + void logNoscryptResult(NCResult result) { switch (result) { case NC_SUCCESS: - PLOG_INFO << "Successfully initialized noscrypt."; + PLOG_INFO << "noscrypt - success"; break; case E_NULL_PTR: - PLOG_ERROR << "Failed to initialize noscrypt: A null pointer was passed to the initializer."; + PLOG_ERROR << "noscrypt - error: A null pointer was passed to the initializer."; break; case E_INVALID_ARG: - PLOG_ERROR << "Failed to initialize noscrypt: An invalid argument was passed to the initializer."; + PLOG_ERROR << "noscrypt - error: An invalid argument was passed to the initializer."; break; case E_INVALID_CONTEXT: - PLOG_ERROR << "Failed to initialize noscrypt: The NCContext struct is in an invalid state."; + PLOG_ERROR << "noscrypt - error: The NCContext struct is in an invalid state."; break; case E_ARGUMENT_OUT_OF_RANGE: - PLOG_ERROR << "Failed to initialize noscrypt: An initializer argument was outside the range of acceptable values."; + PLOG_ERROR << "noscrypt - error: An initializer argument was outside the range of acceptable values."; break; case E_OPERATION_FAILED: - PLOG_ERROR << "Failed to initialize noscrypt."; + PLOG_ERROR << "noscrypt - error"; break; } }; + + /** + * @brief Generates a private/public key pair for local use. + * @returns The generated keypair of the form `[privateKey, publicKey]`, or a pair of empty + * strings if the function failed. + * @remarks This keypair is intended for temporary use, and should not be saved or used outside + * of this class. + */ + tuple<string, string> createLocalKeypair() + { + string privateKey; + string publicKey; + + // To generate a private key, all we need is a random 32-bit buffer. + unique_ptr<NCSecretKey> secretKey(new NCSecretKey); + + random_device rd; + mt19937 gen(rd()); + uniform_int_distribution<> dist(0, NC_SEC_KEY_SIZE); + generate_n(secretKey.get()->key, NC_SEC_KEY_SIZE, [&]() { return dist(gen); }); + + // Convert the buffer into a hex string for a more human-friendly representation. + stringstream secretKeyStream; + for (int i = 0; i < NC_SEC_KEY_SIZE; i++) + { + secretKeyStream << hex << setw(2) << setfill('0') << static_cast<int>(secretKey->key[i]); + } + privateKey = secretKeyStream.str(); + + // Use noscrypt to derive the public key from its private counterpart. + unique_ptr<NCPublicKey> pubkey(new NCPublicKey); + NCResult result = NCGetPublicKey( + this->noscryptContext.get(), + secretKey.get(), + pubkey.get()); + this->logNoscryptResult(result); + + if (result != NC_SUCCESS) + { + // Return empty strings if the key generation fails. + return make_tuple(string(), string()); + } + + // Convert the now-populated pubkey buffer into a hex string for the pubkey representation + // used by Nostr events. + stringstream pubkeyStream; + for (int i = 0; i < NC_SEC_KEY_SIZE; i++) + { + pubkeyStream << hex << setw(2) << setfill('0') << static_cast<int>(pubkey->key[i]); + } + publicKey = pubkeyStream.str(); + + return make_tuple(privateKey, publicKey); + }; }; } // namespace signer } // namespace nostr |