QList<AutoUpdater::UpdateFileMeta> AutoUpdater::parseFlist(QByteArray flistData) { QList<UpdateFileMeta> flist; if (flistData.isEmpty()) { qWarning() << "AutoUpdater::parseflist: Empty data"; return flist; } // Check version if (flistData[0] != '1') { qWarning() << "AutoUpdater: parseflist: Bad version "<<(uint8_t)flistData[0]; return flist; } flistData = flistData.mid(1); // Check signature if (flistData.size() < (int)(crypto_sign_BYTES)) { qWarning() << "AutoUpdater::parseflist: Truncated data"; return flist; } else { QByteArray msgData = flistData.mid(crypto_sign_BYTES); unsigned char* msg = (unsigned char*)msgData.data(); if (crypto_sign_verify_detached((unsigned char*)flistData.data(), msg, msgData.size(), key) != 0) { qCritical() << "AutoUpdater: parseflist: FORGED FLIST FILE"; return flist; } flistData = flistData.mid(crypto_sign_BYTES); } // Parse. We assume no errors handling needed since the signature is valid. while (!flistData.isEmpty()) { UpdateFileMeta newFile; memcpy(newFile.sig, flistData.data(), crypto_sign_BYTES); flistData = flistData.mid(crypto_sign_BYTES); newFile.id = dataToString(flistData); flistData = flistData.mid(newFile.id.size() + getVUint32Size(flistData)); newFile.installpath = dataToString(flistData); flistData = flistData.mid(newFile.installpath.size() + getVUint32Size(flistData)); newFile.size = dataToUint64(flistData); flistData = flistData.mid(8); flist += newFile; } return flist; }
SEXP R_sig_verify(SEXP msg, SEXP sig, SEXP pubkey) { if(LENGTH(pubkey) != crypto_sign_PUBLICKEYBYTES) Rf_error("Invalid pubkey: must be exactly %d bytes", crypto_sign_PUBLICKEYBYTES); if(LENGTH(sig) != crypto_sign_BYTES) Rf_error("Invalid sig: must be exactly %d bytes", crypto_sign_BYTES); if(crypto_sign_verify_detached(RAW(sig), RAW(msg), LENGTH(msg), RAW(pubkey))) Rf_error("Signature verification failed"); return ScalarLogical(TRUE); }
// Verifies the signature of a message. int EdDSA::verify(const unsigned char* msg, unsigned long long msglen, const unsigned char* sig, const unsigned char* pubKey) { int result = crypto_sign_verify_detached(sig, msg, msglen, pubKey); if (result == 0) { return(1); } else { // crypto_sign_open() returns -1 on failure. return(0); } }
int cpn_sign_sig_verify(const struct cpn_sign_pk *key, const struct cpn_sign_sig *sig, uint8_t *data, size_t datalen) { if (crypto_sign_verify_detached(sig->data, data, datalen, key->data) != 0) { cpn_log(LOG_LEVEL_ERROR, "Could not verify signature"); return -1; } return 0; }
AutoUpdater::VersionInfo AutoUpdater::getUpdateVersion() { VersionInfo versionInfo; versionInfo.timestamp = 0; // Updates only for supported platforms if (platform.isEmpty()) return versionInfo; QNetworkAccessManager *manager = new QNetworkAccessManager; QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(checkURI))); while (!reply->isFinished()) qApp->processEvents(); if (reply->error() != QNetworkReply::NoError) { qWarning() << "AutoUpdater: getUpdateVersion: network error: "<<reply->errorString(); reply->deleteLater(); manager->deleteLater(); return versionInfo; } QByteArray data = reply->readAll(); reply->deleteLater(); manager->deleteLater(); if (data.size() < (int)(1+crypto_sign_BYTES)) return versionInfo; // Check updater protocol version if ((int)data[0] != '2') { qWarning() << "AutoUpdater: getUpdateVersion: Bad version "<<(uint8_t)data[0]; return versionInfo; } // Check the signature QByteArray sigData = data.mid(1, crypto_sign_BYTES); unsigned char* sig = (unsigned char*)sigData.data(); QByteArray msgData = data.mid(1+crypto_sign_BYTES); unsigned char* msg = (unsigned char*)msgData.data(); if (crypto_sign_verify_detached(sig, msg, msgData.size(), key) != 0) { qCritical() << "AutoUpdater: getUpdateVersion: RECEIVED FORGED VERSION FILE FROM "<<updateServer; return versionInfo; } int sepPos = msgData.indexOf('!'); versionInfo.timestamp = QString(msgData.left(sepPos)).toInt(); versionInfo.versionString = msgData.mid(sepPos+1); qDebug() << "timestamp:"<<versionInfo.timestamp << ", str:"<<versionInfo.versionString; return versionInfo; }
bool RippleAddress::verifySignature(uint256 const& hash, Blob const& vchSig) const { if (vchData.size() != crypto_sign_PUBLICKEYBYTES || vchSig.size () != crypto_sign_BYTES) throw std::runtime_error("bad inputs to verifySignature"); bool verified = crypto_sign_verify_detached(vchSig.data(), hash.data(), hash.bytes, vchData.data()) == 0; bool canonical = signatureIsCanonical (vchSig); return verified && canonical; }
bool AutoUpdater::isUpToDate(AutoUpdater::UpdateFileMeta fileMeta) { QString appDir = qApp->applicationDirPath(); QFile file(appDir+QDir::separator()+fileMeta.installpath); if (!file.open(QIODevice::ReadOnly)) return false; // If the data we have is corrupted or old, mark it for update QByteArray data = file.readAll(); if (crypto_sign_verify_detached(fileMeta.sig, (unsigned char*)data.data(), data.size(), key) != 0) return false; return true; }
int crypto_sign_open(unsigned char *m, unsigned long long *mlen, const unsigned char *sm, unsigned long long smlen, const unsigned char *pk) { if (smlen < 64 || smlen > SIZE_MAX) { goto badsig; } if (crypto_sign_verify_detached(sm, sm + 64, smlen - 64, pk) != 0) { memset(m, 0, smlen - 64); goto badsig; } *mlen = smlen - 64; memmove(m, sm + 64, *mlen); return 0; badsig: *mlen = 0; return -1; }
bool AutoUpdater::downloadUpdate() { // Updates only for supported platforms if (platform.isEmpty()) return false; // Get a list of files to update QByteArray newFlistData = getUpdateFlist(); QList<UpdateFileMeta> newFlist = parseFlist(newFlistData); QList<UpdateFileMeta> diff = genUpdateDiff(newFlist); if (abortFlag) return false; qDebug() << "AutoUpdater: Need to update "<<diff.size()<<" files"; // Create an empty directory to download updates into QString updateDirStr = Settings::getInstance().getSettingsDirPath() + "/update/"; QDir updateDir(updateDirStr); if (updateDir.exists()) updateDir.removeRecursively(); QDir().mkdir(updateDirStr); updateDir = QDir(updateDirStr); if (!updateDir.exists()) { qWarning() << "AutoUpdater::downloadUpdate: Can't create update directory, aborting..."; return false; } // Write the new flist for the updater QFile newFlistFile(updateDirStr+"flist"); if (!newFlistFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { qWarning() << "AutoUpdater::downloadUpdate: Can't save new flist file, aborting..."; return false; } newFlistFile.write(newFlistData); newFlistFile.close(); // Download and write each new file for (UpdateFileMeta fileMeta : diff) { if (abortFlag) return false; qDebug() << "AutoUpdater: Downloading '"+fileMeta.installpath+"' ..."; // Create subdirs if necessary QString fileDirStr{QFileInfo(updateDirStr+fileMeta.installpath).absolutePath()}; if (!QDir(fileDirStr).exists()) QDir().mkpath(fileDirStr); // Download UpdateFile file = getUpdateFile(fileMeta); if (abortFlag) return false; if (file.data.isNull()) { qWarning() << "AutoUpdater::downloadUpdate: Error downloading a file, aborting..."; return false; } // Check signature if (crypto_sign_verify_detached(file.metadata.sig, (unsigned char*)file.data.data(), file.data.size(), key) != 0) { qCritical() << "AutoUpdater: downloadUpdate: RECEIVED FORGED FILE, aborting..."; return false; } // Save QFile fileFile(updateDirStr+fileMeta.installpath); if (!fileFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { qWarning() << "AutoUpdater::downloadUpdate: Can't save new update file, aborting..."; return false; } fileFile.write(file.data); fileFile.close(); } return true; }
void Widget::update() { /// 1. Find and parse the update (0-5%) // Check that the dir exists QString updateDirStr = getSettingsDirPath()+"/update/"; QDir updateDir(updateDirStr); if (!updateDir.exists()) fatalError(tr("No update found.")); // Check that we have a flist and that every file on the diff exists QFile updateFlistFile(updateDirStr+"flist"); if (!updateFlistFile.open(QIODevice::ReadOnly)) fatalError(tr("The update is incomplete.")); QByteArray updateFlistData = updateFlistFile.readAll(); updateFlistFile.close(); setProgress(1); QList<UpdateFileMeta> updateFlist = parseFlist(updateFlistData); setProgress(2); QList<UpdateFileMeta> diff = genUpdateDiff(updateFlist); setProgress(4); for (UpdateFileMeta fileMeta : diff) if (!QFile::exists(updateDirStr+fileMeta.installpath)) fatalError(tr("The update is incomplete.")); if (diff.size() == 0) fatalError(tr("The diff list is empty.")); setProgress(5); /// 2. Check the update (5-50%) float checkProgressStep = 45.0/(float)diff.size(); float checkProgress = 5; for (UpdateFileMeta fileMeta : diff) { UpdateFile file; file.metadata = fileMeta; QFile fileFile(updateDirStr+fileMeta.installpath); if (!fileFile.open(QIODevice::ReadOnly)) fatalError(tr("Update files are unreadable.")); file.data = fileFile.readAll(); fileFile.close(); if (file.data.size() != (int)fileMeta.size) fatalError(tr("Update files are corrupted.")); if (crypto_sign_verify_detached(file.metadata.sig, (unsigned char*)file.data.data(), file.data.size(), key) != 0) fatalError(tr("Update files are corrupted.")); checkProgress += checkProgressStep; setProgress(checkProgress); } setProgress(50); /// 3. Install the update (50-95%) float installProgressStep = 45.0/(float)diff.size(); float installProgress = 50; for (UpdateFileMeta fileMeta : diff) { // Backup old files if (QFile(fileMeta.installpath).exists()) { QFile(fileMeta.installpath+".bak").remove(); QFile(fileMeta.installpath).rename(fileMeta.installpath+".bak"); backups.append(fileMeta.installpath); } // Install new ones QDir().mkpath(QFileInfo(fileMeta.installpath).absolutePath()); QFile fileFile(updateDirStr+fileMeta.installpath); if (!fileFile.copy(fileMeta.installpath)) fatalError(tr("Unable to copy the update's files from ")+(updateDirStr+fileMeta.installpath)+" to "+fileMeta.installpath); installProgress += installProgressStep; setProgress(installProgress); } setProgress(95); /// 4. Delete the update and backups (95-100%) deleteUpdate(); setProgress(97); deleteBackups(); setProgress(100); /// 5. Start qTox and exit startQToxAndExit(); }
static int verify(PubkeyStruct *pubkey_struct, const char *message_file, const char *sig_file, int quiet, int output) { char trusted_comment[TRUSTEDCOMMENTMAXBYTES]; unsigned char global_sig[crypto_sign_BYTES]; FILE *info_fp = stdout; unsigned char *sig_and_trusted_comment; SigStruct *sig_struct; unsigned char *message; size_t message_len; size_t trusted_comment_len; int hashed; if (output != 0) { info_fp = stderr; } sig_struct = sig_load(sig_file, global_sig, &hashed, trusted_comment, sizeof trusted_comment); message = message_load(&message_len, message_file, hashed); if (memcmp(sig_struct->keynum, pubkey_struct->keynum_pk.keynum, sizeof sig_struct->keynum) != 0) { fprintf(stderr, "Signature key id in %s is %" PRIX64 "\n" "but the key id in the public key is %" PRIX64 "\n", sig_file, le64_load(sig_struct->keynum), le64_load(pubkey_struct->keynum_pk.keynum)); exit(1); } if (crypto_sign_verify_detached(sig_struct->sig, message, message_len, pubkey_struct->keynum_pk.pk) != 0) { if (quiet == 0) { fprintf(stderr, "Signature verification failed\n"); } exit(1); } free(message); trusted_comment_len = strlen(trusted_comment); sig_and_trusted_comment = xmalloc((sizeof sig_struct->sig) + trusted_comment_len); memcpy(sig_and_trusted_comment, sig_struct->sig, sizeof sig_struct->sig); memcpy(sig_and_trusted_comment + sizeof sig_struct->sig, trusted_comment, trusted_comment_len); if (crypto_sign_verify_detached(global_sig, sig_and_trusted_comment, (sizeof sig_struct->sig) + trusted_comment_len, pubkey_struct->keynum_pk.pk) != 0) { if (quiet == 0) { fprintf(stderr, "Comment signature verification failed\n"); } exit(1); } free(sig_and_trusted_comment); free(pubkey_struct); free(sig_struct); if (quiet == 0) { fprintf(info_fp, "Signature and comment signature verified\n" "Trusted comment: %s\n", trusted_comment); } else if (quiet == 2) { fprintf(info_fp, "%s\n", trusted_comment); } if (output != 0 && output_file(message_file) != 0) { exit(2); } return 0; }
std::string verifyne::Api::provider_key(void) { /* HTTP query */ verifyne::HttpInvoker hi; std::map<std::string, std::string> params; std::string url = API_BASE_URL + "/provider-key"; std::string resp = hi.GET(url, params); ApiResponse *ar = new ApiResponse(resp); std::string pkey_b64 = (*ar->content)["pkey"].asString(); std::string psig_b64 = (*ar->content)["psig"].asString(); delete ar; /* Base64 decode - CA signature */ std::string psig = b64decode(psig_b64); /* Verify CA signature */ const unsigned char ca_key[] = { 0x8B,0xB7,0x5B,0x5A,0xF9,0x45,0x74,0x7C, 0x2F,0x89,0x45,0xDA,0xBF,0xB3,0x75,0x2F, 0x0A,0x22,0xF8,0x33,0x89,0x0C,0x6F,0x52, 0xB8,0x51,0xCD,0xC0,0xFF,0xC0,0x52,0x35 }; if(0 != crypto_sign_verify_detached((unsigned char *)psig.c_str(), (unsigned char *)pkey_b64.c_str(), pkey_b64.length(), ca_key)) { throw std::runtime_error("Provider key signature verification failed"); } /* Base64 decode - Public Key data */ std::string pkey = b64decode(pkey_b64); /* Split on ':' */ std::size_t pos = pkey.find(":"); if(pos == std::string::npos || pos < 2 || pos > (pkey.length() - 2)) { throw std::runtime_error("Invalid provider key"); } std::string algo = pkey.substr(0, pos); std::string key_b64 = pkey.substr(pos+1, std::string::npos); /* Verify */ if(algo != "ed25519") { throw std::runtime_error("Unsupported algorithm: " + algo); } /* Base64 decode - Provider key */ std::string key = b64decode(key_b64); return key; }
bool AutoUpdater::downloadUpdate() { // Updates only for supported platforms if (platform.isEmpty()) return false; bool expectFalse = false; if (!isDownloadingUpdate.compare_exchange_strong(expectFalse,true)) return false; // Get a list of files to update QByteArray newFlistData = getUpdateFlist(); QList<UpdateFileMeta> newFlist = parseFlist(newFlistData); QList<UpdateFileMeta> diff = genUpdateDiff(newFlist); // Progress progressValue = 0; if (abortFlag) { isDownloadingUpdate = false; return false; } qDebug() << "Need to update" << diff.size() << "files"; // Create an empty directory to download updates into QString updateDirStr = Settings::getInstance().getSettingsDirPath() + "/update/"; QDir updateDir(updateDirStr); if (!updateDir.exists()) QDir().mkdir(updateDirStr); updateDir = QDir(updateDirStr); if (!updateDir.exists()) { qWarning() << "downloadUpdate: Can't create update directory, aborting..."; isDownloadingUpdate = false; return false; } // Write the new flist for the updater QFile newFlistFile(updateDirStr+"flist"); if (!newFlistFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { qWarning() << "downloadUpdate: Can't save new flist file, aborting..."; isDownloadingUpdate = false; return false; } newFlistFile.write(newFlistData); newFlistFile.close(); progressValue = 1; // Download and write each new file for (UpdateFileMeta fileMeta : diff) { float initialProgress = progressValue, step = 99./diff.size(); auto stepProgressCallback = [&](int current, int total) { progressValue = initialProgress + step * (float)current/total; }; if (abortFlag) { isDownloadingUpdate = false; return false; } // Skip files we already have QFile fileFile(updateDirStr+fileMeta.installpath); if (fileFile.open(QIODevice::ReadOnly) && fileFile.size() == (qint64)fileMeta.size) { qDebug() << "Skipping already downloaded file '" + fileMeta.installpath+ "'"; fileFile.close(); progressValue = initialProgress + step; continue; } qDebug() << "Downloading '" + fileMeta.installpath + "' ..."; // Create subdirs if necessary QString fileDirStr{QFileInfo(updateDirStr+fileMeta.installpath).absolutePath()}; if (!QDir(fileDirStr).exists()) QDir().mkpath(fileDirStr); // Download UpdateFile file = getUpdateFile(fileMeta, stepProgressCallback); if (abortFlag) goto fail; if (file.data.isNull()) { qCritical() << "downloadUpdate: Error downloading a file, aborting..."; goto fail; } // Check signature if (crypto_sign_verify_detached(file.metadata.sig, (unsigned char*)file.data.data(), file.data.size(), key) != 0) { qCritical() << "downloadUpdate: RECEIVED FORGED FILE, aborting..."; goto fail; } // Save if (!fileFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { qCritical() << "downloadUpdate: Can't save new update file, aborting..."; goto fail; } fileFile.write(file.data); fileFile.close(); progressValue = initialProgress + step; } qDebug() << "downloadUpdate: The update is ready, it'll be installed on the next restart"; isDownloadingUpdate = false; progressValue = 100; return true; fail: isDownloadingUpdate = false; progressValue = 0; setProgressVersion(""); return false; }
void run() { testBase58(RippleAddress::VER_NODE_PUBLIC, 'n'); testBase58(RippleAddress::VER_NODE_PRIVATE, 'h'); testBase58(RippleAddress::VER_ACCOUNT_PUBLIC, 'p'); testBase58(RippleAddress::VER_ACCOUNT_PRIVATE, 'h'); testBase58(RippleAddress::VER_SEED, 's'); // check pass phrase std::string strPass("paysharesmaster"); std::string strBase58Seed("s3q5ZGX2ScQK2rJ4JATp7rND6X5npG3De8jMbB7tuvm2HAVHcCN"); std::string strBase58NodePublic("nfbbWHgJqzqfH1cfRpMdPRkJ19cxTsdHkBtz1SLJJQfyf9Ax6vd"); std::string strBase58AccountPublic("pGreoXKYybde1keKZwDCv8m5V1kT6JH37pgnTUVzdMkdygTixG8"); AccountPrivateKey accountPrivateKey; NodePrivateKey nodePrivateKey; accountPrivateKey.fromPassPhrase(strPass); nodePrivateKey.fromPassPhrase(strPass); expect(accountPrivateKey.base58Seed() == "s3q5ZGX2ScQK2rJ4JATp7rND6X5npG3De8jMbB7tuvm2HAVHcCN", accountPrivateKey.base58Seed()); expect(accountPrivateKey.base58AccountID() == "ganVp9o5emfzpwrG5QVUXqMv8AgLcdvySb", accountPrivateKey.base58AccountID()); expect(accountPrivateKey.base58PublicKey() == strBase58AccountPublic, accountPrivateKey.base58PublicKey()); expect(nodePrivateKey.base58PublicKey() == strBase58NodePublic, nodePrivateKey.base58PublicKey()); Blob sig; uint256 message; accountPrivateKey.sign(message, sig); PaysharesPublicKey publicKey(accountPrivateKey.getPublicKey(), RippleAddress::VER_NODE_PUBLIC); expect(publicKey.verifySignature(message, sig), "Signature didn't verify"); expect(publicKey.getAccountID() == accountPrivateKey.getAccountID(), "Account Id's mis match"); expect(publicKey.base58AccountID() == accountPrivateKey.base58AccountID(), "Account Id's mis match"); Blob nonCanonicalSig(sig); add_l(nonCanonicalSig.data() + 32); expect(sig != nonCanonicalSig, "Non-canonical signature equal to canonical signature"); expect(crypto_sign_verify_detached(nonCanonicalSig.data(), message.data(), message.bytes, publicKey.vchData.data()) == 0, "Non-canonical signature didn't verify (ignoring canonical-ness)"); expect(!publicKey.verifySignature(message, nonCanonicalSig), "Non-canonical signature verified"); AccountPrivateKey privateKey2; privateKey2.fromString(strBase58Seed); // key from base58seed expect(privateKey2.base58Seed() == "s3q5ZGX2ScQK2rJ4JATp7rND6X5npG3De8jMbB7tuvm2HAVHcCN", privateKey2.base58Seed()); expect(privateKey2.base58AccountID() == "ganVp9o5emfzpwrG5QVUXqMv8AgLcdvySb", privateKey2.base58AccountID()); expect(privateKey2.base58PublicKey() == strBase58AccountPublic, privateKey2.base58PublicKey()); privateKey2.sign(message, sig); expect(publicKey.verifySignature(message, sig), "Signature didn't verify"); // check with the previous pubkey // check random /// ======= OLD ==== // Construct a seed. RippleAddress naSeed; expect(naSeed.setSeedGeneric("masterpassphrase")); expect(naSeed.humanSeed() == "s3q5ZGX2ScQK2rJ4JATp7rND6X5npG3De8jMbB7tuvm2HAVHcCN", naSeed.humanSeed()); // Create node public/private key pair RippleAddress naNodePublic = RippleAddress::createNodePublic(naSeed); expect(naNodePublic.verifySignature(message, sig), "Signature didn't verify"); expect(naNodePublic.humanNodePublic() == strBase58NodePublic, naNodePublic.humanNodePublic()); naNodePublic.setNodePublic(strBase58NodePublic); expect(naNodePublic.verifySignature(message, sig), "Signature didn't verify"); expect(naNodePublic.humanNodePublic() == strBase58NodePublic, naNodePublic.humanNodePublic()); RippleAddress naAccountPublic = RippleAddress::createAccountPublic(naSeed); expect(naAccountPublic.humanAccountID() == "ganVp9o5emfzpwrG5QVUXqMv8AgLcdvySb", naAccountPublic.humanAccountID()); expect(naAccountPublic.verifySignature(message, sig), "Signature didn't verify"); expect(naAccountPublic.humanAccountPublic() == strBase58AccountPublic, naAccountPublic.humanAccountPublic()); naAccountPublic.setAccountPublic(strBase58AccountPublic); expect(naAccountPublic.humanAccountID() == "ganVp9o5emfzpwrG5QVUXqMv8AgLcdvySb", naAccountPublic.humanAccountID()); expect(naAccountPublic.verifySignature(message, sig), "Signature didn't verify"); expect(naAccountPublic.humanAccountPublic() == strBase58AccountPublic, naAccountPublic.humanAccountPublic()); Blob rippleSig; RippleAddress naAccountPrivate = RippleAddress::createAccountPrivate(naSeed); naAccountPrivate.sign(message, rippleSig); expect(rippleSig==sig, "Signature don't match"); RippleAddress naNodePrivate = RippleAddress::createNodePrivate(naSeed); naNodePrivate.sign(message, rippleSig); expect(rippleSig == sig, "Signature don't match"); std::string strPrivateKey("ssQMHypYAPSPgniSyvJQccuL1dJUbXJWVgAPV5QcAuBVEWsZTVQwffsnwTY6Mivoy3NRSVR28ZaCW74F67VSq4VRC4zY1XR"); expect(naNodePrivate.humanNodePrivate() == strPrivateKey, naNodePrivate.humanNodePrivate()); expect(naNodePrivate.setNodePrivate(strPrivateKey),"couldn't create private node"); expect(naNodePrivate.humanNodePrivate() == strPrivateKey, naNodePrivate.humanNodePrivate()); naNodePrivate.sign(message, rippleSig); expect(rippleSig == sig, "Signature don't match"); /* RippleAddress naNodePrivate = RippleAddress::createNodePrivate(naSeed); expect(naNodePrivate.humanNodePrivate() == "pnen77YEeUd4fFKG7iycBWcwKpTaeFRkW2WFostaATy1DSupwXe", naNodePrivate.humanNodePrivate()); // Check node signing. Blob vucTextSrc = strCopy("Hello, nurse!"); uint256 uHash = Serializer::getSHA512Half(vucTextSrc); Blob vucTextSig; naNodePrivate.signNodePrivate(uHash, vucTextSig); expect(naNodePublic.verifyNodePublic(uHash, vucTextSig, ECDSA::strict), "Verify failed."); */ }