summaryrefslogtreecommitdiffstats
path: root/tests/benchmarks/corelib/tools/qcryptographichash/tst_bench_qcryptographichash.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/benchmarks/corelib/tools/qcryptographichash/tst_bench_qcryptographichash.cpp')
-rw-r--r--tests/benchmarks/corelib/tools/qcryptographichash/tst_bench_qcryptographichash.cpp223
1 files changed, 223 insertions, 0 deletions
diff --git a/tests/benchmarks/corelib/tools/qcryptographichash/tst_bench_qcryptographichash.cpp b/tests/benchmarks/corelib/tools/qcryptographichash/tst_bench_qcryptographichash.cpp
new file mode 100644
index 0000000000..9f2d1c57f2
--- /dev/null
+++ b/tests/benchmarks/corelib/tools/qcryptographichash/tst_bench_qcryptographichash.cpp
@@ -0,0 +1,223 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2017 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QByteArray>
+#include <QCryptographicHash>
+#include <QFile>
+#include <QMetaEnum>
+#include <QMessageAuthenticationCode>
+#include <QRandomGenerator>
+#include <QString>
+#include <QTest>
+
+#include <qxpfunctional.h>
+#include <numeric>
+
+#include <time.h>
+
+class tst_QCryptographicHash : public QObject
+{
+ Q_OBJECT
+ QByteArray blockOfData;
+
+ using Algorithm = QCryptographicHash::Algorithm;
+
+public:
+ tst_QCryptographicHash();
+
+private Q_SLOTS:
+ void hash_data();
+ void hash();
+ void addData_data() { hash_data(); }
+ void addData();
+ void addDataChunked_data() { hash_data(); }
+ void addDataChunked();
+
+ // QMessageAuthenticationCode:
+ void hmac_hash_data() { hash_data(); }
+ void hmac_hash();
+ void hmac_addData_data() { hash_data(); }
+ void hmac_addData();
+ void hmac_setKey_data();
+ void hmac_setKey();
+};
+
+const int MaxBlockSize = 65536;
+
+static void for_each_algorithm(qxp::function_ref<void(QCryptographicHash::Algorithm, const char*) const> f)
+{
+ using A = QCryptographicHash::Algorithm;
+ static const auto metaEnum = QMetaEnum::fromType<A>();
+ for (int i = 0, value = metaEnum.value(i); value != -1; value = metaEnum.value(++i))
+ f(A(value), metaEnum.key(i));
+}
+
+tst_QCryptographicHash::tst_QCryptographicHash()
+ : blockOfData(MaxBlockSize, Qt::Uninitialized)
+{
+#ifdef Q_OS_UNIX
+ QFile urandom("/dev/urandom");
+ if (urandom.open(QIODevice::ReadOnly | QIODevice::Unbuffered)) {
+ QCOMPARE(urandom.read(blockOfData.data(), blockOfData.size()), qint64(MaxBlockSize));
+ } else
+#endif
+ {
+ for (int i = 0; i < MaxBlockSize; ++i)
+ blockOfData[i] = QRandomGenerator::global()->generate();
+ }
+}
+
+void tst_QCryptographicHash::hash_data()
+{
+ QTest::addColumn<Algorithm>("algo");
+ QTest::addColumn<QByteArray>("data");
+
+ static const int datasizes[] = { 0, 1, 64, 65, 512, 4095, 4096, 4097, 65536 };
+ for (uint i = 0; i < sizeof(datasizes)/sizeof(datasizes[0]); ++i) {
+ Q_ASSERT(datasizes[i] < MaxBlockSize);
+ QByteArray data = QByteArray::fromRawData(blockOfData.constData(), datasizes[i]);
+
+ for_each_algorithm([&] (Algorithm algo, const char *name) {
+ if (algo == Algorithm::NumAlgorithms)
+ return;
+ QTest::addRow("%s-%d", name, datasizes[i]) << algo << data;
+ });
+ }
+}
+
+#define SKIP_IF_NOT_SUPPORTED(algo) do { \
+ if (!QCryptographicHash::supportsAlgorithm(algo)) \
+ QSKIP("This algorithm is not supported in this configuration"); \
+ } while (false) \
+ /* end */
+
+void tst_QCryptographicHash::hash()
+{
+ QFETCH(const Algorithm, algo);
+ QFETCH(QByteArray, data);
+
+ SKIP_IF_NOT_SUPPORTED(algo);
+
+ QBENCHMARK {
+ [[maybe_unused]]
+ auto r = QCryptographicHash::hash(data, algo);
+ }
+}
+
+void tst_QCryptographicHash::addData()
+{
+ QFETCH(const Algorithm, algo);
+ QFETCH(QByteArray, data);
+
+ SKIP_IF_NOT_SUPPORTED(algo);
+
+ QCryptographicHash hash(algo);
+ QBENCHMARK {
+ hash.reset();
+ hash.addData(data);
+ [[maybe_unused]]
+ auto r = hash.resultView();
+ }
+}
+
+void tst_QCryptographicHash::addDataChunked()
+{
+ QFETCH(const Algorithm, algo);
+ QFETCH(QByteArray, data);
+
+ SKIP_IF_NOT_SUPPORTED(algo);
+
+ QCryptographicHash hash(algo);
+ QBENCHMARK {
+ hash.reset();
+
+ // add the data in chunks of 64 bytes
+ for (int i = 0; i < data.size() / 64; ++i)
+ hash.addData({data.constData() + 64 * i, 64});
+ hash.addData({data.constData() + data.size() / 64 * 64, data.size() % 64});
+
+ [[maybe_unused]]
+ auto r = hash.resultView();
+ }
+}
+
+static QByteArray hmacKey() {
+ static QByteArray key = [] {
+ QByteArray result(277, Qt::Uninitialized);
+ std::iota(result.begin(), result.end(), uchar(0)); // uchar so wraps after UCHAR_MAX
+ return result;
+ }();
+ return key;
+}
+
+void tst_QCryptographicHash::hmac_hash()
+{
+ QFETCH(const Algorithm, algo);
+ QFETCH(const QByteArray, data);
+
+ SKIP_IF_NOT_SUPPORTED(algo);
+
+ const auto key = hmacKey();
+ QBENCHMARK {
+ [[maybe_unused]]
+ auto r = QMessageAuthenticationCode::hash(data, key, algo);
+ }
+}
+
+void tst_QCryptographicHash::hmac_addData()
+{
+ QFETCH(const Algorithm, algo);
+ QFETCH(const QByteArray, data);
+
+ SKIP_IF_NOT_SUPPORTED(algo);
+
+ const auto key = hmacKey();
+ QMessageAuthenticationCode mac(algo, key);
+ QBENCHMARK {
+ mac.reset();
+ mac.addData(data);
+ [[maybe_unused]]
+ auto r = mac.resultView();
+ }
+}
+
+void tst_QCryptographicHash::hmac_setKey_data()
+{
+ QTest::addColumn<Algorithm>("algo");
+ for_each_algorithm([] (Algorithm algo, const char *name) {
+ if (algo == Algorithm::NumAlgorithms)
+ return;
+ QTest::addRow("%s", name) << algo;
+ });
+}
+
+void tst_QCryptographicHash::hmac_setKey()
+{
+ QFETCH(const Algorithm, algo);
+
+ SKIP_IF_NOT_SUPPORTED(algo);
+
+ const QByteArrayList keys = [] {
+ QByteArrayList result;
+ const auto fullKey = hmacKey();
+ result.reserve(fullKey.size());
+ for (auto i = fullKey.size(); i > 0; --i)
+ result.push_back(fullKey.sliced(i));
+ return result;
+ }();
+
+ QMessageAuthenticationCode mac(algo);
+ QBENCHMARK {
+ for (const auto &key : keys) {
+ mac.setKey(key);
+ mac.addData("abc", 3); // avoid lazy setKey()
+ }
+ }
+}
+
+#undef SKIP_IF_NOT_SUPPORTED
+
+QTEST_APPLESS_MAIN(tst_QCryptographicHash)
+
+#include "tst_bench_qcryptographichash.moc"